view.php 20.4 KB
Newer Older
1
2
3
4
5
<?php
/**
 *
 * @package    mahara
 * @subpackage core
6
 * @author     Catalyst IT Ltd
7
8
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
 * @copyright  For copyright information on Mahara, please see the README file distributed with this software.
9
10
11
12
 *
 */

define('INTERNAL', 1);
13
define('PUBLIC', 1);
14
15
16
17
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'view');
define('SECTION_PAGE', 'view');

18
require(dirname(dirname(__FILE__)) . '/init.php');
19

20
require_once(get_config('libroot') . 'view.php');
21
require_once(get_config('libroot') . 'collection.php');
22
require_once(get_config('libroot') . 'objectionable.php');
23
require_once('institution.php');
24
require_once('group.php');
25
safe_require('artefact', 'comment');
26
safe_require('artefact', 'file');
27

28
29
30
31
32
33
34
35
36
37
38
39
40
// Used by the Mahara assignment submission plugin for Moodle, to indicate that a user
// coming over from mnet should be able to view a certain page (i.e. a teacher viewing
// an assignmnet submission)
$mnetviewid = param_integer('mnetviewid', false);
$mnetcollid = param_integer('mnetcollid', false);
if (
        ($mnetviewid || $mnetcollid)
        && $SESSION->get('mnetuser')
        && safe_require_plugin('auth', 'xmlrpc')
) {
    auth_xmlrpc_mnet_view_access($mnetviewid, $mnetcollid);
}

41
// access key for roaming teachers
42
43
// TODO: The mt token is used by the old token-based Mahara assignment submission
// access system, which is now deprecated. Remove eventually.
44
45
$mnettoken = param_alphanum('mt', null);
$mnettokenaccess = $SESSION->get('mnetuser') ? $mnettoken : null;
46
47

// access key for logged out users
48
$usertoken = (is_null($mnettokenaccess) && get_config('allowpublicviews')) ? param_alphanum('t', null) : null;
49
$viewtoken = null;
50
if ($mnettoken) {
51
52
    $viewtoken = get_view_from_token($mnettoken, false);
    if (!$viewtoken->viewid) {
53
54
        throw new AccessDeniedException(get_string('accessdenied', 'error'));
    }
55
    $viewid = $viewtoken->viewid;
56
57
}
else if ($usertoken) {
58
59
    $viewtoken = get_view_from_token($usertoken, true);
    if (!$viewtoken->viewid) {
60
        throw new AccessDeniedException(get_string('accessdenied', 'error'));
Richard Mansfield's avatar
Richard Mansfield committed
61
    }
62
    $viewid = $viewtoken->viewid;
Richard Mansfield's avatar
Richard Mansfield committed
63
}
64
65
66
67
68
69
70
71
72
73
74
75
else if ($pageurl = param_alphanumext('page', null)) {
    if ($profile = param_alphanumext('profile', null)) {
        $view = new View(array('urlid' => $pageurl, 'ownerurlid' => $profile));
    }
    else if ($homepage = param_alphanumext('homepage', null)) {
        $view = new View(array('urlid' => $pageurl, 'groupurlid' => $homepage));
    }
    else {
        throw new ViewNotFoundException(get_string('viewnotfoundexceptiontitle', 'error'));
    }
    $viewid = $view->get('id');
}
Richard Mansfield's avatar
Richard Mansfield committed
76
77
78
else {
    $viewid = param_integer('id');
}
79

80
81
82
83
$showmore = param_boolean('showmore');
if (!$showmore) {
    $showmore = 0;
}
84

85
86
87
88
if (!isset($view)) {
    $view = new View($viewid);
}

89
90
$is_admin = $USER->get('admin') || $USER->is_institutional_admin();
$is_owner = $view->get('owner') == $USER->get('id');
91
92
93
94
95
96
97

// check if this is a group page and the user is group admin
if ($groupid = $view->get('group')) {
    $is_group_admin = (group_user_access($groupid) == 'admin');
}

if (is_view_suspended($view) && !$is_admin && !$is_owner && !($groupid && $is_group_admin)) {
98
99
100
101
    $errorstr = get_string('accessdeniedsuspension', 'error');
    throw new AccessDeniedException($errorstr);
}

