Esempio n. 1
0
 /**
  * Test update_activity_completion_status_manually
  */
 public function test_update_activity_completion_status_manually()
 {
     global $DB, $CFG;
     $this->resetAfterTest(true);
     $CFG->enablecompletion = true;
     $user = $this->getDataGenerator()->create_user();
     $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
     $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id), array('completion' => 1));
     $cm = get_coursemodule_from_id('data', $data->cmid);
     $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
     $this->setUser($user);
     $result = core_completion_external::update_activity_completion_status_manually($data->cmid, true);
     // We need to execute the return values cleaning process to simulate the web service server.
     $result = external_api::clean_returnvalue(core_completion_external::update_activity_completion_status_manually_returns(), $result);
     // Check in DB.
     $this->assertEquals(1, $DB->get_field('course_modules_completion', 'completionstate', array('coursemoduleid' => $data->cmid)));
     // Check using the API.
     $completion = new completion_info($course);
     $completiondata = $completion->get_data($cm);
     $this->assertEquals(1, $completiondata->completionstate);
     $this->assertTrue($result['status']);
     $result = core_completion_external::update_activity_completion_status_manually($data->cmid, false);
     // We need to execute the return values cleaning process to simulate the web service server.
     $result = external_api::clean_returnvalue(core_completion_external::update_activity_completion_status_manually_returns(), $result);
     $this->assertEquals(0, $DB->get_field('course_modules_completion', 'completionstate', array('coursemoduleid' => $data->cmid)));
     $completiondata = $completion->get_data($cm);
     $this->assertEquals(0, $completiondata->completionstate);
     $this->assertTrue($result['status']);
 }
Esempio n. 2
0
 /**
  * Taken from /format/renderer.php
  * Generate a summary of the activites in a section
  *
  * @param stdClass $section The course_section entry from DB
  * @param stdClass $course the course record from DB
  * @param array    $mods (argument not used)
  * @return string HTML to output.
  */
 public static function section_activity_summary($section, $course, $mods)
 {
     global $CFG;
     require_once $CFG->libdir . '/completionlib.php';
     $modinfo = get_fast_modinfo($course);
     if (empty($modinfo->sections[$section->section])) {
         return '';
     }
     // Generate array with count of activities in this section.
     $sectionmods = array();
     $total = 0;
     $complete = 0;
     $cancomplete = isloggedin() && !isguestuser();
     $completioninfo = new completion_info($course);
     foreach ($modinfo->sections[$section->section] as $cmid) {
         $thismod = $modinfo->cms[$cmid];
         if ($thismod->uservisible) {
             if (isset($sectionmods[$thismod->modname])) {
                 $sectionmods[$thismod->modname]['name'] = $thismod->modplural;
                 $sectionmods[$thismod->modname]['count']++;
             } else {
                 $sectionmods[$thismod->modname]['name'] = $thismod->modfullname;
                 $sectionmods[$thismod->modname]['count'] = 1;
             }
             if ($cancomplete && $completioninfo->is_enabled($thismod) != COMPLETION_TRACKING_NONE) {
                 $total++;
                 $completiondata = $completioninfo->get_data($thismod, true);
                 if ($completiondata->completionstate == COMPLETION_COMPLETE || $completiondata->completionstate == COMPLETION_COMPLETE_PASS) {
                     $complete++;
                 }
             }
         }
     }
     if (empty($sectionmods)) {
         // No sections.
         return '';
     }
     // Output section activities summary.
     $o = '';
     $o .= "<div class='section-summary-activities mdl-right'>";
     foreach ($sectionmods as $mod) {
         $o .= "<span class='activity-count'>";
         $o .= $mod['name'] . ': ' . $mod['count'];
         $o .= "</span>";
     }
     $o .= "</div>";
     $a = false;
     // Output section completion data.
     if ($total > 0) {
         $a = new stdClass();
         $a->complete = $complete;
         $a->total = $total;
         $a->percentage = $complete / $total * 100;
         $o .= "<div class='section-summary-activities mdl-right'>";
         $o .= "<span class='activity-count'>" . get_string('progresstotal', 'completion', $a) . "</span>";
         $o .= "</div>";
     }
     $retobj = (object) array('output' => $o, 'progress' => $a, 'complete' => $complete, 'total' => $total);
     return $retobj;
 }
Esempio n. 3
0
 public function is_available($not, \core_availability\info $info, $grabthelot, $userid)
 {
     $modinfo = $info->get_modinfo();
     $completion = new \completion_info($modinfo->get_course());
     if (!array_key_exists($this->cmid, $modinfo->cms)) {
         // If the cmid cannot be found, always return false regardless
         // of the condition or $not state. (Will be displayed in the
         // information message.)
         $allow = false;
     } else {
         // The completion system caches its own data so no caching needed here.
         $completiondata = $completion->get_data((object) array('id' => $this->cmid), $grabthelot, $userid, $modinfo);
         $allow = true;
         if ($this->expectedcompletion == COMPLETION_COMPLETE) {
             // Complete also allows the pass, fail states.
             switch ($completiondata->completionstate) {
                 case COMPLETION_COMPLETE:
                 case COMPLETION_COMPLETE_FAIL:
                 case COMPLETION_COMPLETE_PASS:
                     break;
                 default:
                     $allow = false;
             }
         } else {
             // Other values require exact match.
             if ($completiondata->completionstate != $this->expectedcompletion) {
                 $allow = false;
             }
         }
         if ($not) {
             $allow = !$allow;
         }
     }
     return $allow;
 }
/**
 * Check if an activity is configured to only show navbuttons when
 * complete and then check if the activity is complete
 * @param cm_info $cm the course module for the activity
 * @return boolean true if the navbuttons should be shown
 */
function navbuttons_activity_showbuttons($cm)
{
    $modname = $cm->modname;
    $show = get_config('block_navbuttons', 'activity' . $modname);
    if ($show === false || $show == NAVBUTTONS_ACTIVITY_ALWAYS) {
        return true;
        // No config or 'always show'
    }
    if ($show == NAVBUTTONS_ACTIVITY_NEVER) {
        return false;
    }
    if ($show == NAVBUTTONS_ACTIVITY_COMPLETE) {
        $completion = new completion_info($cm->get_course());
        if (!$completion->is_enabled($cm)) {
            return true;
            // No completion tracking - show the buttons
        }
        $cmcompletion = $completion->get_data($cm);
        if ($cmcompletion->completionstate == COMPLETION_INCOMPLETE) {
            return false;
        }
        return true;
    }
    if (!isloggedin() || isguestuser()) {
        return true;
        // Always show the buttons if not logged in
    }
    // NAVBUTTONS_ACTIVITY_CUSTOM
    $funcname = 'navbuttons_mod_' . $modname . '_showbuttons';
    if (!function_exists($funcname)) {
        return true;
        // Shouldn't have got to here, but allow the buttons anyway
    }
    return $funcname($cm);
}
Esempio n. 5
0
 /**
  * Test survey_view
  * @return void
  */
 public function test_survey_view()
 {
     global $CFG;
     $CFG->enablecompletion = 1;
     $this->resetAfterTest();
     $this->setAdminUser();
     // Setup test data.
     $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
     $survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id), array('completion' => 2, 'completionview' => 1));
     $context = context_module::instance($survey->cmid);
     $cm = get_coursemodule_from_instance('survey', $survey->id);
     // Trigger and capture the event.
     $sink = $this->redirectEvents();
     survey_view($survey, $course, $cm, $context, 'form');
     $events = $sink->get_events();
     // 2 additional events thanks to completion.
     $this->assertCount(3, $events);
     $event = array_shift($events);
     // Checking that the event contains the expected values.
     $this->assertInstanceOf('\\mod_survey\\event\\course_module_viewed', $event);
     $this->assertEquals($context, $event->get_context());
     $moodleurl = new \moodle_url('/mod/survey/view.php', array('id' => $cm->id));
     $this->assertEquals($moodleurl, $event->get_url());
     $this->assertEquals('form', $event->other['viewed']);
     $this->assertEventContextNotUsed($event);
     $this->assertNotEmpty($event->get_name());
     // Check completion status.
     $completion = new completion_info($course);
     $completiondata = $completion->get_data($cm);
     $this->assertEquals(1, $completiondata->completionstate);
 }
Esempio n. 6
0
 public function test_glossary_view()
 {
     global $CFG;
     $origcompletion = $CFG->enablecompletion;
     $CFG->enablecompletion = true;
     $this->resetAfterTest(true);
     // Generate all the things.
     $c1 = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
     $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1));
     $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1));
     $u1 = $this->getDataGenerator()->create_user();
     $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
     $modinfo = course_modinfo::instance($c1->id);
     $cm1 = $modinfo->get_cm($g1->cmid);
     $cm2 = $modinfo->get_cm($g2->cmid);
     $ctx1 = $cm1->context;
     $completion = new completion_info($c1);
     $this->setUser($u1);
     // Confirm what we've set up.
     $this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm1, false, $u1->id)->viewed);
     $this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm1, false, $u1->id)->completionstate);
     $this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm2, false, $u1->id)->viewed);
     $this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm2, false, $u1->id)->completionstate);
     // Simulate the view call.
     $sink = $this->redirectEvents();
     glossary_view($g1, $c1, $cm1, $ctx1, 'letter');
     $events = $sink->get_events();
     // Assertions.
     $this->assertCount(3, $events);
     $this->assertEquals('\\core\\event\\course_module_completion_updated', $events[0]->eventname);
     $this->assertEquals('\\core\\event\\course_module_completion_updated', $events[1]->eventname);
     $this->assertEquals('\\mod_glossary\\event\\course_module_viewed', $events[2]->eventname);
     $this->assertEquals($g1->id, $events[2]->objectid);
     $this->assertEquals('letter', $events[2]->other['mode']);
     $this->assertEquals(COMPLETION_VIEWED, $completion->get_data($cm1, false, $u1->id)->viewed);
     $this->assertEquals(COMPLETION_COMPLETE, $completion->get_data($cm1, false, $u1->id)->completionstate);
     $this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm2, false, $u1->id)->viewed);
     $this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm2, false, $u1->id)->completionstate);
     // Tear down.
     $sink->close();
     $CFG->enablecompletion = $origcompletion;
 }
Esempio n. 7
0
/**
 * get_activity_tree :: course_modinfo -> integer -> context -> array
 * @param \course_modinfo $modinfo
 * @param integer $section_number
 * @param \context $context
 * @return array
 */
