Has the feedback file been modified?

@param stdClass $grade Grade object.
@param stdClass $data Form data.
@return boolean True if the file area has been modified, else false.
541518
public function is_feedback_modified(stdClass $grade, stdClass $data) {
        global $USER;

        $filekey = null;
        $draftareainfo = null;
        foreach ($data as $key => $value) {
            if (strpos($key, 'files_') === 0 && strpos($key, '_filemanager')) {
                $filekey = $key;
            }
        }
        if (isset($filekey)) {
            $draftareainfo = file_get_draft_area_info($data->$filekey);
            $filecount = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA);
            if ($filecount != $draftareainfo['filecount']) {
                return true;
            } else {
                // We need to check that the files in the draft area are the same as in the file area.
                $usercontext = context_user::instance($USER->id);
                $fs = get_file_storage();
                $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $data->$filekey, 'id', true);
                $files = $fs->get_area_files($this->assignment->get_context()->id,
                                     'assignfeedback_file',
                                     ASSIGNFEEDBACK_FILE_FILEAREA,
                                     $grade->id,
                                     'id',
                                     false);
                foreach ($files as $key => $file) {
                    // Flag for recording if we have a matching file.
                    $matchflag = false;
                    foreach ($draftfiles as $draftkey => $draftfile) {
                        if (!$file->is_directory()) {
                            // File name is the same, but it could be a different file with the same name.
                            if ($draftfile->get_filename() == $file->get_filename()) {
                                // If the file name is the same but the content hash is different, or
                                // The file path for the file has changed, then we have a modification.
                                if ($draftfile->get_contenthash() != $file->get_contenthash() ||
                                        $draftfile->get_filepath() != $file->get_filepath()) {
                                    return true;
                                }
                                // These files match. Check the next file.
                                $matchflag = true;
                                // We have a match on the file name so we can move to the next file and not
                                // proceed through the other draftfiles.
                                break;
                            }
                        }
                    }
                    // If the file does not match then there has been a modification.
                    if (!$matchflag) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
1187818
function write_setting($data) {
        global $CFG;

        $previous = $this->get_setting();
        $result = parent::write_setting($data);

        // If saved and the value has changed.
        if (empty($result) && $previous != $data) {
            require_once($CFG->libdir . '/gradelib.php');
            grade_force_site_regrading();
        }

        return $result;
    }
670858
public function save_submission(stdClass $data, & $notices) {
        global $CFG, $USER, $DB;

        $userid = $USER->id;
        if (!empty($data->userid)) {
            $userid = $data->userid;
        }

        $user = clone($USER);
        if ($userid == $USER->id) {
            require_capability('mod/assign:submit', $this->context);
        } else {
            $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
            if (!$this->can_edit_submission($userid, $USER->id)) {
                print_error('nopermission');
            }
        }
        $instance = $this->get_instance();

        if ($instance->teamsubmission) {
            $submission = $this->get_group_submission($userid, 0, true);
        } else {
            $submission = $this->get_user_submission($userid, true);
        }

        if ($this->new_submission_empty($data)) {
            $notices[] = get_string('submissionempty', 'mod_assign');
            return false;
        }

        // Check that no one has modified the submission since we started looking at it.
        if (isset($data->lastmodified) && ($submission->timemodified > $data->lastmodified)) {
            // Another user has submitted something. Notify the current user.
            if ($submission->status !== ASSIGN_SUBMISSION_STATUS_NEW) {
                $notices[] = $instance->teamsubmission ? get_string('submissionmodifiedgroup', 'mod_assign')
                                                       : get_string('submissionmodified', 'mod_assign');
                return false;
            }
        }

        if ($instance->submissiondrafts) {
            $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
        } else {
            $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
        }

        $flags = $this->get_user_flags($userid, false);

        // Get the flags to check if it is locked.
        if ($flags && $flags->locked) {
            print_error('submissionslocked', 'assign');
            return true;
        }

        $pluginerror = false;
        foreach ($this->submissionplugins as $plugin) {
            if ($plugin->is_enabled() && $plugin->is_visible()) {
                if (!$plugin->save($submission, $data)) {
                    $notices[] = $plugin->get_error();
                    $pluginerror = true;
                }
            }
        }

        $allempty = $this->submission_empty($submission);
        if ($pluginerror || $allempty) {
            if ($allempty) {
                $notices[] = get_string('submissionempty', 'mod_assign');
            }
            return false;
        }

        $this->update_submission($submission, $userid, true, $instance->teamsubmission);

        if ($instance->teamsubmission && !$instance->requireallteammemberssubmit) {
            $team = $this->get_submission_group_members($submission->groupid, true);

            foreach ($team as $member) {
                if ($member->id != $userid) {
                    $membersubmission = clone($submission);
                    $this->update_submission($membersubmission, $member->id, true, $instance->teamsubmission);
                }
            }
        }

        // Logging.
        if (isset($data->submissionstatement) && ($userid == $USER->id)) {
            \mod_assign\event\statement_accepted::create_from_submission($this, $submission)->trigger();
        }

        $complete = COMPLETION_INCOMPLETE;
        if ($submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
            $complete = COMPLETION_COMPLETE;
        }
        $completion = new completion_info($this->get_course());
        if ($completion->is_enabled($this->get_course_module()) && $instance->completionsubmit) {
            $completion->update_state($this->get_course_module(), $complete, $userid);
        }

        if (!$instance->submissiondrafts) {
            $this->notify_student_submission_receipt($submission);
            $this->notify_graders($submission);
            \mod_assign\event\assessable_submitted::create_from_submission($this, $submission, true)->trigger();
        }
        return true;
    }
203025
public function update($data) {
        global $DB;
        $currentgrade = $this->get_guide_filling();
        parent::update($data);

        foreach ($data['criteria'] as $criterionid => $record) {
            if (!array_key_exists($criterionid, $currentgrade['criteria'])) {
                $newrecord = array('instanceid' => $this->get_id(), 'criterionid' => $criterionid,
                    'score' => $record['score'], 'remarkformat' => FORMAT_MOODLE);
                if (isset($record['remark'])) {
                    $newrecord['remark'] = $record['remark'];
                }
                $DB->insert_record('gradingform_guide_fillings', $newrecord);
            } else {
                $newrecord = array('id' => $currentgrade['criteria'][$criterionid]['id']);
                foreach (array('score', 'remark'/*, 'remarkformat' TODO */) as $key) {
                    if (isset($record[$key]) && $currentgrade['criteria'][$criterionid][$key] != $record[$key]) {
                        $newrecord[$key] = $record[$key];
                    }
                }
                if (count($newrecord) > 1) {
                    $DB->update_record('gradingform_guide_fillings', $newrecord);
                }
            }
        }
        foreach ($currentgrade['criteria'] as $criterionid => $record) {
            if (!array_key_exists($criterionid, $data['criteria'])) {
                $DB->delete_records('gradingform_guide_fillings', array('id' => $record['id']));
            }
        }
        $this->get_guide_filling(true);
    }
876199
function validation($data, $files) {
        global $COURSE;
        $grade_item = false;
        if ($data['id']) {
            $grade_item = new grade_item(array('id' => $data['id'], 'courseid' => $data['courseid']));
        }

        $errors = parent::validation($data, $files);

        if (array_key_exists('idnumber', $data)) {
            if ($grade_item) {
                if ($grade_item->itemtype == 'mod') {
                    $cm = get_coursemodule_from_instance($grade_item->itemmodule, $grade_item->iteminstance, $grade_item->courseid);
                } else {
                    $cm = null;
                }
            } else {
                $grade_item = null;
                $cm = null;
            }
            if (!grade_verify_idnumber($data['idnumber'], $COURSE->id, $grade_item, $cm)) {
                $errors['idnumber'] = get_string('idnumbertaken');
            }
        }

        if (array_key_exists('gradetype', $data) and $data['gradetype'] == GRADE_TYPE_SCALE) {
            if (empty($data['scaleid'])) {
                $errors['scaleid'] = get_string('missingscale', 'grades');
            }
        }

        if (array_key_exists('grademin', $data) and array_key_exists('grademax', $data)) {
            if ($data['grademax'] == $data['grademin'] or $data['grademax'] < $data['grademin']) {
                $errors['grademin'] = get_string('incorrectminmax', 'grades');
                $errors['grademax'] = get_string('incorrectminmax', 'grades');
            }
        }

        // We do not want the user to be able to change the grade type or scale for this item if grades exist.
        if ($grade_item && $grade_item->has_grades()) {
            // Check that grade type is set - should never not be set unless form has been modified.
            if (!isset($data['gradetype'])) {
                $errors['gradetype'] = get_string('modgradecantchangegradetype', 'grades');
            } else if ($data['gradetype'] !== $grade_item->gradetype) { // Check if we are changing the grade type.
                $errors['gradetype'] = get_string('modgradecantchangegradetype', 'grades');
            } else if ($data['gradetype'] == GRADE_TYPE_SCALE) {
                // Check if we are changing the scale - can't do this when grades exist.
                if (isset($data['scaleid']) && ($data['scaleid'] !== $grade_item->scaleid)) {
                    $errors['scaleid'] = get_string('modgradecantchangescale', 'grades');
                }
            }
        }
        if ($grade_item) {
            if ($grade_item->gradetype == GRADE_TYPE_VALUE) {
                if ((((bool) get_config('moodle', 'grade_report_showmin')) &&
                    grade_floats_different($data['grademin'], $grade_item->grademin)) ||
                    grade_floats_different($data['grademax'], $grade_item->grademax)) {
                    if ($grade_item->has_grades() && empty($data['rescalegrades'])) {
                        $errors['rescalegrades'] = get_string('mustchooserescaleyesorno', 'grades');
                    }
                }
            }
        }

        return $errors;
    }
1159870
protected function update_peer_grade(stdclass $assessment) {
        $grades     = $this->get_current_assessment_data($assessment);
        $suggested  = $this->calculate_peer_grade($grades);
        if (!is_null($suggested)) {
            $this->workshop->set_peer_grade($assessment->id, $suggested);
        }
        return $suggested;
    }
1330444
protected function helper_grading_report_grade($grade, $over=null) {
        $a = new stdclass();
        $a->grade = is_null($grade) ? get_string('nullgrade', 'workshop') : $grade;
        if (is_null($over)) {
            $text = get_string('formataggregatedgrade', 'workshop', $a);
        } else {
            $a->over = is_null($over) ? get_string('nullgrade', 'workshop') : $over;
            $text = get_string('formataggregatedgradeover', 'workshop', $a);
        }
        return $text;
    }
1272846
public function view(stdClass $grade) {
        global $PAGE;
        $html = '';
        // Show a link to download the pdf.
        if (page_editor::has_annotations_or_comments($grade->id, false)) {
            $html = $this->assignment->render_area_files('assignfeedback_editpdf',
                                                         document_services::FINAL_PDF_FILEAREA,
                                                         $grade->id);

            // Also show the link to the read-only interface.
            $renderer = $PAGE->get_renderer('assignfeedback_editpdf');
            $widget = $this->get_widget($grade->userid, $grade, true);

            $html .= $renderer->render($widget);
        }
        return $html;
    }
266939
function validation($data, $files) {
        $errors = parent::validation($data, $files);

        $mform =& $this->_form;

        // check the calculation formula
        if ($data['calculation'] != '') {
            $grade_item = grade_item::fetch(array('id'=>$data['id'], 'courseid'=>$data['courseid']));
            $calculation = calc_formula::unlocalize(stripslashes($data['calculation']));
            $result = $grade_item->validate_formula($calculation);
            if ($result !== true) {
                $errors['calculation'] = $result;
            }
        }

        return $errors;
    }
1091655
public function process($data) {
        $bulk = new bulk_insert($this->item);
        // Bulk insert messages the data to be passed in
        // ie: for all grades of empty grades apply the specified value.
        if ($bulk->is_applied($data)) {
            $filter = $bulk->get_type($data);
            $insertvalue = $bulk->get_insert_value($data);

            $userid = $this->item->id;
            foreach ($this->items as $gradeitemid => $gradeitem) {
                $null = $gradeitem->gradetype == GRADE_TYPE_SCALE ? -1 : '';
                $field = "finalgrade_{$gradeitem->id}_{$this->itemid}";
                if (isset($data->$field)) {
                    continue;
                }

                $oldfinalgradefield = "oldfinalgrade_{$gradeitem->id}_{$this->itemid}";
                // Bulk grade changes for all grades need to be processed and shouldn't be skipped if they had a previous grade.
                if ($gradeitem->is_course_item() || ($filter != 'all' && !empty($data->$oldfinalgradefield))) {
                    if ($gradeitem->is_course_item()) {
                        // The course total should not be overridden.
                        unset($data->$field);
                        unset($data->oldfinalgradefield);
                        $oldoverride = "oldoverride_{$gradeitem->id}_{$this->itemid}";
                        unset($data->$oldoverride);
                        $oldfeedback = "oldfeedback_{$gradeitem->id}_{$this->itemid}";
                        unset($data->$oldfeedback);
                    }
                    continue;
                }
                $grade = grade_grade::fetch(array(
                    'itemid' => $gradeitemid,
                    'userid' => $userid
                ));

                $data->$field = empty($grade) ? $null : $grade->finalgrade;
                $data->{"old$field"} = $data->$field;
            }

            foreach ($data as $varname => $value) {
                if (preg_match('/^oldoverride_(\d+)_(\d+)/', $varname, $matches)) {
                    // If we've selected overriding all grades.
                    if ($filter == 'all') {
                        $override = "override_{$matches[1]}_{$matches[2]}";
                        $data->$override = '1';
                    }
                }
                if (!preg_match('/^finalgrade_(\d+)_(\d+)/', $varname, $matches)) {
                    continue;
                }

                $gradeitem = grade_item::fetch(array(
                    'courseid' => $this->courseid,
                    'id' => $matches[1]
                ));

                $isscale = ($gradeitem->gradetype == GRADE_TYPE_SCALE);

                $empties = (trim($value) === '' or ($isscale and $value == -1));

                if ($filter == 'all' or $empties) {
                    $data->$varname = ($isscale and empty($insertvalue)) ?
                        -1 : $insertvalue;
                }
            }
        }
        return parent::process($data);
    }
335588
public function save(stdClass $submission, stdClass $data) {
        global $USER, $DB;

        $fileoptions = $this->get_file_options();

        $data = file_postupdate_standard_filemanager($data,
                                                     'files',
                                                     $fileoptions,
                                                     $this->assignment->get_context(),
                                                     'assignsubmission_file',
                                                     ASSIGNSUBMISSION_FILE_FILEAREA,
                                                     $submission->id);

        $filesubmission = $this->get_file_submission($submission->id);

        // Plagiarism code event trigger when files are uploaded.

        $fs = get_file_storage();
        $files = $fs->get_area_files($this->assignment->get_context()->id,
                                     'assignsubmission_file',
                                     ASSIGNSUBMISSION_FILE_FILEAREA,
                                     $submission->id,
                                     'id',
                                     false);

        $count = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA);

        $params = array(
            'context' => context_module::instance($this->assignment->get_course_module()->id),
            'courseid' => $this->assignment->get_course()->id,
            'objectid' => $submission->id,
            'other' => array(
                'content' => '',
                'pathnamehashes' => array_keys($files)
            )
        );
        if (!empty($submission->userid) && ($submission->userid != $USER->id)) {
            $params['relateduserid'] = $submission->userid;
        }
        if ($this->assignment->is_blind_marking()) {
            $params['anonymous'] = 1;
        }
        $event = \assignsubmission_file\event\assessable_uploaded::create($params);
        $event->set_legacy_files($files);
        $event->trigger();

        $groupname = null;
        $groupid = 0;
        // Get the group name as other fields are not transcribed in the logs and this information is important.
        if (empty($submission->userid) && !empty($submission->groupid)) {
            $groupname = $DB->get_field('groups', 'name', array('id' => $submission->groupid), MUST_EXIST);
            $groupid = $submission->groupid;
        } else {
            $params['relateduserid'] = $submission->userid;
        }

        // Unset the objectid and other field from params for use in submission events.
        unset($params['objectid']);
        unset($params['other']);
        $params['other'] = array(
            'submissionid' => $submission->id,
            'submissionattempt' => $submission->attemptnumber,
            'submissionstatus' => $submission->status,
            'filesubmissioncount' => $count,
            'groupid' => $groupid,
            'groupname' => $groupname
        );

        if ($filesubmission) {
            $filesubmission->numfiles = $this->count_files($submission->id,
                                                           ASSIGNSUBMISSION_FILE_FILEAREA);
            $updatestatus = $DB->update_record('assignsubmission_file', $filesubmission);
            $params['objectid'] = $filesubmission->id;

            $event = \assignsubmission_file\event\submission_updated::create($params);
            $event->set_assign($this->assignment);
            $event->trigger();
            return $updatestatus;
        } else {
            $filesubmission = new stdClass();
            $filesubmission->numfiles = $this->count_files($submission->id,
                                                           ASSIGNSUBMISSION_FILE_FILEAREA);
            $filesubmission->submission = $submission->id;
            $filesubmission->assignment = $this->assignment->get_instance()->id;
            $filesubmission->id = $DB->insert_record('assignsubmission_file', $filesubmission);
            $params['objectid'] = $filesubmission->id;

            $event = \assignsubmission_file\event\submission_created::create($params);
            $event->set_assign($this->assignment);
            $event->trigger();
            return $filesubmission->id > 0;
        }
    }
477113
public function validate($data) {
        global $CFG;
        if (((string)(int)$data === (string)$data && $data > 0 && $data <= $CFG->gradepointmax)) {
            return true;
        } else {
            return get_string('gradepointdefault_validateerror', 'grades');
        }
    }
860879
protected function update(Data $data)
    {
        $this->__before('update', $data);
        $data->validate();

        if (!$this->doUpdate($data)) {
            return false;
        }

        $this->pack([], $data);
        $this->__after('update', $data);

        return true;
    }
701877
public function process_gradebook_grade_item(array $data, array $raw) {

        // here we use get_nextid() to get a nondecreasing sequence
        $data['sortorder'] = $this->converter->get_nextid();

        if ($data['itemtype'] === 'mod') {
            return $this->process_mod_grade_item($data, $raw);

        } else if (in_array($data['itemtype'], array('manual', 'course', 'category'))) {
            return $this->process_nonmod_grade_item($data, $raw);

        } else {
            $this->log('unsupported grade_item type', backup::LOG_ERROR, $data['itemtype']);
        }
    }
996644
public function data_postprocessing($data) {
        parent::data_postprocessing($data);

        foreach (['text', 'file'] as $type) {
            $field = 'submissiontype' . $type;
            $available = $field . 'available';
            $required = $field . 'required';
            if ($data->$required) {
                $data->$field = WORKSHOP_SUBMISSION_TYPE_REQUIRED;
            } else if ($data->$available) {
                $data->$field = WORKSHOP_SUBMISSION_TYPE_AVAILABLE;
            } else {
                $data->$field = WORKSHOP_SUBMISSION_TYPE_DISABLED;
            }
            unset($data->$available);
            unset($data->$required);
        }
    }
242944
public function save_grade($userid, $data) {

        // Need grade permission.
        require_capability('mod/assign:grade', $this->context);

        $instance = $this->get_instance();
        $submission = null;
        if ($instance->teamsubmission) {
            // We need to know what the most recent group submission is.
            // Specifically when determining if we are adding another attempt (we only want to add one attempt per team),
            // and when deciding if we need to update the gradebook with an edited grade.
            $mostrecentsubmission = $this->get_group_submission($userid, 0, false, -1);
            $this->set_most_recent_team_submission($mostrecentsubmission);
            // Get the submission that we are saving grades for. The data attempt number determines which submission attempt.
            $submission = $this->get_group_submission($userid, 0, false, $data->attemptnumber);
        } else {
            $submission = $this->get_user_submission($userid, false, $data->attemptnumber);
        }
        if ($instance->teamsubmission && !empty($data->applytoall)) {
            $groupid = 0;
            if ($this->get_submission_group($userid)) {
                $group = $this->get_submission_group($userid);
                if ($group) {
                    $groupid = $group->id;
                }
            }
            $members = $this->get_submission_group_members($groupid, true, $this->show_only_active_users());
            foreach ($members as $member) {
                // We only want to update the grade for this group submission attempt. The data attempt number could be
                // -1 which may end up in additional attempts being created for each group member instead of just one
                // additional attempt for the group.
                $this->apply_grade_to_user($data, $member->id, $submission->attemptnumber);
                $this->process_outcomes($member->id, $data, $userid);
            }
        } else {
            $this->apply_grade_to_user($data, $userid, $data->attemptnumber);

            $this->process_outcomes($userid, $data);
        }

        return true;
    }
785189
public function save(stdClass $grade, stdClass $data) {
        // Source user id is only added to the form if there was a pdf.
        if (!empty($data->editpdf_source_userid)) {
            $sourceuserid = $data->editpdf_source_userid;
            // Copy drafts annotations and comments if current user is different to sourceuserid.
            if ($sourceuserid != $grade->userid) {
                page_editor::copy_drafts_from_to($this->assignment, $grade, $sourceuserid);
            }
        }
        if (page_editor::has_annotations_or_comments($grade->id, true)) {
            document_services::generate_feedback_document($this->assignment, $grade->userid, $grade->attemptnumber);
        }

        return true;
    }