102
if (!can_view_view($view)) {
103
104
    $errorstr = (param_integer('objection', null)) ? get_string('accessdeniedobjection', 'error') : get_string('accessdenied', 'error');
    throw new AccessDeniedException($errorstr);
105
}
106

107
// Comment list pagination requires limit/offset params
108
109
110
$limit       = param_integer('limit', 10);
$offset      = param_integer('offset', 0);
$showcomment = param_integer('showcomment', null);
111

112
// Create the "make comment private form" now if it's been submitted
113
if (param_exists('make_public_submit')) {
114
    pieform(ArtefactTypeComment::make_public_form(param_integer('comment')));
115
}
116
else if (param_exists('delete_comment_submit')) {
Richard Mansfield's avatar
Richard Mansfield committed
117
    pieform(ArtefactTypeComment::delete_comment_form(param_integer('comment')));
118
119
}

120
121
$owner    = $view->get('owner');
$viewtype = $view->get('type');
122

123
124
if ($viewtype == 'profile' || $viewtype == 'dashboard' || $viewtype == 'grouphomepage') {
    redirect($view->get_url());
125
}
126

127
128
define('TITLE', $view->get('title'));

129
$collection = $view->get('collection');
130
131
132
133
// Do we need to redirect to the matrix page on first visit via token access?
if ($viewtoken && $viewtoken->gotomatrix && $collection && $collection->has_framework()) {
    redirect($collection->get_framework_url($collection, true));
}
134
$submittedgroup = (int)$view->get('submittedgroup');
135
if ($USER->is_logged_in() && $submittedgroup && group_user_can_assess_submitted_views($submittedgroup, $USER->get('id'))) {
136
    // The user is a tutor of the group that this view has
137
    // been submitted to, and is entitled to release the view
138
    $submittedgroup = get_group_by_id($submittedgroup, true);
139
140

    // Form for LTI grading
141
142
143
144
145
146
147
    if (is_plugin_active('lti', 'module')) {
        if ($collection) {
            $ltigradeform = PluginModuleLti::get_grade_dialogue($collection->get('id'), null);
        }
        else {
            $ltigradeform = PluginModuleLti::get_grade_dialogue(null, $view->get('id'));
        }
148
149
    }

150
151
    // If the view is part of a submitted collection, the whole
    // collection must be released at once.
152
153
    $releasecollection = !empty($collection) && $collection->get('submittedgroup') == $submittedgroup->id && empty($ltigradeform);

154
    if ($releasecollection) {
155
        if (isset($ltigradeform) && $ltigradeform && $ctime = $collection->get('submittedtime')) {
156
157
158
159
160
161
            preg_match("/^.*?\"(.*?)\" - \"(.*?)\"/", $submittedgroup->name, $matches);
            $lticoursename = hsc($matches[1]);
            $ltiassignmentname = hsc($matches[2]);
            $text = get_string('collectionsubmittedtogroupgrade', 'view', group_homepage_url($submittedgroup), $ltiassignmentname, $lticoursename, format_date(strtotime($ctime)));
        }
        else if ($ctime = $collection->get('submittedtime')) {
162
163
164
165
166
167
168
169
170
            $text = get_string(
                'collectionsubmittedtogroupon', 'view', group_homepage_url($submittedgroup), hsc($submittedgroup->name),
                format_date(strtotime($ctime))
            );
        }
        else {
            $text = get_string('collectionsubmittedtogroup', 'view', group_homepage_url($submittedgroup), hsc($submittedgroup->name));
        }
    }
171
172
173
174
175
176
    else if ($ltigradeform && $view->get('submittedtime')) {
        preg_match("/^.*?\"(.*?)\" - \"(.*?)\"/", $submittedgroup->name, $matches);
        $lticoursename = hsc($matches[1]);
        $ltiassignmentname = hsc($matches[2]);
        $text = get_string('viewsubmittedtogroupgrade', 'view', group_homepage_url($submittedgroup), $ltiassignmentname, $lticoursename, format_date(strtotime($view->get('submittedtime'))));
    }
177
    else if ($view->get('submittedtime')) {
178
        $text = get_string('viewsubmittedtogroupon1', 'view', group_homepage_url($submittedgroup), hsc($submittedgroup->name), format_date(strtotime($view->get('submittedtime'))));
179
180
    }
    else {
181
        $text = get_string('viewsubmittedtogroup1', 'view', group_homepage_url($submittedgroup), hsc($submittedgroup->name));
182
    }
183
    if (($releasecollection && $collection->get('submittedstatus') == Collection::SUBMITTED) || $view->get('submittedstatus') == View::SUBMITTED && empty($ltigradeform)) {
184
185
186
        $releaseform = pieform(array(
            'name'     => 'releaseview',
            'method'   => 'post',
Pat Kira's avatar
Pat Kira committed
187
            'class' => 'form-inline',
188
189
190
191
192
193
194
195
196
            'plugintype' => 'core',
            'pluginname' => 'view',
            'autofocus' => false,
            'elements' => array(
                'submittedview' => array(
                    'type'  => 'html',
                    'value' => $text,
                ),
                'submit' => array(
Pat Kira's avatar
Pat Kira committed
197
198
                    'type'  => 'button',
                    'usebuttontag' => true,
199
                    'class' => 'btn-default pull-right',
200
                    'value' => $releasecollection ? '<span class="icon icon-unlock left" role="presentation" aria-hidden="true"></span>' . get_string('releasecollection', 'group') : '<span class="icon icon-unlock left" role="presentation" aria-hidden="true"></span>' . get_string('releaseview', 'group'),
201
                ),
202
            ),
203
204
        ));
    }
205
206
207
    else if ($ltigradeform) {
        $releaseform = $text;
    }
208
209
210
    else {
        $releaseform = $text . ' ' . get_string('submittedpendingrelease', 'view');
    }
211
212
213
214
215

    if (!empty($ltigradeform)) {
        $releaseform .= $ltigradeform;
    }

216
}
217
218
219
220
221
else {
    $releaseform = '';
}