function get_activity_tree(\course_modinfo $modinfo, $section_number, \context $context)
{
    $completion_info = new \completion_info($modinfo->get_course());
    return F\map(F\filter($modinfo->get_section_info_all(), function (\section_info $section_info) {
        return $section_info->visible;
    }), function (\section_info $section_info) use($completion_info, $section_number, $context) {
        $mods = F\map(F\filter($section_info->modinfo->cms, function (\cm_info $cm_info) use($section_info) {
            global $CFG;
            return ($cm_info->uservisible || $CFG->enableavailability && !empty($cm_info->availableinfo)) && (int) $cm_info->sectionnum === (int) $section_info->section;
        }), function (\cm_info $cm_info) use($completion_info, $context) {
            global $CFG;
            $canComplete = $CFG->enablecompletion && isloggedin() && !isguestuser() && (int) $completion_info->is_enabled($cm_info) === COMPLETION_TRACKING_MANUAL;
            $hasCompleted = false;
            if ($canComplete) {
                $completion_data = $completion_info->get_data($cm_info, true);
                $hasCompleted = F\contains([COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS], (int) $completion_data->completionstate);
            }
            return (object) ['id' => (int) $cm_info->id, 'name' => $cm_info->name, 'modname' => $cm_info->modname, 'current' => is_current_mod($cm_info, $context), 'available' => $cm_info->available, 'canComplete' => $canComplete, 'hasCompleted' => $hasCompleted];
        });
        return (object) ['id' => (int) $section_info->id, 'section' => (int) $section_info->section, 'name' => \get_section_name($section_info->modinfo->courseid, $section_info->section), 'current' => is_current_section($section_info, $section_number, $context), 'activities' => array_values($mods)];
    });
}
Esempio n. 8
0
 /**
  * Renders html for completion box on course page
  *
  * If completion is disabled, returns empty string
  * If completion is automatic, returns an icon of the current completion state
  * If completion is manual, returns a form (with an icon inside) that allows user to
  * toggle completion
  *
  * @param stdClass $course course object
  * @param completion_info $completioninfo completion info for the course, it is recommended
  *     to fetch once for all modules in course/section for performance
  * @param cm_info $mod module to show completion for
  * @param array $displayoptions display options, not used in core
  * @return string
  */
 public function course_section_cm_completion($course, &$completioninfo, cm_info $mod, $displayoptions = array())
 {
     global $CFG;
     $output = '';
     if (!empty($displayoptions['hidecompletion']) || !isloggedin() || isguestuser() || !$mod->uservisible) {
         return $output;
     }
     if ($completioninfo === null) {
         $completioninfo = new completion_info($course);
     }
     $completion = $completioninfo->is_enabled($mod);
     if ($completion == COMPLETION_TRACKING_NONE) {
         if ($this->page->user_is_editing()) {
             $output .= html_writer::span('&nbsp;', 'filler');
         }
         return $output;
     }
     $completiondata = $completioninfo->get_data($mod, true);
     $completionicon = '';
     if ($this->page->user_is_editing()) {
         switch ($completion) {
             case COMPLETION_TRACKING_MANUAL:
                 $completionicon = 'manual-enabled';
                 break;
             case COMPLETION_TRACKING_AUTOMATIC:
                 $completionicon = 'auto-enabled';
                 break;
         }
     } else {
         if ($completion == COMPLETION_TRACKING_MANUAL) {
             switch ($completiondata->completionstate) {
                 case COMPLETION_INCOMPLETE:
                     $completionicon = 'manual-n';
                     break;
                 case COMPLETION_COMPLETE:
                     $completionicon = 'manual-y';
                     break;
             }
         } else {
             // Automatic
             switch ($completiondata->completionstate) {
                 case COMPLETION_INCOMPLETE:
                     $completionicon = 'auto-n';
                     break;
                 case COMPLETION_COMPLETE:
                     $completionicon = 'auto-y';
                     break;
                 case COMPLETION_COMPLETE_PASS:
                     $completionicon = 'auto-pass';
                     break;
                 case COMPLETION_COMPLETE_FAIL:
                     $completionicon = 'auto-fail';
                     break;
             }
         }
     }
     if ($completionicon) {
         $formattedname = $mod->get_formatted_name();
         $imgalt = get_string('completion-alt-' . $completionicon, 'completion', $formattedname);
         if ($this->page->user_is_editing()) {
             // When editing, the icon is just an image.
             $completionpixicon = new pix_icon('i/completion-' . $completionicon, $imgalt, '', array('title' => $imgalt, 'class' => 'iconsmall'));
             $output .= html_writer::tag('span', $this->output->render($completionpixicon), array('class' => 'autocompletion'));
         } else {
             if ($completion == COMPLETION_TRACKING_MANUAL) {
                 $imgtitle = get_string('completion-title-' . $completionicon, 'completion', $formattedname);
                 $newstate = $completiondata->completionstate == COMPLETION_COMPLETE ? COMPLETION_INCOMPLETE : COMPLETION_COMPLETE;
                 // In manual mode the icon is a toggle form...
                 // If this completion state is used by the
                 // conditional activities system, we need to turn
                 // off the JS.
                 $extraclass = '';
                 if (!empty($CFG->enableavailability) && core_availability\info::completion_value_used($course, $mod->id)) {
                     $extraclass = ' preventjs';
                 }
                 $output .= html_writer::start_tag('form', array('method' => 'post', 'action' => new moodle_url('/course/togglecompletion.php'), 'class' => 'togglecompletion' . $extraclass));
                 $output .= html_writer::start_tag('div');
                 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'id', 'value' => $mod->id));
                 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
                 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'modulename', 'value' => $mod->name));
                 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'completionstate', 'value' => $newstate));
                 $output .= html_writer::empty_tag('input', array('type' => 'image', 'src' => $this->output->pix_url('i/completion-' . $completionicon), 'alt' => $imgalt, 'title' => $imgtitle, 'aria-live' => 'polite'));
                 $output .= html_writer::end_tag('div');
                 $output .= html_writer::end_tag('form');
             } else {
                 // In auto mode, the icon is just an image.
                 $completionpixicon = new pix_icon('i/completion-' . $completionicon, $imgalt, '', array('title' => $imgalt));
                 $output .= html_writer::tag('span', $this->output->render($completionpixicon), array('class' => 'autocompletion'));
             }
         }
     }
     return $output;
 }
Esempio n. 9
0
 /**
  * Performs the synchronisation of grades.
  *
  * @return bool|void
  */
 public function execute()
 {
     global $DB, $CFG;
     require_once $CFG->dirroot . '/enrol/lti/ims-blti/OAuth.php';
     require_once $CFG->dirroot . '/enrol/lti/ims-blti/OAuthBody.php';
     require_once $CFG->dirroot . '/lib/completionlib.php';
     require_once $CFG->libdir . '/gradelib.php';
     require_once $CFG->dirroot . '/grade/querylib.php';
     // Check if the authentication plugin is disabled.
     if (!is_enabled_auth('lti')) {
         mtrace('Skipping task - ' . get_string('pluginnotenabled', 'auth', get_string('pluginname', 'auth_lti')));
         return true;
     }
     // Check if the enrolment plugin is disabled - isn't really necessary as the task should not run if
     // the plugin is disabled, but there is no harm in making sure core hasn't done something wrong.
     if (!enrol_is_enabled('lti')) {
         mtrace('Skipping task - ' . get_string('enrolisdisabled', 'enrol_lti'));
         return true;
     }
     // Get all the enabled tools.
     if ($tools = \enrol_lti\helper::get_lti_tools(array('status' => ENROL_INSTANCE_ENABLED, 'gradesync' => 1))) {
         foreach ($tools as $tool) {
             mtrace("Starting - Grade sync for shared tool '{$tool->id}' for the course '{$tool->courseid}'.");
             // Variables to keep track of information to display later.
             $usercount = 0;
             $sendcount = 0;
             // We check for all the users - users can access the same tool from different consumers.
             if ($ltiusers = $DB->get_records('enrol_lti_users', array('toolid' => $tool->id), 'lastaccess DESC')) {
                 $completion = new \completion_info(get_course($tool->courseid));
                 foreach ($ltiusers as $ltiuser) {
                     $mtracecontent = "for the user '{$ltiuser->userid}' in the tool '{$tool->id}' for the course " . "'{$tool->courseid}'";
                     $usercount = $usercount + 1;
                     // Check if we do not have a serviceurl - this can happen if the sync process has an unexpected error.
                     if (empty($ltiuser->serviceurl)) {
                         mtrace("Skipping - Empty serviceurl {$mtracecontent}.");
                         continue;
                     }
                     // Check if we do not have a sourceid - this can happen if the sync process has an unexpected error.
                     if (empty($ltiuser->sourceid)) {
                         mtrace("Skipping - Empty sourceid {$mtracecontent}.");
                         continue;
                     }
                     // Need a valid context to continue.
                     if (!($context = \context::instance_by_id($tool->contextid))) {
                         mtrace("Failed - Invalid contextid '{$tool->contextid}' for the tool '{$tool->id}'.");
                         continue;
                     }
                     // Ok, let's get the grade.
                     $grade = false;
                     if ($context->contextlevel == CONTEXT_COURSE) {
                         // Check if the user did not completed the course when it was required.
                         if ($tool->gradesynccompletion && !$completion->is_course_complete($ltiuser->userid)) {
                             mtrace("Skipping - Course not completed {$mtracecontent}.");
                             continue;
                         }
                         // Get the grade.
                         if ($grade = grade_get_course_grade($ltiuser->userid, $tool->courseid)) {
                             $grademax = floatval($grade->item->grademax);
                             $grade = $grade->grade;
                         }
                     } else {
                         if ($context->contextlevel == CONTEXT_MODULE) {
                             $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST);
                             if ($tool->gradesynccompletion) {
                                 $data = $completion->get_data($cm, false, $ltiuser->userid);
                                 if ($data->completionstate != COMPLETION_COMPLETE_PASS && $data->completionstate != COMPLETION_COMPLETE) {
                                     mtrace("Skipping - Activity not completed {$mtracecontent}.");
                                     continue;
                                 }
                             }
                             $grades = grade_get_grades($cm->course, 'mod', $cm->modname, $cm->instance, $ltiuser->userid);
                             if (!empty($grades->items[0]->grades)) {
                                 $grade = reset($grades->items[0]->grades);
                                 if (!empty($grade->item)) {
                                     $grademax = floatval($grade->item->grademax);
                                 } else {
                                     $grademax = floatval($grades->items[0]->grademax);
                                 }
                                 $grade = $grade->grade;
                             }
                         }
                     }
                     if ($grade === false || $grade === null || strlen($grade) < 1) {
                         mtrace("Skipping - Invalid grade {$mtracecontent}.");
                         continue;
                     }
                     // No need to be dividing by zero.
                     if (empty($grademax)) {
                         mtrace("Skipping - Invalid grade {$mtracecontent}.");
                         continue;
                     }
                     // This can happen if the sync process has an unexpected error.
                     if ($grade == $ltiuser->lastgrade) {
                         mtrace("Not sent - The grade {$mtracecontent} was not sent as the grades are the same.");
                         continue;
                     }
                     // Sync with the external system.
                     $floatgrade = $grade / $grademax;
                     $body = \enrol_lti\helper::create_service_body($ltiuser->sourceid, $floatgrade);
                     try {
                         $response = sendOAuthBodyPOST('POST', $ltiuser->serviceurl, $ltiuser->consumerkey, $ltiuser->consumersecret, 'application/xml', $body);
                     } catch (\Exception $e) {
                         mtrace("Failed - The grade '{$floatgrade}' {$mtracecontent} failed to send.");
                         mtrace($e->getMessage());
                         continue;
                     }
                     if (strpos(strtolower($response), 'success') !== false) {
                         $DB->set_field('enrol_lti_users', 'lastgrade', intval($grade), array('id' => $ltiuser->id));
                         mtrace("Success - The grade '{$floatgrade}' {$mtracecontent} was sent.");
                         $sendcount = $sendcount + 1;
                     } else {
                         mtrace("Failed - The grade '{$floatgrade}' {$mtracecontent} failed to send.");
                     }
                 }
             }
             mtrace("Completed - Synced grades for tool '{$tool->id}' in the course '{$tool->courseid}'. " . "Processed {$usercount} users; sent {$sendcount} grades.");
             mtrace("");
         }
     }
 }
