Get Activities completion status

@param int $courseid ID of the Course
@param int $userid ID of the User
@return array of activities progress and warnings
@throws moodle_exception
@since Moodle 2.9
@throws moodle_exception
167260
public static function get_activities_completion_status($courseid, $userid) {
        global $CFG, $USER;
        require_once($CFG->libdir . '/grouplib.php');

        $warnings = array();
        $arrayparams = array(
            'courseid' => $courseid,
            'userid'   => $userid,
        );

        $params = self::validate_parameters(self::get_activities_completion_status_parameters(), $arrayparams);

        $course = get_course($params['courseid']);
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
        core_user::require_active_user($user);

        $context = context_course::instance($course->id);
        self::validate_context($context);

        // Check that current user have permissions to see this user's activities.
        if ($user->id != $USER->id) {
            require_capability('report/progress:view', $context);
            if (!groups_user_groups_visible($course, $user->id)) {
                // We are not in the same group!
                throw new moodle_exception('accessdenied', 'admin');
            }
        }

        $completion = new completion_info($course);
        $activities = $completion->get_activities();

        $results = array();
        foreach ($activities as $activity) {

            // Check if current user has visibility on this activity.
            if (!$activity->uservisible) {
                continue;
            }

            // Get progress information and state (we must use get_data because it works for all user roles in course).
            $activitycompletiondata = $completion->get_data($activity, true, $user->id);

            $results[] = array(
                       'cmid'          => $activity->id,
                       'modname'       => $activity->modname,
                       'instance'      => $activity->instance,
                       'state'         => $activitycompletiondata->completionstate,
                       'timecompleted' => $activitycompletiondata->timemodified,
                       'tracking'      => $activity->completion,
                       'overrideby'    => $activitycompletiondata->overrideby,
                       'valueused'     => core_availability\info::completion_value_used($course, $activity->id)
            );
        }

        $results = array(
            'statuses' => $results,
            'warnings' => $warnings
        );
        return $results;
    }
140794
public function sync(progress_trace $trace, $courseid = null) {
        global $DB;

        if (!enrol_is_enabled('self')) {
            $trace->finished();
            return 2;
        }

        // Unfortunately this may take a long time, execution can be interrupted safely here.
        core_php_time_limit::raise();
        raise_memory_limit(MEMORY_HUGE);

        $trace->output('Verifying self-enrolments...');

        $params = array('now'=>time(), 'useractive'=>ENROL_USER_ACTIVE, 'courselevel'=>CONTEXT_COURSE);
        $coursesql = "";
        if ($courseid) {
            $coursesql = "AND e.courseid = :courseid";
            $params['courseid'] = $courseid;
        }

        // Note: the logic of self enrolment guarantees that user logged in at least once (=== u.lastaccess set)
        //       and that user accessed course at least once too (=== user_lastaccess record exists).

        // First deal with users that did not log in for a really long time - they do not have user_lastaccess records.
        $sql = "SELECT e.*, ue.userid
                  FROM {user_enrolments} ue
                  JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'self' AND e.customint2 > 0)
                  JOIN {user} u ON u.id = ue.userid
                 WHERE :now - u.lastaccess > e.customint2
                       $coursesql";
        $rs = $DB->get_recordset_sql($sql, $params);
        foreach ($rs as $instance) {
            $userid = $instance->userid;
            unset($instance->userid);
            $this->unenrol_user($instance, $userid);
            $days = $instance->customint2 / 60*60*24;
            $trace->output("unenrolling user $userid from course $instance->courseid as they have did not log in for at least $days days", 1);
        }
        $rs->close();

        // Now unenrol from course user did not visit for a long time.
        $sql = "SELECT e.*, ue.userid
                  FROM {user_enrolments} ue
                  JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'self' AND e.customint2 > 0)
                  JOIN {user_lastaccess} ul ON (ul.userid = ue.userid AND ul.courseid = e.courseid)
                 WHERE :now - ul.timeaccess > e.customint2
                       $coursesql";
        $rs = $DB->get_recordset_sql($sql, $params);
        foreach ($rs as $instance) {
            $userid = $instance->userid;
            unset($instance->userid);
            $this->unenrol_user($instance, $userid);
                $days = $instance->customint2 / 60*60*24;
            $trace->output("unenrolling user $userid from course $instance->courseid as they have did not access course for at least $days days", 1);
        }
        $rs->close();

        $trace->output('...user self-enrolment updates finished.');
        $trace->finished();

        $this->process_expirations($trace, $courseid);

        return 0;
    }
