/**
  * Get course information - progress / grades, etc
  *
  * @return string
  */
 public function get_courseinfo_action()
 {
     $courseids = optional_param('courseids', false, PARAM_SEQUENCE);
     if (!empty($courseids)) {
         $courseids = explode(',', $courseids);
     }
     $courseinfo = \theme_snap\local::courseinfo($courseids);
     return json_encode(array('info' => $courseinfo));
 }
 /**
  * Read page
  *
  * @throws \coding_exception
  * @return stdClass
  */
 private function read_page()
 {
     global $PAGE, $COURSE;
     $cm = $PAGE->cm;
     $page = \theme_snap\local::get_page_mod($cm);
     $context = $PAGE->context;
     // Trigger module instance viewed event.
     $event = \mod_page\event\course_module_viewed::create(array('objectid' => $page->id, 'context' => $context));
     $event->add_record_snapshot('course_modules', $cm);
     $event->add_record_snapshot('course', $COURSE);
     $event->add_record_snapshot('page', $page);
     $event->trigger();
     return $page;
 }
 /**
  * @throws coding_exception
  */
 public function __construct()
 {
     global $PAGE, $COURSE;
     // Page path blacklist for admin menu.
     $adminblockblacklist = ['/user/profile.php'];
     if (in_array(local::current_url_path(), $adminblockblacklist)) {
         return;
     }
     // Admin users always see the admin menu with the exception of blacklisted pages.
     // The admin menu shows up for other users if they are a teacher in the current course.
     if (!is_siteadmin()) {
         // We don't want students to see the admin menu ever.
         // Editing teachers are identified as people who can manage activities and non editing teachers as those who
         // can view the gradebook. As editing teachers are almost certain to also be able to view the gradebook, the
         // grader:view capability is checked first.
         $caps = ['gradereport/grader:view', 'moodle/course:manageactivities'];
         $canmanageacts = has_any_capability($caps, $PAGE->context);
         $isstudent = !$canmanageacts && !is_role_switched($COURSE->id);
         if ($isstudent) {
             return;
         }
     }
     if (!$PAGE->blocks->is_block_present('settings')) {
         // Throw error if on front page or course page.
         // (There are pages that don't have a settings block so we shouldn't throw an error on those pages).
         if (strpos($PAGE->pagetype, 'course-view') === 0 || $PAGE->pagetype === 'site-index') {
             debugging('Settings block was not found on this page', DEBUG_DEVELOPER);
         }
         return;
     }
     // Core Moodle API appears to be missing a 'get block by name' function.
     // Cycle through all regions and block instances until we find settings.
     foreach ($PAGE->blocks->get_regions() as $region) {
         foreach ($PAGE->blocks->get_blocks_for_region($region) as $block) {
             if (isset($block->instance) && $block->instance->blockname == 'settings') {
                 $this->instanceid = $block->instance->id;
                 break 2;
             }
         }
     }
     if (!has_capability('moodle/block:view', \context_block::instance($this->instanceid))) {
         return;
     }
     $this->output = true;
 }
Example #4
0
/**
 * CSS Processor
 *
 * @param string $css
 * @param theme_config $theme
 * @return string
 */