Esempio n. 10
0
 /**
  * Get course completion progress for specific course.
  * NOTE: It is by design that even teachers get course completion progress, this is so that they see exactly the
  * same as a student would in the personal menu.
  *
  * @param $course
  * @return stdClass | null
  */
 public static function course_completion_progress($course)
 {
     if (!isloggedin() || isguestuser()) {
         return null;
         // Can't get completion progress for users who aren't logged in.
     }
     // Security check - are they enrolled on course.
     $context = \context_course::instance($course->id);
     if (!is_enrolled($context, null, '', true)) {
         return null;
     }
     $completioninfo = new \completion_info($course);
     $trackcount = 0;
     $compcount = 0;
     if ($completioninfo->is_enabled()) {
         $modinfo = get_fast_modinfo($course);
         foreach ($modinfo->cms as $thismod) {
             if (!$thismod->uservisible) {
                 // Skip when mod is not user visible.
                 continue;
             }
             $completioninfo->get_data($thismod, true);
             if ($completioninfo->is_enabled($thismod) != COMPLETION_TRACKING_NONE) {
                 $trackcount++;
                 $completiondata = $completioninfo->get_data($thismod, true);
                 if ($completiondata->completionstate == COMPLETION_COMPLETE || $completiondata->completionstate == COMPLETION_COMPLETE_PASS) {
                     $compcount++;
                 }
             }
         }
     }
     $compobj = (object) array('complete' => $compcount, 'total' => $trackcount, 'progresshtml' => '');
     if ($trackcount > 0) {
         $progress = get_string('progresstotal', 'completion', $compobj);
         // TODO - we should be putting our HTML in a renderer.
         $progressinfo = '<div class="completionstatus outoftotal">' . $progress . '</div>';
         $compobj->progresshtml = $progressinfo;
     }
     return $compobj;
 }
Esempio n. 11
0
    function test_get_data() {
        global $DB, $SESSION;

        $c = new completion_info((object)array('id'=>42));
        $cm = (object)array('id'=>13, 'course'=>42);

        // 1. Not current user, record exists
        $sillyrecord = (object)array('frog'=>'kermit');

        /** @var $DB PHPUnit_Framework_MockObject_MockObject */
        $DB->expects($this->at(0))
            ->method('get_record')
            ->with('course_modules_completion', array('coursemoduleid'=>13,'userid'=>123))
            ->will($this->returnValue($sillyrecord));
        $result = $c->get_data($cm,false,123);
        $this->assertEquals($sillyrecord, $result);
        $this->assertTrue(empty($SESSION->completioncache));

        // 2. Not current user, default record, wholecourse (ignored)
        $DB->expects($this->at(0))
            ->method('get_record')
            ->with('course_modules_completion', array('coursemoduleid'=>13,'userid'=>123))
            ->will($this->returnValue(false));
        $result=$c->get_data($cm,true,123);
        $this->assertEquals((object)array(
            'id'=>'0','coursemoduleid'=>13,'userid'=>123,'completionstate'=>0,
            'viewed'=>0,'timemodified'=>0),$result);
        $this->assertTrue(empty($SESSION->completioncache));

        // 3. Current user, single record, not from cache
        $DB->expects($this->at(0))
            ->method('get_record')
            ->with('course_modules_completion', array('coursemoduleid'=>13,'userid'=>314159))
            ->will($this->returnValue($sillyrecord));
        $result = $c->get_data($cm);
        $this->assertEquals($sillyrecord, $result);
        $this->assertEquals($sillyrecord, $SESSION->completioncache[42][13]);
        // When checking time(), allow for second overlaps
        $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);

        // 4. Current user, 'whole course', but from cache
        $result = $c->get_data($cm, true);
        $this->assertEquals($sillyrecord, $result);

        // 5. Current user, single record, cache expired
        $SESSION->completioncache[42]['updated']=37; // Quite a long time ago
        $now = time();
        $SESSION->completioncache[17]['updated']=$now;
        $SESSION->completioncache[39]['updated']=72; // Also a long time ago
        $DB->expects($this->at(0))
            ->method('get_record')
            ->with('course_modules_completion', array('coursemoduleid'=>13,'userid'=>314159))
            ->will($this->returnValue($sillyrecord));
        $result = $c->get_data($cm, false);
        $this->assertEquals($sillyrecord, $result);

        // Check that updated value is right, then fudge it to make next compare
        // work
        $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);
        $SESSION->completioncache[42]['updated']=$now;
        // Check things got expired from cache
        $this->assertEquals(array(42=>array(13=>$sillyrecord, 'updated'=>$now), 17=>array('updated'=>$now)), $SESSION->completioncache);

        // 6. Current user, 'whole course' and record not in cache
        unset($SESSION->completioncache);

        // Scenario: Completion data exists for one CMid
        $basicrecord = (object)array('coursemoduleid'=>13);
        $DB->expects($this->at(0))
            ->method('get_records_sql')
            ->will($this->returnValue(array('1'=>$basicrecord)));

/*
        $DB->expectAt(0,'get_records_sql',array(new IgnoreWhitespaceExpectation("
SELECT
    cmc.*
FROM
    {course_modules} cm
    INNER JOIN {course_modules_completion} cmc ON cmc.coursemoduleid=cm.id
WHERE
    cm.course=? AND cmc.userid=?"),array(42,314159)));
*/
        // There are two CMids in total, the one we had data for and another one
        $modinfo = new stdClass();
        $modinfo->cms = array((object)array('id'=>13), (object)array('id'=>14));
        $result = $c->get_data($cm, true, 0, $modinfo);

        // Check result
        $this->assertEquals($basicrecord, $result);

        // Check the cache contents
        $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);
        $SESSION->completioncache[42]['updated'] = $now;
        $this->assertEquals(array(42=>array(13=>$basicrecord, 14=>(object)array(
            'id'=>'0', 'coursemoduleid'=>14, 'userid'=>314159, 'completionstate'=>0,
            'viewed'=>0, 'timemodified'=>0), 'updated'=>$now)), $SESSION->completioncache);
    }
 /**
  * Review this criteria and decide if the user has completed
  *
  * @param completion_completion $completion     The user's completion record
  * @param bool $mark Optionally set false to not save changes to database
  * @return bool
  */
 public function review($completion, $mark = true)
 {
     global $DB;
     $course = $DB->get_record('course', array('id' => $completion->course));
     $cm = $DB->get_record('course_modules', array('id' => $this->moduleinstance));
     $info = new completion_info($course);
     $data = $info->get_data($cm, false, $completion->userid);
     // If the activity is complete
     if (in_array($data->completionstate, array(COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS, COMPLETION_COMPLETE_FAIL))) {
         if ($mark) {
             $completion->mark_complete();
         }
         return true;
     }
     return false;
 }
Esempio n. 13
0
 /**
  * Test wiki_page_view.
  *
  * @return void
  */
 public function test_wiki_page_view()
 {
     global $CFG;
     $CFG->enablecompletion = COMPLETION_ENABLED;
     $this->resetAfterTest();
     $this->setAdminUser();
     // Setup test data.
     $course = $this->getDataGenerator()->create_course(array('enablecompletion' => COMPLETION_ENABLED));
     $options = array('completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => COMPLETION_VIEW_REQUIRED);
     $wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id), $options);
     $context = context_module::instance($wiki->cmid);
     $cm = get_coursemodule_from_instance('wiki', $wiki->id);
     $firstpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_first_page($wiki);
     // Trigger and capture the event.
     $sink = $this->redirectEvents();
     wiki_page_view($wiki, $firstpage, $course, $cm, $context);
     $events = $sink->get_events();
     // 2 additional events thanks to completion.
     $this->assertCount(3, $events);
     $event = array_shift($events);
     // Checking that the event contains the expected values.
     $this->assertInstanceOf('\\mod_wiki\\event\\page_viewed', $event);
     $this->assertEquals($context, $event->get_context());
     $pageurl = new \moodle_url('/mod/wiki/view.php', array('pageid' => $firstpage->id));
     $this->assertEquals($pageurl, $event->get_url());
     $this->assertEventContextNotUsed($event);
     $this->assertNotEmpty($event->get_name());
     // Check completion status.
     $completion = new completion_info($course);
     $completiondata = $completion->get_data($cm);
     $this->assertEquals(1, $completiondata->completionstate);
 }
 public function test_course_completion()
 {
     global $DB;
     $this->resetAfterTest();
     // Enable avaibility.
     // If not enabled all conditional fields will be ignored.
     set_config('enableavailability', 1);
     // Enable course completion.
     // If not enabled all completion settings will be ignored.
     set_config('enablecompletion', COMPLETION_ENABLED);
     $generator = $this->getDataGenerator();
     // Create course with completion tracking enabled.
     $course = $generator->create_course(['enablecompletion' => 1, 'numsections' => 3], ['createsections' => true]);
     // Enrol user to completion tracking course.
     $sturole = $DB->get_record('role', array('shortname' => 'student'));
     $generator->enrol_user($this->user1->id, $course->id, $sturole->id);
     // Create page with completion marked on view.
     $page1 = $generator->create_module('page', array('course' => $course->id, 'name' => 'page1 complete on view'), array('completion' => 2, 'completionview' => 1));
     $modinfo = get_fast_modinfo($course);
     $page1cm = $modinfo->get_cm($page1->cmid);
     // Create page restricted to only show when first page is viewed.
     $moduleinfo = (object) [];
     $moduleinfo->course = $course->id;
     $moduleinfo->name = 'page2 available after page1 viewed';
     $moduleinfo->availability = json_encode(\core_availability\tree::get_root_json([\availability_completion\condition::get_json($page1->cmid, COMPLETION_COMPLETE)], '&'));
     $page2 = $generator->create_module('page', $moduleinfo);
     // Make section 2 restricted to only show when first page is viewed.
     $section = $modinfo->get_section_info(2);
     $sectionupdate = ['id' => $section->id, 'availability' => json_encode(\core_availability\tree::get_root_json([\availability_completion\condition::get_json($page1->cmid, COMPLETION_COMPLETE)], '&'))];
     $DB->update_record('course_sections', $sectionupdate);
     // Check user1 has expected unavailable section and mod.
     $this->setUser($this->user1);
     // Dump cache and reget modinfo.
     get_fast_modinfo($course, 0, true);
     $modinfo = get_fast_modinfo($course);
     $page2cm = $modinfo->get_cm($page2->cmid);
     list($previouslyunavailablesections, $previouslyunavailablemods) = local::conditionally_unavailable_elements($course);
     $this->assertContains(2, $previouslyunavailablesections);
     $this->assertContains($page2cm->id, $previouslyunavailablemods);
     // View page1 to trigger completion
     $context = context_module::instance($page1->cmid);
     page_view($page1, $course, $page1cm, $context);
     $completion = new completion_info($course);
     $completiondata = $completion->get_data($page1cm);
     $this->assertEquals(COMPLETION_COMPLETE, $completiondata->completionstate);
     get_fast_modinfo($course, 0, true);
     // Reset modinfo.
     // Make sure that unavailable sections and mods no longer contain the ones requiring availabililty criteria
     // satisfying.
     list($unavailablesections, $unavailablemods) = local::conditionally_unavailable_elements($course);
     $this->assertNotContains($page2cm->id, $unavailablemods);
     $this->assertNotContains(2, $unavailablesections);
     $result = $this->courseservice->course_completion($course->shortname, $previouslyunavailablesections, $previouslyunavailablemods);
     // Make sure that the second page module (which is now newly available) appears in the list of newly available
     // module html.
     $this->assertTrue(isset($result['newlyavailablemodhtml'][$page2->cmid]));
     // Make sure that the second section (which is now wnely available) appears in the list of newly available
     // section html.
     $this->assertTrue(isset($result['newlyavailablesectionhtml'][2]));
 }