1132067
public static function data_for_user_competency_summary_in_course($userid, $competencyid, $courseid) {
        global $PAGE;
        $params = self::validate_parameters(self::data_for_user_competency_summary_in_course_parameters(), array(
            'userid' => $userid,
            'competencyid' => $competencyid,
            'courseid' => $courseid
        ));
        $context = context_user::instance($params['userid']);
        self::validate_context($context);
        $output = $PAGE->get_renderer('tool_lp');

        $renderable = new user_competency_summary_in_course($params['userid'], $params['competencyid'], $params['courseid']);
        return $renderable->export_for_template($output);
    }
201110
public static function is_user_gradable_in_course($courseid, $userid) {
        global $CFG;

        $gradableuser = false;
        $coursecontext = \context_course::instance($courseid);
        if (is_enrolled($coursecontext, $userid, '', false)) {
            $roles = get_user_roles($coursecontext, $userid);
            $gradebookroles = explode(',', $CFG->gradebookroles);
            foreach ($roles as $role) {
                foreach ($gradebookroles as $gradebookrole) {
                    if ($role->roleid = $gradebookrole) {
                        $gradableuser = true;
                    }
                }
            }
        }

        return $gradableuser;
    }
839567
public static function viewed($context, $courseid, $userid) {
        $event = \gradereport_overview\event\grade_report_viewed::create(
            array(
                'context' => $context,
                'courseid' => $courseid,
                'relateduserid' => $userid,
            )
        );
        $event->trigger();
    }
1103007
public static function get_course_notes($courseid, $userid = 0) {
        global $CFG, $USER;

        if (empty($CFG->enablenotes)) {
            throw new moodle_exception('notesdisabled', 'notes');
        }

        $warnings = array();
        $arrayparams = array(
            'courseid' => $courseid,
            'userid'   => $userid,
        );
        $params = self::validate_parameters(self::get_course_notes_parameters(), $arrayparams);

        if (empty($params['courseid'])) {
            $params['courseid'] = SITEID;
        }
        $user = null;
        if (!empty($params['userid'])) {
            $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
            core_user::require_active_user($user);
        }

        $course = get_course($params['courseid']);

        $systemcontext = context_system::instance();
        $canmanagesystemnotes = has_capability('moodle/notes:manage', $systemcontext);

        if ($course->id == SITEID) {
            $context = $systemcontext;
            $canmanagecoursenotes = $canmanagesystemnotes;
        } else {
            $context = context_course::instance($course->id);
            $canmanagecoursenotes = has_capability('moodle/notes:manage', $context);
        }
        self::validate_context($context);

        $sitenotes = array();
        $coursenotes = array();
        $personalnotes = array();

        if ($course->id != SITEID) {

            require_capability('moodle/notes:view', $context);
            $sitenotes = self::create_note_list(0, $systemcontext, $params['userid'], NOTES_STATE_SITE);
            $coursenotes = self::create_note_list($course->id, $context, $params['userid'], NOTES_STATE_PUBLIC);
            $personalnotes = self::create_note_list($course->id, $context, $params['userid'], NOTES_STATE_DRAFT,
                                                        $USER->id);
        } else {
            if (has_capability('moodle/notes:view', $context)) {
                $sitenotes = self::create_note_list(0, $context, $params['userid'], NOTES_STATE_SITE);
            }
            // It returns notes only for a specific user!
            if (!empty($user)) {
                $usercourses = enrol_get_users_courses($user->id, true);
                foreach ($usercourses as $c) {
                    // All notes at course level, only if we have capability on every course.
                    if (has_capability('moodle/notes:view', context_course::instance($c->id))) {
                        $coursenotes += self::create_note_list($c->id, $context, $params['userid'], NOTES_STATE_PUBLIC);
                    }
                }
            }
        }

        $results = array(
            'sitenotes'     => $sitenotes,
            'coursenotes'   => $coursenotes,
            'personalnotes' => $personalnotes,
            'canmanagesystemnotes' => $canmanagesystemnotes,
            'canmanagecoursenotes' => $canmanagecoursenotes,
            'warnings'      => $warnings
        );
        return $results;

    }