function theme_snap_process_css($css, theme_config $theme)
{
    // Set the background image for the logo.
    $logo = $theme->setting_file_url('logo', 'logo');
    $css = theme_snap_set_logo($css, $logo);
    // Set the background image for the poster.
    $css = \theme_snap\local::site_coverimage_css($css);
    // Set the custom css.
    if (!empty($theme->settings->customcss)) {
        $customcss = $theme->settings->customcss;
    } else {
        $customcss = null;
    }
    $css = theme_snap_set_customcss($css, $customcss);
    // Set bootswatch.
    $css = theme_snap_set_bootswatch($css, theme_snap_get_bootswatch_variables($theme));
    return $css;
}
 /**
  * Read page
  *
  * @throws \coding_exception
  * @return stdClass
  */
 private function read_page()
 {
     global $PAGE, $COURSE;
     $cm = $PAGE->cm;
     $page = \theme_snap\local::get_page_mod($cm);
     $context = $PAGE->context;
     // Trigger module instance viewed event.
     $event = \mod_page\event\course_module_viewed::create(array('objectid' => $page->id, 'context' => $context));
     $event->add_record_snapshot('course_modules', $cm);
     $event->add_record_snapshot('course', $COURSE);
     $event->add_record_snapshot('page', $page);
     $event->trigger();
     // Update 'viewed' state if required by completion system.
     $completion = new \completion_info($COURSE);
     $completion->set_module_viewed($cm);
     $renderer = $PAGE->get_renderer('core', 'course');
     $page->completionhtml = $renderer->course_section_cm_completion($COURSE, $completion, $cm);
     return $page;
 }
Example #6
0
    $url = new moodle_url('/admin/settings.php', ['section' => 'themesettingsnap'], 'admin-poster');
    echo $OUTPUT->cover_image_selector();
}
?>
</div>

<section id="region-main">
<?php 
echo $OUTPUT->course_content_header();
// Ensure edit blocks button is only shown for appropriate pages.
$hasadminbutton = stripos($PAGE->button, '"adminedit"') || stripos($PAGE->button, '"edit"');
if ($hasadminbutton) {
    // List paths to black list for 'turn editting on' button here.
    // Note, to use regexs start and end with a pipe symbol - e.g. |^/report/| .
    $editbuttonblacklist = array('/comment/', '/cohort/index.php', '|^/report/|', '|^/admin/|', '|^/mod/data/|', '/tag/manage.php', '/grade/edit/scale/index.php', '/outcome/admin.php', '/mod/assign/adminmanageplugins.php', '/message/defaultoutputs.php', '/theme/index.php', '/user/editadvanced.php', '/user/profile/index.php', '/mnet/service/enrol/index.php', '/local/mrooms/view.php');
    $pagepath = local::current_url_path();
    foreach ($editbuttonblacklist as $blacklisted) {
        if ($blacklisted[0] == '|' && $blacklisted[strlen($blacklisted) - 1] == '|') {
            // Use regex to determine blacklisting.
            if (preg_match($blacklisted, $pagepath) === 1) {
                // This url path is blacklisted, stop button from being displayed.
                $PAGE->set_button('');
            }
        } else {
            if ($pagepath == $blacklisted) {
                // This url path is blacklisted, stop button from being displayed.
                $PAGE->set_button('');
            }
        }
    }
}
 /**
  * Populate forum id arrays.
  * @throws \coding_exception
  */
 protected function populate_forums()
 {
     local::swap_global_user($this->user->id);
     // Note - we don't include the site in the list of courses. This is intentional - we want student engagement to
     // be increased in courses where learning takes place and the front page is unlikely to fit that model.
     // Currently we are using local::swap_global_user as a hack for the following function (MDL-51353).
     $this->courses = enrol_get_my_courses();
     $forums = [];
     $hsuforums = [];
     foreach ($this->courses as $course) {
         $forums = $forums + forum_get_readable_forums($this->user->id, $course->id);
         if (function_exists('hsuforum_get_readable_forums')) {
             $hsuforums = $hsuforums + hsuforum_get_readable_forums($this->user->id, $course->id, true);
         }
     }
     // Remove Q&A forums from array.
     $forums = $this->purge_qa_forums($forums);
     $hsuforums = $this->purge_qa_forums($hsuforums);
     // Rmove forums in courses not accessed for a long time.
     $forums = $this->process_stale_forums($forums);
     $hsuforums = $this->process_stale_forums($hsuforums, true);
     $this->forums = $forums;
     $this->hsuforums = $hsuforums;
     $this->forumids = array_keys($forums);
     $this->forumidsallgroups = $this->forumids_accessallgroups($forums);
     $this->hsuforumids = array_keys($hsuforums);
     $this->hsuforumidsallgroups = $this->forumids_accessallgroups($hsuforums, 'hsuforum');
     local::swap_global_user(false);
 }
 /**
  * Get page module html
  * @param $mod
  * @return string
  */
 protected function mod_page_html($mod)
 {
     if (!$mod->uservisible) {
         return "";
     }
     global $DB;
     $sql = "SELECT * FROM {course_modules} cm\n                  JOIN {page} p ON p.id = cm.instance\n                WHERE cm.id = ?";
     $page = $DB->get_record_sql($sql, array($mod->id));
     $context = context_module::instance($mod->id);
     $formatoptions = new stdClass();
     $formatoptions->noclean = true;
     $formatoptions->overflowdiv = true;
     $formatoptions->context = $context;
     // Make sure we have some summary/extract text for the course page.
     if (!empty($page->intro)) {
         $page->summary = file_rewrite_pluginfile_urls($page->intro, 'pluginfile.php', $context->id, 'mod_page', 'intro', null);
         $page->summary = format_text($page->summary, $page->introformat, $formatoptions);
     } else {
         $preview = html_to_text($page->content, 0, false);
         $page->summary = shorten_text($preview, 200);
     }
     $content = file_rewrite_pluginfile_urls($page->content, 'pluginfile.php', $context->id, 'mod_page', 'content', $page->revision);
     $content = format_text($content, $page->contentformat, $formatoptions);
     $imgarr = \theme_snap\local::extract_first_image($content);
     $thumbnail = '';
     if ($imgarr) {
         $img = html_writer::img($imgarr['src'], $imgarr['alt']);
         $thumbnail = "<div class=summary-figure>{$img}</div>";
     }
     $readmore = get_string('readmore', 'theme_snap');
     $close = get_string('close', 'theme_snap');
     $o = "\n        {$thumbnail}\n        <div class='summary-text'>\n            {$page->summary}\n            <p><a class='pagemod-readmore' href='{$mod->url}'>{$readmore}</a></p>\n        </div>\n\n        <div class=pagemod-content tabindex='-1'>\n            {$content}\n            <div><hr><a  class='snap-action-icon' href='#'>\n            <i class='icon icon-office-52'></i><small>{$close}</small></a></div>\n        </div>";
     return $o;
 }