function releaseview_submit() {
222
    global $USER, $SESSION, $view, $collection, $submittedgroup, $releasecollection;
223

224
    if ($releasecollection) {
225
226
227
228
229
230
231
232
        if (is_object($submittedgroup) && $submittedgroup->allowarchives) {
            $collection->pendingrelease($USER);
            $SESSION->add_ok_msg(get_string('collectionreleasedpending', 'group'));
        }
        else {
            $collection->release($USER);
            $SESSION->add_ok_msg(get_string('collectionreleasedsuccess', 'group'));
        }
233
234
    }
    else {
235
236
237
238
239
240
241
242
        if (is_object($submittedgroup) && $submittedgroup->allowarchives) {
            $view->pendingrelease($USER);
            $SESSION->add_ok_msg(get_string('viewreleasedpending', 'group'));
        }
        else {
            $view->release($USER);
            $SESSION->add_ok_msg(get_string('viewreleasedsuccess', 'group'));
        }
243
    }
244
    if ($submittedgroup) {
245
246
        // The tutor might not have access to the view any more; send
        // them back to the group page.
247
        redirect(group_homepage_url($submittedgroup));
248
    }
249
    redirect($view->get_url());
250
}
251

252
$javascript = array('paginator', 'viewmenu', 'js/collection-navigation.js', 'js/jquery/jquery-mobile/jquery.mobile.custom.min.js');
253
254
$blocktype_js = $view->get_all_blocktype_javascript();
$javascript = array_merge($javascript, $blocktype_js['jsfiles']);
255
if (is_plugin_active('externalvideo', 'blocktype')) {
256
257
    $javascript = array_merge($javascript, array((is_https() ? 'https:' : 'http:') . '//cdn.embedly.com/widgets/platform.js'));
}
258
$inlinejs = "jQuery( function() {\n" . join("\n", $blocktype_js['initjs']) . "\n});";
259

