view.php 20.2 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
91
92
93
94
95
$is_admin = $USER->get('admin') || $USER->is_institutional_admin();
$is_owner = $view->get('owner') == $USER->get('id');
if (is_view_suspended($view) && !$is_admin && !$is_owner) {
    $errorstr = get_string('accessdeniedsuspension', 'error');
    throw new AccessDeniedException($errorstr);
}

96
if (!can_view_view($view)) {
97
98
    $errorstr = (param_integer('objection', null)) ? get_string('accessdeniedobjection', 'error') : get_string('accessdenied', 'error');
    throw new AccessDeniedException($errorstr);
99
}
100

101
// Comment list pagination requires limit/offset params
102
103
104
$limit       = param_integer('limit', 10);
$offset      = param_integer('offset', 0);
$showcomment = param_integer('showcomment', null);
105

106
// Create the "make comment private form" now if it's been submitted
107
if (param_exists('make_public_submit')) {
108
    pieform(ArtefactTypeComment::make_public_form(param_integer('comment')));
109
}
110
else if (param_exists('delete_comment_submit')) {
Richard Mansfield's avatar
Richard Mansfield committed
111
    pieform(ArtefactTypeComment::delete_comment_form(param_integer('comment')));
112
113
}

114
115
$owner    = $view->get('owner');
$viewtype = $view->get('type');
116

117
118
if ($viewtype == 'profile' || $viewtype == 'dashboard' || $viewtype == 'grouphomepage') {
    redirect($view->get_url());
119
}
120

121
122
define('TITLE', $view->get('title'));

123
$collection = $view->get('collection');
124
125
126
127
// 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));
}
128
$submittedgroup = (int)$view->get('submittedgroup');
129
if ($USER->is_logged_in() && $submittedgroup && group_user_can_assess_submitted_views($submittedgroup, $USER->get('id'))) {
130
    // The user is a tutor of the group that this view has
131
    // been submitted to, and is entitled to release the view
132
    $submittedgroup = get_group_by_id($submittedgroup, true);
133
134

    // Form for LTI grading
135
136
137
138
139
140
141
    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'));
        }
142
143
    }

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

148
    if ($releasecollection) {
149
150
151
152
153
154
155
        if ($ltigradeform && $ctime = $collection->get('submittedtime')) {
            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')) {
156
157
158
159
160
161
162
163
164
            $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));
        }
    }
165
166
167
168
169
170
    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'))));
    }
171
    else if ($view->get('submittedtime')) {
172
        $text = get_string('viewsubmittedtogroupon', 'view', group_homepage_url($submittedgroup), hsc($submittedgroup->name), format_date(strtotime($view->get('submittedtime'))));
173
174
    }
    else {
175
        $text = get_string('viewsubmittedtogroup', 'view', group_homepage_url($submittedgroup), hsc($submittedgroup->name));
176
    }
177
    if (($releasecollection && $collection->get('submittedstatus') == Collection::SUBMITTED) || $view->get('submittedstatus') == View::SUBMITTED && empty($ltigradeform)) {
178
179
180
        $releaseform = pieform(array(
            'name'     => 'releaseview',
            'method'   => 'post',
Pat Kira's avatar
Pat Kira committed
181
            'class' => 'form-inline',
182
183
184
185
186
187
188
189
190
            'plugintype' => 'core',
            'pluginname' => 'view',
            'autofocus' => false,
            'elements' => array(
                'submittedview' => array(
                    'type'  => 'html',
                    'value' => $text,
                ),
                'submit' => array(
Pat Kira's avatar
Pat Kira committed
191
192
                    'type'  => 'button',
                    'usebuttontag' => true,
193
                    'class' => 'btn-default pull-right',
194
                    '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'),
195
                ),
196
            ),
197
198
        ));
    }
199
200
201
    else if ($ltigradeform) {
        $releaseform = $text;
    }
202
203
204
    else {
        $releaseform = $text . ' ' . get_string('submittedpendingrelease', 'view');
    }
205
206
207
208
209

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

210
}
211
212
213
214
215
else {
    $releaseform = '';
}

function releaseview_submit() {
216
    global $USER, $SESSION, $view, $collection, $submittedgroup, $releasecollection;
217

218
    if ($releasecollection) {
219
220
221
222
223
224
225
226
        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'));
        }
227
228
    }
    else {
229
230
231
232
233
234
235
236
        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'));
        }
237
    }
238
    if ($submittedgroup) {
239
240
        // The tutor might not have access to the view any more; send
        // them back to the group page.
241
        redirect(group_homepage_url($submittedgroup));
242
    }
243
    redirect($view->get_url());
244
}
245

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

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

275
$viewbeingwatched = (int)record_exists('usr_watchlist_view', 'usr', $USER->get('id'), 'view', $viewid);
276
277
278
279
280
281
$commentoptions = ArtefactTypeComment::get_comment_options();
$commentoptions->limit = $limit;
$commentoptions->offset = $offset;
$commentoptions->showcomment = $showcomment;
$commentoptions->view = $view;
$feedback = ArtefactTypeComment::get_comments($commentoptions);
282

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

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

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

311
$can_edit = $USER->can_edit_view($view) && !$submittedgroup && !$view->is_submitted();
312
$can_copy = $view->is_copyable();
313