function slides_make_outline($course,$topics_info,$sections,$editing){
	// TOPICS OUTLINE list
	echo '<li id="section--1" class="section outline clearfix" >';
	echo "<ul id='section-outline'>\n";
	
	// check activity completion and add to array where section id is key
	$completionbysection = array();
    $completioninfo = new completion_info($course);
    $activitieswithcompletion = $completioninfo->get_activities();
    //  unknown > 0 = incomplete < complete
	foreach($activitieswithcompletion as $activity){
		$completionbysection[$activity->section] = "complete";
		$activity_status_data = $completioninfo->get_data($activity->id, $USER->id);
	 	if($activity_status_data->completionstate < 0) {
	 		$completionbysection[$activity->section] = "unknown";
	 	} else if ($activity_status_data->completionstate === 0 && $completionbysection[$activity->section] != "unknown") {
	 		$completionbysection[$activity->section] = "incomplete";
	 	}
	}

	//sort by id
	for($i=0; $i<=$course->numsections; $i++) {
		$section = $sections[$i];
		$section_complete = isset($completionbysection[$section->id]) ? $completionbysection[$section->id] : "complete"; 
		
	    $sectionname = !empty($section->name) ? $section->name : "Topic " . $section->section;
	    $style = "left:" . $topics_info[$section->id]->x_offset . "; top:" .$topics_info[$section->id]->y_offset;
	    $css = $editing ? "$section_complete editing" : "$section_complete";
	    $css .= $section->visible ? "" : " hidden";
	    $css .= $course->marker == $i ? " highlight" : "";
	    echo '<li class="'. $css . '" id="topiclink' . $section->id . '" style="' .$style . ';">';
		echo '<a href="view.php?id='.$course->id.'&amp;topic='.$section->section.'" title="'.$sectionname.'" class="outline-link">' .$sectionname;
	  //  echo "</a> $complete</li>\n";
	  // TODO: Fix complete
	    echo "</a></li>\n";
	}
	
	echo "</ul>\n";
  	echo "</li>\n";
  	
  
}
Esempio n. 16
0
 /**
  * Test book_view
  * @return void
  */
 public function test_book_view()
 {
     global $CFG, $DB;
     $CFG->enablecompletion = 1;
     $this->resetAfterTest();
     $this->setAdminUser();
     // Setup test data.
     $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
     $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id), array('completion' => 2, 'completionview' => 1));
     $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
     $chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
     $context = context_module::instance($book->cmid);
     $cm = get_coursemodule_from_instance('book', $book->id);
     // Trigger and capture the event.
     $sink = $this->redirectEvents();
     // Check just opening the book.
     book_view($book, 0, false, $course, $cm, $context);
     $events = $sink->get_events();
     $this->assertCount(1, $events);
     $event = array_shift($events);
     // Checking that the event contains the expected values.
     $this->assertInstanceOf('\\mod_book\\event\\course_module_viewed', $event);
     $this->assertEquals($context, $event->get_context());
     $moodleurl = new \moodle_url('/mod/book/view.php', array('id' => $cm->id));
     $this->assertEquals($moodleurl, $event->get_url());
     $this->assertEventContextNotUsed($event);
     $this->assertNotEmpty($event->get_name());
     // Check viewing one book chapter (the only one so it will be the first and last).
     book_view($book, $chapter, true, $course, $cm, $context);
     $events = $sink->get_events();
     // We expect a total of 4 events. One for module viewed, one for chapter viewed and two belonging to completion.
     $this->assertCount(4, $events);
     // Check completion status.
     $completion = new completion_info($course);
     $completiondata = $completion->get_data($cm);
     $this->assertEquals(1, $completiondata->completionstate);
 }
Esempio n. 17
0
 /**
  * Determines whether this particular item is currently available
  * according to these criteria.
  *
  * - This does not include the 'visible' setting (i.e. this might return
  *   true even if visible is false); visible is handled independently.
  * - This does not take account of the viewhiddenactivities capability.
  *   That should apply later.
  *
  * @global stdClass $COURSE
  * @global moodle_database $DB
  * @uses COMPLETION_COMPLETE
  * @uses COMPLETION_COMPLETE_FAIL
  * @uses COMPLETION_COMPLETE_PASS
  * @param string $information If the item has availability restrictions,
  *   a string that describes the conditions will be stored in this variable;
  *   if this variable is set blank, that means don't display anything
  * @param bool $grabthelot Performance hint: if true, caches information
  *   required for all course-modules, to make the front page and similar
  *   pages work more quickly (works only for current user)
  * @param int $userid If set, specifies a different user ID to check availability for
  * @param object $modinfo Usually leave as null for default. Specify when
  *   calling recursively from inside get_fast_modinfo. The value supplied
  *   here must include list of all CMs with 'id' and 'name'
  * @return bool True if this item is available to the user, false otherwise
  */
 public function is_available(&$information, $grabthelot = false, $userid = 0, $modinfo = null)
 {
     global $COURSE, $DB;
     $this->require_data();
     $available = true;
     $information = '';
     // Check each completion condition
     if (count($this->item->conditionscompletion) > 0) {
         if ($this->item->course == $COURSE->id) {
             $course = $COURSE;
         } else {
             $course = $DB->get_record('course', array('id' => $this->item->course), 'id, enablecompletion, modinfo, sectioncache', MUST_EXIST);
         }
         $completion = new completion_info($course);
         foreach ($this->item->conditionscompletion as $cmid => $expectedcompletion) {
             // If this depends on a deleted module, handle that situation
             // gracefully.
             if (!$modinfo) {
                 $modinfo = get_fast_modinfo($course);
             }
             if (empty($modinfo->cms[$cmid])) {
                 global $PAGE;
                 if (isset($PAGE) && strpos($PAGE->pagetype, 'course-view-') === 0) {
                     debugging("Warning: activity {$this->cm->id} '{$this->cm->name}' has condition " . "on deleted activity {$cmid} (to get rid of this message, edit the named activity)");
                 }
                 continue;
             }
             // The completion system caches its own data
             $completiondata = $completion->get_data((object) array('id' => $cmid), $grabthelot, $userid, $modinfo);
             $thisisok = true;
             if ($expectedcompletion == COMPLETION_COMPLETE) {
                 // 'Complete' also allows the pass, fail states
                 switch ($completiondata->completionstate) {
                     case COMPLETION_COMPLETE:
                     case COMPLETION_COMPLETE_FAIL:
                     case COMPLETION_COMPLETE_PASS:
                         break;
                     default:
                         $thisisok = false;
                 }
             } else {
                 // Other values require exact match
                 if ($completiondata->completionstate != $expectedcompletion) {
                     $thisisok = false;
                 }
             }
             if (!$thisisok) {
                 $available = false;
                 $information .= get_string('requires_completion_' . $expectedcompletion, 'condition', $modinfo->cms[$cmid]->name) . ' ';
             }
         }
     }
     // Check each grade condition
     if (count($this->item->conditionsgrade) > 0) {
         foreach ($this->item->conditionsgrade as $gradeitemid => $minmax) {
             $score = $this->get_cached_grade_score($gradeitemid, $grabthelot, $userid);
             if ($score === false || !is_null($minmax->min) && $score < $minmax->min || !is_null($minmax->max) && $score >= $minmax->max) {
                 // Grade fail
                 $available = false;
                 // String depends on type of requirement. We are coy about
                 // the actual numbers, in case grades aren't released to
                 // students.
                 if (is_null($minmax->min) && is_null($minmax->max)) {
                     $string = 'any';
                 } else {
                     if (is_null($minmax->max)) {
                         $string = 'min';
                     } else {
                         if (is_null($minmax->min)) {
                             $string = 'max';
                         } else {
                             $string = 'range';
                         }
                     }
                 }
                 $information .= get_string('requires_grade_' . $string, 'condition', $minmax->name) . ' ';
             }
         }
     }
     // Check if user field condition
     if (count($this->item->conditionsfield) > 0) {
         foreach ($this->item->conditionsfield as $field => $details) {
             $uservalue = $this->get_cached_user_profile_field($userid, $field);
             if (!$this->is_field_condition_met($details->operator, $uservalue, $details->value)) {
                 // Set available to false
                 $available = false;
                 $a = new stdClass();
                 $a->field = $details->fieldname;
                 $a->value = $details->value;
                 $information .= get_string('requires_user_field_' . $details->operator, 'condition', $a) . ' ';
             }
         }
     }
     // Test dates
     if ($this->item->availablefrom) {
         if (time() < $this->item->availablefrom) {
             $available = false;
             $information .= get_string('requires_date', 'condition', self::show_time($this->item->availablefrom, self::is_midnight($this->item->availablefrom)));
         }
     }
     if ($this->item->availableuntil) {
         if (time() >= $this->item->availableuntil) {
             $available = false;
             // But we don't display any information about this case. This is
             // because the only reason to set a 'disappear' date is usually
             // to get rid of outdated information/clutter in which case there
             // is no point in showing it...
             // Note it would be nice if we could make it so that the 'until'
             // date appears below the item while the item is still accessible,
             // unfortunately this is not possible in the current system. Maybe
             // later, or if somebody else wants to add it.
         }
     }
     // If the item is marked as 'not visible' then we don't change the available
     // flag (visible/available are treated distinctly), but we remove any
     // availability info. If the item is hidden with the eye icon, it doesn't
     // make sense to show 'Available from <date>' or similar, because even
     // when that date arrives it will still not be available unless somebody
     // toggles the eye icon.
     if (!$this->item->visible) {
         $information = '';
     }
     $information = trim($information);
     return $available;
 }
Esempio n. 18
0
 /**
  * Test badges observer when course module completion event id fired.
  */
 public function test_badges_observer_course_module_criteria_review()
 {
     $this->preventResetByRollback();
     // Messaging is not compatible with transactions.
     $badge = new badge($this->coursebadge);
     $this->assertFalse($badge->is_issued($this->user->id));
     $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
     $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
     $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_ACTIVITY, 'badgeid' => $badge->id));
     $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'module_' . $this->module->cmid => $this->module->cmid));
     // Set completion for forum activity.
     $c = new completion_info($this->course);
     $activities = $c->get_activities();
     $this->assertEquals(1, count($activities));
     $this->assertTrue(isset($activities[$this->module->cmid]));
     $this->assertEquals($activities[$this->module->cmid]->name, $this->module->name);
     $current = $c->get_data($activities[$this->module->cmid], false, $this->user->id);
     $current->completionstate = COMPLETION_COMPLETE;
     $current->timemodified = time();
     $sink = $this->redirectEmails();
     $c->internal_set_data($activities[$this->module->cmid], $current);
     $this->assertCount(1, $sink->get_messages());
     $sink->close();
     // Check if badge is awarded.
     $this->assertDebuggingCalled('Error baking badge image!');
     $this->assertTrue($badge->is_issued($this->user->id));
 }