Example #9
0
/**
 * Process site cover image.
 *
 * @throws Exception
 * @throws coding_exception
 * @throws dml_exception
 */
function theme_snap_process_site_coverimage()
{
    $context = \context_system::instance();
    \theme_snap\local::process_coverimage($context);
    theme_reset_all_caches();
}
 /**
  * Get page module html
  * @param cm_info $mod
  * @return string
  */
 protected function mod_page_html(cm_info $mod)
 {
     if (!$mod->uservisible) {
         return "";
     }
     $page = \theme_snap\local::get_page_mod($mod);
     $imgarr = \theme_snap\local::extract_first_image($page->content);
     $thumbnail = '';
     if ($imgarr) {
         $img = html_writer::img($imgarr['src'], $imgarr['alt']);
         $thumbnail = "<div class=summary-figure>{$img}</div>";
     }
     $readmore = get_string('readmore', 'theme_snap');
     $close = get_string('close', 'theme_snap');
     // Identify content elements which should force an AJAX lazy load.
     $elcontentblist = ['iframe', 'video', 'object', 'embed'];
     $content = $page->content;
     $lazyload = false;
     foreach ($elcontentblist as $el) {
         if (stripos($content, '<' . $el) !== false) {
             $content = '';
             // Don't include the content as it is likely to slow the page load down considerably.
             $lazyload = true;
         }
     }
     $contentloaded = !$lazyload ? 1 : 0;
     $o = "\n        {$thumbnail}\n        <div class='summary-text'>\n            {$page->summary}\n            <p><a class='pagemod-readmore' href='{$mod->url}' data-pagemodcontext='{$mod->context->id}'>{$readmore}</a></p>\n        </div>\n\n        <div class=pagemod-content tabindex='-1' data-content-loaded={$contentloaded}>\n            {$content}\n            <div><hr><a  class='snap-action-icon' href='#'>\n            <i class='icon icon-office-52'></i><small>{$close}</small></a></div>\n        </div>";
     return $o;
 }
 public function test_courseinfo_teacher()
 {
     $this->setUser($this->teachers[0]);
     $actual = local::courseinfo([$this->course->id]);
     $this->assertCount(1, $actual);
 }
 /**
  * Test that the summary, when generated from the intro text, does not strip out images or trim the text in anyway.
  * @throws \coding_exception
  * @throws \moodle_exception
  */
 public function test_get_page_mod_intro_summary()
 {
     $this->resetAfterTest();
     $generator = $this->getDataGenerator();
     $course = $generator->create_course();
     $pagegen = $generator->get_plugin_generator('mod_page');
     $page = $pagegen->create_instance(['course' => $course->id, 'intro' => '<img src="http://fakeurl.local/testimg.png" alt="some alt text" />' . '<p>Some content text</p>' . str_pad('-', 200)]);
     $cm = get_course_and_cm_from_instance($page->id, 'page', $course->id)[1];
     $pagemod = local::get_page_mod($cm);
     // Ensure summary contains text and is sitll within tags.
     $this->assertContains('<p>Some content text</p>', $pagemod->summary);
     // Ensure summary contains images.
     $this->assertContains('<img', $pagemod->summary);
     // Make sure summary text can be greater than 200 chars.
     $this->assertGreaterThan(200, strlen($pagemod->summary));
 }
 /**
  * Assert user activity.
  * @param stdClass $user
  * @param int $expected
  * @param int $limit
  */
 protected function assert_user_activity($user, $expected, $limit = 10)
 {
     $activity = local::recent_forum_activity($user->id, $limit);
     // Ensure number of activity items matched.
     $this->assertEquals($expected, count($activity));
     if (!empty($activity)) {
         // Ensure first activity item contains expected fields.
         $activityitem = $activity[0];
         $this->assertNotEmpty($activityitem->user);
         $this->assertNotEmpty($activityitem->type);
         $this->assertNotEmpty($activityitem->content);
         $this->assertNotEmpty($activityitem->content->discussion);
         $this->assertNotEmpty($activityitem->content->id);
         $this->assertNotEmpty($activityitem->timestamp);
         $this->assertNotEmpty($activityitem->courseshortname);
         $this->assertNotEmpty($activityitem->forumname);
         $this->assertNotEmpty($activityitem->content->subject);
     }
 }
 /**
  * The course update event.
  *
  * process cover image.
  *
  * @param course_updated $event
  * @return void
  */
 public static function course_updated(course_updated $event)
 {
     $course = $event->get_record_snapshot('course', $event->objectid);
     $context = \context_course::instance($course->id);
     local::process_coverimage($context);
 }