314
315
316
317
318
319
320
$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');
        }
    }
321
    if (is_plugin_active('lti', 'module') && PluginModuleLti::can_submit_for_grading()) {
322
323
        $ltisubmissionform = PluginModuleLti::submit_from_view_or_collection_form($view);
    }
324
325
}

326

327
328
329
330
331
// 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.
}
332

333
$smarty = smarty(
334
    $javascript,
335
    $headers,
336
337
338
339
    array('confirmcopytitle' => 'view',
          'confirmcopydesc' => 'view',
          'View' => 'view',
          'Collection' => 'collection'),
340
341
    array(
        'sidebars' => false,
342
        'skin' => $skin
343
    )
344
);
345

346
347
$javascript = <<<EOF
var viewid = {$viewid};
348
var showmore = {$showmore};
349
jQuery(function () {
350
351
    paginator = {$feedback->pagination_js}
});
352

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

    $('.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);
            }
        });
    });
393
394
});

395
396
397
jQuery(window).on('pageupdated', {}, function() {
    dock.init(jQuery(document));
});
398
399
EOF;

400
// collection top navigation
401
if ($collection) {
402
403
    $shownav = $collection->get('navigation');
    if ($shownav) {
404
        if ($views = $collection->get('views')) {
405
406
407
408
409
            $viewnav = $views['views'];
            if ($collection->has_framework()) {
                array_unshift($viewnav, $collection->collection_nav_framework_option());
            }
            $smarty->assign('collection', $viewnav);
410
        }
411
    }
412
413
}

414
415
416
417
$blocktype_toolbar = $view->get_all_blocktype_toolbar();
if (!empty($blocktype_toolbar['toolbarhtml'])) {
    $smarty->assign('toolbarhtml', join("\n", $blocktype_toolbar['toolbarhtml']));
}
418
$smarty->assign('canremove', $can_edit);
419
$smarty->assign('INLINEJAVASCRIPT', $javascript . $inlinejs);
420
$smarty->assign('viewid', $viewid);
421
$smarty->assign('viewtype', $viewtype);
422
$smarty->assign('feedback', $feedback);
Richard Mansfield's avatar
Richard Mansfield committed
423
$smarty->assign('owner', $owner);
424
425
426
list($tagcount, $alltags) = $view->get_all_tags_for_view(10);
$smarty->assign('alltags', $alltags);
$smarty->assign('moretags', ($tagcount > sizeof($alltags) ? true : false));
427
$smarty->assign('PAGEHEADING', null);
428
429
430
431
432
433
434
435
436
437
438
439
440
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);
}

441

442
$titletext = ($collection && $shownav) ? hsc($collection->get('name')) : $view->display_title(true, false, false);
443
$smarty->assign('lastupdatedstr', $view->lastchanged_message());
444
$smarty->assign('visitstring', $view->visit_message());
445
if ($can_edit) {
446
    $smarty->assign('editurl', get_config('wwwroot') . 'view/blocks.php?id=' . $viewid);
447
}
448
449
if ($can_copy) {
    $smarty->assign('copyurl', get_config('wwwroot') . 'view/copy.php?id=' . $viewid . (!empty($collection) ? '&collection=' . $collection->get('id') : ''));
450
451
452
453
    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') : ''));
    }
454
}
455
456
457
458
$versions = View::get_versions($view->get('id'));
if ($versions->count > 0) {
    $smarty->assign('versionurl', get_config('wwwroot') . 'view/versioning.php?view=' . $viewid);
}
459
460
$smarty->assign('createversionurl', get_config('wwwroot') . 'view/createversion.php?view=' . $viewid);

461
462
$title = hsc(TITLE);

463
$smarty->assign('maintitle', $titletext);
464

465
// Provide a link for roaming teachers to return
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
$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,
        ));
492
493
    }
}
494

495
$smarty->assign('viewdescription', ArtefactTypeFolder::append_view_url($view->get('description'), $view->get('id')));
496
$smarty->assign('viewinstructions', ArtefactTypeFolder::append_view_url($view->get('instructions'), $view->get('id')));
497
$smarty->assign('viewcontent', (isset($viewcontent) ? $viewcontent : null));
498
$smarty->assign('releaseform', $releaseform);
499
500
501
502
if (isset($ltisubmissionform)) {
    $smarty->assign('ltisubmissionform', $ltisubmissionform);
}

503
if (isset($addfeedbackform)) {
504
    $smarty->assign('enablecomments', 1);
505
    $smarty->assign('addfeedbackform', $addfeedbackform);
506
}
507
508
if (isset($objectionform)) {
    $smarty->assign('objectionform', $objectionform);
509
510
511
512
    if ($USER->is_logged_in()) {
        $smarty->assign('notrudeform', $notrudeform);
        $smarty->assign('stillrudeform', $stillrudeform);
    }
513
514
515
516
517
518
    $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);
519
}
520
$smarty->assign('viewbeingwatched', $viewbeingwatched);
521

522
523
if ($viewgroupform) {
    $smarty->assign('view_group_submission_form', $viewgroupform);
524
525
}

526
527
528
529
if ($titletext !== $title) {
    $smarty->assign('title', $title);
}

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

532
533
$smarty->display('view/view.tpl');

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