Esempio n. 19
0
 /**
  * Test updating activity completion when submitting an assessment.
  */
 public function test_update_activity_completion_records_team_submission()
 {
     $assign = $this->create_instance(array('grade' => 100, 'completion' => COMPLETION_TRACKING_AUTOMATIC, 'teamsubmission' => 1));
     $cm = $assign->get_course_module();
     $student1 = $this->students[0];
     $student2 = $this->students[1];
     $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
     // Put both users into a group.
     $group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
     $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student1->id));
     $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student2->id));
     $this->setUser($student1);
     // Simulate a submission.
     $data = new stdClass();
     $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(), 'text' => 'Student submission text', 'format' => FORMAT_MOODLE);
     $completion = new completion_info($this->course);
     $notices = array();
     $assign->save_submission($data, $notices);
     $submission = $assign->get_user_submission($student1->id, true);
     $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
     $submission->groupid = $group1->id;
     // Check that completion is not met yet.
     $completiondata = $completion->get_data($cm, false, $student1->id);
     $this->assertEquals(0, $completiondata->completionstate);
     $completiondata = $completion->get_data($cm, false, $student2->id);
     $this->assertEquals(0, $completiondata->completionstate);
     $assign->testable_update_activity_completion_records(1, 0, $submission, $student1->id, COMPLETION_COMPLETE, $completion);
     // Completion should now be met.
     $completiondata = $completion->get_data($cm, false, $student1->id);
     $this->assertEquals(1, $completiondata->completionstate);
     $completiondata = $completion->get_data($cm, false, $student2->id);
     $this->assertEquals(1, $completiondata->completionstate);
 }
Esempio n. 20
0
/**
 * Retrieves the completion status of the LO for an specific user (100 if this is completed and 0 if not), returns NULL if completion tracking is not enabled for that LO (or the entire course) and if the LO corresponds to a section or course LO
 * @author elever
 * @param cm_info $coursemodule_info : Moodle object with information of a module in a course
 * @param int $userid : moodle identifier of the user
 * @return int $completion_status | null
 */
function block_intuitel_get_completion_status(\cm_info $coursemodule_info, $userid)
{
    $completion = new \completion_info($coursemodule_info->get_course());
    if ($completion->is_enabled($coursemodule_info) > 0) {
        //check if completion is enabled for a particular course and activity, returns 0 if it is not enabled, 1 if completion is enabled and is manual and 2 if automatic
        $completion_status = $completion->get_data($coursemodule_info, false, $userid);
        //this object has also information about viewed...is the row of the related table in the database
        $completion_status = $completion_status->completionstate;
        if ($completion_status > 0) {
            $completion_status = 100;
            // moodle completion system retrieves 0 when the activity is not completed, 1 when the activity is completed (regardless of mark), 2 when the activity is completed with a passed mark, 3 when the activity is completed but with a fail mark
        }
    } else {
        $completion_status = null;
    }
    return $completion_status;
}
 /**
  * Test course module completion update event.
  */
 public function test_course_module_completion_updated_event()
 {
     global $USER, $CFG;
     $this->setup_data();
     $this->setAdminUser();
     $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC);
     $forum = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
     $c = new completion_info($this->course);
     $activities = $c->get_activities();
     $this->assertEquals(1, count($activities));
     $this->assertTrue(isset($activities[$forum->cmid]));
     $this->assertEquals($activities[$forum->cmid]->name, $forum->name);
     $current = $c->get_data($activities[$forum->cmid], false, $this->user->id);
     $current->completionstate = COMPLETION_COMPLETE;
     $current->timemodified = time();
     $sink = $this->redirectEvents();
     $c->internal_set_data($activities[$forum->cmid], $current);
     $events = $sink->get_events();
     $event = reset($events);
     $this->assertInstanceOf('\\core\\event\\course_module_completion_updated', $event);
     $this->assertEquals($forum->cmid, $event->get_record_snapshot('course_modules_completion', $event->objectid)->coursemoduleid);
     $this->assertEquals($current, $event->get_record_snapshot('course_modules_completion', $event->objectid));
     $this->assertEquals(context_module::instance($forum->cmid), $event->get_context());
     $this->assertEquals($USER->id, $event->userid);
     $this->assertEquals($this->user->id, $event->relateduserid);
     $this->assertInstanceOf('moodle_url', $event->get_url());
     $this->assertEventLegacyData($current, $event);
 }
Esempio n. 22
0
 /**
  * Test test_view_assign
  */
 public function test_view_assign()
 {
     global $CFG;
     $CFG->enablecompletion = 1;
     $this->resetAfterTest();
     $this->setAdminUser();
     // Setup test data.
     $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
     $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id), array('completion' => 2, 'completionview' => 1));
     $context = context_module::instance($assign->cmid);
     $cm = get_coursemodule_from_instance('assign', $assign->id);
     $result = mod_assign_external::view_assign($assign->id);
     $result = external_api::clean_returnvalue(mod_assign_external::view_assign_returns(), $result);
     $this->assertTrue($result['status']);
     $this->assertEmpty($result['warnings']);
     // Check completion status.
     $completion = new completion_info($course);
     $completiondata = $completion->get_data($cm);
     $this->assertEquals(1, $completiondata->completionstate);
 }
Esempio n. 23
0
/**
 * Prints a section full of activity modules
 */
