diff --git a/README.md b/README.md new file mode 100644 index 0000000..e8ff0a5 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +projectapproval module +====================== + +The projectapproval module is used for the registration and approval of project and bachelor theses. + +Installation +------------ +1. Load the module directory into your "mod" subdirectory. +2. Visit your admin page to create all of the necessary data tables + +License +------- +Licensed under the [GNU GPL License v3](http://www.gnu.org/copyleft/gpl.html). diff --git a/backup/moodle2/backup_projectapproval_activity_task.class.php b/backup/moodle2/backup_projectapproval_activity_task.class.php new file mode 100644 index 0000000..3c89366 --- /dev/null +++ b/backup/moodle2/backup_projectapproval_activity_task.class.php @@ -0,0 +1,70 @@ +. + +/** + * Defines backup_projectapproval_activity_task class + * + * @package mod_projectapproval + * @category backup + * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +require_once($CFG->dirroot . '/mod/projectapproval/backup/moodle2/backup_projectapproval_stepslib.php'); + +/** + * Provides the steps to perform one complete backup of the Page instance + */ +class backup_projectapproval_activity_task extends backup_activity_task { + + /** + * Specific settings for this activity + */ + protected function define_my_settings() { + } + + /** + * Defines a backup step to store the instance data in the projectapproval.xml file + */ + protected function define_my_steps() { + $this->add_step(new backup_projectapproval_activity_structure_step('projectapproval_structure', 'projectapproval.xml')); + } + + /** + * Encodes URLs to the index.php and view.php scripts + * + * @param string $content some HTML text that eventually contains URLs to the activity instance scripts + * @return string the content with the URLs encoded + */ + static public function encode_content_links($content) { + global $CFG; + + $base = preg_quote($CFG->wwwroot,"/"); + + // Link to the list of projectapprovals + $search="/(".$base."\/mod\/projectapproval\/index.php\?id\=)([0-9]+)/"; + $content= preg_replace($search, '$@PAGEINDEX*$2@$', $content); + + // Link to projectapproval view by moduleid + $search="/(".$base."\/mod\/projectapproval\/view.php\?id\=)([0-9]+)/"; + $content= preg_replace($search, '$@PAGEVIEWBYID*$2@$', $content); + + return $content; + } +} diff --git a/backup/moodle2/backup_projectapproval_stepslib.php b/backup/moodle2/backup_projectapproval_stepslib.php new file mode 100644 index 0000000..4ca2ec8 --- /dev/null +++ b/backup/moodle2/backup_projectapproval_stepslib.php @@ -0,0 +1,61 @@ +. + +/** + * @package mod_projectapproval + * @category backup + * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +/** + * Define all the backup steps that will be used by the backup_projectapproval_activity_task + */ + +/** + * Define the complete projectapproval structure for backup, with file and id annotations + */ +class backup_projectapproval_activity_structure_step extends backup_activity_structure_step { + + protected function define_structure() { + + // Define each element separated + $projectapproval = new backup_nested_element('projectapproval', array('id'), array( + 'course', 'name', 'intro', 'introformat', 'manager', 'locknote', 'timemodified')); + $projectapp_project = new backup_nested_element('projectapp_project', array('id'), array( + 'cmid', 'userid', 'company', 'company_attendant', 'company_email', 'attendant', 'title', + 'content', 'comment', 'status', 'locknote', 'timemodified', 'timecreated')); + + // Build the tree + $projectapproval->add_child($projectapp_project); + + // Define sources + $projectapproval->set_source_table('projectapproval', array('id' => backup::VAR_ACTIVITYID)); + $projectapp_project->set_source_table('projectapp_project', array('cmid' => backup::VAR_MODID)); + + // Define id annotations + // (none) + + // Define file annotations + $projectapproval->annotate_files('mod_projectapproval', 'intro', null); // This file areas haven't itemid + + // Return the root element (projectapproval), wrapped into standard activity structure + return $this->prepare_activity_structure($projectapproval); + } +} diff --git a/backup/moodle2/restore_projectapproval_activity_task.class.php b/backup/moodle2/restore_projectapproval_activity_task.class.php new file mode 100644 index 0000000..3071ddc --- /dev/null +++ b/backup/moodle2/restore_projectapproval_activity_task.class.php @@ -0,0 +1,100 @@ +. + +/** + * @package mod_projectapproval + * @category backup + * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/mod/projectapproval/backup/moodle2/restore_projectapproval_stepslib.php'); // Because it exists (must) + +/** + * projectapproval restore task that provides all the settings and steps to perform one + * complete restore of the activity + */ +class restore_projectapproval_activity_task extends restore_activity_task { + + /** + * Define (add) particular settings this activity can have + */ + protected function define_my_settings() { + // No particular settings for this activity + } + + /** + * Define (add) particular steps this activity can have + */ + protected function define_my_steps() { + // label only has one structure step + $this->add_step(new restore_projectapproval_activity_structure_step('projectapproval_structure', 'projectapproval.xml')); + } + + /** + * Define the contents in the activity that must be + * processed by the link decoder + */ + static public function define_decode_contents() { + $contents = array(); + $contents[] = new restore_decode_content('projectapproval', array('intro'), 'projectapproval'); + return $contents; + } + + /** + * Define the decoding rules for links belonging + * to the activity to be executed by the link decoder + */ + static public function define_decode_rules() { + $rules = array(); + $rules[] = new restore_decode_rule('PAGEVIEWBYID', '/mod/projectapproval/view.php?id=$1', 'course_module'); + $rules[] = new restore_decode_rule('PAGEINDEX', '/mod/projectapproval/index.php?id=$1', 'course'); + return $rules; + } + + /** + * Define the restore log rules that will be applied + * by the {@link restore_logs_processor} when restoring + * projectapproval logs. It must return one array + * of {@link restore_log_rule} objects + */ + static public function define_restore_log_rules() { + $rules = array(); + $rules[] = new restore_log_rule('projectapproval', 'add', 'view.php?id={course_module}', '{projectapproval}'); + $rules[] = new restore_log_rule('projectapproval', 'update', 'view.php?id={course_module}', '{projectapproval}'); + $rules[] = new restore_log_rule('projectapproval', 'view', 'view.php?id={course_module}', '{projectapproval}'); + return $rules; + } + + /** + * Define the restore log rules that will be applied + * by the {@link restore_logs_processor} when restoring + * course logs. It must return one array + * of {@link restore_log_rule} objects + * + * Note this rules are applied when restoring course logs + * by the restore final task, but are defined here at + * activity level. All them are rules not linked to any module instance (cmid = 0) + */ + static public function define_restore_log_rules_for_course() { + $rules = array(); + $rules[] = new restore_log_rule('projectapproval', 'view all', 'index.php?id={course}', null); + return $rules; + } +} diff --git a/backup/moodle2/restore_projectapproval_stepslib.php b/backup/moodle2/restore_projectapproval_stepslib.php new file mode 100644 index 0000000..b2e3dbc --- /dev/null +++ b/backup/moodle2/restore_projectapproval_stepslib.php @@ -0,0 +1,81 @@ +. + +/** + * @package mod_projectapproval + * @category backup + * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Define all the restore steps that will be used by the restore_projectapproval_activity_task + */ + +/** + * Structure step to restore one projectapproval activity + */ +class restore_projectapproval_activity_structure_step extends restore_activity_structure_step { + + protected function define_structure() { + $paths = array(); + $paths[] = new restore_path_element('projectapproval', '/activity/projectapproval'); + $paths[] = new restore_path_element('projectapp_project', '/activity/projectapproval/projectapp_project'); + + // Return the paths wrapped into standard activity structure + return $this->prepare_activity_structure($paths); + } + + protected function process_projectapproval($data) { + global $DB; + + $data = (object)$data; + $data->course = $this->get_courseid(); + + // Insert the projectapproval record. + $newitemid = $DB->insert_record('projectapproval', $data); + // Immediately after inserting "activity" record, call this. + $this->apply_activity_instance($newitemid); + } + + protected function process_projectapp_project($data) { + global $DB; + + // To know if we are including userinfo. + $userinfo = $this->get_setting_value('userinfo'); + if (!$userinfo) { + retrun; + } + $data = (object)$data; + // Set new cmid. + $data->cmid = $this->task->get_moduleid(); + if (!$this->task->is_samesite()) { + // Set new userid. + $data->userid = $this->get_mappingid('user', $data->userid); + } + + // Insert the projectapp_project record. + $newitemid = $DB->insert_record('projectapp_project', $data); + // Immediately after inserting "activity" record, call this. + $this->apply_activity_instance($newitemid); + } + + protected function after_execute() { + // Add projectapproval related files, no need to match by itemname (just internally handled context). + $this->add_related_files('mod_projectapproval', 'intro', null); + } +} diff --git a/classes/event/course_module_viewed.php b/classes/event/course_module_viewed.php new file mode 100644 index 0000000..6ca2861 --- /dev/null +++ b/classes/event/course_module_viewed.php @@ -0,0 +1,48 @@ +. + +/** + * The mod_projectapproval course module viewed event. + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_projectapproval\event; +defined('MOODLE_INTERNAL') || die(); + +/** + * The mod_projectapproval course module viewed event class. + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class course_module_viewed extends \core\event\course_module_viewed { + + /** + * Init method. + */ + protected function init() { + $this->data['crud'] = 'r'; + $this->data['edulevel'] = self::LEVEL_PARTICIPATING; + $this->data['objecttable'] = 'projectapproval'; + } + + public static function get_objectid_mapping() { + return array('db' => 'projectapproval', 'restore' => 'projectapproval'); + } +} + diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php new file mode 100644 index 0000000..6a800b6 --- /dev/null +++ b/classes/privacy/provider.php @@ -0,0 +1,214 @@ +. + +/** + * Privacy Subsystem implementation for mod_projectapproval. + * + * @package mod_projectapproval + * @copyright 2022 eLeDia + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_projectapproval\privacy; + +defined('MOODLE_INTERNAL') || die(); + +use \context; +use \core_privacy\local\request\approved_contextlist; +use \core_privacy\local\request\writer; +use \core_privacy\local\metadata\collection; +use \core_privacy\local\request\userlist; +use \core_privacy\local\request\approved_userlist; +use core_privacy\local\request\contextlist; +use core_privacy\local\request\deletion_criteria; +use core_privacy\local\request\helper; + + +/** + * Privacy Subsystem implementation for mod_projectapproval. + * + * @copyright 2019 eLeDia + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements + // The mod_projectapproval stores user provided data. + \core_privacy\local\metadata\provider, + // The mod_projectapproval provides data directly to core. + \core_privacy\local\request\plugin\provider, + // The mod_projectapproval is capable of determining which users have data within it. + \core_privacy\local\request\core_userlist_provider { + + /** + * Returns information about how mod_projectapproval stores its data. + * + * @param collection $collection The initialised collection to add items to. + * + * @return collection A listing of user data stored through this system. + */ + public static function get_metadata(collection $collection): collection { + + $collection->add_database_table('projectapp_project', [ + 'cmid' => 'privacy:metadata:database:projectapp_project:cmid', + 'userid' => 'privacy:metadata:database:projectapp_project:userid', + 'company' => 'privacy:metadata:database:projectapp_project:company', + 'company_attendant' => 'privacy:metadata:database:projectapp_project:company_attendant', + 'company_email' => 'privacy:metadata:database:projectapp_project:company_email', + 'attendant' => 'privacy:metadata:database:projectapp_project:attendant', + 'title' => 'privacy:metadata:database:projectapp_project:title', + 'content' => 'privacy:metadata:database:projectapp_project:content', + 'comment' => 'privacy:metadata:database:projectapp_project:comment', + 'status' => 'privacy:metadata:database:projectapp_project:status', + 'locknote' => 'privacy:metadata:database:projectapp_project:locknote', + 'policy' => 'privacy:metadata:database:projectapp_project:policy', + 'timecreated' => 'privacy:metadata:database:projectapp_project:timecreated', + 'timemodified' => 'privacy:metadata:database:projectapp_project:timemodified', + ], 'privacy:metadata:database:projectapp_project'); + + return $collection; + } + + /** + * Get the list of contexts that contain user information for the specified user. + * + * @param int $userid The user to search. + * @return contextlist $contextlist The contextlist containing the list of contexts used in + * this plugin. + */ + public static function get_contexts_for_userid(int $userid): contextlist { + + // Fetch all projects. + $sql = "SELECT c.id + FROM {context} c + INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel + INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname + INNER JOIN {projectapproval} proj ON proj.id = cm.instance + INNER JOIN {projectapp_project} subs ON subs.cmid = cm.id + WHERE subs.userid = :userid"; + + $params = [ + 'modname' => 'projectapproval', + 'contextlevel' => CONTEXT_MODULE, + 'userid' => $userid, + ]; + $contextlist = new contextlist(); + $contextlist->add_from_sql($sql, $params); + + return $contextlist; + } + + /** + * Get the list of users within a specific context. + * + * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. + * @throws \dml_exception + */ + public static function get_users_in_context(userlist $userlist) { + global $DB; + $context = $userlist->get_context(); + if (!$context instanceof \context_module) { + return; + } + + // Fetch all users who have a project. + $sql = "SELECT projects.userid + FROM {projectapp_project} projects + WHERE cm.id = :cmid"; + $params = [ + 'cmid' => $context->instanceid + ]; + $userlist->add_from_sql('userid', $sql, $params); + } + + /** + * Export all user data for the specified user, in the specified contexts. + * + * @param approved_contextlist $contextlist The approved contexts to export information for. + * + * @throws \coding_exception + * @throws \dml_exception + */ + public static function export_user_data(approved_contextlist $contextlist) { + global $DB; + + if (empty($contextlist->count())) { + return; + } + $user = $contextlist->get_user(); + + // Get user records for table mod_projectapproval_table. + $userdata = $DB->get_records('projectapp_project', array('userid' => $user->id)); + foreach ($userdata as $data) { + unset($data->id);// Dont export the moodle internal id. + $context = \context_module::instance($data->cmid); + $contextdata = (object) array_merge((array) $context, (array) $data); + writer::with_context($context)->export_data([], $contextdata);//$data $subcontext + // Write module intro files. + helper::export_context_files($context, $user); + } + } + + /** + * Delete all data for all users in the specified context. + * + * @param context $context The specific context to delete data for. + * + * @throws \dml_exception + */ + public static function delete_data_for_all_users_in_context(\context $context) { + global $DB; + + if (!$context instanceof \context_user) { + return; + } + + $user = $DB->get_record('user', array('id' => $context->instanceid)); + $DB->delete_records('projectapp_project', array('userid' => $user->id)); + } + + /** + * Delete multiple users within a single context. + * + * @param approved_userlist $userlist The approved context and user information to delete information for. + * + * @throws \coding_exception + * @throws \dml_exception + */ + public static function delete_data_for_users(approved_userlist $userlist) { + global $DB; + + $userids = $userlist->get_userids(); + + foreach ($userids as $userid) { + $user = $DB->get_record('user', array('id' => $userid)); + $DB->delete_records('projectapp_project', array('userid' => $user->id)); + } + } + + /** + * Delete all user data for the specified user, in the specified contexts. + * + * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. + * + * @throws \coding_exception + * @throws \dml_exception + */ + public static function delete_data_for_user(approved_contextlist $contextlist) { + global $DB; + + $user = $contextlist->get_user(); + $DB->delete_records('projectapp_project', array('userid' => $user->id)); + } +} diff --git a/classes/util.php b/classes/util.php new file mode 100644 index 0000000..9681789 --- /dev/null +++ b/classes/util.php @@ -0,0 +1,247 @@ +. + +/** + * + * @package mod_projectapproval + * @author Benjamin Wolf + * @copyright 2022 eLeDia GmbH + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_projectapproval; +defined('MOODLE_INTERNAL') || die(); + +class util { + + /** + * Store the data of a project submission. + * + * @param object $formdata data from the mform. + * @throws \dml_exception + */ + public function save_new_project($formdata) { + global $DB, $USER; + + $project = $DB->record_exists('projectapp_project', array('cmid' => $formdata->cm, 'userid' => $USER->id)); + if ($project) { + // If new submission overwrite old entry. + $DB->delete_records('projectapp_project', array('cmid' => $formdata->cm, 'userid' => $USER->id)); + } + + $new_project = new \stdClass(); + $new_project->cmid = $formdata->cm; + $new_project->userid = $USER->id; + $new_project->company = $formdata->company; + $new_project->company_attendant = $formdata->company_attendant; + $new_project->company_email = $formdata->company_email; + $new_project->attendant = $formdata->attendant; + $new_project->title = $formdata->title; + $new_project->content = $formdata->content; + $new_project->status = 'open'; + if (!empty($formdata->locknote)) { + $new_project->locknote = $formdata->locknote; + } + $new_project->timemodified = time(); + $new_project->timecreated = time(); + return $DB->insert_record('projectapp_project', $new_project); + } + + /** + * Store the data of a project submission. + * + * @param object $formdata data from the mform. + * @throws \dml_exception + */ + public function save_edit_project($formdata) { + global $DB, $CFG; + + $project = $DB->get_record('projectapp_project', array('id' => $formdata->projectid)); + if (empty($project)) { + print_error('project_not_found', 'projectapproval', $CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$project->cmid, + null, 'Project record missing '.$formdata->project); + } + $project->attendant = $formdata->attendant; + $project->status = $formdata->status; + $project->comment = $formdata->comment; + $project->timemodified = time(); + + $DB->update_record('projectapp_project', $project); + } + + /** + * + * @param object $cm course module object. + * @return string + * @throws \dml_exception + * @throws \coding_exception + */ + public function get_student_view(object $cm) { + global $DB, $USER, $CFG; + + $content = ''; + // New project link. + $a = $CFG->httpswwwroot.'/mod/projectapproval/project_submit.php?cm='.$cm->id; + + $project = $DB->get_record('projectapp_project', array('cmid' => $cm->id, 'userid' => $USER->id)); + $instance = $DB->get_record('projectapproval', array('id' => $cm->instance)); + + // First show status. + if (!empty($project)) { + // Print saved data. + $content .= get_string('project_info_string', 'mod_projectapproval', $project); + // Add comment if any. + if (!empty($project->comment)) { + // Print comment if there is any. + $content .= '
'.get_string('comment_info_string', 'mod_projectapproval', $project->comment); + } + // Check status. + switch ($project->status) { + case 'open': + $content .= '

'.get_string('project_needs_validation', 'projectapproval', $instance->name); + // Add reset url. + $reset_url = $CFG->httpswwwroot.'/mod/projectapproval/project_reset.php?projectid='.$project->id; + $content .= '
'.get_string('reset_url', 'mod_projectapproval', $reset_url); + // Add storno url. + $storno_url = $CFG->httpswwwroot.'/mod/projectapproval/project_storno.php?projectid='.$project->id; + $content .= '
'.get_string('storno_url', 'mod_projectapproval', $storno_url); + break; + case 'accepted': + $content .= '

'.get_string('project_accepted', 'projectapproval', $instance->name); + break; + case 'denied': + $content .= '

'.get_string('project_denied', 'projectapproval', $instance->name); + $content .= '
'.get_string('project_edit', 'projectapproval', $a); + // Add storno url. + $storno_url = $CFG->httpswwwroot.'/mod/projectapproval/project_storno.php?projectid='.$project->id; + $content .= '
'.get_string('storno_url', 'mod_projectapproval', $storno_url); + break; + case 'callback': + $content .= '

'.get_string('project_callback', 'projectapproval', $instance->name); + $content .= '
'.get_string('project_edit', 'projectapproval', $a); + // Add storno url. + $storno_url = $CFG->httpswwwroot.'/mod/projectapproval/project_storno.php?projectid='.$project->id; + $content .= '
'.get_string('storno_url', 'mod_projectapproval', $storno_url); + break; + default: + $content .= '

'.get_string('project_edit', 'projectapproval', $a); + // Add storno url. + $storno_url = $CFG->httpswwwroot.'/mod/projectapproval/project_storno.php?projectid='.$project->id; + $content .= '
'.get_string('storno_url', 'mod_projectapproval', $storno_url); + } + } else { + // No submission yet, so only submission link here. + $content .= get_string('project_submit', 'projectapproval', $a); + } + return $content; + } + + /** + * + * @param object $cm course module object. + * @param object $instance module instance object. + * @return string + * @throws \dml_exception + * @throws \coding_exception + */ + public function get_manager_view(object $cm, $instance) { + global $DB, $CFG; + + $content = ''; + // Collect some data. + $projects = $DB->get_records('projectapp_project', array('cmid' => $cm->id)); + + // First show status. + if (!empty($projects)) { + $table = new \html_table(); + $table->head = array(get_string('username', 'projectapproval'), + get_string('title', 'projectapproval'), + get_string('locknote', 'projectapproval'), + get_string('project_status', 'projectapproval'), + get_string('attendant', 'projectapproval'), + ''); + foreach ($projects as $project) { + $a = $CFG->httpswwwroot.'/mod/projectapproval/project_edit.php?projectid='.$project->id; + + $user = $DB->get_record('user', array('id' => $project->userid)); + $username = $user->firstname.' '.$user->lastname; + $locknote_string = $project->locknote ? get_string('yes') : get_string('no'); + $table->data[] = array($username, $project->title, $locknote_string, + get_string($project->status, 'projectapproval'), + $project->attendant, + get_string('project_edit', 'projectapproval', $a)); + } + $content = \html_writer::table($table); + + $download_link = $CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cm->id.'&download=1'; + $content .= "
".get_string('project_download', 'projectapproval', $download_link); + } else { + $content .= get_string('project_empty', 'projectapproval'); + } + // Handle download action. + if (optional_param('download', null, PARAM_RAW)) { + $charset = get_config('mod_projectapproval', 'file_encoding'); + + // Strings for titles. + $titles = array('report_firstname', 'report_lastname', 'report_email', 'report_company', 'report_company_attendant', + 'report_company_email', 'report_attendant', 'report_title', 'report_content', 'report_comment', + 'report_status', 'report_restriction_notice', 'report_timemodified', 'report_timecreated'); + foreach ($titles as $key => $item) { + $item = get_string($item, 'projectapproval'); + $titles[$key] = \core_text::convert($item, 'utf-8', $charset); + } + + $lines = array($titles); + foreach ($projects as $project) { + $line = array(); + + // Resolve user data for export. + $user = $DB->get_record('user', array('id' => $project->userid)); + array_push($line, $user->firstname, $user->lastname, $user->email); + + // Add project infos. + array_push($line, $project->company, $project->company_attendant, $project->company_email, + $project->attendant, $project->title, $project->content, $project->comment, + $project->status); + $line[] = $project->locknote ? get_string('yes') : get_string('no'); + + // Reformat timestamps for export. + array_push($line, date('H:i:s d.m.Y', $project->timemodified), date('H:i:s d.m.Y', $project->timecreated)); + + // Convert to configured encoding for the export. + foreach ($line as $key => $item) { + $line[$key] = \core_text::convert($item, 'utf-8', $charset); + } + $lines[] = $line; + } + $this->array_to_csv_download($lines, clean_param($instance->name, PARAM_FILE).".csv", ";", '"', $charset); + } + return $content; + } + + function array_to_csv_download($array, $filename = "export.csv", $delimiter = ";", $enclosure = '"', $charset = 'UTF-8') { + // Clean output buffer. + ob_end_clean(); + header('Content-Type: application/csv charset='.$charset); + header('Content-Disposition: attachment; filename="'.$filename.'";'); + $f = fopen('php://output', 'w'); + foreach ($array as $line) { + fputcsv($f, (array) $line, $delimiter, $enclosure); + } + fclose($f); + exit(); + } +} diff --git a/db/access.php b/db/access.php new file mode 100644 index 0000000..7ec3de3 --- /dev/null +++ b/db/access.php @@ -0,0 +1,58 @@ +. + +/** + * projectapproval module capability definition + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +$capabilities = array( + 'mod/projectapproval:view' => array( + 'captype' => 'read', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'guest' => CAP_ALLOW, + 'student' => CAP_ALLOW, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ) + ), + 'mod/projectapproval:addinstance' => array( + 'riskbitmask' => RISK_XSS, + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + 'clonepermissionsfrom' => 'moodle/course:manageactivities' + ), + 'mod/projectapproval:manage_submissions' => array( + 'riskbitmask' => RISK_SPAM, + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ) + ), +); diff --git a/db/install.xml b/db/install.xml new file mode 100644 index 0000000..1c79058 --- /dev/null +++ b/db/install.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+
\ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..22201ec --- /dev/null +++ b/index.php @@ -0,0 +1,85 @@ +. + +/** + * List of all projectapproval in course + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); + +$id = required_param('id', PARAM_INT); // course id + +$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); + +require_course_login($course, true); +$PAGE->set_pagelayout('incourse'); + +$strprojectapproval = get_string('modulename', 'mod_projectapproval'); +$strprojectapproval = get_string('modulenameplural', 'mod_projectapproval'); +$strname = get_string('name'); +$strintro = get_string('moduleintro'); +$strlastmodified = get_string('lastmodified'); + +$PAGE->set_url('/mod/projectapproval/index.php', array('id' => $course->id)); +$PAGE->set_title($course->shortname.': '.$strprojectapproval); +$PAGE->set_heading($course->fullname); +$PAGE->navbar->add($strprojectapproval); +echo $OUTPUT->header(); +echo $OUTPUT->heading($strprojectapproval); +if (!$projectapproval = get_all_instances_in_course('projectapproval', $course)) { + notice(get_string('thereareno', 'moodle', $strprojectapproval), "$CFG->wwwroot/course/view.php?id=$course->id"); + exit; +} + +$usesections = course_format_uses_sections($course->format); +// What should be shown on course info page for this plugin type. +$table = new html_table(); +$table->attributes['class'] = 'generaltable mod_index'; + +if ($usesections) { + $strsectionname = get_string('sectionname', 'format_'.$course->format); + $table->head = array ($strsectionname, $strname, $strintro); + $table->align = array ('center', 'left', 'left'); +} else { + $table->head = array ($strlastmodified, $strname, $strintro); + $table->align = array ('left', 'left', 'left'); +} + +$modinfo = get_fast_modinfo($course); +$currentsection = ''; +foreach ($projectapproval as $projectapproval) { + $cm = $modinfo->cms[$projectapproval->coursemodule]; + if ($usesections) { + $printsection = get_section_name($course, $projectapproval->section); + } else { + $printsection = ''.userdate($projectapproval->timemodified).""; + } + + $class = $projectapproval->visible ? '' : 'class="dimmed"'; // hidden modules are dimmed + + $table->data[] = array ( + $printsection, + "id\">".format_string($projectapproval->name)."", + format_module_intro('projectapproval', $projectapproval, $cm->id)); +} + +echo html_writer::table($table); + +echo $OUTPUT->footer(); diff --git a/lang/de/projectapproval.php b/lang/de/projectapproval.php new file mode 100644 index 0000000..bd84b7a --- /dev/null +++ b/lang/de/projectapproval.php @@ -0,0 +1,166 @@ +. + +/** + * Strings for component 'projectapproval', language 'en' + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['attendant'] = 'Name Betreuer/in an der DHBW'; +$string['accepted'] = 'Akzeptiert'; + +$string['createprojectapproval'] = ''; +$string['company'] = 'Dualer Partner'; +$string['company_attendant'] = 'Name Betreuer/in beim Dualen Partner'; +$string['company_email'] = 'E-Mail-Adresse Betreuer/in beim Dualen Partner'; +$string['content'] = 'Erläuterung der Arbeit (Problemstellung / Zielsetzung)'; +$string['comment'] = 'Kommentar'; +$string['comment_info_string'] = 'Kommentar: {$a}'; +$string['callback'] = 'Rücksprache'; + +$string['denied'] = 'Ablehnen'; + +$string['edit_button'] = 'Status speichern'; +$string['email_submission_subject'] = 'Eine Anmeldung zu {$a->instancename} ist eingegangen. '; +$string['email_submission_message'] = 'Sehr geehrte Studiengangsleitung, + +Eine Anmeldung zu "{$a->instancename}" von "{$a->fullname}" mit dem Titel: + +"{$a->project_title}" + +ist eingegangen. + +Bitte melden Sie sich an der Lernplattform an und bestätigen bzw. lehnen die Anmeldung ab: +{$a->instancename}. + +Vielen Dank.'; +$string['email_accepted_subject'] = 'Ihre Anmeldung zu {$a->instancename} wurde angenommen.'; +$string['email_accepted_message'] = 'Sehr geehrte(r) Herr/Frau {$a->fullname}, + +Ihre Anmeldung zu "{$a->instancename}" mit dem Titel + + "{$a->project_title}" + +wurde angenommen. + +Mit freundlichen Grüßen + +Bitte auf diese automatisch generierte E-Mail nicht direkt antworten.'; +$string['email_denied_subject'] = 'Ihre Anmeldung zu {$a->instancename} wurde leider nicht angenommen'; +$string['email_denied_message'] = 'Sehr geehrte(r) Herr/Frau {$a->fullname}, + +Ihre Anmeldung zu "{$a->instancename}" wurde leider nicht angenommen. Bitte reichen Sie einen neuen Vorschlag ein. + +Mit freundlichen Grüßen'; +$string['email_callback_subject'] = 'Zu Ihrer Anmeldung zu "{$a->instancename}" bittet die Studiengangsleitung um Rücksprache'; +$string['email_callback_message'] = 'Sehr geehrte(r) Herr/Frau {$a->fullname}, + +zu Ihrer Anmeldung zu "{$a->instancename}" bittet die Studiengangsleitung um Rücksprache. + +Mit freundlichen Grüßen'; +$string['projectapproval:addinstance'] = 'Instanz anlegen'; +$string['projectapproval:manage_submissions'] = 'Anmeldungen verwalten'; +$string['projectapproval:view'] = 'Anmeldungen ansehen'; + +$string['file_encoding'] = 'Zeichencodierung der Export-Datei'; + +$string['header_submit_project'] = 'Angaben zu'; +$string['header_edit_project'] = 'Status der Anmeldung'; +$string['header_user_data'] = 'Beantragender Nutzer'; + +$string['locknote'] = 'Sperrvermerk'; +$string['locknote_use'] = 'Sperrvermerk verwenden'; + +$string['manager'] = 'Studiengangsleitung'; +$string['modulename'] = 'Projekt-Anmeldung'; +$string['modulenameplural'] = 'Projekt-Anmeldungen'; +$string['matr'] = 'Matrikelnummer'; + +$string['open'] = 'Offen'; + +$string['project_download'] = 'Anmeldungen herunterladen'; +$string['pluginname'] = 'Projekt Anmeldung'; +//$string['privacy:metadata'] = 'The Project submit plugin does not store any personal data.'; +$string['pluginadministration'] = 'Projekt-Anmeldung Modul Administration'; +$string['project_submit'] = 'Eine wissenschaftliche Arbeit anmelden'; +$string['project_needs_validation'] = 'Ihre Anmeldung zu "{$a}" wird zur Zeit geprüft.'; +$string['project_accepted'] = 'Ihre Anmeldung zu "{$a}" wurde angenommen.'; +$string['project_denied'] = 'Ihre Anmeldung zu "{$a}" wurde leider nicht angenommen. Bitte reichen Sie einen neuen Vorschlag ein.'; +$string['project_callback'] = 'Ihre Anmeldung zu "{$a}" wurde noch nicht akzeptiert und muss überarbeitet werden. Kontaktieren Sie ggf. die Studiengangsleitung.'; +$string['project_status'] = 'Status der Anmeldung'; +$string['project_edit'] = 'Anmeldung bearbeiten'; +$string['project_info_string'] = ' + + + + + + + + + + + + +
Dualer Partner:{$a->company}
Name Betreuer/in beim Dualen Partner:{$a->company_attendant}
E-Mail-Adresse Betreuer/in beim Dualen Partner: {$a->company_email}
Name Betreuer/in an DHBW: {$a->attendant}
Titel der Arbeit: {$a->title}
Erläuterung der Arbeit: {$a->content}
'; +$string['project_empty'] = 'Keine Anmeldungen eingegangen'; +$string['privacy:metadata:database:projectapp_project:cmid'] = 'Kurs Aktivitäts id'; +$string['privacy:metadata:database:projectapp_project:userid'] = 'Nutzer id'; +$string['privacy:metadata:database:projectapp_project:company'] = 'Dualer Partner'; +$string['privacy:metadata:database:projectapp_project:company_attendant'] = 'Name Betreuer/in beim Dualen Partner'; +$string['privacy:metadata:database:projectapp_project:company_email'] = 'E-Mail-Adresse Betreuer/in beim Dualen Partner'; +$string['privacy:metadata:database:projectapp_project:attendant'] = 'Name Betreuer/in an DHBW'; +$string['privacy:metadata:database:projectapp_project:title'] = 'Titel der Arbeit'; +$string['privacy:metadata:database:projectapp_project:content'] = 'Erläuterung der Arbeit'; +$string['privacy:metadata:database:projectapp_project:comment'] = 'Kommentar'; +$string['privacy:metadata:database:projectapp_project:status'] = 'Status der Einreichung'; +$string['privacy:metadata:database:projectapp_project:locknote'] = 'Sperrvermerk'; +$string['privacy:metadata:database:projectapp_project:timecreated'] = 'Zeitstempel der Beantragung'; +$string['privacy:metadata:database:projectapp_project:timemodified'] = 'Zeitstempel der letzten Änderung'; +$string['privacy:metadata:database:projectapp_project'] = 'Tabelle der Anmeldungen'; + +$string['reset_url'] = 'Anmeldung zurücksetzen'; +$string['report_firstname'] = 'Vorname'; +$string['report_lastname'] = 'Nachname'; +$string['report_email'] = 'E-Mail'; +$string['report_company'] = 'Dualer Partner'; +$string['report_company_attendant'] = 'Name Betreuer/in beim Dualen Partner'; +$string['report_company_email'] = 'E-Mail-Adresse Betreuer/in beim Dualen Partner'; +$string['report_attendant'] = 'Name Betreuer/in an der DHBW'; +$string['report_title'] = 'Titel der Arbeit'; +$string['report_content'] = 'Erläuterung der Arbeit'; +$string['report_comment'] = 'Kommentar'; +$string['report_status'] = 'Status der Einreichung'; +$string['report_restriction_notice'] = 'Sperrvermerk'; +$string['report_timemodified'] = 'Zeitstempel der letzten Änderung'; +$string['report_timecreated'] = 'Zeitstempel der Beantragung'; + +$string['submit'] = 'Anmeldung einreichen'; +$string['storno'] = 'Anmeldung stornieren'; +$string['storno_url'] = 'Anmeldung stornieren'; +$string['header_storno_project'] = 'Anmeldung stornieren'; +$string['storno_project'] = 'Anmeldung zu {$a} wirklich stornieren?'; +$string['storno_other_user'] = 'Sie können keine Anmeldung anderer stornieren'; + + +$string['title'] = 'Titel der Arbeit'; + +$string['usedfields'] = 'Zusätzliche Nutzerfelder'; +$string['usedfields_hint'] = 'Diese extra Felder werden in der email an die Studiengangsleitung als Platzhalter in der Form {$a->profile_field_Kurzbezeichnung} bereitgestellt'; +$string['username'] = 'Name Studierender'; diff --git a/lang/en/projectapproval.php b/lang/en/projectapproval.php new file mode 100644 index 0000000..d0475a4 --- /dev/null +++ b/lang/en/projectapproval.php @@ -0,0 +1,144 @@ +. + +/** + * Strings for component 'projectapproval', language 'en' + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['attendant'] = 'Name of the supervisor at DHBW'; +$string['accepted'] = 'Accepted'; + +$string['createprojectapproval'] = ''; +$string['company'] = 'Company'; +$string['company_attendant'] = 'Name of the supervisor in the company'; +$string['company_email'] = 'Email of the supervisor in the company'; +$string['content'] = 'Description of the project'; +$string['comment'] = 'Comment'; +$string['comment_info_string'] = 'Comment: {$a}'; +$string['callback'] = 'Callback'; + +$string['denied'] = 'Reject'; + +$string['edit_button'] = 'Save status'; +$string['email_submission_subject'] = 'A registration for {$a->instancename} was submitted. '; +$string['email_submission_message'] = 'Please Login to your moodle to accept or reject the project proposal. +{$a->instancename}'; +$string['email_accepted_subject'] = 'Your registration for {$a->instancename} has been accepted.'; +$string['email_accepted_message'] = 'Dear Sir/Madam {$a->fullname}, + +Your registration for {$a->instancename} has been accepted. Do not send replies to this message. + +Regards'; +$string['email_denied_subject'] = 'Your registration for {$a->instancename} was not accepted.'; +$string['email_denied_message'] = 'Dear Sir/Madam {$a->fullname}, + +Unfortunately, your registration for {$a->instancename} was not accepted. Please submit a new proposal. + +Regards'; +$string['email_callback_subject'] = 'Your registration for {$a->instancename} is currently being reviewed, consultation is necessary, '; +$string['email_callback_message'] = 'Dear Sir/Madam {$a->fullname}, + +Your registration for {$a->instancename} is currently being reviewed. +Please contact the head of department for consultation. + +Regards'; +$string['projectapproval:addinstance'] = 'Create a course isntance of project approval'; +$string['projectapproval:manage_submissions'] = 'Manage registrations'; +$string['projectapproval:view'] = 'View registrations'; + +$string['file_encoding'] = 'encoding of the export file'; + +$string['header_submit_project'] = 'Details of'; +$string['header_edit_project'] = 'Status of project registration'; +$string['header_user_data'] = 'Registration user'; + +$string['locknote'] = 'non-disclosure notice'; +$string['locknote_use'] = 'use non-disclosure notice'; + +$string['manager'] = 'manager'; +$string['modulename'] = 'Project approval'; +$string['modulenameplural'] = 'Project approvals'; + +$string['open'] = 'Open'; + +$string['project_download'] = 'download project list'; +$string['pluginname'] = 'Project Registration'; +//$string['privacy:metadata'] = 'The Projects Registration plugin does not store any personal data.'; +$string['pluginadministration'] = 'Project approval module administration'; +$string['project_submit'] = 'Register your project'; +$string['project_needs_validation'] = 'Your registration for {$a} is currently being reviewed.
'; +$string['project_accepted'] = 'Your registration for {$a} has been accepted.
'; +$string['project_denied'] = 'Your registration for {$a} was rejected. Please submit a new proposal.
'; +$string['project_callback'] = 'Your registration for {$a} is currently being reviewed and changes are required. +Please contact the head of department for more details.
'; +$string['project_status'] = 'Status of registration'; +$string['project_edit'] = 'Edit registration'; +$string['project_info_string'] = 'Company: {$a->company}
+Name of the supervisor in the company: {$a->company_attendant}
+Email of the supervisor in the company: {$a->company_email}
+Name of the supervisor at DHBW: {$a->attendant}
+Title of the project: {$a->title}
+Description of the project: {$a->content}
'; +$string['project_empty'] = 'No project registered'; +$string['privacy:metadata:database:projectapp_project:cmid'] = 'Course module id'; +$string['privacy:metadata:database:projectapp_project:userid'] = 'User id'; +$string['privacy:metadata:database:projectapp_project:company'] = 'Company'; +$string['privacy:metadata:database:projectapp_project:company_attendant'] = 'Name of the supervisor in the company'; +$string['privacy:metadata:database:projectapp_project:company_email'] = 'Email of the supervisor in the company'; +$string['privacy:metadata:database:projectapp_project:attendant'] = 'Name of the supervisor at DHBW'; +$string['privacy:metadata:database:projectapp_project:title'] = 'Title of the project'; +$string['privacy:metadata:database:projectapp_project:content'] = 'Description of the project'; +$string['privacy:metadata:database:projectapp_project:comment'] = 'Comment'; +$string['privacy:metadata:database:projectapp_project:status'] = 'Status of the submission'; +$string['privacy:metadata:database:projectapp_project:locknote'] = 'non-disclosure notice'; +$string['privacy:metadata:database:projectapp_project:timecreated'] = 'Creation timestamp'; +$string['privacy:metadata:database:projectapp_project:timemodified'] = 'Last modified timestamp'; +$string['privacy:metadata:database:projectapp_project'] = 'Project submission table'; + +$string['reset_url'] = 'Reset registration'; +$string['report_firstname'] = 'firstname'; +$string['report_lastname'] = 'lastname'; +$string['report_email'] = 'email'; +$string['report_company'] = 'company'; +$string['report_company_attendant'] = 'company supervisor'; +$string['report_company_email'] = 'company email'; +$string['report_attendant'] = 'supervisor'; +$string['report_title'] = 'title'; +$string['report_content'] = 'content'; +$string['report_comment'] = 'comment'; +$string['report_status'] = 'status'; +$string['report_restriction_notice'] = 'non-disclosure notice'; +$string['report_timemodified'] = 'timemodified'; +$string['report_timecreated'] = 'timecreated'; + +$string['submit'] = 'Submit registration'; +$string['storno'] = 'withdraw registration'; +$string['storno_url'] = 'withdraw registration'; +$string['header_storno_project'] = 'withdraw registration'; +$string['storno_project'] = 'Do you really want to withdraw your registration from {$a}?'; +$string['storno_other_user'] = 'You cannot withdraw registrations of others'; + +$string['title'] = 'Titel of the project'; + +$string['userdata'] = 'project'; + +$string['usedfields'] = 'additional user fields'; +$string['usedfields_hint'] = 'This fields will be added as placeholder to the manger email as {$a->profile_field_Shortname}'; +$string['username'] = 'student name'; diff --git a/lib.php b/lib.php new file mode 100644 index 0000000..8fc8612 --- /dev/null +++ b/lib.php @@ -0,0 +1,544 @@ +. + +/** + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +/** + * List of features supported in projectapproval module + * @param string $feature constant for requested feature + * @return mixed True if module supports feature, false if not, null if not listed + */ +function projectapproval_supports($feature) { + switch($feature) { +// case FEATURE_MOD_ARCHETYPE: return MOD_ARCHETYPE_RESOURCE; + case FEATURE_GROUPS: return true; + case FEATURE_GROUPINGS: return false; + case FEATURE_MOD_INTRO: return true; + case FEATURE_COMPLETION_TRACKS_VIEWS: return true; + case FEATURE_GRADE_HAS_GRADE: return false; + case FEATURE_GRADE_OUTCOMES: return false; + case FEATURE_BACKUP_MOODLE2: return true; + case FEATURE_SHOW_DESCRIPTION: return true; + default: return null; + } +} + +///** +// * This function is used by the reset_course_userdata function in moodlelib. +// * @param $data the data submitted from the reset course. +// * @return array status array +// */ +//function projectapproval_reset_userdata($data) { +// // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset. +// // See MDL-9367. +// return array(); +//} + +/** + * List the actions that correspond to a view of this module. + * This is used by the participation report. + * + * Note: This is not used by new logging system. Event with + * crud = 'r' and edulevel = LEVEL_PARTICIPATING will + * be considered as view action. + * + * @return array + */ +function projectapproval_get_view_actions() { + return array('view','view all'); +} + +/** + * List the actions that correspond to a post of this module. + * This is used by the participation report. + * + * Note: This is not used by new logging system. Event with + * crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING + * will be considered as post action. + * + * @return array + */ +function projectapproval_get_post_actions() { + return array('update', 'add'); +} + +/** + * Add projectapproval instance. + * @param stdClass $data + * @param mod_projectapproval_mod_form $mform + * @return int new projectapproval instance id + */ +function projectapproval_add_instance($data, $mform = null) { + global $CFG, $DB; + require_once("$CFG->libdir/resourcelib.php"); + + $cmid = $data->coursemodule; + $data->timemodified = time(); + $data->id = $DB->insert_record('projectapproval', $data); + + // We need to use context now, so we need to make sure all needed info is already in db. + $DB->set_field('course_modules', 'instance', $data->id, array('id' => $cmid)); + $context = context_module::instance($cmid); + + if ($mform and !empty($data->desc['itemid'])) { + $draftitemid = $data->desc['itemid']; + $data->content = file_save_draft_area_files($draftitemid, $context->id, 'mod_projectapproval', 'content', 0, + projectapproval_get_editor_options($context), $data->content); + $DB->update_record('projectapproval', $data); + } + + $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null; + \core_completion\api::update_completion_date_event($cmid, 'projectapproval', $data->id, $completiontimeexpected); + + return $data->id; +} + +/** + * Update projectapproval instance. + * @param object $data + * @param object $mform + * @return bool true + */ +function projectapproval_update_instance($data, $mform) { + global $CFG, $DB; + require_once("$CFG->libdir/resourcelib.php"); + + $cmid = $data->coursemodule; + + $data->timemodified = time(); + $data->id = $data->instance; + $DB->update_record('projectapproval', $data); + + $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null; + \core_completion\api::update_completion_date_event($cmid, 'projectapproval', $data->id, $completiontimeexpected); + + return true; +} + +/** + * Delete projectapproval instance. + * @param int $id + * @return bool true + */ +function projectapproval_delete_instance($id) { + global $DB; + + // Delete project records for this instance. + $cm = get_coursemodule_from_instance('projectapproval', $id); + \core_completion\api::update_completion_date_event($cm->id, 'projectapproval', $id, null); + $DB->delete_records('projectapp_project', array('cmid' => $cm->id)); + + // Delete instance record. + $DB->delete_records('projectapproval', array('id' => $id)); + + // Note: all context files are deleted automatically. + return true; +} + +/** + * Given a course_module object, this function returns any + * "extra" information that may be needed when printing + * this activity in a course listing. + * + * See {@link get_array_of_activities()} in course/lib.php + * + * @param stdClass $coursemodule + * @return cached_cm_info Info to customise main projectapproval display + */ +function projectapproval_get_coursemodule_info($coursemodule) { + global $CFG, $DB; + require_once("$CFG->libdir/resourcelib.php"); + + if (!$projectapproval = $DB->get_record('projectapproval', array('id' => $coursemodule->instance), + 'id, name, intro, introformat')) { + return NULL; + } + + $info = new cached_cm_info(); + $info->name = $projectapproval->name; + + if ($coursemodule->showdescription) { + // Convert intro to html. Do not filter cached version, filters run at display time. + $info->content = format_module_intro('projectapproval', $projectapproval, $coursemodule->id, false); + } + return $info; +} + + +/** + * Lists all browsable file areas + * + * @package mod_projectapproval + * @category files + * @param stdClass $course course object + * @param stdClass $cm course module object + * @param stdClass $context context object + * @return array + */ +function projectapproval_get_file_areas($course, $cm, $context) { + $areas = array(); + $areas['content'] = get_string('content', 'projectapproval'); + return $areas; +} + +/** + * File browsing support for projectapproval module content area. + * + * @package mod_projectapproval + * @category files + * @param stdClass $browser file browser instance + * @param stdClass $areas file areas + * @param stdClass $course course object + * @param stdClass $cm course module object + * @param stdClass $context context object + * @param string $filearea file area + * @param int $itemid item ID + * @param string $filepath file path + * @param string $filename file name + * @return file_info instance or null if not found + */ +function projectapproval_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) { + global $CFG; + + if (!has_capability('moodle/course:managefiles', $context)) { + // students can not peak here! + return null; + } + + $fs = get_file_storage(); + + if ($filearea === 'content') { + $filepath = is_null($filepath) ? '/' : $filepath; + $filename = is_null($filename) ? '.' : $filename; + + $urlbase = $CFG->wwwroot.'/pluginfile.php'; + if (!$storedfile = $fs->get_file($context->id, 'mod_projectapproval', 'content', 0, $filepath, $filename)) { + if ($filepath === '/' and $filename === '.') { + $storedfile = new virtual_root_file($context->id, 'mod_projectapproval', 'content', 0); + } else { + // not found + return null; + } + } + require_once("$CFG->dirroot/mod/projectapproval/locallib.php"); + return new projectapproval_content_file_info($browser, $context, $storedfile, $urlbase, $areas[$filearea], + true, true, true, false); + } + + // note: projectapproval_intro handled in file_browser automatically + return null; +} + +/** + * Serves the projectapproval files. + * + * @package mod_projectapproval + * @category files + * @param stdClass $course course object + * @param stdClass $cm course module object + * @param stdClass $context context object + * @param string $filearea file area + * @param array $args extra arguments + * @param bool $forcedownload whether or not force download + * @param array $options additional options affecting the file serving + * @return bool false if file not found, does not return if found - just send the file + */ +function projectapproval_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) { + global $CFG, $DB; + require_once("$CFG->libdir/resourcelib.php"); + + if ($context->contextlevel != CONTEXT_MODULE) { + return false; + } + + require_course_login($course, true, $cm); + if (!has_capability('mod/projectapproval:view', $context)) { + return false; + } + + if ($filearea !== 'content') { + // intro is handled automatically in pluginfile.php + return false; + } + + // $arg could be revision number or index.html + $arg = array_shift($args); + if ($arg == 'index.html' || $arg == 'index.htm') { + // serve projectapproval content + $filename = $arg; + + if (!$projectapproval = $DB->get_record('projectapproval', array('id'=>$cm->instance), '*', MUST_EXIST)) { + return false; + } + + // We need to rewrite the pluginfile URLs so the media filters can work. + $content = file_rewrite_pluginfile_urls($projectapproval->content, 'webservice/pluginfile.php', + $context->id, 'mod_projectapproval', 'content', + $projectapproval->revision); + $formatoptions = new stdClass; + $formatoptions->noclean = true; + $formatoptions->overflowdiv = true; + $formatoptions->context = $context; + $content = format_text($content, $projectapproval->contentformat, $formatoptions); + + // Remove @@PLUGINFILE@@/. + $options = array('reverse' => true); + $content = file_rewrite_pluginfile_urls($content, 'webservice/pluginfile.php', $context->id, + 'mod_projectapproval', 'content', + $projectapproval->revision, $options); + $content = str_replace('@@PLUGINFILE@@/', '', $content); + + send_file($content, $filename, 0, 0, true, true); + } else { + $fs = get_file_storage(); + $relativepath = implode('/', $args); + $fullpath = "/$context->id/mod_projectapproval/$filearea/0/$relativepath"; + if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { + $projectapproval = $DB->get_record('projectapproval', array('id'=>$cm->instance), 'id, legacyfiles', MUST_EXIST); + if ($projectapproval->legacyfiles != RESOURCELIB_LEGACYFILES_ACTIVE) { + return false; + } + if (!$file = resourcelib_try_file_migration('/'.$relativepath, $cm->id, $cm->course, 'mod_projectapproval', 'content', 0)) { + return false; + } + //file migrate - update flag + $projectapproval->legacyfileslast = time(); + $DB->update_record('projectapproval', $projectapproval); + } + + // finally send the file + send_stored_file($file, null, 0, $forcedownload, $options); + } +} + +/** + * Return a list of projectapproval types + * @param string $projectapprovaltype current projectapproval type + * @param stdClass $parentcontext Block's parent context + * @param stdClass $currentcontext Current context of block + */ +function projectapproval_projectapproval_type_list($projectapprovaltype, $parentcontext, $currentcontext) { + $module_projectapprovaltype = array('mod-projectapproval-*' => + get_string('projectapproval-mod-projectapproval-x', 'projectapproval')); + return $module_projectapprovaltype; +} + +///** +// * Export projectapproval resource contents +// * +// * @return array of file content +// */ +//function projectapproval_export_contents($cm, $baseurl) { +// global $CFG, $DB; +// $contents = array(); +// $context = context_module::instance($cm->id); +// +// $projectapproval = $DB->get_record('projectapproval', array('id'=>$cm->instance), '*', MUST_EXIST); +// +// // projectapproval contents +// $fs = get_file_storage(); +// $files = $fs->get_area_files($context->id, 'mod_projectapproval', 'content', 0, 'sortorder DESC, id ASC', false); +// foreach ($files as $fileinfo) { +// $file = array(); +// $file['type'] = 'file'; +// $file['filename'] = $fileinfo->get_filename(); +// $file['filepath'] = $fileinfo->get_filepath(); +// $file['filesize'] = $fileinfo->get_filesize(); +// $file['fileurl'] = file_encode_url("$CFG->wwwroot/" . $baseurl, '/'.$context->id. +// '/mod_projectapproval/content/'.$projectapproval->revision.$fileinfo->get_filepath(). +// $fileinfo->get_filename(), true); +// $file['timecreated'] = $fileinfo->get_timecreated(); +// $file['timemodified'] = $fileinfo->get_timemodified(); +// $file['sortorder'] = $fileinfo->get_sortorder(); +// $file['userid'] = $fileinfo->get_userid(); +// $file['author'] = $fileinfo->get_author(); +// $file['license'] = $fileinfo->get_license(); +// $file['mimetype'] = $fileinfo->get_mimetype(); +// $file['isexternalfile'] = $fileinfo->is_external_file(); +// if ($file['isexternalfile']) { +// $file['repositorytype'] = $fileinfo->get_repository_type(); +// } +// $contents[] = $file; +// } +// +// // projectapproval html conent +// $filename = 'index.html'; +// $projectapprovalfile = array(); +// $projectapprovalfile['type'] = 'file'; +// $projectapprovalfile['filename'] = $filename; +// $projectapprovalfile['filepath'] = '/'; +// $projectapprovalfile['filesize'] = 0; +// $projectapprovalfile['fileurl'] = file_encode_url("$CFG->wwwroot/" . $baseurl, '/'.$context->id.'/mod_projectapproval/content/' . $filename, true); +// $projectapprovalfile['timecreated'] = null; +// $projectapprovalfile['timemodified'] = $projectapproval->timemodified; +// // make this file as main file +// $projectapprovalfile['sortorder'] = 1; +// $projectapprovalfile['userid'] = null; +// $projectapprovalfile['author'] = null; +// $projectapprovalfile['license'] = null; +// $contents[] = $projectapprovalfile; +// +// return $contents; +//} + +/** + * Register the ability to handle drag and drop file uploads + * @return array containing details of the files / types the mod can handle + */ +function projectapproval_dndupload_register() { + return array('types' => array( + array('identifier' => 'text/html', 'message' => + get_string('createprojectapproval', 'mod_projectapproval')), + array('identifier' => 'text', 'message' => get_string('createprojectapproval', 'mod_projectapproval')) + )); +} + +/** + * Handle a file that has been uploaded + * @param object $uploadinfo details of the file / content that has been uploaded + * @return int instance id of the newly created mod + */ +function projectapproval_dndupload_handle($uploadinfo) { + // Gather the required info. + $data = new stdClass(); + $data->course = $uploadinfo->course->id; + $data->name = $uploadinfo->displayname; + $data->intro = '

'.$uploadinfo->displayname.'

'; + $data->introformat = FORMAT_HTML; + if ($uploadinfo->type == 'text/html') { + $data->contentformat = FORMAT_HTML; + $data->content = clean_param($uploadinfo->content, PARAM_CLEANHTML); + } else { + $data->contentformat = FORMAT_PLAIN; + $data->content = clean_param($uploadinfo->content, PARAM_TEXT); + } + $data->coursemodule = $uploadinfo->coursemodule; + + // Set the display options to the site defaults. + $config = get_config('projectapproval'); + $data->popupheight = $config->popupheight; + $data->popupwidth = $config->popupwidth; + $data->printheading = $config->printheading; + $data->printintro = $config->printintro; + $data->printlastmodified = $config->printlastmodified; + + return projectapproval_add_instance($data, null); +} + +/** + * Mark the activity completed (if required) and trigger the course_module_viewed event. + * + * @param stdClass $projectapproval projectapproval object + * @param stdClass $course course object + * @param stdClass $cm course module object + * @param stdClass $context context object + * @since Moodle 3.0 + */ +function projectapproval_view($projectapproval, $course, $cm, $context) { + + // Trigger course_module_viewed event. + $params = array( + 'context' => $context, + 'objectid' => $projectapproval->id + ); + + $event = \mod_projectapproval\event\course_module_viewed::create($params); + $event->add_record_snapshot('course_modules', $cm); + $event->add_record_snapshot('course', $course); + $event->add_record_snapshot('projectapproval', $projectapproval); + $event->trigger(); + + // Completion. + $completion = new completion_info($course); + $completion->set_module_viewed($cm); +} + +/** + * Check if the module has any update that affects the current user since a given time. + * + * @param cm_info $cm course module data + * @param int $from the time to check updates from + * @param array $filter if we need to check only specific updates + * @return stdClass an object with the different type of areas indicating if they were updated or not + * @since Moodle 3.2 + */ +function projectapproval_check_updates_since(cm_info $cm, $from, $filter = array()) { + $updates = course_check_module_updates_since($cm, $from, array('content'), $filter); + return $updates; +} + +/** + * This function receives a calendar event and returns the action associated with it, or null if there is none. + * + * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event + * is not displayed on the block. + * + * @param calendar_event $event + * @param \core_calendar\action_factory $factory + * @return \core_calendar\local\event\entities\action_interface|null + */ +function mod_projectapproval_core_calendar_provide_event_action(calendar_event $event, + \core_calendar\action_factory $factory, $userid = 0) { + global $USER; + + if (empty($userid)) { + $userid = $USER->id; + } + + $cm = get_fast_modinfo($event->courseid, $userid)->instances['projectapproval'][$event->instance]; + $completion = new \completion_info($cm->get_course()); + $completiondata = $completion->get_data($cm, false, $userid); + if ($completiondata->completionstate != COMPLETION_INCOMPLETE) { + return null; + } + + return $factory->create_instance( + get_string('view'), + new \moodle_url('/mod/projectapproval/view.php', ['id' => $cm->id]), + 1, + true + ); +} + +/** + * Given an array with a file path, it returns the itemid and the filepath for the defined filearea. + * + * @param string $filearea The filearea. + * @param array $args The path (the part after the filearea and before the filename). + * @return array The itemid and the filepath inside the $args path, for the defined filearea. + */ +function mod_projectapproval_get_path_from_pluginfile(string $filearea, array $args) : array { + // projectapproval never has an itemid (the number represents the revision but it's not stored in database). + array_shift($args); + + // Get the filepath. + if (empty($args)) { + $filepath = '/'; + } else { + $filepath = '/' . implode('/', $args) . '/'; + } + + return [ + 'itemid' => 0, + 'filepath' => $filepath, + ]; +} diff --git a/locallib.php b/locallib.php new file mode 100644 index 0000000..20e9d21 --- /dev/null +++ b/locallib.php @@ -0,0 +1,54 @@ +. + +/** + * Private projectapproval module utility functions + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +require_once("$CFG->libdir/filelib.php"); +require_once("$CFG->libdir/resourcelib.php"); +require_once("$CFG->dirroot/mod/projectapproval/lib.php"); + + +/** + * File browsing support class + */ +class projectapproval_content_file_info extends file_info_stored { + public function get_parent() { + if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') { + return $this->browser->get_file_info($this->context); + } + return parent::get_parent(); + } + public function get_visible_name() { + if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') { + return $this->topvisiblename; + } + return parent::get_visible_name(); + } +} + +function projectapproval_get_editor_options($context) { + global $CFG; + return array('subdirs'=>1, 'maxbytes'=>$CFG->maxbytes, 'maxfiles'=>-1, + 'changeformat'=>1, 'context'=>$context, 'noclean'=>1, 'trusttext'=>0); +} \ No newline at end of file diff --git a/mod_form.php b/mod_form.php new file mode 100644 index 0000000..8b43ff9 --- /dev/null +++ b/mod_form.php @@ -0,0 +1,100 @@ +. + +/** + * projectapproval configuration form + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; +global $CFG, $DB, $COURSE; +require_once($CFG->dirroot.'/course/moodleform_mod.php'); +require_once($CFG->dirroot.'/mod/projectapproval/locallib.php'); +require_once($CFG->libdir.'/filelib.php'); + +class mod_projectapproval_mod_form extends moodleform_mod { + function definition() { + global $CFG, $DB, $COURSE; + + $mform = $this->_form; + + $courseid = optional_param('course', $COURSE->id, PARAM_RAW); + + //------------------------------------------------------- + $mform->addElement('header', 'general', get_string('general', 'form')); + $mform->addElement('text', 'name', get_string('name'), array('size'=>'48')); + if (!empty($CFG->formatstringstriptags)) { + $mform->setType('name', PARAM_TEXT); + } else { + $mform->setType('name', PARAM_CLEANHTML); + } + $mform->addRule('name', null, 'required', null, 'client'); + $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client'); + $this->standard_intro_elements(); + + //------------------------------------------------------- + $course_manager = array(); + $course_manager[0] = get_string('choose'); + $context = context_course::instance($courseid); + $role = $DB->get_record('role', array('shortname' => 'editingteacher')); + $user_assignmenents = get_users_from_role_on_context($role, $context); + if (!empty($user_assignmenents)) { + foreach ($user_assignmenents as $user_assignmenent) { + $user = $DB->get_record('user', array('id' => $user_assignmenent->userid)); + $course_manager[$user_assignmenent->userid] = $user->firstname.' '.$user->lastname; + } + } + $mform->addElement('select', 'manager', get_string('manager', 'projectapproval'), $course_manager); + $mform->addRule('manager', null, 'required', null, 'client'); + $mform->setType('manager', PARAM_RAW); + + $mform->addElement('advcheckbox', 'locknote', '', + get_string('locknote_use', 'mod_projectapproval'), array('group' => 1), array(0, 1)); + + //------------------------------------------------------- + $this->standard_coursemodule_elements(); + + //------------------------------------------------------- + $this->add_action_buttons(); + } + + public function validation($data, $files) { + + $errors = parent::validation($data, $files); + if ($data['manager'] == 0) { + $errors['manager'] = get_string('missingteacher'); + } + + return $errors; + } + + /** + * Enforce defaults here. + * + * @param array $defaultvalues Form defaults + * @return void + **/ + public function data_preprocessing(&$defaultvalues) { + if ($this->current->instance) { + $draftitemid = file_get_submitted_draft_itemid('projectapproval'); + $defaultvalues['projectapproval']['itemid'] = $draftitemid; + } + } +} + diff --git a/pix/icon.png b/pix/icon.png new file mode 100644 index 0000000..fe5c82d Binary files /dev/null and b/pix/icon.png differ diff --git a/pix/icon.svg b/pix/icon.svg new file mode 100644 index 0000000..bd7eaf8 --- /dev/null +++ b/pix/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/project_edit.php b/project_edit.php new file mode 100644 index 0000000..dae671a --- /dev/null +++ b/project_edit.php @@ -0,0 +1,108 @@ +. + +/** + * + * @package mod_projectapproval + * @copyright 2022 eLeDia GmbH {@link http://www.eledia.de} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); + +use mod_projectapproval\util; +global $FULLME, $PAGE, $DB, $CFG, $OUTPUT, $USER; + +require_once('locallib.php'); +require_once('project_edit_form.php'); + +$projectid = required_param('projectid', PARAM_INT); +$project = $DB->get_record('projectapp_project', array('id' => $projectid)); + +$cm = get_coursemodule_from_id('projectapproval', $project->cmid); +$instance = $DB->get_record('projectapproval', array('id' => $cm->instance)); + +require_login(); +require_capability('mod/projectapproval:manage_submissions', context_module::instance($cm->id)); + +$myurl = new moodle_url($FULLME); + +$PAGE->set_url($myurl); +$PAGE->set_context(context_system::instance()); +$PAGE->set_pagelayout('course'); + +$mform = new projectedit_form(null, + array('cm' => $cm, 'instance' => $instance, 'project' => $project)); +$mform->set_data($project); +$modlink = $CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cm->id; + +$util = new util(); + +if ($mform->is_cancelled()) { + redirect($modlink); +} + +if ($formdata = $mform->get_data()) { + + // Save edit submission. + $util->save_edit_project($formdata); + + // Email to student. + $supportuser = core_user::get_support_user(); + $data = new stdClass(); + $data->instancename = $instance->name; + $data->modlink = $modlink; + $student = $DB->get_record('user', array('id' => $project->userid)); + $data->fullname = fullname($student); + $data->project_title = $project->title; + + switch ($formdata->status) { + case 'accepted': + $subject = get_string('email_accepted_subject', 'mod_projectapproval', $data); + $message = get_string('email_accepted_message', 'mod_projectapproval', $data); + $messagehtml = text_to_html(get_string('email_accepted_message', 'mod_projectapproval', + $data), false, false); + break; + case 'denied': + $subject = get_string('email_denied_subject', 'mod_projectapproval', $data); + $message = get_string('email_denied_message', 'mod_projectapproval', $data); + $messagehtml = text_to_html(get_string('email_denied_message', 'mod_projectapproval', + $data), false, false); + break; + case 'callback': + $subject = get_string('email_callback_subject', 'mod_projectapproval', $data); + $message = get_string('email_callback_message', 'mod_projectapproval', $data); + $messagehtml = text_to_html(get_string('email_callback_message', 'mod_projectapproval', + $data), false, false); + break; + default: + // Return to view page without email if status open. + redirect($modlink); + } + + $student->mailformat = 1; // Always send HTML version as well. + email_to_user($student, $supportuser, $subject, $message, $messagehtml); + + // Return to view page after edit. + redirect($modlink); +} + +$cm_link = ''.$instance->name.''; +$PAGE->navbar->add($cm_link); +$header = get_string('header_submit_project', 'mod_projectapproval').' '.$instance->name; +$PAGE->set_heading($header); +echo $OUTPUT->header(); +$mform->display(); +echo $OUTPUT->footer(); diff --git a/project_edit_form.php b/project_edit_form.php new file mode 100644 index 0000000..fda2963 --- /dev/null +++ b/project_edit_form.php @@ -0,0 +1,124 @@ +. + +/** + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->libdir.'/formslib.php'); + +class projectedit_form extends moodleform { + + protected function definition() { + global $DB; + + $mform =& $this->_form; + $project = $this->_customdata['project']; + $instance = $this->_customdata['instance']; + $user = $DB->get_record('user', array('id' => $project->userid)); + + $mform->addElement('hidden', 'projectid', $project->id); + $mform->setType('projectid', PARAM_INT); + + //------------------------------------------------------- + // Show user data part. + $mform->addElement('header', '', get_string('header_user_data', 'mod_projectapproval'), + 'header_projectapproval'); + + $mform->addElement('static', 'username', get_string('name'), + fullname($user)); + $mform->addElement('static', 'email', get_string('email'), + $user->email); + + //------------------------------------------------------- + // Project data part. + $mform->addElement('header', '', get_string('header_submit_project', 'mod_projectapproval') + .' '.$instance->name, 'header_projectapproval'); + + $mform->addElement('text', 'company', get_string('company', 'mod_projectapproval'), + array('size' => '48', 'readonly' => true)); + $mform->setType('company', PARAM_RAW); + + $mform->addElement('text', 'company_attendant', + get_string('company_attendant', 'mod_projectapproval'), array('size' => '48', 'readonly' => true)); + $mform->setType('company_attendant', PARAM_RAW); + + $mform->addElement('text', 'company_email', + get_string('company_email', 'mod_projectapproval'), array('size' => '48', 'readonly' => true)); + $mform->setType('company_email', PARAM_EMAIL); + + $mform->addElement('text', 'attendant', + get_string('attendant', 'mod_projectapproval'), array('size' => '48')); + $mform->setType('attendant', PARAM_RAW); + $mform->addRule('attendant', null, 'required', null, 'client'); + + $mform->addElement('textarea', 'title', + get_string('title', 'mod_projectapproval'), array('rows' => '2', 'cols' => '48', 'readonly' => true)); + $mform->setType('title', PARAM_RAW); + + $mform->addElement('textarea', 'content', + get_string('content', 'mod_projectapproval'), array('rows' => '7', 'cols' => '68', 'readonly' => true)); + $mform->setType('content', PARAM_RAW); + + if (!empty($instance->locknote)) { + if ($project->locknote) { + $mform->addElement('static', '', get_string('locknote', 'mod_projectapproval'), get_string('yes')); + } else { + $mform->addElement('static', '', get_string('locknote', 'mod_projectapproval'), get_string('no')); + } + } + + //------------------------------------------------------- + // Editing part. + $mform->addElement('header', '', get_string('header_edit_project', 'mod_projectapproval'), + 'header_projectapproval'); + + // Comment field. + $mform->addElement('textarea', 'comment', + get_string('comment', 'mod_projectapproval'), array('rows' => '7', 'cols' => '68')); + $mform->setType('comment', PARAM_RAW); + + // Status options. + $radioarray = array(); + $radioarray[] = $mform->createElement('radio', 'status', '', + get_string('open', 'mod_projectapproval'), 'open'); + $radioarray[] = $mform->createElement('radio', 'status', '', + get_string('accepted', 'mod_projectapproval'), 'accepted'); + $radioarray[] = $mform->createElement('radio', 'status', '', + get_string('denied', 'mod_projectapproval'), 'denied'); + $radioarray[] = $mform->createElement('radio', 'status', '', + get_string('callback', 'mod_projectapproval'), 'callback'); + $mform->addGroup($radioarray, 'statusar', '', array(' '), false); + $mform->addRule('statusar', null, 'required', null, 'client'); + + $this->add_action_buttons(true, get_string('edit_button', 'mod_projectapproval')); + } + + public function validation($data, $files) { + $errors = parent::validation($data, $files); + if (!empty($data['company_email'])){ + if (! validate_email($data['company_email'])) { + $errors['company_email'] = get_string('invalidemail'); + } + } + + return $errors; + } +} diff --git a/project_reset.php b/project_reset.php new file mode 100644 index 0000000..d9ec613 --- /dev/null +++ b/project_reset.php @@ -0,0 +1,40 @@ +. + +/** + * + * @package mod_projectapproval + * @copyright 2022 eLeDia GmbH {@link http://www.eledia.de} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); +global $DB, $CFG, $USER; + +$projectid = required_param('projectid', PARAM_INT); +$project = $DB->get_record('projectapp_project', array('id' => $projectid)); +$cm = get_coursemodule_from_id('projectapproval', $project->cmid); + +require_login(); +require_capability('mod/projectapproval:view', context_module::instance($cm->id)); + +if ($USER->id != $project->userid) { + // You can't reset for someone else! + print_error('reset_other_user', 'mod_projectapproval', + $CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cm->id); +} + +$DB->set_field('projectapp_project', 'status', 'callback', array('id' => $projectid)); +redirect($CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cm->id); diff --git a/project_storno.php b/project_storno.php new file mode 100644 index 0000000..712a6bd --- /dev/null +++ b/project_storno.php @@ -0,0 +1,64 @@ +. + +/** + * + * @package mod_projectapproval + * @copyright 2022 eLeDia GmbH {@link http://www.eledia.de} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); +global $DB, $CFG, $FULLME, $PAGE, $DB, $CFG, $OUTPUT, $USER; + +$projectid = required_param('projectid', PARAM_INT); +$project = $DB->get_record('projectapp_project', array('id' => $projectid)); +$cm = get_coursemodule_from_id('projectapproval', $project->cmid); + +require_login(); +require_capability('mod/projectapproval:view', context_module::instance($cm->id)); + +require_once('project_storno_form.php'); +$myurl = new moodle_url($FULLME); + +$PAGE->set_url($myurl); +$PAGE->set_context(context_system::instance()); +$PAGE->set_pagelayout('course'); + +$instance = $DB->get_record('projectapproval', array('id' => $cm->instance)); +$mform = new projectstorno_form(null, array('project' => $project)); + +if ($mform->is_cancelled()) { + redirect($CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cm->id); +} +if ($formdata = $mform->get_data()) { + if ($USER->id != $project->userid) { + // You can't storno for someone else! + print_error('storno_other_user', 'mod_projectapproval', + $CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cm->id); + } + + $DB->delete_records('projectapp_project', array('id' => $projectid)); + redirect($CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cm->id); +} + +$a = $CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cm->id; +$cm_link = ''.$instance->name.''; +$PAGE->navbar->add($cm_link); +$header = get_string('header_storno_project', 'mod_projectapproval').' '.$instance->name; +$PAGE->set_heading($header); +echo $OUTPUT->header(); +$mform->display(); +echo $OUTPUT->footer(); diff --git a/project_storno_form.php b/project_storno_form.php new file mode 100644 index 0000000..1468b8d --- /dev/null +++ b/project_storno_form.php @@ -0,0 +1,52 @@ +. + +/** + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->libdir.'/formslib.php'); + +class projectstorno_form extends moodleform { + + protected function definition() { + global $DB; + + $mform =& $this->_form; + $project = $this->_customdata['project']; + $cm = get_coursemodule_from_id('projectapproval', $project->cmid); + $instance = $DB->get_record('projectapproval', array('id' => $cm->instance)); + + $mform->addElement('hidden', 'projectid', $project->id); + $mform->setType('projectid', PARAM_INT); + +// $mform->addElement('header', '', get_string('header_storno_project', 'mod_projectapproval') +// .' '.$instance->name, 'header_projectapproval'); + $mform->addElement('html', get_string('storno_project', 'mod_projectapproval', $instance->name)); + + $this->add_action_buttons(true, get_string('storno', 'mod_projectapproval')); + } + + public function validation($data, $files) { + $errors = parent::validation($data, $files); + + return $errors; + } +} diff --git a/project_submit.php b/project_submit.php new file mode 100644 index 0000000..579107f --- /dev/null +++ b/project_submit.php @@ -0,0 +1,106 @@ +. + +/** + * + * @package mod_projectapproval + * @copyright 2022 eLeDia GmbH {@link http://www.eledia.de} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); + +use mod_projectapproval\util; +global $FULLME, $PAGE, $DB, $CFG, $OUTPUT, $USER; + +require_once('locallib.php'); +require_once('project_submit_form.php'); + +$cmid = required_param('cm', PARAM_INT); + +require_login(); +require_capability('mod/projectapproval:view', context_module::instance($cmid)); + +$myurl = new moodle_url($FULLME); + +$PAGE->set_url($myurl); +$PAGE->set_context(context_system::instance()); +$PAGE->set_pagelayout('course'); + +$cm = get_coursemodule_from_id('projectapproval', $cmid); +$instance = $DB->get_record('projectapproval', array('id' => $cm->instance)); +$mform = new projectsubmit_form(null, array('cm' => $cm, 'instance' => $instance)); +$util = new util(); + +// Load data when project exists. +$project = $DB->get_record('projectapp_project', array('cmid' => $cmid, 'userid' => $USER->id)); +if ($project) { + if ($project->status == 'callback' ) { + // Only load data on callback. Prevent old data wehn previous try was denied. + $mform->set_data($project); + } +} + +if ($mform->is_cancelled()) { + redirect($CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cmid); +} + +if ($formdata = $mform->get_data()) { + // Save the new submission. + $projectid = $util->save_new_project($formdata); + + // Email to manager. + $supportuser = core_user::get_support_user(); + $data = new stdClass(); + $data->instancename = $instance->name; + $data->modlink = $CFG->httpswwwroot.'/mod/projectapproval/project_edit.php?projectid='.$projectid; + if (!empty($project)) { + $user = $DB->get_record('user', array('id' => $project->userid)); + } else { + $user = $USER; + // We need to get reload project data. + $project = $DB->get_record('projectapp_project', array('id' => $projectid)); + } + if (isset($project->title)) { + $data->project_title = $project->title; + } + $data->fullname = fullname($user); + +// profile_load_data($user); +// $fields = explode(',', get_config('mod_projectapproval')->usedfields); +// foreach ($fields as $field) { +// $data->$field = $user->$field; +// } + + $subject = get_string('email_submission_subject', 'mod_projectapproval', $data); + $message = get_string('email_submission_message', 'mod_projectapproval', $data); + $messagehtml = text_to_html(get_string('email_submission_message', 'mod_projectapproval', + $data), false, false); + $manager = $DB->get_record('user', array('id' => $instance->manager)); + $manager->mailformat = 1; // Always send HTML version as well. + email_to_user($manager, $supportuser, $subject, $message, $messagehtml); + + // Return to view page after submission. + redirect($CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cmid); +} + +$a = $CFG->httpswwwroot.'/mod/projectapproval/view.php?id='.$cmid; +$cm_link = ''.$instance->name.''; +$PAGE->navbar->add($cm_link); +$header = get_string('header_submit_project', 'mod_projectapproval').' '.$instance->name; +$PAGE->set_heading($header); +echo $OUTPUT->header(); +$mform->display(); +echo $OUTPUT->footer(); diff --git a/project_submit_form.php b/project_submit_form.php new file mode 100644 index 0000000..78b8159 --- /dev/null +++ b/project_submit_form.php @@ -0,0 +1,88 @@ +. + +/** + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->libdir.'/formslib.php'); + +class projectsubmit_form extends moodleform { + + protected function definition() { + global $DB; + + $mform =& $this->_form; + $cm = $this->_customdata['cm']; + + $instance = $DB->get_record('projectapproval', array('id' => $cm->instance)); + + $mform->addElement('hidden', 'cm', $cm->id); + $mform->setType('cm', PARAM_INT); + + $mform->addElement('header', '', get_string('header_submit_project', 'mod_projectapproval') + .' '.$instance->name, 'header_projectapproval'); + + $mform->addElement('text', 'company', get_string('company', 'mod_projectapproval'), array('size' => '48')); + $mform->setType('company', PARAM_RAW); + $mform->addRule('company', null, 'required', null, 'client'); + + $mform->addElement('text', 'company_attendant', + get_string('company_attendant', 'mod_projectapproval'), array('size' => '48')); + $mform->setType('company_attendant', PARAM_RAW); + + $mform->addElement('text', 'company_email', + get_string('company_email', 'mod_projectapproval'), array('size' => '48')); + $mform->setType('company_email', PARAM_EMAIL); + + $mform->addElement('text', 'attendant', + get_string('attendant', 'mod_projectapproval'), array('size' => '48')); + $mform->setType('attendant', PARAM_RAW); + + $mform->addElement('textarea', 'title', + get_string('title', 'mod_projectapproval'), array('rows' => '2', 'cols' => '48')); + $mform->setType('title', PARAM_RAW); + $mform->addRule('title', null, 'required', null, 'client'); + + $mform->addElement('textarea', 'content', + get_string('content', 'mod_projectapproval'), array('rows' => '7', 'cols' => '68')); + $mform->setType('content', PARAM_RAW); + $mform->addRule('content', null, 'required', null, 'client'); + + // Locknote. + if (!empty($instance->locknote)) { + $mform->addElement('advcheckbox', 'locknote', '', + get_string('locknote', 'mod_projectapproval'), array('group' => 1), array(0, 1)); + } + + $this->add_action_buttons(true, get_string('submit', 'mod_projectapproval')); + } + + public function validation($data, $files) { + $errors = parent::validation($data, $files); + if (!empty($data['company_email'])){ + if (! validate_email($data['company_email'])) { + $errors['company_email'] = get_string('invalidemail'); + } + } + + return $errors; + } +} diff --git a/settings.php b/settings.php new file mode 100644 index 0000000..8e2a06a --- /dev/null +++ b/settings.php @@ -0,0 +1,49 @@ +. + +/** + * projectapproval module admin settings and defaults + * + * @package mod_projectapproval + * @copyright 2009 Petr Skoda (http://skodak.org) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +if ($ADMIN->fulltree) { + global $DB, $CFG; + require_once("$CFG->libdir/resourcelib.php"); + + $configs = array(); + + $options = array('utf-8' => 'utf-8', 'iso-8859-15' => 'iso-8859-15'); + $configs[] = new admin_setting_configselect('file_encoding', + get_string('file_encoding', 'projectapproval'), + '', + 'iso-8859-15', + $options); + + foreach ($configs as $config) { + $config->plugin = 'mod_projectapproval'; + $settings->add($config); + } + + //--- modedit defaults ----------------------------------------------------------------------------------- + $settings->add(new admin_setting_heading('projectapprovalmodeditdefaults', get_string('modeditdefaults', + 'admin'), get_string('condifmodeditdefaults', 'admin'))); +} diff --git a/version.php b/version.php new file mode 100644 index 0000000..42ad8f7 --- /dev/null +++ b/version.php @@ -0,0 +1,28 @@ +. + +/** + * projectapproval module version information + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2023050400; // The current module version (Date: YYYYMMDDXX). +$plugin->requires = 2020060900; // Requires this Moodle version. +$plugin->component = 'mod_projectapproval'; // Full name of the plugin (used for diagnostics) diff --git a/view.php b/view.php new file mode 100644 index 0000000..8f42287 --- /dev/null +++ b/view.php @@ -0,0 +1,89 @@ +. + +/** + * projectapproval module version information + * + * @package mod_projectapproval + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); +global $CFG, $DB, $PAGE, $OUTPUT; +require_once($CFG->dirroot.'/mod/projectapproval/lib.php'); +require_once($CFG->dirroot.'/mod/projectapproval/locallib.php'); +require_once($CFG->libdir.'/completionlib.php'); + +use mod_projectapproval\util; + +$id = optional_param('id', 0, PARAM_INT); // Course Module ID +$p = optional_param('p', 0, PARAM_INT); // projectapproval instance ID + +if ($p) { + if (!$projectapproval = $DB->get_record('projectapproval', array('id'=>$p))) { + print_error('invalidaccessparameter'); + } + $cm = get_coursemodule_from_instance('projectapproval', $projectapproval->id, + $projectapproval->course, false, MUST_EXIST); +} else { + if (!$cm = get_coursemodule_from_id('projectapproval', $id)) { + print_error('invalidcoursemodule'); + } + $projectapproval = $DB->get_record('projectapproval', array('id' => $cm->instance), '*', MUST_EXIST); +} + +$course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST); + +require_course_login($course, true, $cm); +$context = context_module::instance($cm->id); +require_capability('mod/projectapproval:view', $context); +$util = new util(); + +// Completion and trigger events. +projectapproval_view($projectapproval, $course, $cm, $context); + +$content = $projectapproval->intro; + +// Check cap and switch list and personal view. +if (has_capability('mod/projectapproval:manage_submissions', $context)) { + $content .= $util->get_manager_view($cm, $projectapproval); +} else { + $content .= $util->get_student_view($cm); +} + +$formatoptions = new stdClass; +$formatoptions->noclean = false; +$formatoptions->overflowdiv = true; +$formatoptions->context = $context; +$content = format_text($content, FORMAT_HTML, $formatoptions); + +$PAGE->set_url('/mod/projectapproval/view.php', array('id' => $cm->id)); + +$PAGE->set_title($course->shortname.': '.$projectapproval->name); +$PAGE->set_heading($course->fullname); +$PAGE->set_activity_record($projectapproval); + +echo $OUTPUT->header(); + +//// Display any activity information (eg completion requirements / dates). +//$cminfo = cm_info::create($cm); +//$completiondetails = \core_completion\cm_completion_details::get_instance($cminfo, $USER->id); +//$activitydates = \core\activity_dates::get_dates_for_module($cminfo, $USER->id); +//echo $OUTPUT->activity_information($cminfo, $completiondetails, $activitydates); + +echo $OUTPUT->box($content, "generalbox center clearfix"); +echo $OUTPUT->footer();