collection.php 30.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
/**
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
 * Copyright (C) 2006-2009 Catalyst IT Ltd and others; see:
 *                         http://wiki.mahara.org/Contributors
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @package    mahara
 * @subpackage core
 * @author     Catalyst IT Ltd
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @copyright  (C) 2006-2009 Catalyst IT Ltd http://catalyst.net.nz
 *
 */

defined('INTERNAL') || die();

30
31
32
33
34
35
class Collection {

    private $id;
    private $name;
    private $description;
    private $owner;
36
37
    private $group;
    private $institution;
38
39
    private $mtime;
    private $ctime;
40
    private $navigation;
41
42
43
    private $submittedgroup;
    private $submittedhost;
    private $submittedtime;
44
    private $views;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

    public function __construct($id=0, $data=null) {

        if (!empty($id)) {
            $tempdata = get_record('collection','id',$id);
            if (empty($tempdata)) {
                throw new CollectionNotFoundException("Collection with id $id not found");
            }
            if (!empty($data)) {
                $data = array_merge((array)$tempdata, $data);
            }
            else {
                $data = $tempdata; // use what the database has
            }
            $this->id = $id;
        }
        else {
            $this->ctime = time();
            $this->mtime = time();
        }
65

66
67
68
69
70
71
72
        if (empty($data)) {
            $data = array();
        }
        foreach ((array)$data as $field => $value) {
            if (property_exists($this, $field)) {
                $this->{$field} = $value;
            }
73
        }
74
75
76
77
        if (empty($this->group) && empty($this->institution) && empty($this->owner)) {
            global $USER;
            $this->owner = $USER->get('id');
        }
78
79
    }

80
81
82
83
    public function get($field) {
        if (!property_exists($this, $field)) {
            throw new InvalidArgumentException("Field $field wasn't found in class " . get_class($this));
        }
84
85
86
        if ($field == 'views') {
            return $this->views();
        }
87
88
        return $this->{$field};
    }
89

90
91
92
93
94
95
96
97
    public function set($field, $value) {
        if (property_exists($this, $field)) {
            $this->{$field} = $value;
            $this->mtime = time();
            return true;
        }
        throw new InvalidArgumentException("Field $field wasn't found in class " . get_class($this));
    }
98

99
100
101
102
103
104
105
106
107
108
    /**
     * Creates a new Collection for the given user.
     *
     * @param array $data
     * @return collection           The newly created Collection
     */
    public static function save($data) {
        $collection = new Collection(0, $data);
        $collection->commit();

109
        return $collection; // return newly created Collections id
110
    }
111

112
113
114
115
116
    /**
     * Deletes a Collection
     *
     */
    public function delete() {
117
        $viewids = get_column('collection_view', 'view', 'collection', $this->id);
118
        db_begin();
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

        // Delete navigation blocks within the collection's views which point at this collection.
        if ($viewids) {
            $values = $viewids;
            $values[] = 'navigation';
            $navigationblocks = get_records_select_assoc(
                'block_instance', 'view IN (' . join(',', array_fill(0, count($viewids), '?')) . ') AND blocktype = ?',
                $values
            );
            if ($navigationblocks) {
                safe_require('blocktype', 'navigation');
                foreach ($navigationblocks as $b) {
                    $bi = new BlockInstance($b->id, $b);
                    $configdata = $bi->get('configdata');
                    if (isset($configdata['collection']) && $configdata['collection'] == $this->id) {
                        $bi->delete();
                    }
                }
            }
        }

Stacey Walker's avatar
Stacey Walker committed
140
        delete_records('collection_view','collection',$this->id);
141
        delete_records('collection','id',$this->id);
142
143
144
145
146
147
148

        // Secret url records belong to the collection, so remove them from the view.
        // @todo: add user message to whatever calls this.
        if ($viewids) {
            delete_records_select('view_access', 'view IN (' . join(',', $viewids) . ') AND token IS NOT NULL');
        }

149
150
151
        db_commit();
    }

152
153
154
155
156
157
158
159
    /**
     * This method updates the contents of the collection table only.
     */
    public function commit() {

        $fordb = new StdClass;
        foreach (get_object_vars($this) as $k => $v) {
            $fordb->{$k} = $v;
160
            if (in_array($k, array('mtime', 'ctime', 'submittedtime')) && !empty($v)) {
161
162
163
                $fordb->{$k} = db_format_timestamp($v);
            }
        }
164

165
        db_begin();
166

167
168
169
170
171
        // if id is not empty we are editing an existing collection
        if (!empty($this->id)) {
            update_record('collection', $fordb, 'id');
        }
        else {
172
173
            $id = insert_record('collection', $fordb, 'id', true);
            if ($id) {
174
                $this->set('id', $id);
175
            }
176
        }
177

178
179
        db_commit();
    }
180

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
    /**
     * Generates a name for a newly created Collection
     */
    private static function new_name($name, $ownerdata) {
        $taken = get_column_sql('
            SELECT name
            FROM {collection}
            WHERE ' . self::owner_sql($ownerdata) . "
                AND name LIKE ? || '%'", array($name));
        $ext = ''; $i = 0;
        if ($taken) {
            while (in_array($name . $ext, $taken)) {
                $ext = ' (' . ++$i . ')';
            }
        }
        return $name . $ext;
    }

    /**
     * Creates a Collection for the given user, based off a given template and other
     * Collection information supplied.
     *
     * Will set a default title of 'Copy of $collectiontitle' if title is not
     * specified in $collectiondata.
     *
     * @param array $collectiondata Contains information of the old collection, submitted in form
     * @param int $templateid The ID of the Collection to copy
     * @param int $userid     The user who has issued the command to create the
     *                        collection.
     * @param int $checkaccess Whether to check that the user can see the collection before copying it
     * @return array A list consisting of the new collection, the template collection and
     *               information about the copy - i.e. how many blocks and
     *               artefacts were copied
     * @throws SystemException under various circumstances, see the source for
     *                         more information
     */
    public static function create_from_template($collectiondata, $templateid, $userid=null, $checkaccess=true) {
        require_once(get_config('libroot') . 'view.php');
        global $SESSION;

        if (is_null($userid)) {
            global $USER;
            $userid = $USER->get('id');
        }

        db_begin();

        $colltemplate = new Collection($templateid);

        $data = new StdClass;
231
232
233
234
235
        $desiredname = $colltemplate->get('name');
        if (get_config('renamecopies')) {
            $desiredname = get_string('Copyof', 'mahara', $desiredname);
        }
        $data->name = self::new_name($desiredname, (object)$collectiondata);
236
237
        $data->description = $colltemplate->get('description');
        $data->navigation = $colltemplate->get('navigation');
238
239
240
241
242
243
244
245
246
247
248
249
        if (!empty($collectiondata['group'])) {
            $data->group = $collectiondata['group'];
        }
        else if (!empty($collectiondata['institution'])) {
            $data->institution = $collectiondata['institution'];
        }
        else if (!empty($collectiondata['owner'])) {
            $data->owner = $collectiondata['owner'];
        }
        else {
            $data->owner = $userid;
        }
250
251
252
253
254
255
256
257

        $collection = self::save($data);

        $numcopied = array('pages' => 0, 'blocks' => 0, 'artefacts' => 0);

        $views = $colltemplate->get('views');
        $copyviews = array();
        foreach ($views['views'] as $v) {
258
259
260
261
262
263
264
            $values = array(
                'new' => true,
                'owner' => isset($data->owner) ? $data->owner : null,
                'group' => isset($data->group) ? $data->group : null,
                'institution' => isset($data->institution) ? $data->institution : null,
                'usetemplate' => $v->view
            );
265
266
267
268
269
270
271
272
273
274
275
276
277
            list($view, $template, $copystatus) = View::create_from_template($values, $v->view, $userid, $checkaccess);
            if (isset($copystatus['quotaexceeded'])) {
                $SESSION->clear('messages');
                return array(null, $colltemplate, array('quotaexceeded' => true));
            }
            $copyviews['view_' . $view->get('id')] = true;
            $numcopied['blocks'] += $copystatus['blocks'];
            $numcopied['artefacts'] += $copystatus['artefacts'];
        }
        $numcopied['pages'] = count($views['views']);

        $collection->add_views($copyviews);

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
        // Update all the navigation blocks referring to this collection
        if ($viewids = get_column('collection_view', 'view', 'collection', $collection->get('id'))) {
            $navblocks = get_records_select_array(
                'block_instance',
                'view IN (' . join(',', array_fill(0, count($viewids), '?')) . ") AND blocktype = 'navigation'",
                $viewids
            );

            if ($navblocks) {
                safe_require('blocktype', 'navigation');
                foreach ($navblocks as $b) {
                    $bi = new BlockInstance($b->id, $b);
                    $configdata = $bi->get('configdata');
                    if (isset($configdata['collection']) && $configdata['collection'] == $templateid) {
                        $bi->set('configdata', array('collection' => $collection->get('id')));
                        $bi->commit();
                    }
                }
            }
        }

299
300
301
302
303
304
305
306
307
        db_commit();

        return array(
            $collection,
            $colltemplate,
            $numcopied,
        );
    }

308
    /**
309
     * Returns a list of the current user, group, or institution collections
310
311
312
     *
     * @param offset current page to display
     * @param limit how many collections to display per page
313
314
     * @param groupid current group ID
     * @param institutionname current institution name
315
316
     * @return array (count: integer, data: array, offset: integer, limit: integer)
     */
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
    public static function get_mycollections_data($offset=0, $limit=10, $owner=null, $groupid=null, $institutionname=null) {
        if (!empty($groupid)) {
            $wherestm = '"group" = ?';
            $values = array($groupid);
            $count  = count_records('collection', 'group', $groupid);
        }
        else if (!empty($institutionname)) {
            $wherestm = 'institution = ?';
            $values = array($institutionname);
            $count  = count_records('collection', 'institution', $institutionname);
        }
        else if (!empty($owner)) {
            $wherestm = 'owner = ?';
            $values = array($owner);
            $count  = count_records('collection', 'owner', $owner);
        }
        else {
            $count = 0;
        }
        $data = array();
        if ($count > 0) {
            $data = get_records_sql_assoc("
                SELECT c.id, c.description, c.name
340
                FROM {collection} c
341
342
343
344
                WHERE " . $wherestm .
                " ORDER BY c.name, c.ctime, c.id ASC
                ", $values, $offset, $limit);
        }
345

346
347
        self::add_submission_info($data);

348
        $result = (object) array(
349
350
            'count'  => $count,
            'data'   => $data,
351
352
353
354
355
            'offset' => $offset,
            'limit'  => $limit,
        );
        return $result;
    }
356

357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
    private static function add_submission_info(&$data) {
        if (empty($data)) {
            return;
        }

        $records = get_records_sql_assoc('
            SELECT c.id, c.submittedgroup, c.submittedhost, ' . db_format_tsfield('submittedtime') . ',
                   sg.name AS groupname, sg.urlid, sh.name AS hostname
              FROM {collection} c
         LEFT JOIN {group} sg ON c.submittedgroup = sg.id
         LEFT JOIN {host} sh ON c.submittedhost = sh.wwwroot
             WHERE c.id IN (' . join(',', array_fill(0, count($data), '?')) . ')
               AND (c.submittedgroup IS NOT NULL OR c.submittedhost IS NOT NULL)',
            array_keys($data)
        );

        if (empty($records)) {
            return;
        }

        foreach ($records as $r) {
            if (!empty($r->submittedgroup)) {
                $groupdata = (object) array(
                    'id'    => $r->submittedgroup,
                    'name'  => $r->groupname,
                    'urlid' => $r->urlid,
                    'time'  => $r->submittedtime,
                );
                $groupdata->url = group_homepage_url($groupdata);
                $data[$r->id]->submitinfo = $groupdata;
            }
            else if (!empty($r->submittedhost)) {
                $data[$r->id]->submitinfo = (object) array(
                    'name' => $r->hostname,
                    'url'  => $r->submittedhost,
                    'time'  => $r->submittedtime,
                );
            }
        }
    }

398
399
400
401
    /**
    * Gets the fields for the new/edit collection form
    * - populates the fields with collection data if it is an edit
    *
402
    * @param array $collection
403
404
    * @return array $elements
    */
405
    public function get_collectionform_elements() {
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
        $elements = array(
            'name' => array(
                'type' => 'text',
                'defaultvalue' => null,
                'title' => get_string('name', 'collection'),
                'size' => 30,
                'rules' => array(
                    'required' => true,
                ),
            ),
            'description' => array(
                'type'  => 'textarea',
                'rows' => 10,
                'cols' => 50,
                'resizable' => false,
                'defaultvalue' => null,
                'title' => get_string('description', 'collection'),
            ),
424
425
426
427
428
429
            'navigation' => array(
                'type'  => 'checkbox',
                'title' => get_string('viewnavigation','collection'),
                'description' => get_string('viewnavigationdesc','collection'),
                'defaultvalue' => 1,
            ),
430
        );
431

432
        // populate the fields with the existing values if any
433
        if (!empty($this->id)) {
434
            foreach ($elements as $k => $element) {
435
                $elements[$k]['defaultvalue'] = $this->$k;
436
437
438
            }
            $elements['id'] = array(
                'type' => 'hidden',
439
                'value' => $this->id,
440
            );
441
442
443
444
445
446
447
448
449
450
451
452
453
454
        }
        if (!empty($this->group)) {
            $elements['group'] = array(
                'type' => 'hidden',
                'value' => $this->group,
            );
        }
        else if (!empty($this->institution)) {
            $elements['institution'] = array(
                'type' => 'hidden',
                'value' => $this->institution,
            );
        }
        else if (!empty($this->owner)) {
455
456
            $elements['owner'] = array(
                'type' => 'hidden',
457
                'value' => $this->owner,
458
            );
459
460
        }

461
462
        return $elements;
    }
463

464
    /**
465
     * Returns array of views in the current collection
466
467
468
     *
     * @return array views 
     */
469
470
471
    public function views() {

        if (!isset($this->views)) {
472

473
            $sql = "SELECT v.id, cv.*, v.title, v.owner, v.group, v.institution, v.ownerformat, v.urlid
474
475
                FROM {collection_view} cv JOIN {view} v ON cv.view = v.id
                WHERE cv.collection = ?
476
                ORDER BY cv.displayorder, v.title, v.ctime ASC";
477

478
            $result = get_records_sql_assoc($sql, array($this->get('id')));
479

480
            if (!empty($result)) {
481
482
483
484
485
486
487
488
489
                require_once('view.php');
                View::get_extra_view_info($result, false, false);
                $result = array_values($result);
                $max = $min = $result[0]['displayorder'];
                foreach ($result as &$r) {
                    $max = max($max, $r['displayorder']);
                    $min = min($min, $r['displayorder']);
                    $r = (object) $r;
                }
490
                $this->views = array(
491
                    'views'     => array_values($result),
492
                    'count'     => count($result),
493
494
                    'max'       => $max,
                    'min'       => $min,
495
496
497
498
499
                );
            }
            else {
                $this->views = array();
            }
500

501
502
        }

503
        return $this->views;
504
    }
505

506
507
508
    /**
     * Get the available views the current user can choose from
     * - currently dashboard, group and profile views are ignored to solve access issues
509
     * - each view can only belong to one collection
510
511
512
     *
     * @return array $views
     */
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
    public static function available_views($owner=null, $groupid=null, $institutionname=null) {
        if (!empty($groupid)) {
            $wherestm = '"group" = ?';
            $values = array($groupid);
        }
        else if (!empty($institutionname)) {
            $wherestm = 'institution = ?';
            $values = array($institutionname);
        }
        else if (!empty($owner)) {
            $wherestm = 'owner = ?';
            $values = array($owner);
        }
        else {
            return array();
        }
529
        ($views = get_records_sql_array("SELECT v.id, v.title
530
531
532
533
            FROM {view} v
            LEFT JOIN {collection_view} cv ON cv.view = v.id
            WHERE " . $wherestm .
            "   AND cv.view IS NULL
534
                AND v.type NOT IN ('dashboard','grouphomepage','profile')
535
536
537
538
            GROUP BY v.id, v.title
            ORDER BY v.title ASC
            ", $values))
            || ($views = array());
539
        return $views;
540
541
    }

542
    /**
543
     * Submits the selected views to the collection
544
545
546
547
548
     *
     * @param array values selected views
     * @return integer count so we know what SESSION message to display
     */
    public function add_views($values) {
549
        require_once(get_config('libroot') . 'view.php');
550

551
        $count = 0; // how many views we are adding
552
553
        db_begin();

554
        // each view was marked with a key of view_<id> in order to identify the correct items
555
        // from the form values
556
557
558
559
560
        foreach ($values as $key => $value) {
            if (substr($key,0,5) === 'view_' AND $value == true) {
                $cv = array();
                $cv['view'] = substr($key,5);
                $cv['collection'] = $this->get('id');
561
562
563
564
565

                // set displayorder value
                $max = get_field('collection_view', 'MAX(displayorder)', 'collection', $this->get('id'));
                $cv['displayorder'] = is_numeric($max) ? $max + 1 : 0;

566
567
568
569
                insert_record('collection_view', (object)$cv);
                $count++;
            }
        }
570

571
        $viewids = get_column('collection_view', 'view', 'collection', $this->id);
572
573

        // Set the most permissive access records on all views
574
        View::combine_access($viewids, true);
575

576
577
578
579
580
581
582
        // Copy the whole view config from the first view to all the others
        if (count($viewids)) {
            $firstview = new View($viewids[0]);
            $viewconfig = array(
                'startdate'       => $firstview->get('startdate'),
                'stopdate'        => $firstview->get('stopdate'),
                'template'        => $firstview->get('template'),
583
                'retainview'      => $firstview->get('retainview'),
584
585
586
587
588
589
590
                'allowcomments'   => $firstview->get('allowcomments'),
                'approvecomments' => (int) ($firstview->get('allowcomments') && $firstview->get('approvecomments')),
                'accesslist'      => $firstview->get_access(),
            );
            View::update_view_access($viewconfig, $viewids);
        }

591
592
        db_commit();

593
594
        return $count;
    }
595

596
    /**
597
     * Removes the selected views from the collection
598
599
600
601
602
603
     *
     * @param integer $view the view to remove
     */
    public function remove_view($view) {
        db_begin();
        delete_records('collection_view','view',$view,'collection',$this->get('id'));
604
605
606
607
608

        // Secret url records belong to the collection, so remove them from the view.
        // @todo: add user message to whatever calls this.
        delete_records_select('view_access', 'view = ? AND token IS NOT NULL', array($view));

609
610
611
        db_commit();
    }

612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
    /**
     * Sets the displayorder for a view
     *
     * @param integer view
     * @param string direction
     *
     */
    public function set_viewdisplayorder($id, $direction) {

        $ids = get_column_sql('
            SELECT view FROM {collection_view}
            WHERE collection = ?
            ORDER BY displayorder', array($this->get('id')));

        foreach ($ids as $k => $v) {
            if ($v == $id) {
                $oldorder = $k;
                break;
            }
        }

        if ($direction == 'up' && $oldorder > 0) {
            $neworder = array_merge(array_slice($ids, 0, $oldorder - 1),
                                    array($id, $ids[$oldorder-1]),
                                    array_slice($ids, $oldorder+1));
        }
        else if ($direction == 'down' && ($oldorder + 1 < count($ids))) {
            $neworder = array_merge(array_slice($ids, 0, $oldorder),
                                    array($ids[$oldorder+1], $id),
                                    array_slice($ids, $oldorder+2));
        }

        if (isset($neworder)) {
            foreach ($neworder as $k => $v) {
                set_field('collection_view', 'displayorder', $k, 'view', $v, 'collection',$this->get('id'));
            }
            $this->set('mtime', time());
            $this->commit();
        }
    }

653
654
655
    /**
     * after editing the collection, redirect back to the appropriate place
     */
656
657
658
659
    public function post_edit_redirect($new=false, $copy=false, $urlparams=null) {
        if ($new || $copy) {
            $urlparams['id'] = $this->get('id');
            $redirecturl = '/collection/views.php';
660
661
        }
        else {
662
            $redirecturl = '/collection/index.php';
663
        }
664
665
666
        if ($urlparams) {
            $redirecturl .= '?' . http_build_query($urlparams);
        }
667
668
669
        redirect($redirecturl);
    }

670
    public static function search_by_view_id($viewid) {
671
672
673
674
675
676
677
678
679
680
681
682
        $record = get_record_sql('
            SELECT c.*
            FROM {collection} c JOIN {collection_view} cv ON c.id = cv.collection
            WHERE cv.view = ?',
            array($viewid)
        );
        if ($record) {
            return new Collection(0, $record);
        }
        return false;
    }

683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
    /**
     * Returns an SQL snippet that can be used in a where clause to get views
     * with the given owner.
     *
     * @param object $ownerobj An object that has view ownership information -
     *                         either the institution, group or owner fields set
     * @return string
     */
    private static function owner_sql($ownerobj) {
        if (isset($ownerobj->institution)) {
            return 'institution = ' . db_quote($ownerobj->institution);
        }
        if (isset($ownerobj->group) && is_numeric($ownerobj->group)) {
            return '"group" = ' . (int)$ownerobj->group;
        }
        if (isset($ownerobj->owner) && is_numeric($ownerobj->owner)) {
            return 'owner = ' . (int)$ownerobj->owner;
        }
        throw new SystemException("View::owner_sql: Passed object did not have an institution, group or owner field");
    }
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743

    /**
     * Makes a URL for a collection
     *
     * @param bool $full return a full url
     * @param bool $useid ignore clean url settings and always return a url with an id in it
     *
     * @return string
     */
    public function get_url($full=true, $useid=false) {
        global $USER;

        $views = $this->views();
        if (!empty($views)) {
            $v = new View(0, $views['views'][0]);
            $v->set('dirty', false);
            return $v->get_url($full, $useid);
        }

        log_warn("Attempting to get url for an empty collection");

        if ($this->owner === $USER->get('id')) {
            $url = 'collection/views.php?id=' . $this->id;
        }
        else {
            $url = '';
        }

        if ($full) {
            $url = get_config('wwwroot') . $url;
        }

        return $url;
    }

    /**
     * Release a submitted collection
     *
     * @param object $releaseuser The user releasing the collection
     */
    public function release($releaseuser=null) {
744
745

        if (!$this->is_submitted()) {
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
            throw new ParameterException("Collection with id " . $this->id . " has not been submitted");
        }

        // One day there might be group and institution collections, so be safe
        if (empty($this->owner)) {
            throw new ParameterException("Collection with id " . $this->id . " has no owner");
        }

        $viewids = $this->get_viewids();

        db_begin();
        execute_sql('
            UPDATE {collection}
            SET submittedgroup = NULL, submittedhost = NULL, submittedtime = NULL
            WHERE id = ?',
            array($this->id)
        );
        View::_db_release($viewids, $this->owner, $this->submittedgroup);
        db_commit();

        $releaseuser = optional_userobj($releaseuser);
        $releaseuserdisplay = display_name($releaseuser, $this->owner);
768
        $submitinfo = $this->submitted_to();
769
770
771
772
773
774
775
776
777
778

        require_once('activity.php');
        activity_occurred(
            'maharamessage',
            array(
                'users' => array($this->get('owner')),
                'strings' => (object) array(
                    'subject' => (object) array(
                        'key'     => 'collectionreleasedsubject',
                        'section' => 'group',
779
                        'args'    => array($this->name, $submitinfo->name, $releaseuserdisplay),
780
781
782
783
                    ),
                    'message' => (object) array(
                        'key'     => 'collectionreleasedmessage',
                        'section' => 'group',
784
                        'args'    => array($this->name, $submitinfo->name, $releaseuserdisplay),
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
                    ),
                ),
                'url' => $this->get_url(false),
                'urltext' => $this->name,
            )
        );
    }

    public function get_viewids() {
        $ids = array();
        $viewdata = $this->views();

        if (!empty($viewdata['views'])) {
            foreach ($viewdata['views'] as $v) {
                $ids[] = $v->id;
            }
        }

        return $ids;
    }
805
806
807
808
809

    public function is_submitted() {
        return $this->submittedgroup || $this->submittedhost;
    }

810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
    public function submitted_to() {
        if ($this->submittedgroup) {
            $record = get_record('group', 'id', $this->submittedgroup, null, null, null, null, 'id, name, urlid');
            $record->url = group_homepage_url($record);
        }
        else if ($this->submittedhost) {
            $record = get_record('host', 'wwwroot', $this->submittedhost, null, null, null, null, 'wwwroot, name');
            $record->url = $record->wwwroot;
        }
        else {
            throw new SystemException("Collection with id " . $this->id . " has not been submitted");
        }

        return $record;
    }

826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
    public function submit($group) {
        global $USER;

        if ($this->is_submitted()) {
            throw new SystemException('Attempting to submit a submitted collection');
        }

        $viewids = $this->get_viewids();
        $idstr = join(',', array_map('intval', $viewids));

        // Check that none of the views is submitted to some other group.  This is bound to happen to someone,
        // because collection submission is being introduced at a time when it is still possible to submit
        // individual views in a collection.
        $submittedtitles = get_column_sql("
            SELECT title FROM {view}
            WHERE id IN ($idstr) AND (submittedhost IS NOT NULL OR (submittedgroup IS NOT NULL AND submittedgroup != ?))",
            array($group->id)
        );

        if (!empty($submittedtitles)) {
            die_info(get_string('viewsalreadysubmitted', 'view', implode('<br>', $submittedtitles)));
        }

        $group->roles = get_column('grouptype_roles', 'role', 'grouptype', $group->grouptype, 'see_submitted_views', 1);

        db_begin();
        View::_db_submit($viewids, $group);
        $this->set('submittedgroup', $group->id);
        $this->set('submittedhost', null);
        $this->set('submittedtime', time());
        $this->commit();
        db_commit();

        activity_occurred(
            'groupmessage',
            array(
                'group'         => $group->id,
                'roles'         => $group->roles,
                'url'           => $this->get_url(false),
                'strings'       => (object) array(
                    'urltext' => (object) array(
                        'key'     => 'Collection',
                        'section' => 'collection',
                    ),
                    'subject' => (object) array(
                        'key'     => 'viewsubmittedsubject1',
                        'section' => 'activity',
                        'args'    => array($group->name),
                    ),
                    'message' => (object) array(
                        'key'     => 'viewsubmittedmessage1',
                        'section' => 'activity',
                        'args'    => array(
                            display_name($USER, null, false, true),
                            $this->name,
                            $group->name,
                        ),
                    ),
                ),
            )
        );
    }
888
}