function print_section($course, $section, $mods, $modnamesused, $absolute = false, $width = "100%", $hidecompletion = false)
{
    global $CFG, $USER, $DB, $PAGE, $OUTPUT;
    static $initialised;
    static $groupbuttons;
    static $groupbuttonslink;
    static $isediting;
    static $ismoving;
    static $strmovehere;
    static $strmovefull;
    static $strunreadpostsone;
    static $usetracking;
    static $groupings;
    if (!isset($initialised)) {
        $groupbuttons = ($course->groupmode or !$course->groupmodeforce);
        $groupbuttonslink = !$course->groupmodeforce;
        $isediting = $PAGE->user_is_editing();
        $ismoving = $isediting && ismoving($course->id);
        if ($ismoving) {
            $strmovehere = get_string("movehere");
            $strmovefull = strip_tags(get_string("movefull", "", "'{$USER->activitycopyname}'"));
        }
        include_once $CFG->dirroot . '/mod/forum/lib.php';
        if ($usetracking = forum_tp_can_track_forums()) {
            $strunreadpostsone = get_string('unreadpostsone', 'forum');
        }
        $initialised = true;
    }
    $labelformatoptions = new stdClass();
    $labelformatoptions->noclean = true;
    $labelformatoptions->overflowdiv = true;
    /// Casting $course->modinfo to string prevents one notice when the field is null
    $modinfo = get_fast_modinfo($course);
    $completioninfo = new completion_info($course);
    //Accessibility: replace table with list <ul>, but don't output empty list.
    if (!empty($section->sequence)) {
        // Fix bug #5027, don't want style=\"width:$width\".
        echo "<ul class=\"section img-text\">\n";
        $sectionmods = explode(",", $section->sequence);
        foreach ($sectionmods as $modnumber) {
            if (empty($mods[$modnumber])) {
                continue;
            }
            $mod = $mods[$modnumber];
            if ($ismoving and $mod->id == $USER->activitycopy) {
                // do not display moving mod
                continue;
            }
            if (isset($modinfo->cms[$modnumber])) {
                // We can continue (because it will not be displayed at all)
                // if:
                // 1) The activity is not visible to users
                // and
                // 2a) The 'showavailability' option is not set (if that is set,
                //     we need to display the activity so we can show
                //     availability info)
                // or
                // 2b) The 'availableinfo' is empty, i.e. the activity was
                //     hidden in a way that leaves no info, such as using the
                //     eye icon.
                if (!$modinfo->cms[$modnumber]->uservisible && (empty($modinfo->cms[$modnumber]->showavailability) || empty($modinfo->cms[$modnumber]->availableinfo))) {
                    // visibility shortcut
                    continue;
                }
            } else {
                if (!file_exists("{$CFG->dirroot}/mod/{$mod->modname}/lib.php")) {
                    // module not installed
                    continue;
                }
                if (!coursemodule_visible_for_user($mod) && empty($mod->showavailability)) {
                    // full visibility check
                    continue;
                }
            }
            // In some cases the activity is visible to user, but it is
            // dimmed. This is done if viewhiddenactivities is true and if:
            // 1. the activity is not visible, or
            // 2. the activity has dates set which do not include current, or
            // 3. the activity has any other conditions set (regardless of whether
            //    current user meets them)
            $canviewhidden = has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_MODULE, $mod->id));
            $accessiblebutdim = false;
            if ($canviewhidden) {
                $accessiblebutdim = !$mod->visible;
                if (!empty($CFG->enableavailability)) {
                    $accessiblebutdim = $accessiblebutdim || $mod->availablefrom > time() || $mod->availableuntil && $mod->availableuntil < time() || count($mod->conditionsgrade) > 0 || count($mod->conditionscompletion) > 0;
                }
            }
            $liclasses = array();
            $liclasses[] = 'activity';
            $liclasses[] = $mod->modname;
            $liclasses[] = 'modtype_' . $mod->modname;
            echo html_writer::start_tag('li', array('class' => join(' ', $liclasses), 'id' => 'module-' . $modnumber));
            if ($ismoving) {
                echo '<a title="' . $strmovefull . '"' . ' href="' . $CFG->wwwroot . '/course/mod.php?moveto=' . $mod->id . '&amp;sesskey=' . sesskey() . '">' . '<img class="movetarget" src="' . $OUTPUT->pix_url('movehere') . '" ' . ' alt="' . $strmovehere . '" /></a><br />
                     ';
            }
            $classes = array('mod-indent');
            if (!empty($mod->indent)) {
                $classes[] = 'mod-indent-' . $mod->indent;
                if ($mod->indent > 15) {
                    $classes[] = 'mod-indent-huge';
                }
            }
            echo html_writer::start_tag('div', array('class' => join(' ', $classes)));
            $extra = '';
            if (!empty($modinfo->cms[$modnumber]->extra)) {
                $extra = $modinfo->cms[$modnumber]->extra;
            }
            if ($mod->modname == "label") {
                if ($accessiblebutdim || !$mod->uservisible) {
                    echo '<div class="dimmed_text"><span class="accesshide">' . get_string('hiddenfromstudents') . '</span>';
                } else {
                    echo '<div>';
                }
                echo format_text($extra, FORMAT_HTML, $labelformatoptions);
                echo "</div>";
                if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
                    if (!isset($groupings)) {
                        $groupings = groups_get_all_groupings($course->id);
                    }
                    echo " <span class=\"groupinglabel\">(" . format_string($groupings[$mod->groupingid]->name) . ')</span>';
                }
            } else {
                // Normal activity
                $instancename = format_string($modinfo->cms[$modnumber]->name, true, $course->id);
                $customicon = $modinfo->cms[$modnumber]->icon;
                if (!empty($customicon)) {
                    if (substr($customicon, 0, 4) === 'mod/') {
                        list($modname, $iconname) = explode('/', substr($customicon, 4), 2);
                        $icon = $OUTPUT->pix_url($iconname, $modname);
                    } else {
                        $icon = $OUTPUT->pix_url($customicon);
                    }
                } else {
                    $icon = $OUTPUT->pix_url('icon', $mod->modname);
                }
                //Accessibility: for files get description via icon, this is very ugly hack!
                $altname = '';
                $altname = $mod->modfullname;
                if (!empty($customicon)) {
                    $archetype = plugin_supports('mod', $mod->modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
                    if ($archetype == MOD_ARCHETYPE_RESOURCE) {
                        $mimetype = mimeinfo_from_icon('type', $customicon);
                        $altname = get_mimetype_description($mimetype);
                    }
                }
                // Avoid unnecessary duplication.
                if (false !== stripos($instancename, $altname)) {
                    $altname = '';
                }
                // File type after name, for alphabetic lists (screen reader).
                if ($altname) {
                    $altname = get_accesshide(' ' . $altname);
                }
                // We may be displaying this just in order to show information
                // about visibility, without the actual link
                if ($mod->uservisible) {
                    // Display normal module link
                    if (!$accessiblebutdim) {
                        $linkcss = '';
                        $accesstext = '';
                    } else {
                        $linkcss = ' class="dimmed" ';
                        $accesstext = '<span class="accesshide">' . get_string('hiddenfromstudents') . ': </span>';
                    }
                    echo '<a ' . $linkcss . ' ' . $extra . ' href="' . $CFG->wwwroot . '/mod/' . $mod->modname . '/view.php?id=' . $mod->id . '">' . '<img src="' . $icon . '" class="activityicon" alt="' . get_string('modulename', $mod->modname) . '" /> ' . $accesstext . '<span class="instancename">' . $instancename . $altname . '</span></a>';
                    if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
                        if (!isset($groupings)) {
                            $groupings = groups_get_all_groupings($course->id);
                        }
                        echo " <span class=\"groupinglabel\">(" . format_string($groupings[$mod->groupingid]->name) . ')</span>';
                    }
                } else {
                    // Display greyed-out text of link
                    echo '<span class="dimmed_text" ' . $extra . ' ><span class="accesshide">' . get_string('notavailableyet', 'condition') . ': </span>' . '<img src="' . $icon . '" class="activityicon" alt="' . get_string('modulename', $mod->modname) . '" /> <span>' . $instancename . $altname . '</span></span>';
                }
            }
            if ($usetracking && $mod->modname == 'forum') {
                if ($unread = forum_tp_count_forum_unread_posts($mod, $course)) {
                    echo '<span class="unread"> <a href="' . $CFG->wwwroot . '/mod/forum/view.php?id=' . $mod->id . '">';
                    if ($unread == 1) {
                        echo $strunreadpostsone;
                    } else {
                        print_string('unreadpostsnumber', 'forum', $unread);
                    }
                    echo '</a></span>';
                }
            }
            if ($isediting) {
                if ($groupbuttons and plugin_supports('mod', $mod->modname, FEATURE_GROUPS, 0)) {
                    if (!($mod->groupmodelink = $groupbuttonslink)) {
                        $mod->groupmode = $course->groupmode;
                    }
                } else {
                    $mod->groupmode = false;
                }
                echo '&nbsp;&nbsp;';
                echo make_editing_buttons($mod, $absolute, true, $mod->indent, $section->section);
            }
            // Completion
            $completion = $hidecompletion ? COMPLETION_TRACKING_NONE : $completioninfo->is_enabled($mod);
            if ($completion != COMPLETION_TRACKING_NONE && isloggedin() && !isguestuser() && $mod->uservisible) {
                $completiondata = $completioninfo->get_data($mod, true);
                $completionicon = '';
                if ($isediting) {
                    switch ($completion) {
                        case COMPLETION_TRACKING_MANUAL:
                            $completionicon = 'manual-enabled';
                            break;
                        case COMPLETION_TRACKING_AUTOMATIC:
                            $completionicon = 'auto-enabled';
                            break;
                        default:
                            // wtf
                    }
                } else {
                    if ($completion == COMPLETION_TRACKING_MANUAL) {
                        switch ($completiondata->completionstate) {
                            case COMPLETION_INCOMPLETE:
                                $completionicon = 'manual-n';
                                break;
                            case COMPLETION_COMPLETE:
                                $completionicon = 'manual-y';
                                break;
                        }
                    } else {
                        // Automatic
                        switch ($completiondata->completionstate) {
                            case COMPLETION_INCOMPLETE:
                                $completionicon = 'auto-n';
                                break;
                            case COMPLETION_COMPLETE:
                                $completionicon = 'auto-y';
                                break;
                            case COMPLETION_COMPLETE_PASS:
                                $completionicon = 'auto-pass';
                                break;
                            case COMPLETION_COMPLETE_FAIL:
                                $completionicon = 'auto-fail';
                                break;
                        }
                    }
                }
                if ($completionicon) {
                    $imgsrc = $OUTPUT->pix_url('i/completion-' . $completionicon);
                    $imgalt = s(get_string('completion-alt-' . $completionicon, 'completion'));
                    if ($completion == COMPLETION_TRACKING_MANUAL && !$isediting) {
                        $imgtitle = s(get_string('completion-title-' . $completionicon, 'completion'));
                        $newstate = $completiondata->completionstate == COMPLETION_COMPLETE ? COMPLETION_INCOMPLETE : COMPLETION_COMPLETE;
                        // In manual mode the icon is a toggle form...
                        // If this completion state is used by the
                        // conditional activities system, we need to turn
                        // off the JS.
                        if (!empty($CFG->enableavailability) && condition_info::completion_value_used_as_condition($course, $mod)) {
                            $extraclass = ' preventjs';
                        } else {
                            $extraclass = '';
                        }
                        echo "\n<form class='togglecompletion{$extraclass}' method='post' action='togglecompletion.php'><div>\n<input type='hidden' name='id' value='{$mod->id}' />\n<input type='hidden' name='sesskey' value='" . sesskey() . "' />\n<input type='hidden' name='completionstate' value='{$newstate}' />\n<input type='image' src='{$imgsrc}' alt='{$imgalt}' title='{$imgtitle}' />\n</div></form>";
                    } else {
                        // In auto mode, or when editing, the icon is just an image
                        echo "<span class='autocompletion'>";
                        echo "<img src='{$imgsrc}' alt='{$imgalt}' title='{$imgalt}' /></span>";
                    }
                }
            }
            // Show availability information (for someone who isn't allowed to
            // see the activity itself, or for staff)
            if (!$mod->uservisible) {
                echo '<div class="availabilityinfo">' . $mod->availableinfo . '</div>';
            } else {
                if ($canviewhidden && !empty($CFG->enableavailability)) {
                    $ci = new condition_info($mod);
                    $fullinfo = $ci->get_full_information();
                    if ($fullinfo) {
                        echo '<div class="availabilityinfo">' . get_string($mod->showavailability ? 'userrestriction_visible' : 'userrestriction_hidden', 'condition', $fullinfo) . '</div>';
                    }
                }
            }
            echo html_writer::end_tag('div');
            echo html_writer::end_tag('li') . "\n";
        }
    } elseif ($ismoving) {
        echo "<ul class=\"section\">\n";
    }
    if ($ismoving) {
        echo '<li><a title="' . $strmovefull . '"' . ' href="' . $CFG->wwwroot . '/course/mod.php?movetosection=' . $section->id . '&amp;sesskey=' . sesskey() . '">' . '<img class="movetarget" src="' . $OUTPUT->pix_url('movehere') . '" ' . ' alt="' . $strmovehere . '" /></a></li>
             ';
    }
    if (!empty($section->sequence) || $ismoving) {
        echo "</ul><!--class='section'-->\n\n";
    }
}
Esempio n. 24
0
 /**
  * Generate a summary of the activites in a section
  *
  * @param stdClass $section The course_section entry from DB
  * @param stdClass $course the course record from DB
  * @param array    $mods (argument not used)
  * @return string HTML to output.
  */
 protected function section_activity_summary($section, $course, $mods)
 {
     $modinfo = get_fast_modinfo($course);
     if (empty($modinfo->sections[$section->section])) {
         return '';
     }
     // Generate array with count of activities in this section:
     $sectionmods = array();
     $total = 0;
     $complete = 0;
     $cancomplete = isloggedin() && !isguestuser();
     $completioninfo = new completion_info($course);
     foreach ($modinfo->sections[$section->section] as $cmid) {
         $thismod = $modinfo->cms[$cmid];
         if ($thismod->modname == 'label') {
             // Labels are special (not interesting for students)!
             continue;
         }
         if ($thismod->uservisible) {
             if (isset($sectionmods[$thismod->modname])) {
                 $sectionmods[$thismod->modname]['name'] = $thismod->modplural;
                 $sectionmods[$thismod->modname]['count']++;
             } else {
                 $sectionmods[$thismod->modname]['name'] = $thismod->modfullname;
                 $sectionmods[$thismod->modname]['count'] = 1;
             }
             if ($cancomplete && $completioninfo->is_enabled($thismod) != COMPLETION_TRACKING_NONE) {
                 $total++;
                 $completiondata = $completioninfo->get_data($thismod, true);
                 if ($completiondata->completionstate == COMPLETION_COMPLETE || $completiondata->completionstate == COMPLETION_COMPLETE_PASS) {
                     $complete++;
                 }
             }
         }
     }
     if (empty($sectionmods)) {
         // No sections
         return '';
     }
     // Output section activities summary:
     $o = '';
     $o .= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
     foreach ($sectionmods as $mod) {
         $o .= html_writer::start_tag('span', array('class' => 'activity-count'));
         $o .= $mod['name'] . ': ' . $mod['count'];
         $o .= html_writer::end_tag('span');
     }
     $o .= html_writer::end_tag('div');
     // Output section completion data
     if ($total > 0) {
         $a = new stdClass();
         $a->complete = $complete;
         $a->total = $total;
         $o .= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
         $o .= html_writer::tag('span', get_string('progresstotal', 'completion', $a), array('class' => 'activity-count'));
         $o .= html_writer::end_tag('div');
     }
     return $o;
 }
Esempio n. 25
0
/**
 * Prints a section full of activity modules
 */