Example #15
0
 public function test_poster_image_upload()
 {
     $this->resetAfterTest();
     $beforeupload = local::site_coverimage_original();
     $this->assertFalse($beforeupload);
     $fixtures = ['bpd_bikes_3888px.jpg' => true, 'bpd_bikes_1381px.jpg' => true, 'bpd_bikes_1380px.jpg' => false, 'bpd_bikes_1379px.jpg' => false, 'bpd_bikes_1280px.jpg' => false, 'testpng.png' => false, 'testpng_small.png' => false, 'testgif.gif' => false, 'testgif_small.gif' => false];
     foreach ($fixtures as $filename => $shouldberesized) {
         $this->fake_site_image_setting_upload($filename);
         $css = '[[setting:poster]]';
         $css = local::site_coverimage_css($css);
         $this->assertContains('/theme_snap/coverimage/', $css);
         $ext = pathinfo($filename, PATHINFO_EXTENSION);
         $this->assertContains("/site-image.{$ext}", $css);
         if ($shouldberesized) {
             $image = local::site_coverimage();
             $finfo = $image->get_imageinfo();
             $this->assertSame(1280, $finfo['width']);
         }
     }
     $this->fake_site_image_setting_cleared();
     $css = '[[setting:poster]]';
     $css = local::site_coverimage_css($css);
     $this->assertSame('', $css);
     $this->assertFalse(local::site_coverimage());
 }