60022
public static function check_autologin_prerequisites($userid) {
        global $CFG;

        if (!$CFG->enablewebservices or !$CFG->enablemobilewebservice) {
            throw new moodle_exception('enablewsdescription', 'webservice');
        }

        if (!is_https()) {
            throw new moodle_exception('httpsrequired', 'tool_mobile');
        }

        if (has_capability('moodle/site:config', context_system::instance(), $userid) or is_siteadmin($userid)) {
            throw new moodle_exception('autologinnotallowedtoadmins', 'tool_mobile');
        }
    }
537990
public function get_contexts_for_userid(int $userid) : contextlist_collection {
        $progress = static::get_log_tracer();

        $components = $this->get_component_list();
        $a = (object) [
            'total' => count($components),
            'progress' => 0,
            'component' => '',
            'datetime' => userdate(time()),
        ];
        $clcollection = new contextlist_collection($userid);

        $progress->output(get_string('trace:fetchcomponents', 'core_privacy', $a), 1);
        foreach ($components as $component) {
            $a->component = $component;
            $a->progress++;
            $a->datetime = userdate(time());
            $progress->output(get_string('trace:processingcomponent', 'core_privacy', $a), 2);
            $contextlist = $this->handled_component_class_callback($component, core_user_data_provider::class,
                'get_contexts_for_userid', [$userid]);
            if ($contextlist === null) {
                $contextlist = new local\request\contextlist();
            }

            // Each contextlist is tied to its respective component.
            $contextlist->set_component($component);

            // Add contexts that the component may not know about.
            // Example of these include activity completion which modules do not know about themselves.
            $contextlist = local\request\helper::add_shared_contexts_to_contextlist_for($userid, $contextlist);

            if (count($contextlist)) {
                $clcollection->add_contextlist($contextlist);
            }
        }
        $progress->output(get_string('trace:done', 'core_privacy'), 1);

        return $clcollection;
    }
965428
private function get_conversations_for_user(int $userid) : moodle_recordset {
        global $DB;

        // We shouldn't be joining directly on the group table as group
        // conversations may (in the future) be something created that
        // isn't related to an actual group in a course. However, for
        // now this will have to do before 3.7 code freeze.
        // See related MDL-63814.
        $sql = "SELECT DISTINCT mc.id, mc.name, c.id as courseid, c.fullname as coursename, g.id as groupid,
                                g.picture, g.hidepicture
                  FROM {message_conversations} mc
                  JOIN {groups} g
                    ON mc.itemid = g.id
                  JOIN {course} c
                    ON g.courseid = c.id
                  JOIN {message_email_messages} mem
                    ON mem.conversationid = mc.id
                 WHERE mem.useridto = ?
                   AND mem.id <= ?";

        return $DB->get_recordset_sql($sql, [$userid, $this->maxid]);
    }
58353
public function block_community_add_course($course, $userid) {
        global $DB;

        $community = $this->block_community_get_course($course->url, $userid);

        if (empty($community)) {
            $community = new stdClass();
            $community->userid = $userid;
            $community->coursename = $course->name;
            $community->coursedescription = $course->description;
            $community->courseurl = $course->url;
            $community->imageurl = $course->imageurl;
            return $DB->insert_record('block_community', $community);
        } else {
            return false;
        }
    }