260
261
// If the view has comments turned off, tutors can still leave
// comments if the view is submitted to their group.
262
if (!empty($releaseform) || ($commenttype = $view->user_comments_allowed($USER))) {
263
    $defaultprivate = !empty($releaseform);
264
    $moderate = !$USER->is_logged_in() || (isset($commenttype) && $commenttype === 'private');
265
    $addfeedbackform = pieform(ArtefactTypeComment::add_comment_form($defaultprivate, $moderate));
266
}
267
$objectionform = false;
268
269
if ($USER->is_logged_in()) {
    $objectionform = pieform(objection_form());
270
    $reviewform = pieform(review_form($view->get('id')));
271
    if ($notrudeform = notrude_form()) {
272
273
        $notrudeform = pieform($notrudeform);
    }
274
275
276
277
278
    // For for admin to review objection claim, add comment
    // about objectionable content and possibly remove access
    if ($stillrudeform = stillrude_form()) {
        $stillrudeform = pieform($stillrudeform);
    }
279
280
}

281
$viewbeingwatched = (int)record_exists('usr_watchlist_view', 'usr', $USER->get('id'), 'view', $viewid);
282
283
284
285
286
287
$commentoptions = ArtefactTypeComment::get_comment_options();
$commentoptions->limit = $limit;
$commentoptions->offset = $offset;
$commentoptions->showcomment = $showcomment;
$commentoptions->view = $view;
$feedback = ArtefactTypeComment::get_comments($commentoptions);
288

289
// Set up theme
290
// if the view theme is set in view table
291
292
$viewtheme = $view->get('theme');
if ($viewtheme && $THEME->basename != $viewtheme) {
293
    $THEME = new Theme($view);
294
}
295
296
// if it's another users view, it should be displayed with the other users institution theme
else if ($owner && $owner != $USER->get('id')) {
297
    $THEME = new Theme((int)$owner);
298
299
}

Naomi Guyer's avatar
Naomi Guyer committed
300
$headers = array();
301
$headers[] = '<link rel="stylesheet" type="text/css" href="' . append_version_number(get_config('wwwroot') . 'js/jquery/jquery-ui/css/smoothness/jquery-ui.min.css') . '">';
302
$headers = array_merge($headers, $view->get_all_blocktype_css());
303
304
// Set up skin, if the page has one
$viewskin = $view->get('skin');
305
306
$issiteview = $view->get('institution') == 'mahara';
if ($viewskin && get_config('skins') && can_use_skins($owner, false, $issiteview) && (!isset($THEME->skins) || $THEME->skins !== false)) {
307
    $skin = array('skinid' => $viewskin, 'viewid' => $view->get('id'));
308
309
310
311
312
}
else {
    $skin = false;
}

313
314
315
if (!$view->is_public()) {
    $headers[] = '<meta name="robots" content="noindex">';  // Tell search engines not to index non-public views
}
316

317
$can_edit = $USER->can_edit_view($view) && !$submittedgroup && !$view->is_submitted();
318
$can_copy = $view->is_copyable();
319

320
321
322
323
324
325
326
$viewgroupform = false;
if ($owner && $owner == $USER->get('id')) {
    if ($tutorgroupdata = group_get_user_course_groups()) {
        if (!$view->is_submitted()) {
            $viewgroupform = view_group_submission_form($view, $tutorgroupdata, 'view');
        }
    }
327
    if (is_plugin_active('lti', 'module') && PluginModuleLti::can_submit_for_grading()) {
328
329
        $ltisubmissionform = PluginModuleLti::submit_from_view_or_collection_form($view);
    }
330
331
}

332

333
334
335
336
337
// Don't show page content to a user with peer role
// if the view doesn't have a peer assessment block
if (!$USER->has_peer_role_only($view) || $view->has_peer_assessement_block()) {
    $viewcontent = $view->build_rows(); // Build content before initialising smarty in case pieform elements define headers.
}
338

339
$smarty = smarty(
340
    $javascript,
341
    $headers,
342
343
344
345
    array('confirmcopytitle' => 'view',
          'confirmcopydesc' => 'view',
          'View' => 'view',
          'Collection' => 'collection'),
346
347
    array(
        'sidebars' => false,
348
        'skin' => $skin
349
    )
350
);
351