Example #16
0
echo $OUTPUT->page_title();
?>
</title>
<link rel="shortcut icon" href="<?php 
echo $OUTPUT->favicon();
?>
"/>
<?php 
echo $OUTPUT->standard_head_html();
?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href='//fonts.googleapis.com/css?family=Roboto:500,100,400,300' rel='stylesheet' type='text/css'>
<?php 
// Output course cover image?
if ($COURSE->id != SITEID) {
    $courseimagecss = \theme_snap\local::course_coverimage_css($COURSE->id);
}
if (!empty($courseimagecss)) {
    echo "<style>{$courseimagecss}</style>";
}
?>

</head>

<body <?php 
echo $OUTPUT->body_attributes();
?>
>

<?php 
echo $OUTPUT->standard_top_of_body_html();
Example #17
0
"/>
<?php 
echo $OUTPUT->standard_head_html();
?>
<meta name="theme-color" content="<?php 
echo $PAGE->theme->settings->themecolor;
?>
">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href='//fonts.googleapis.com/css?family=Roboto:500,100,400,300' rel='stylesheet' type='text/css'>
<?php 
// Output course cover image?
if ($COURSE->id != SITEID) {
    $coverimagecss = \theme_snap\local::course_coverimage_css($COURSE->id);
} else {
    $coverimagecss = \theme_snap\local::site_coverimage_css();
}
if (!empty($coverimagecss)) {
    echo "<style>{$coverimagecss}</style>";
}
?>

</head>

<body <?php 
echo $OUTPUT->body_attributes();
?>
>