520920
protected static function export_user_data_in_course_contexts($userid, array $contexts) {
        global $DB;

        $contexts = array_filter($contexts, function($context) {
            return $context->contextlevel == CONTEXT_COURSE;
        });
        if (empty($contexts)) {
            return;
        }

        $helper = new performance_helper();
        $path = [get_string('competencies', 'core_competency')];
        $courseids = array_map(function($context) {
            return $context->instanceid;
        }, $contexts);

        // Fetch all the records of competency proficiency in the course.
        $ffields = competency_framework::get_sql_fields('f', 'f_');
        $compfields = competency::get_sql_fields('c', 'c_');
        $uccfields = user_competency_course::get_sql_fields('ucc', 'ucc_');
        $ctxfields = context_helper::get_preload_record_columns_sql('ctx');
        list($insql, $inparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
        $sql = "
            SELECT $ffields, $compfields, $uccfields, $ctxfields
              FROM {" . user_competency_course::TABLE . "} ucc
              JOIN {" . competency::TABLE . "} c
                ON c.id = ucc.competencyid
              JOIN {" . competency_framework::TABLE . "} f
                ON f.id = c.competencyframeworkid
              JOIN {context} ctx
                ON ctx.id = f.contextid
             WHERE ucc.userid = :userid
               AND ucc.courseid $insql
          ORDER BY ucc.courseid, c.id";
        $params = array_merge($inparams, ['userid' => $userid]);

        // Export data.
        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'ucc_courseid', [], function($carry, $record) use ($helper) {
            context_helper::preload_from_record($record);
            $framework = new competency_framework(null, competency_framework::extract_record($record, 'f_'));
            $competency = new competency(null, competency::extract_record($record, 'c_'));
            $ucc = new user_competency_course(null, user_competency_course::extract_record($record, 'ucc_'));
            $helper->ingest_framework($framework);

            $carry[] = array_merge(static::transform_competency_brief($competency), [
                'rating' => [
                    'rating' => static::transform_competency_grade($competency, $ucc->get('grade'), $helper),
                    'proficient' => static::transform_proficiency($ucc->get('proficiency')),
                    'timecreated' => transform::datetime($ucc->get('timecreated')),
                    'timemodified' => transform::datetime($ucc->get('timemodified')),
                ]
            ]);
            return $carry;

        }, function($courseid, $data) use ($path) {
            $context = context_course::instance($courseid);
            writer::with_context($context)->export_data($path, (object) ['ratings' => $data]);
        });

        // Export usermodified data.
        static::export_user_data_in_course_contexts_associations($userid, $courseids, $path);
        static::export_user_data_in_course_contexts_settings($userid, $courseids, $path);
        static::export_user_data_in_course_contexts_rated_by_me($userid, $courseids, $path, $helper);
    }
505211
public static function count_competencies($courseid) {
        global $DB;

        $sql = 'SELECT COUNT(comp.id)
                  FROM {' . self::TABLE . '} coursecomp
                  JOIN {' . competency::TABLE . '} comp
                    ON coursecomp.competencyid = comp.id
                 WHERE coursecomp.courseid = ? ';
        $params = array($courseid);

        $results = $DB->count_records_sql($sql, $params);

        return $results;
    }
308155
public static function count_competencies_in_course($courseid) {
        static::require_enabled();
        // Check the user have access to the course.
        self::validate_course($courseid);

        // First we do a permissions check.
        $context = context_course::instance($courseid);

        $capabilities = array('moodle/competency:coursecompetencyview', 'moodle/competency:coursecompetencymanage');
        if (!has_any_capability($capabilities, $context)) {
             throw new required_capability_exception($context, 'moodle/competency:coursecompetencyview', 'nopermissions', '');
        }

        // OK - all set.
        return course_competency::count_competencies($courseid);
    }