function print_section($course, $section, $mods, $modnamesused, $absolute = false, $width = "100%", $hidecompletion = false)
{
    global $CFG, $USER, $DB, $PAGE, $OUTPUT;
    static $initialised;
    static $groupbuttons;
    static $groupbuttonslink;
    static $isediting;
    static $ismoving;
    static $strmovehere;
    static $strmovefull;
    static $strunreadpostsone;
    static $groupings;
    static $modulenames;
    if (!isset($initialised)) {
        $groupbuttons = ($course->groupmode or !$course->groupmodeforce);
        $groupbuttonslink = !$course->groupmodeforce;
        $isediting = $PAGE->user_is_editing();
        $ismoving = $isediting && ismoving($course->id);
        if ($ismoving) {
            $strmovehere = get_string("movehere");
            $strmovefull = strip_tags(get_string("movefull", "", "'{$USER->activitycopyname}'"));
        }
        $modulenames = array();
        $initialised = true;
    }
    $modinfo = get_fast_modinfo($course);
    $completioninfo = new completion_info($course);
    //Accessibility: replace table with list <ul>, but don't output empty list.
    if (!empty($section->sequence)) {
        // Fix bug #5027, don't want style=\"width:$width\".
        echo "<ul class=\"section img-text\">\n";
        $sectionmods = explode(",", $section->sequence);
        foreach ($sectionmods as $modnumber) {
            if (empty($mods[$modnumber])) {
                continue;
            }
            /**
             * @var cm_info
             */
            $mod = $mods[$modnumber];
            if ($ismoving and $mod->id == $USER->activitycopy) {
                // do not display moving mod
                continue;
            }
            if (isset($modinfo->cms[$modnumber])) {
                // We can continue (because it will not be displayed at all)
                // if:
                // 1) The activity is not visible to users
                // and
                // 2a) The 'showavailability' option is not set (if that is set,
                //     we need to display the activity so we can show
                //     availability info)
                // or
                // 2b) The 'availableinfo' is empty, i.e. the activity was
                //     hidden in a way that leaves no info, such as using the
                //     eye icon.
                if (!$modinfo->cms[$modnumber]->uservisible && (empty($modinfo->cms[$modnumber]->showavailability) || empty($modinfo->cms[$modnumber]->availableinfo))) {
                    // visibility shortcut
                    continue;
                }
            } else {
                if (!file_exists("{$CFG->dirroot}/mod/{$mod->modname}/lib.php")) {
                    // module not installed
                    continue;
                }
                if (!coursemodule_visible_for_user($mod) && empty($mod->showavailability)) {
                    // full visibility check
                    continue;
                }
            }
            if (!isset($modulenames[$mod->modname])) {
                $modulenames[$mod->modname] = get_string('modulename', $mod->modname);
            }
            $modulename = $modulenames[$mod->modname];
            // In some cases the activity is visible to user, but it is
            // dimmed. This is done if viewhiddenactivities is true and if:
            // 1. the activity is not visible, or
            // 2. the activity has dates set which do not include current, or
            // 3. the activity has any other conditions set (regardless of whether
            //    current user meets them)
            $canviewhidden = has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_MODULE, $mod->id));
            $accessiblebutdim = false;
            if ($canviewhidden) {
                $accessiblebutdim = !$mod->visible;
                if (!empty($CFG->enableavailability)) {
                    $accessiblebutdim = $accessiblebutdim || $mod->availablefrom > time() || $mod->availableuntil && $mod->availableuntil < time() || count($mod->conditionsgrade) > 0 || count($mod->conditionscompletion) > 0;
                }
            }
            $liclasses = array();
            $liclasses[] = 'activity';
            $liclasses[] = $mod->modname;
            $liclasses[] = 'modtype_' . $mod->modname;
            $extraclasses = $mod->get_extra_classes();
            if ($extraclasses) {
                $liclasses = array_merge($liclasses, explode(' ', $extraclasses));
            }
            echo html_writer::start_tag('li', array('class' => join(' ', $liclasses), 'id' => 'module-' . $modnumber));
            if ($ismoving) {
                echo '<a title="' . $strmovefull . '"' . ' href="' . $CFG->wwwroot . '/course/mod.php?moveto=' . $mod->id . '&amp;sesskey=' . sesskey() . '">' . '<img class="movetarget" src="' . $OUTPUT->pix_url('movehere') . '" ' . ' alt="' . $strmovehere . '" /></a><br />
                     ';
            }
            $classes = array('mod-indent');
            if (!empty($mod->indent)) {
                $classes[] = 'mod-indent-' . $mod->indent;
                if ($mod->indent > 15) {
                    $classes[] = 'mod-indent-huge';
                }
            }
            echo html_writer::start_tag('div', array('class' => join(' ', $classes)));
            // Get data about this course-module
            list($content, $instancename) = get_print_section_cm_text($modinfo->cms[$modnumber], $course);
            //Accessibility: for files get description via icon, this is very ugly hack!
            $altname = '';
            $altname = $mod->modfullname;
            if (!empty($customicon)) {
                $archetype = plugin_supports('mod', $mod->modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
                if ($archetype == MOD_ARCHETYPE_RESOURCE) {
                    $mimetype = mimeinfo_from_icon('type', $customicon);
                    $altname = get_mimetype_description($mimetype);
                }
            }
            // Avoid unnecessary duplication: if e.g. a forum name already
            // includes the word forum (or Forum, etc) then it is unhelpful
            // to include that in the accessible description that is added.
            if (false !== strpos(textlib::strtolower($instancename), textlib::strtolower($altname))) {
                $altname = '';
            }
            // File type after name, for alphabetic lists (screen reader).
            if ($altname) {
                $altname = get_accesshide(' ' . $altname);
            }
            // We may be displaying this just in order to show information
            // about visibility, without the actual link
            $contentpart = '';
            if ($mod->uservisible) {
                // Nope - in this case the link is fully working for user
                $linkclasses = '';
                $textclasses = '';
                if ($accessiblebutdim) {
                    $linkclasses .= ' dimmed';
                    $textclasses .= ' dimmed_text';
                    $accesstext = '<span class="accesshide">' . get_string('hiddenfromstudents') . ': </span>';
                } else {
                    $accesstext = '';
                }
                if ($linkclasses) {
                    $linkcss = 'class="' . trim($linkclasses) . '" ';
                } else {
                    $linkcss = '';
                }
                if ($textclasses) {
                    $textcss = 'class="' . trim($textclasses) . '" ';
                } else {
                    $textcss = '';
                }
                // Get on-click attribute value if specified
                $onclick = $mod->get_on_click();
                if ($onclick) {
                    $onclick = ' onclick="' . $onclick . '"';
                }
                if ($url = $mod->get_url()) {
                    // Display link itself
                    echo '<a ' . $linkcss . $mod->extra . $onclick . ' href="' . $url . '"><img src="' . $mod->get_icon_url() . '" class="activityicon" alt="' . $modulename . '" /> ' . $accesstext . '<span class="instancename">' . $instancename . $altname . '</span></a>';
                    // If specified, display extra content after link
                    if ($content) {
                        $contentpart = '<div class="' . trim('contentafterlink' . $textclasses) . '">' . $content . '</div>';
                    }
                } else {
                    // No link, so display only content
                    $contentpart = '<div ' . $textcss . $mod->extra . '>' . $accesstext . $content . '</div>';
                }
                if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
                    if (!isset($groupings)) {
                        $groupings = groups_get_all_groupings($course->id);
                    }
                    echo " <span class=\"groupinglabel\">(" . format_string($groupings[$mod->groupingid]->name) . ')</span>';
                }
            } else {
                $textclasses = $extraclasses;
                $textclasses .= ' dimmed_text';
                if ($textclasses) {
                    $textcss = 'class="' . trim($textclasses) . '" ';
                } else {
                    $textcss = '';
                }
                $accesstext = '<span class="accesshide">' . get_string('notavailableyet', 'condition') . ': </span>';
                if ($url = $mod->get_url()) {
                    // Display greyed-out text of link
                    echo '<div ' . $textcss . $mod->extra . ' >' . '<img src="' . $mod->get_icon_url() . '" class="activityicon" alt="' . $modulename . '" /> <span>' . $instancename . $altname . '</span></div>';
                    // Do not display content after link when it is greyed out like this.
                } else {
                    // No link, so display only content (also greyed)
                    $contentpart = '<div ' . $textcss . $mod->extra . '>' . $accesstext . $content . '</div>';
                }
            }
            // Module can put text after the link (e.g. forum unread)
            echo $mod->get_after_link();
            // If there is content but NO link (eg label), then display the
            // content here (BEFORE any icons). In this case cons must be
            // displayed after the content so that it makes more sense visually
            // and for accessibility reasons, e.g. if you have a one-line label
            // it should work similarly (at least in terms of ordering) to an
            // activity.
            if (empty($url)) {
                echo $contentpart;
            }
            if ($isediting) {
                if ($groupbuttons and plugin_supports('mod', $mod->modname, FEATURE_GROUPS, 0)) {
                    if (!($mod->groupmodelink = $groupbuttonslink)) {
                        $mod->groupmode = $course->groupmode;
                    }
                } else {
                    $mod->groupmode = false;
                }
                echo '&nbsp;&nbsp;';
                echo make_editing_buttons($mod, $absolute, true, $mod->indent, $section->section);
                echo $mod->get_after_edit_icons();
            }
            // Completion
            $completion = $hidecompletion ? COMPLETION_TRACKING_NONE : $completioninfo->is_enabled($mod);
            if ($completion != COMPLETION_TRACKING_NONE && isloggedin() && !isguestuser() && $mod->uservisible) {
                $completiondata = $completioninfo->get_data($mod, true);
                $completionicon = '';
                if ($isediting) {
                    switch ($completion) {
                        case COMPLETION_TRACKING_MANUAL:
                            $completionicon = 'manual-enabled';
                            break;
                        case COMPLETION_TRACKING_AUTOMATIC:
                            $completionicon = 'auto-enabled';
                            break;
                        default:
                            // wtf
                    }
                } else {
                    if ($completion == COMPLETION_TRACKING_MANUAL) {
                        switch ($completiondata->completionstate) {
                            case COMPLETION_INCOMPLETE:
                                $completionicon = 'manual-n';
                                break;
                            case COMPLETION_COMPLETE:
                                $completionicon = 'manual-y';
                                break;
                        }
                    } else {
                        // Automatic
                        switch ($completiondata->completionstate) {
                            case COMPLETION_INCOMPLETE:
                                $completionicon = 'auto-n';
                                break;
                            case COMPLETION_COMPLETE:
                                $completionicon = 'auto-y';
                                break;
                            case COMPLETION_COMPLETE_PASS:
                                $completionicon = 'auto-pass';
                                break;
                            case COMPLETION_COMPLETE_FAIL:
                                $completionicon = 'auto-fail';
                                break;
                        }
                    }
                }
                if ($completionicon) {
                    $imgsrc = $OUTPUT->pix_url('i/completion-' . $completionicon);
                    $imgalt = s(get_string('completion-alt-' . $completionicon, 'completion', $mod->name));
                    if ($completion == COMPLETION_TRACKING_MANUAL && !$isediting) {
                        $imgtitle = s(get_string('completion-title-' . $completionicon, 'completion', $mod->name));
                        $newstate = $completiondata->completionstate == COMPLETION_COMPLETE ? COMPLETION_INCOMPLETE : COMPLETION_COMPLETE;
                        // In manual mode the icon is a toggle form...
                        // If this completion state is used by the
                        // conditional activities system, we need to turn
                        // off the JS.
                        if (!empty($CFG->enableavailability) && condition_info::completion_value_used_as_condition($course, $mod)) {
                            $extraclass = ' preventjs';
                        } else {
                            $extraclass = '';
                        }
                        echo "\n<form class='togglecompletion{$extraclass}' method='post' action='" . $CFG->wwwroot . "/course/togglecompletion.php'><div>\n<input type='hidden' name='id' value='{$mod->id}' />\n<input type='hidden' name='modulename' value='" . s($mod->name) . "' />\n<input type='hidden' name='sesskey' value='" . sesskey() . "' />\n<input type='hidden' name='completionstate' value='{$newstate}' />\n<input type='image' src='{$imgsrc}' alt='{$imgalt}' title='{$imgtitle}' />\n</div></form>";
                    } else {
                        // In auto mode, or when editing, the icon is just an image
                        echo "<span class='autocompletion'>";
                        echo "<img src='{$imgsrc}' alt='{$imgalt}' title='{$imgalt}' /></span>";
                    }
                }
            }
            // If there is content AND a link, then display the content here
            // (AFTER any icons). Otherwise it was displayed before
            if (!empty($url)) {
                echo $contentpart;
            }
            // Show availability information (for someone who isn't allowed to
            // see the activity itself, or for staff)
            if (!$mod->uservisible) {
                echo '<div class="availabilityinfo">' . $mod->availableinfo . '</div>';
            } else {
                if ($canviewhidden && !empty($CFG->enableavailability)) {
                    $ci = new condition_info($mod);
                    $fullinfo = $ci->get_full_information();
                    if ($fullinfo) {
                        echo '<div class="availabilityinfo">' . get_string($mod->showavailability ? 'userrestriction_visible' : 'userrestriction_hidden', 'condition', $fullinfo) . '</div>';
                    }
                }
            }
            echo html_writer::end_tag('div');
            echo html_writer::end_tag('li') . "\n";
        }
    } elseif ($ismoving) {
        echo "<ul class=\"section\">\n";
    }
    if ($ismoving) {
        echo '<li><a title="' . $strmovefull . '"' . ' href="' . $CFG->wwwroot . '/course/mod.php?movetosection=' . $section->id . '&amp;sesskey=' . sesskey() . '">' . '<img class="movetarget" src="' . $OUTPUT->pix_url('movehere') . '" ' . ' alt="' . $strmovehere . '" /></a></li>
             ';
    }
    if (!empty($section->sequence) || $ismoving) {
        echo "</ul><!--class='section'-->\n\n";
    }
}
Esempio n. 26
0
 /**
  * Determines whether this particular course-module is currently available
  * according to these criteria. 
  * 
  * - This does not include the 'visible' setting (i.e. this might return 
  *   true even if visible is false); visible is handled independently.
  * - This does not take account of the viewhiddenactivities capability.
  *   That should apply later.
  *
  * @global object
  * @global object
  * @uses COMPLETION_COMPLETE
  * @uses COMPLETION_COMPLETE_FAIL
  * @uses COMPLETION_COMPLETE_PASS
  * @param string $information If the item has availability restrictions,
  *   a string that describes the conditions will be stored in this variable; 
  *   if this variable is set blank, that means don't display anything
  * @param bool $grabthelot Performance hint: if true, caches information 
  *   required for all course-modules, to make the front page and similar
  *   pages work more quickly (works only for current user)
  * @param int $userid If set, specifies a different user ID to check availability for
  * @param object $modinfo Usually leave as null for default. Specify when
  *   calling recursively from inside get_fast_modinfo. The value supplied 
  *   here must include list of all CMs with 'id' and 'name'
  * @return bool True if this item is available to the user, false otherwise
  */
 public function is_available(&$information, $grabthelot = false, $userid = 0, $modinfo = null)
 {
     $this->require_data();
     global $COURSE, $DB;
     $available = true;
     $information = '';
     // Check each completion condition
     if (count($this->cm->conditionscompletion) > 0) {
         if ($this->cm->course == $COURSE->id) {
             $course = $COURSE;
         } else {
             $course = $DB->get_record('course', array('id' => $this->cm->course), 'id,enablecompletion,modinfo');
         }
         $completion = new completion_info($course);
         foreach ($this->cm->conditionscompletion as $cmid => $expectedcompletion) {
             // The completion system caches its own data
             $completiondata = $completion->get_data((object) array('id' => $cmid), $grabthelot, $userid, $modinfo);
             $thisisok = true;
             if ($expectedcompletion == COMPLETION_COMPLETE) {
                 // 'Complete' also allows the pass, fail states
                 switch ($completiondata->completionstate) {
                     case COMPLETION_COMPLETE:
                     case COMPLETION_COMPLETE_FAIL:
                     case COMPLETION_COMPLETE_PASS:
                         break;
                     default:
                         $thisisok = false;
                 }
             } else {
                 // Other values require exact match
                 if ($completiondata->completionstate != $expectedcompletion) {
                     $thisisok = false;
                 }
             }
             if (!$thisisok) {
                 $available = false;
                 if (!$modinfo) {
                     $modinfo = get_fast_modinfo($course);
                 }
                 $information .= get_string('requires_completion_' . $expectedcompletion, 'condition', $modinfo->cms[$cmid]->name) . ' ';
             }
         }
     }
     // Check each grade condition
     if (count($this->cm->conditionsgrade) > 0) {
         foreach ($this->cm->conditionsgrade as $gradeitemid => $minmax) {
             $score = $this->get_cached_grade_score($gradeitemid, $grabthelot, $userid);
             if ($score === false || !is_null($minmax->min) && $score < $minmax->min || !is_null($minmax->max) && $score >= $minmax->max) {
                 // Grade fail
                 $available = false;
                 // String depends on type of requirement. We are coy about
                 // the actual numbers, in case grades aren't released to
                 // students.
                 if (is_null($minmax->min) && is_null($minmax->max)) {
                     $string = 'any';
                 } else {
                     if (is_null($minmax->max)) {
                         $string = 'min';
                     } else {
                         if (is_null($minmax->min)) {
                             $string = 'max';
                         } else {
                             $string = 'range';
                         }
                     }
                 }
                 $information .= get_string('requires_grade_' . $string, 'condition', $minmax->name) . ' ';
             }
         }
     }
     // Test dates
     if ($this->cm->availablefrom) {
         if (time() < $this->cm->availablefrom) {
             $available = false;
             $information .= get_string('requires_date', 'condition', self::show_time($this->cm->availablefrom, false));
         }
     }
     if ($this->cm->availableuntil) {
         if (time() >= $this->cm->availableuntil) {
             $available = false;
             // But we don't display any information about this case. This is
             // because the only reason to set a 'disappear' date is usually
             // to get rid of outdated information/clutter in which case there
             // is no point in showing it...
             // Note it would be nice if we could make it so that the 'until'
             // date appears below the item while the item is still accessible,
             // unfortunately this is not possible in the current system. Maybe
             // later, or if somebody else wants to add it.
         }
     }
     $information = trim($information);
     return $available;
 }