<?php 
echo $OUTPUT->standard_top_of_body_html();
 /**
  * Set image css for course card (cover image, etc).
  */
 private function apply_image_css()
 {
     $bgcolor = local::get_course_color($this->courseid);
     $this->imagecss = "background-color: #{$bgcolor};";
     $bgimage = local::course_coverimage_url($this->courseid);
     if (!empty($bgimage)) {
         $this->imagecss .= "background-image: url({$bgimage});";
     }
 }
    /**
     * Custom hook that requires a patch to /index.php
     * for customized rendering of front page news.
     *
     * @return string
     */
    public function site_frontpage_news()
    {
        global $CFG, $SITE;
        require_once $CFG->dirroot . '/mod/forum/lib.php';
        if (!($forum = forum_get_course_forum($SITE->id, 'news'))) {
            print_error('cannotfindorcreateforum', 'forum');
        }
        $cm = get_coursemodule_from_instance('forum', $forum->id, $SITE->id, false, MUST_EXIST);
        $context = context_module::instance($cm->id, MUST_EXIST);
        $output = html_writer::start_tag('div', array('id' => 'site-news-forum', 'class' => 'clearfix'));
        $output .= $this->heading(format_string($forum->name, true, array('context' => $context)));
        $groupmode = groups_get_activity_groupmode($cm, $SITE);
        $currentgroup = groups_get_activity_group($cm);
        if (!($discussions = forum_get_discussions($cm, 'p.modified DESC', true, null, $SITE->newsitems, false, -1, $SITE->newsitems))) {
            $output .= html_writer::tag('div', '(' . get_string('nonews', 'forum') . ')', array('class' => 'forumnodiscuss'));
            if (forum_user_can_post_discussion($forum, $currentgroup, $groupmode, $cm, $context)) {
                $output .= html_writer::link(new moodle_url('/mod/forum/post.php', array('forum' => $forum->id)), get_string('addanewtopic', 'forum'), array('class' => 'btn btn-primary'));
            } else {
                // No news and user cannot edit, so return nothing.
                return '';
            }
            return $output . '</div>';
        }
        $output .= html_writer::start_div('', array('id' => 'news-articles'));
        foreach ($discussions as $discussion) {
            if (!forum_user_can_see_discussion($forum, $discussion, $context)) {
                continue;
            }
            $message = file_rewrite_pluginfile_urls($discussion->message, 'pluginfile.php', $context->id, 'mod_forum', 'post', $discussion->id);
            $imagestyle = '';
            $imgarr = \theme_snap\local::extract_first_image($message);
            if ($imgarr) {
                $imageurl = s($imgarr['src']);
                $imagestyle = " style=\"background-image:url('{$imageurl}')\"";
            }
            $name = format_string($discussion->name, true, array('context' => $context));
            $date = userdate($discussion->timemodified, get_string('strftimedatetime', 'langconfig'));
            $readmorebtn = "<a class='btn btn-default toggle' href='" . $CFG->wwwroot . "/mod/forum/discuss.php?d=" . $discussion->discussion . "'>" . get_string('readmore', 'theme_snap') . "</a>";
            $preview = '';
            $newsimage = '';
            if (!$imagestyle) {
                $preview = html_to_text($message, 0, false);
                $preview = "<div class='news-article-preview'><p>" . shorten_text($preview, 200) . "</p>\n                <p class='text-right'>" . $readmorebtn . "</p></div>";
            } else {
                $newsimage = '<div class="news-article-image toggle"' . $imagestyle . ' title="' . get_string('readmore', 'theme_snap') . '"></div>';
            }
            $close = get_string('close', 'theme_snap');
            $output .= <<<HTML
<div class="news-article clearfix">
    {$newsimage}
    <div class="news-article-inner">
        <div class="news-article-content">
            <h3 class='toggle'><a href="{$CFG->wwwroot}/mod/forum/discuss.php?d={$discussion->discussion}">{$name}</a></h3>
            <em class="news-article-date">{$date}</em>
        </div>
    </div>
    {$preview}
    <div class="news-article-message" tabindex="-1">
        {$message}
        <div><hr><a class="snap-action-icon toggle" href="#">
        <i class="icon icon-office-52"></i><small>{$close}</small></a></div>
    </div>
</div>
HTML;
        }
        $actionlinks = html_writer::link(new moodle_url('/mod/forum/view.php', array('id' => $cm->id)), get_string('morenews', 'theme_snap'), array('class' => 'btn btn-default'));
        if (forum_user_can_post_discussion($forum, $currentgroup, $groupmode, $cm, $context)) {
            $actionlinks .= html_writer::link(new moodle_url('/mod/forum/post.php', array('forum' => $forum->id)), get_string('addanewtopic', 'forum'), array('class' => 'btn btn-primary'));
        }
        $output .= html_writer::end_div();
        $output .= "<br><div class='text-center'>{$actionlinks}</div>";
        $output .= html_writer::end_tag('div');
        return $output;
    }