1305741
public static function get_by_user_and_competency($userid, $competencyid) {
        global $DB;

        $sql = 'SELECT p.*
                  FROM {' . self::TABLE . '} p
             LEFT JOIN {' . plan_competency::TABLE . '} pc
                    ON pc.planid = p.id
                   AND pc.competencyid = :competencyid1
             LEFT JOIN {' . user_competency_plan::TABLE . '} ucp
                    ON ucp.planid = p.id
                   AND ucp.competencyid = :competencyid2
             LEFT JOIN {' . template_competency::TABLE . '} tc
                    ON tc.templateid = p.templateid
                   AND tc.competencyid = :competencyid3
                 WHERE p.userid = :userid
                   AND (pc.id IS NOT NULL
                    OR ucp.id IS NOT NULL
                    OR tc.id IS NOT NULL)
              ORDER BY p.id ASC';

        $params = array(
            'competencyid1' => $competencyid,
            'competencyid2' => $competencyid,
            'competencyid3' => $competencyid,
            'userid' => $userid
        );

        $plans = array();
        $records = $DB->get_records_sql($sql, $params);
        foreach ($records as $record) {
            $plans[$record->id] = new plan(0, $record);
        }

        return $plans;
    }
629644
public function get_user_completion($user_id, $criteria) {
        $params = array(
            'course'        => $this->course_id,
            'userid'        => $user_id,
            'criteriaid'    => $criteria->id,
        );

        $completion = new completion_criteria_completion($params);
        return $completion;
    }
859877
public static function get_contexts_for_userid(int $userid) : contextlist {
        global $DB;

        $contextlist = new contextlist();

        $publishstates = [
            NOTES_STATE_PUBLIC,
            NOTES_STATE_SITE
        ];
        list($publishstatesql, $publishstateparams) = $DB->get_in_or_equal($publishstates, SQL_PARAMS_NAMED);

        // Retrieve all the Course contexts associated with notes written by the user, and also written about the user.
        // Only notes written about the user that are public or site wide will be exported.
        $sql = "SELECT c.id
                  FROM {context} c
            INNER JOIN {post} p ON p.courseid = c.instanceid AND c.contextlevel = :contextcoursewrittenby
                 WHERE p.module = 'notes'
                   AND p.usermodified = :usermodified
                 UNION
                SELECT c.id
                  FROM {context} c
            INNER JOIN {post} p ON p.courseid = c.instanceid AND c.contextlevel = :contextcoursewrittenfor
                 WHERE p.module = 'notes'
                   AND p.userid = :userid
                   AND p.publishstate {$publishstatesql}";

        $params = [
            'contextcoursewrittenby'  => CONTEXT_COURSE,
            'usermodified'            => $userid,
            'contextcoursewrittenfor' => CONTEXT_COURSE,
            'userid'                  => $userid
        ];
        $params += $publishstateparams;

        $contextlist->add_from_sql($sql, $params);

        return $contextlist;
    }
1275021
public function _checkTrackCount($userId)
    {
        $sqlCount  = 'SELECT COUNT(*) AS count,
                SUM(CASE WHEN gto_completion_time IS NULL THEN 0 ELSE 1 END) AS completed
            FROM gems__tokens INNER JOIN
                gems__reception_codes ON gto_reception_code = grc_id_reception_code AND grc_success = 1
            WHERE gto_id_respondent_track = ?';

        $counts = $this->db->fetchRow($sqlCount, $this->_respTrackId);
        if (! $counts) {
            $counts = array('count' => 0, 'completed' => 0);
        }

        $values['gr2t_count']      = intval($counts['count']);
        $values['gr2t_completed']  = intval($counts['completed']);

        if (! $this->_respTrackData['gr2t_end_date_manual']) {
            $values['gr2t_end_date'] = $this->calculateEndDate();
        }

        if ($values['gr2t_count'] == $values['gr2t_completed']) {
            if (null === $this->_respTrackData['gr2t_end_date']) {
                $now =  new \MUtil_Date();
                $values['gr2t_end_date'] = $now->toString(\Gems_Tracker::DB_DATETIME_FORMAT);
            }
            //Handle TrackCompletionEvent, send only changed fields in $values array
            $this->handleTrackCompletion($values, $userId);
        }

        // Remove unchanged values
        $this->tracker->filterChangesOnly($this->_respTrackData, $values);

        return $this->_updateTrack($values, $userId);
    }