Esempio n. 27
0
/**
 * Check whether a user or a component of a group has completed an activity
 * If the group identifier provided is not 0, the group is checked, else the user is checked.
 * 
 * @param int $cmid The identifier of course module activity.
 * @param int $userid The identifier of user.
 * @param int $groupid The identifier of group.
 * @param stdClass $context The context object.
 * @return bool True/false.
 */
function treasurehunt_check_completion_activity($cmid, $userid, $groupid, $context)
{
    global $COURSE;
    $users = array();
    if ($cmid != 0) {
        $modinfo = get_fast_modinfo($COURSE);
        $cmactivitytoend = $modinfo->get_cm($cmid);
    } else {
        return true;
    }
    // Get all users.
    if ($groupid) {
        $users = get_enrolled_users($context, 'mod/treasurehunt:play', $groupid, 'u.id');
    } else {
        $user = new stdClass();
        $user->id = $userid;
        $users[] = $user;
    }
    foreach ($users as $user) {
        // Check if a user has complete that activity.
        $completioninfo = new completion_info($COURSE);
        $current = $completioninfo->get_data($cmactivitytoend, false, $user->id);
        if ($current->completionstate == 1) {
            return $user->id;
        }
    }
    return false;
}
Esempio n. 28
0
 $grade = false;
 if ($context = $DB->get_record('context', array('id' => $tool->contextid))) {
     if ($context->contextlevel == CONTEXT_COURSE) {
         if ($tool->requirecompletion and !$completion->is_course_complete($user->userid)) {
             mtrace("   Skipping user {$user->userid} since he didn't complete the course");
             continue;
         }
         if ($grade = grade_get_course_grade($user->userid, $tool->courseid)) {
             $grademax = floatval($grade->item->grademax);
             $grade = $grade->grade;
         }
     } else {
         if ($context->contextlevel == CONTEXT_MODULE) {
             $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST);
             if ($tool->requirecompletion) {
                 $data = $completion->get_data($cm, false, $user->userid);
                 if ($data->completionstate != COMPLETION_COMPLETE_PASS and $data->completionstate != COMPLETION_COMPLETE) {
                     mtrace("   Skipping user {$user->userid} since he didn't complete the activity");
                     continue;
                 }
             }
             $grades = grade_get_grades($cm->course, 'mod', $cm->modname, $cm->instance, $user->userid);
             if (empty($grades->items[0]->grades)) {
                 $grade = false;
             } else {
                 $grade = reset($grades->items[0]->grades);
                 if (!empty($grade->item)) {
                     $grademax = floatval($grade->item->grademax);
                 } else {
                     $grademax = floatval($grades->items[0]->grademax);
                 }
 /**
  * Return criteria progress details for display in reports
  *
  * @param completion_completion $completion The user's completion record
  * @return array An array with the following keys:
  *     type, criteria, requirement, status
  */
 public function get_details($completion)
 {
     global $DB, $CFG;
     // Get completion info
     $course = new stdClass();
     $course->id = $completion->course;
     $info = new completion_info($course);
     $module = $DB->get_record('course_modules', array('id' => $this->moduleinstance));
     $data = $info->get_data($module, false, $completion->userid);
     $activity = $DB->get_record($this->module, array('id' => $module->instance));
     $details = array();
     $details['type'] = $this->get_title();
     $details['criteria'] = '<a href="' . $CFG->wwwroot . '/mod/' . $this->module . '/view.php?id=' . $this->moduleinstance . '">' . $activity->name . '</a>';
     // Build requirements
     $details['requirement'] = array();
     if ($module->completion == 1) {
         $details['requirement'][] = get_string('markingyourselfcomplete', 'completion');
     } elseif ($module->completion == 2) {
         if ($module->completionview) {
             $details['requirement'][] = get_string('viewingactivity', 'completion', $this->module);
         }
         if (!is_null($module->completiongradeitemnumber)) {
             $details['requirement'][] = get_string('achievinggrade', 'completion');
         }
     }
     $details['requirement'] = implode($details['requirement'], ', ');
     $details['status'] = '';
     return $details;
 }
 /**
  * Review this criteria and decide if it has been completed
  *
  * @param int $userid User whose criteria completion needs to be reviewed.
  * @param bool $filtered An additional parameter indicating that user list
  *        has been reduced and some expensive checks can be skipped.
  *
  * @return bool Whether criteria is complete
  */
 public function review($userid, $filtered = false)
 {
     $completionstates = array(COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS);
     $course = new stdClass();
     $course->id = $this->courseid;
     if ($this->coursestartdate > time()) {
         return false;
     }
     $info = new completion_info($course);
     $overall = false;
     foreach ($this->params as $param) {
         $cm = new stdClass();
         $cm->id = $param['module'];
         $data = $info->get_data($cm, false, $userid);
         $check_date = true;
         if (isset($param['bydate'])) {
             $date = $data->timemodified;
             $check_date = $date <= $param['bydate'];
         }
         if ($this->method == BADGE_CRITERIA_AGGREGATION_ALL) {
             if (in_array($data->completionstate, $completionstates) && $check_date) {
                 $overall = true;
                 continue;
             } else {
                 return false;
             }
         } else {
             if (in_array($data->completionstate, $completionstates) && $check_date) {
                 return true;
             } else {
                 $overall = false;
                 continue;
             }
         }
     }
     return $overall;
 }