Example #20
0
 /**
  * Get coursecompletion data by course shortname.
  * @param string $shortname
  * @param array $previouslyunavailablesections
  * @param array $previouslyunavailablemods
  * @return array
  */
 public function course_completion($shortname, $previouslyunavailablesections, $previouslyunavailablemods)
 {
     global $PAGE, $OUTPUT;
     $course = $this->coursebyshortname($shortname);
     list($unavailablesections, $unavailablemods) = local::conditionally_unavailable_elements($course);
     $newlyavailablesections = array_diff($previouslyunavailablesections, $unavailablesections);
     $newlyavailablemods = array_diff($previouslyunavailablemods, $unavailablemods);
     /** @var \theme_snap_core_course_renderer $courserenderer */
     $courserenderer = $PAGE->get_renderer('core', 'course', RENDERER_TARGET_GENERAL);
     $newlyavailablesectionhtml = [];
     if (!empty($newlyavailablesections)) {
         foreach ($newlyavailablesections as $sectionnumber) {
             $html = $courserenderer->course_section_cm_list($course, $sectionnumber, $sectionnumber);
             $newlyavailablesectionhtml[$sectionnumber] = $html;
         }
     }
     $newlyavailablemodhtml = [];
     if (!empty($newlyavailablemods)) {
         $modinfo = get_fast_modinfo($course);
         foreach ($newlyavailablemods as $modid) {
             $completioninfo = new \completion_info($course);
             $cm = $modinfo->get_cm($modid);
             if (isset($newlyavailablesectionhtml[$cm->sectionnum])) {
                 // This module's html has already been included in a newly available section.
                 continue;
             }
             $html = $courserenderer->course_section_cm_list_item($course, $completioninfo, $cm, $cm->sectionnum);
             $newlyavailablemodhtml[$modid] = $html;
         }
     }
     $unavailablesections = implode(',', $unavailablesections);
     $unavailablemods = implode(',', $unavailablemods);
     $toc = new course_toc($course);
     return ['unavailablesections' => $unavailablesections, 'unavailablemods' => $unavailablemods, 'newlyavailablemodhtml' => $newlyavailablemodhtml, 'newlyavailablesectionhtml' => $newlyavailablesectionhtml, 'toc' => $toc->export_for_template($OUTPUT)];
 }