352
353
$javascript = <<<EOF
var viewid = {$viewid};
354
var showmore = {$showmore};
355
jQuery(function () {
356
357
    paginator = {$feedback->pagination_js}
});
358

359
360
361
jQuery(function($) {
    $('#column-container .blockinstance-content .commentlink').each(function() {
        var blockid = $(this).attr('id').match(/\d+/);
362
        // only use comments expander if there are comments on the artefact
363
364
        $(this).on('click', function(e) {
            var commentlink = $(this);
365
366
            var chtml = commentlink.parent().parent().find('#feedbacktable_' + blockid).parent();
            // add a 'close' link at the bottom of the list for convenience
367
            if ($('#closer_' + blockid).length == 0) {
368
                var closer = $('<a id="closer_' + blockid + '" href="#" class="close-link">Close</a>').on("click", function(e) {
369
                    $(this).parent().toggle(400, function() {
370
                        commentlink.trigger("focus");
371
372
373
374
375
376
377
                    });
                    e.preventDefault();
                });
                chtml.append(closer);
            }
            chtml.toggle(400, function() {
                if (chtml.is(':visible')) {
378
                    chtml.find('a').first().trigger("focus");
379
380
                }
                else {
381
                    commentlink.trigger("focus");
382
383
384
385
386
                }
            });
            e.preventDefault();
        });
    });
387
388
389
390
391
392
393
394
395
396
397
398

    $('.moretags').on('click', function(e) {
        e.preventDefault();
        var params = {
            'viewid': viewid
        }
        sendjsonrequest(config['wwwroot'] + 'view/viewtags.json.php',  params, 'POST', function(data) {
            if (data.count) {
                $('.tags').html(data.html);
            }
        });
    });
399
400
});

401
402
403
jQuery(window).on('pageupdated', {}, function() {
    dock.init(jQuery(document));
});
404
405
EOF;

406
// collection top navigation
407
if ($collection) {
408
409
    $shownav = $collection->get('navigation');
    if ($shownav) {
410
        if ($views = $collection->get('views')) {
411
412
413
414
415
            $viewnav = $views['views'];
            if ($collection->has_framework()) {
                array_unshift($viewnav, $collection->collection_nav_framework_option());
            }
            $smarty->assign('collection', $viewnav);
416
        }
417
    }
418
419
}

420
421
422
423
$blocktype_toolbar = $view->get_all_blocktype_toolbar();
if (!empty($blocktype_toolbar['toolbarhtml'])) {
    $smarty->assign('toolbarhtml', join("\n", $blocktype_toolbar['toolbarhtml']));
}
424
$smarty->assign('canremove', $can_edit);
425
$smarty->assign('INLINEJAVASCRIPT', $javascript . $inlinejs);
426
$smarty->assign('viewid', $viewid);
427
$smarty->assign('viewtype', $viewtype);
428
$smarty->assign('feedback', $feedback);
Richard Mansfield's avatar
Richard Mansfield committed
429
$smarty->assign('owner', $owner);
430
431
432
list($tagcount, $alltags) = $view->get_all_tags_for_view(10);
$smarty->assign('alltags', $alltags);
$smarty->assign('moretags', ($tagcount > sizeof($alltags) ? true : false));
433
$smarty->assign('PAGEHEADING', null);
434
435
436
437
438
439
440
441
442
443
444
445
446
if ($view->is_anonymous()) {
  $smarty->assign('PAGEAUTHOR', get_string('anonymoususer'));
  $smarty->assign('author', get_string('anonymoususer'));
  if ($view->is_staff_or_admin_for_page()) {
    $smarty->assign('realauthor', $view->display_author());
  }
  $smarty->assign('anonymous', TRUE);
} else {
  $smarty->assign('PAGEAUTHOR', $view->formatted_owner());
  $smarty->assign('author', $view->display_author());
  $smarty->assign('anonymous', FALSE);
}

447