Example #21
0
 /**
  * Javascript required by both standard header layout and flexpage layout
  *
  * @return void
  */
 public static function page_requires_js()
 {
     global $CFG, $PAGE, $COURSE, $USER;
     $PAGE->requires->jquery();
     $PAGE->requires->strings_for_js(array('close', 'debugerrors', 'problemsfound', 'error:coverimageexceedsmaxbytes', 'error:coverimageresolutionlow', 'forumtopic', 'forumauthor', 'forumpicturegroup', 'forumreplies', 'forumlastpost', 'hiddencoursestoggle', 'loading', 'more', 'moving', 'movingcount', 'movehere', 'movefailed', 'movingdropsectionhelp', 'movingstartedhelp'), 'theme_snap');
     $PAGE->requires->strings_for_js(['ok', 'cancel'], 'moodle');
     $PAGE->requires->strings_for_js(['printbook'], 'booktool_print');
     // Are we viewing /course/view.php - note, this is different from just checking the page type.
     // We only ever want to load course.js when on site page or view.php - no point in loading it when on
     // course settings page, etc.
     $courseviewpage = local::current_url_path() === '/course/view.php';
     $pagehascoursecontent = $PAGE->pagetype === 'site-index' || $courseviewpage;
     $cancomplete = isloggedin() && !isguestuser();
     $unavailablesections = [];
     $unavailablemods = [];
     if ($cancomplete) {
         $completioninfo = new \completion_info($COURSE);
         if ($completioninfo->is_enabled()) {
             $modinfo = get_fast_modinfo($COURSE);
             $sections = $modinfo->get_section_info_all();
             foreach ($sections as $number => $section) {
                 $ci = new \core_availability\info_section($section);
                 $information = '';
                 if (!$ci->is_available($information, true)) {
                     $unavailablesections[] = $number;
                 }
             }
             foreach ($modinfo as $mod) {
                 $ci = new \core_availability\info_module($mod);
                 if (!$ci->is_available($information, true)) {
                     $unavailablemods[] = $mod->id;
                 }
             }
         }
     }
     list($unavailablesections, $unavailablemods) = local::conditionally_unavailable_elements($COURSE);
     $coursevars = (object) ['id' => $COURSE->id, 'shortname' => $COURSE->shortname, 'contextid' => $PAGE->context->id, 'ajaxurl' => '/course/rest.php', 'unavailablesections' => $unavailablesections, 'unavailablemods' => $unavailablemods, 'enablecompletion' => $COURSE->enablecompletion];
     $initvars = [$coursevars, $pagehascoursecontent, get_max_upload_file_size($CFG->maxbytes)];
     $PAGE->requires->js_call_amd('theme_snap/snap', 'snapInit', $initvars);
     // Does the page have editable course content?
     if ($pagehascoursecontent && $PAGE->user_allowed_editing()) {
         $canmanageacts = has_capability('moodle/course:manageactivities', context_course::instance($COURSE->id));
         if ($canmanageacts && empty($USER->editing)) {
             $modinfo = get_fast_modinfo($COURSE);
             $modnamesused = $modinfo->get_used_module_names();
             // Temporarily change edit mode to on for course ajax to be included.
             $USER->editing = true;
             self::include_course_ajax($COURSE, $modnamesused);
             $USER->editing = false;
         }
     }
 }
 /**
  * Render recent forum activity.
  *
  * @param array $activities
  * @return string
  */
 public function recent_forum_activity(array $activities)
 {
     global $OUTPUT;
     $output = '';
     if (empty($activities)) {
         return '';
     }
     $formatoptions = new stdClass();
     $formatoptions->filter = false;
     foreach ($activities as $activity) {
         if (!empty($activity->user)) {
             $userpicture = new user_picture($activity->user);
             $userpicture->link = false;
             $userpicture->alttext = false;
             $userpicture->size = 32;
             $picture = $OUTPUT->render($userpicture);
         } else {
             $picture = '';
         }
         $url = new moodle_url('/mod/' . $activity->type . '/discuss.php', ['d' => $activity->content->discussion], 'p' . $activity->content->id);
         $fullname = fullname($activity->user);
         $forumpath = $activity->courseshortname . ' / ' . $activity->forumname;
         $meta = [local::relative_time($activity->timestamp), format_text($forumpath, FORMAT_HTML, $formatoptions)];
         $formattedsubject = '<p>' . format_text($activity->content->subject, FORMAT_HTML, $formatoptions) . '</p>';
         $output .= $this->snap_media_object($url, $picture, $fullname, $meta, $formattedsubject);
     }
     return $output;
 }
 /**
  * get course image
  *
  * @return bool|moodle_url
  */
 public function get_course_image()
 {
     global $COURSE;
     return \theme_snap\local::course_coverimage_url($COURSE->id);
 }
 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]));
 }
Example #25
0
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
/**
 * Theme config
 *
 * @package   theme_snap
 * @copyright Copyright (c) 2015 Moodlerooms Inc. (http://www.moodlerooms.com)
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
defined('MOODLE_INTERNAL') || die;
use theme_snap\local;
global $SESSION, $COURSE, $USER, $PAGE;
$theme = local::resolve_theme();
$themeissnap = $theme === 'snap';
$notajaxscript = !defined('AJAX_SCRIPT') || AJAX_SCRIPT == false;
// The code inside this conditional block is to be executed prior to page rendering when the theme is set to snap and
// when the current request is not an ajax request.
// There doesn't appear to be an official hook we can use for doing things prior to page rendering, so this is a
// workaround.
if ($themeissnap && $notajaxscript) {
    // Setup debugging html.
    // This allows javascript to target debug messages and move them to footer.
    if (!empty($CFG->snapwrapdebug) && !function_exists('xdebug_break')) {
        ini_set('error_prepend_string', '<div class="php-debug">');
        ini_set('error_append_string', '</div>');
    }
    // SL - dec 2015 - Make sure editing sessions are not carried over between courses.
    if (empty($SESSION->theme_snap_last_course) || $SESSION->theme_snap_last_course != $COURSE->id) {