448
$titletext = ($collection && $shownav) ? hsc($collection->get('name')) : $view->display_title(true, false, false);
449
$smarty->assign('lastupdatedstr', $view->lastchanged_message());
450
$smarty->assign('visitstring', $view->visit_message());
451
if ($can_edit) {
452
    $smarty->assign('editurl', get_config('wwwroot') . 'view/blocks.php?id=' . $viewid);
453
}
454
455
if ($can_copy) {
    $smarty->assign('copyurl', get_config('wwwroot') . 'view/copy.php?id=' . $viewid . (!empty($collection) ? '&collection=' . $collection->get('id') : ''));
456
457
458
459
    if (!$USER->is_logged_in() && $view->get('owner')) {
        // if no user is loggedin and the personal profile is public, the Copy button should download the portfolio
        $smarty->assign('downloadurl', get_config('wwwroot') . 'view/download.php?id=' . $viewid . (!empty($collection) ? '&collection=' . $collection->get('id') : ''));
    }
460
}
461
462
463
464
$versions = View::get_versions($view->get('id'));
if ($versions->count > 0) {
    $smarty->assign('versionurl', get_config('wwwroot') . 'view/versioning.php?view=' . $viewid);
}
465
466
$smarty->assign('createversionurl', get_config('wwwroot') . 'view/createversion.php?view=' . $viewid);

467
468
$title = hsc(TITLE);

469
$smarty->assign('maintitle', $titletext);
470

471
// Provide a link for roaming teachers to return
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
$showmnetlink = false;
// Old token-based access list
if (
    $mnetviewlist = $SESSION->get('mnetviewaccess')
    && isset($mnetviewlist[$view->get('id')])
) {
    $showmnetlink = true;
}

// New mnet-based access list
if (
    $SESSION->get('mnetviews')
    && in_array($view->get('id'), $SESSION->get('mnetviews'))
) {
    $showmnetlink = true;
}


if ($showmnetlink) {
    $returnurl = $SESSION->get('mnetuserfrom');
    require_once(get_config('docroot') . 'api/xmlrpc/lib.php');
    if ($peer = get_peer_from_instanceid($SESSION->get('authinstance'))) {
        $smarty->assign('mnethost', array(
            'name'      => $peer->name,
            'url'       => $returnurl ? $returnurl : $peer->wwwroot,
        ));
498
499
    }
}
500

501
$smarty->assign('viewdescription', ArtefactTypeFolder::append_view_url($view->get('description'), $view->get('id')));
502
$smarty->assign('viewinstructions', ArtefactTypeFolder::append_view_url($view->get('instructions'), $view->get('id')));
503
$smarty->assign('viewcontent', (isset($viewcontent) ? $viewcontent : null));
504
$smarty->assign('releaseform', $releaseform);
505
506
507
508
if (isset($ltisubmissionform)) {
    $smarty->assign('ltisubmissionform', $ltisubmissionform);
}

509
if (isset($addfeedbackform)) {
510
    $smarty->assign('enablecomments', 1);
511
    $smarty->assign('addfeedbackform', $addfeedbackform);
512
}
513
514
if (isset($objectionform)) {
    $smarty->assign('objectionform', $objectionform);
515
516
517
518
    if ($USER->is_logged_in()) {
        $smarty->assign('notrudeform', $notrudeform);
        $smarty->assign('stillrudeform', $stillrudeform);
    }
519
520
521
522
523
524
    $smarty->assign('objectedpage', $view->is_objectionable());
    $smarty->assign('objector', $view->is_objectionable($USER->get('id')));
    $smarty->assign('objectionreplied', $view->is_objectionable(null, true));
}
if (isset($reviewform)) {
    $smarty->assign('reviewform', $reviewform);
525
}
526
$smarty->assign('viewbeingwatched', $viewbeingwatched);
527

528
529
if ($viewgroupform) {
    $smarty->assign('view_group_submission_form', $viewgroupform);
530
531
}

532
533
534
535
if ($titletext !== $title) {
    $smarty->assign('title', $title);
}

536
537
$smarty->assign('userisowner', ($owner && $owner == $USER->get('id')));

538
539
$smarty->display('view/view.tpl');

540
mahara_touch_record('view', $viewid); // Update record 'atime'
541
mahara_log('views', "$viewid"); // Log view visits