lib.php 36.3 KB
Newer Older
1
2
3
4
5
<?php
/**
 *
 * @package    mahara
 * @subpackage artefact-blog
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
13
14
15
16
17
18
19
20
21
22
23
24
 *
 */

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

/** 
 * Users can create blogs and blog posts using this plugin.
 */
class PluginArtefactBlog extends PluginArtefact {

    public static function get_artefact_types() {
        return array(
            'blog',
            'blogpost',
        );
    }
25
26
27
28
    
    public static function get_block_types() {
        return array();
    }
29
30
31
32
33

    public static function get_plugin_name() {
        return 'blog';
    }

34
35
36
37
    public static function is_active() {
        return get_field('artefact_installed', 'active', 'name', 'blog');
    }

38
    public static function menu_items() {
39
        global $USER;
40
        $tab = array(
41
42
            'path'   => 'content/blogs',
            'weight' => 40,
43
        );
44
        if ($USER->get_account_preference('multipleblogs')) {
45
            $tab['url']   = 'artefact/blog/index.php';
46
            $tab['title'] = get_string('blogs', 'artefact.blog');
47
48
        }
        else {
49
            $tab['url']   = 'artefact/blog/view/index.php';
50
            $tab['title'] = get_string('blog', 'artefact.blog');
51
        }
52
        return array('content/blogs' => $tab);
53
    }
54

55
    public static function get_cron() {
56
        return array();
57
58
    }

59

60
61
62
63
64
65
66
67
68
69
    public static function get_event_subscriptions() {
        return array(
            (object)array(
                'plugin'       => 'blog',
                'event'        => 'createuser',
                'callfunction' => 'create_default_blog',
            ),
        );
    }

70
71
72
73
74
75
76
    public static function block_advanced_options_element($configdata, $artefacttype) {
        $strartefacttype = get_string($artefacttype, 'artefact.blog');
        return array(
            'type' => 'fieldset',
            'name' => 'advanced',
            'collapsible' => true,
            'collapsed' => false,
77
            'legend' => get_string('moreoptions', 'artefact.blog'),
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
            'elements' => array(
                'copytype' => array(
                    'type' => 'select',
                    'title' => get_string('blockcopypermission', 'view'),
                    'description' => get_string('blockcopypermissiondesc', 'view'),
                    'defaultvalue' => isset($configdata['copytype']) ? $configdata['copytype'] : 'nocopy',
                    'options' => array(
                        'nocopy' => get_string('copynocopy', 'artefact.blog'),
                        'reference' => get_string('copyreference', 'artefact.blog', $strartefacttype),
                        'full' => get_string('copyfull', 'artefact.blog', $strartefacttype),
                    ),
                ),
            ),
        );
    }

94
95
96
97
98
99
100
101
    public static function create_default_blog($event, $user) {
        $name = display_name($user, null, true);
        $blog = new ArtefactTypeBlog(0, (object) array(
            'title'       => get_string('defaultblogtitle', 'artefact.blog', $name),
            'owner'       => $user['id'],
        ));
        $blog->commit();
    }
102
103
104
105
106
107

    public static function get_artefact_type_content_types() {
        return array(
            'blogpost' => array('text'),
        );
    }
108

109
    public static function progressbar_link($artefacttype) {
110
111
        return 'artefact/blog/view/index.php';
    }
112
113
114
115
116
117
118
}

/**
 * A Blog artefact is a collection of BlogPost artefacts.
 */
class ArtefactTypeBlog extends ArtefactType {

Alastair Pharo's avatar
Alastair Pharo committed
119
120
121
122
    /**
     * This constant gives the per-page pagination for listing blogs.
     */
    const pagination = 10;
123
124


125
126
127
128
129
130
131
132
    /**
     * We override the constructor to fetch the extra data.
     *
     * @param integer
     * @param object
     */
    public function __construct($id = 0, $data = null) {
        parent::__construct($id, $data);
133
134
135
136
137
138

        if (empty($this->id)) {
            $this->container = 1;
        }
    }

Alastair Pharo's avatar
Alastair Pharo committed
139
    /**
140
141
142
     * This function updates or inserts the artefact.  This involves putting
     * some data in the artefact table (handled by parent::commit()), and then
     * some data in the artefact_blog_blog table.
Alastair Pharo's avatar
Alastair Pharo committed
143
     */
144
    public function commit() {
145
146
147
148
149
150
151
152
153
154
155
156
        // Just forget the whole thing when we're clean.
        if (empty($this->dirty)) {
            return;
        }
      
        // We need to keep track of newness before and after.
        $new = empty($this->id);
        
        // Commit to the artefact table.
        parent::commit();

        $this->dirty = false;
157
158
    }

Alastair Pharo's avatar
Alastair Pharo committed
159
    /**
160
161
     * This function extends ArtefactType::delete() by deleting blog-specific
     * data.
Alastair Pharo's avatar
Alastair Pharo committed
162
     */
163
    public function delete() {
164
165
166
167
168
169
        if (empty($this->id)) {
            return;
        }

        // Delete the artefact and all children.
        parent::delete();
170
171
    }

172
173
174
175
176
177
178
179
180
181
182
183
184
    /**
     * Checks that the person viewing this blog is the owner. If not, throws an 
     * AccessDeniedException. Used in the blog section to ensure only the 
     * owners of the blogs can view or change them there. Other people see 
     * blogs when they are placed in views.
     */
    public function check_permission() {
        global $USER;
        if ($USER->get('id') != $this->owner) {
            throw new AccessDeniedException(get_string('youarenottheownerofthisblog', 'artefact.blog'));
        }
    }

185

186
187
    public function describe_size() {
        return $this->count_children() . ' ' . get_string('posts', 'artefact.blog');
188
189
    }

190
    /**
191
     * Renders a blog.
192
193
194
195
196
     *
     * @param  array  Options for rendering
     * @return array  A two key array, 'html' and 'javascript'.
     */
    public function render_self($options) {
197
198
199
200
201
202
203
204
205
206
207
        if (!isset($options['limit'])) {
            $limit = self::pagination;
        }
        else if ($options['limit'] === false) {
            $limit = null;
        }
        else {
            $limit = (int) $options['limit'];
        }
        $offset = isset($options['offset']) ? intval($options['offset']) : 0;

208
209
210
211
212
        if (!isset($options['countcomments'])) {
            // Count comments if this is a view
            $options['countcomments'] = (!empty($options['viewid']));
        }

213
214
215
216
        $posts = ArtefactTypeBlogpost::get_posts($this->id, $limit, $offset, $options);

        $template = 'artefact:blog:viewposts.tpl';

217
        $baseurl = get_config('wwwroot') . 'artefact/artefact.php?artefact=' . $this->id;
218
219
220
        if (!empty($options['viewid'])) {
            $baseurl .= '&view=' . $options['viewid'];
        }
221
222
223
224
225
226
227
228
229
        $pagination = array(
            'baseurl' => $baseurl,
            'id' => 'blogpost_pagination',
            'datatable' => 'postlist',
            'jsonscript' => 'artefact/blog/posts.json.php',
        );

        ArtefactTypeBlogpost::render_posts($posts, $template, $options, $pagination);

230
231
        $smarty = smarty_core();
        if (isset($options['viewid'])) {
232
            $smarty->assign('artefacttitle', '<a href="' . get_config('wwwroot') . 'artefact/artefact.php?artefact='
233
                                             . $this->get('id') . '&view=' . $options['viewid']
Richard Mansfield's avatar
Richard Mansfield committed
234
                                             . '">' . hsc($this->get('title')) . '</a>');
235
236
        }
        else {
Richard Mansfield's avatar
Richard Mansfield committed
237
            $smarty->assign('artefacttitle', hsc($this->get('title')));
238
239
        }

240
241
242
243
244
245
246
        if (!empty($options['details']) and get_config('licensemetadata')) {
            $smarty->assign('license', render_license($this));
        }
        else {
            $smarty->assign('license', false);
        }

247
        $options['hidetitle'] = true;
248
        $smarty->assign('options', $options);
249
        $smarty->assign('description', $this->get('description'));
250
251
        $smarty->assign('owner', $this->get('owner'));
        $smarty->assign('tags', $this->get('tags'));
252

253
        $smarty->assign_by_ref('posts', $posts);
254

255
        return array('html' => $smarty->fetch('artefact:blog:blog.tpl'), 'javascript' => '');
256
257
    }

258
                
259
    public static function get_icon($options=null) {
260
        global $THEME;
261
        return $THEME->get_url('images/journal.png', false);
262
263
    }

Nigel McNie's avatar
Nigel McNie committed
264
    public static function is_singular() {
Penny Leach's avatar
Penny Leach committed
265
266
267
        return false;
    }

Alastair Pharo's avatar
Alastair Pharo committed
268
    public static function collapse_config() {
269
270
    }

Alastair Pharo's avatar
Alastair Pharo committed
271
272
273
274
275
276
    /**
     * This function returns a list of the given user's blogs.
     *
     * @param User
     * @return array (count: integer, data: array)
     */
277
278
    public static function get_blog_list($limit, $offset) {
        global $USER;
Alastair Pharo's avatar
Alastair Pharo committed
279
        ($result = get_records_sql_array("
280
         SELECT b.id, b.title, b.description, b.locked, COUNT(p.id) AS postcount
281
282
         FROM {artefact} b LEFT JOIN {artefact} p ON (p.parent = b.id AND p.artefacttype = 'blogpost')
         WHERE b.owner = ? AND b.artefacttype = 'blog'
283
         GROUP BY b.id, b.title, b.description, b.locked
284
         ORDER BY b.title", array($USER->get('id')), $offset, $limit))
Alastair Pharo's avatar
Alastair Pharo committed
285
286
            || ($result = array());

287
288
        foreach ($result as &$r) {
            if (!$r->locked) {
289
                $r->deleteform = ArtefactTypeBlog::delete_form($r->id, $r->title);
290
291
292
            }
        }

293
        $count = (int)get_field('artefact', 'COUNT(*)', 'owner', $USER->get('id'), 'artefacttype', 'blog');
Alastair Pharo's avatar
Alastair Pharo committed
294
295
296
297

        return array($count, $result);
    }

298
299
300
    public static function build_blog_list_html(&$blogs) {
        $smarty = smarty_core();
        $smarty->assign_by_ref('blogs', $blogs);
301
302
        $blogs->tablerows = $smarty->fetch('artefact:blog:bloglist.tpl');
        $pagination = build_pagination(array(
303
304
305
            'id' => 'bloglist_pagination',
            'class' => 'center',
            'url' => get_config('wwwroot') . 'artefact/blog/index.php',
306
307
            'jsonscript' => 'artefact/blog/index.json.php',
            'datatable' => 'bloglist',
308
309
310
311
312
313
314
315
316
317
318
            'count' => $blogs->count,
            'limit' => $blogs->limit,
            'offset' => $blogs->offset,
            'firsttext' => '',
            'previoustext' => '',
            'nexttext' => '',
            'lasttext' => '',
            'numbersincludefirstlast' => false,
            'resultcounttextsingular' => get_string('blog', 'artefact.blog'),
            'resultcounttextplural' => get_string('blogs', 'artefact.blog'),
        ));
319
320
        $blogs->pagination = $pagination['html'];
        $blogs->pagination_js = $pagination['javascript'];
321
322
    }

Alastair Pharo's avatar
Alastair Pharo committed
323
324
325
326
327
328
    /**
     * This function creates a new blog.
     *
     * @param User
     * @param array
     */
Alastair Pharo's avatar
Alastair Pharo committed
329
    public static function new_blog(User $user, array $values) {
Alastair Pharo's avatar
Alastair Pharo committed
330
331
332
333
        $artefact = new ArtefactTypeBlog();
        $artefact->set('title', $values['title']);
        $artefact->set('description', $values['description']);
        $artefact->set('owner', $user->get('id'));
334
        $artefact->set('tags', $values['tags']);
335
336
337
338
339
        if (get_config('licensemetadata')) {
            $artefact->set('license', $values['license']);
            $artefact->set('licensor', $values['licensor']);
            $artefact->set('licensorurl', $values['licensorurl']);
        }
Alastair Pharo's avatar
Alastair Pharo committed
340
        $artefact->commit();
341
    }
Alastair Pharo's avatar
Alastair Pharo committed
342
343
344
345
346
347
348
349
350
351
352
353
354

    /**
     * This function updates an existing blog.
     *
     * @param User
     * @param array
     */
    public static function edit_blog(User $user, array $values) {
        if (empty($values['id']) || !is_numeric($values['id'])) {
            return;
        }

        $artefact = new ArtefactTypeBlog($values['id']);
355
356
357
        if ($user->get('id') != $artefact->get('owner')) {
            return;
        }
358

Alastair Pharo's avatar
Alastair Pharo committed
359
360
        $artefact->set('title', $values['title']);
        $artefact->set('description', $values['description']);
361
        $artefact->set('tags', $values['tags']);
362
363
364
365
366
        if (get_config('licensemetadata')) {
            $artefact->set('license', $values['license']);
            $artefact->set('licensor', $values['licensor']);
            $artefact->set('licensorurl', $values['licensorurl']);
        }
Alastair Pharo's avatar
Alastair Pharo committed
367
368
        $artefact->commit();
    }
369

Martyn Smith's avatar
Martyn Smith committed
370
371
    public static function get_links($id) {
        $wwwroot = get_config('wwwroot');
372

Martyn Smith's avatar
Martyn Smith committed
373
        return array(
374
375
            '_default'                                  => $wwwroot . 'artefact/blog/view/index.php?id=' . $id,
            get_string('blogsettings', 'artefact.blog') => $wwwroot . 'artefact/blog/settings/index.php?id=' . $id,
Martyn Smith's avatar
Martyn Smith committed
376
377
        );
    }
378
379
380
381
382

    public function copy_extra($new) {
        $new->set('title', get_string('Copyof', 'mahara', $this->get('title')));
    }

383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
    /**
     * Returns the number of posts in this blog that have been published.
     *
     * The result of this function looked up from the database each time, so 
     * cache it if you know it's safe to do so.
     *
     * @return int
     */
    public function count_published_posts() {
        return (int)get_field_sql("
            SELECT COUNT(*)
            FROM {artefact} a
            LEFT JOIN {artefact_blog_blogpost} bp ON a.id = bp.blogpost
            WHERE a.parent = ?
            AND bp.published = 1", array($this->get('id')));
    }

400
    public static function delete_form($id, $title = '') {
401
        global $THEME;
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

        $confirm = get_string('deleteblog?', 'artefact.blog');

        // Check if this blog has posts.
        $postcnt = count_records_sql("
            SELECT COUNT(*)
            FROM {artefact} a
            INNER JOIN {artefact_blog_blogpost} bp ON a.id = bp.blogpost
            WHERE a.parent = ?
            ", array($id));
        if ($postcnt > 0) {
            $confirm = get_string('deletebloghaspost?', 'artefact.blog', $postcnt);

            // Check if this blog posts used in views.
            $viewscnt = count_records_sql("
                SELECT COUNT(DISTINCT(va.view))
                FROM {artefact} a
                INNER JOIN {view_artefact} va ON a.id = va.artefact
                WHERE a.parent = ? OR a.id = ?
                ", array($id, $id));
            if ($viewscnt > 0) {
                $confirm = get_string('deletebloghasview?', 'artefact.blog', $viewscnt);
            }
        }

427
428
429
430
431
432
433
434
435
436
437
        return pieform(array(
            'name' => 'delete_' . $id,
            'successcallback' => 'delete_blog_submit',
            'renderer' => 'oneline',
            'elements' => array(
                'delete' => array(
                    'type' => 'hidden',
                    'value' => $id,
                ),
                'submit' => array(
                    'type' => 'image',
438
                    'src' => $THEME->get_url('images/btn_deleteremove.png'),
439
440
                    'alt' => get_string('deletespecific', 'mahara', $title),
                    'elementtitle' => get_string('delete'),
441
                    'confirm' => $confirm,
442
                    'value' => get_string('delete'),
443
444
445
446
                ),
            ),
        ));
    }
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463

    /**
     * During the copying of a view, we might be allowed to copy
     * blogs. Users need to have multipleblogs enabled for these
     * to be visible.
     */
    public function default_parent_for_copy(&$view, &$template, $artefactstoignore) {
        global $USER, $SESSION;

        $viewid = $view->get('id');

        try {
            $user = get_user($view->get('owner'));
            set_account_preference($user->id, 'multipleblogs', 1);
            $SESSION->add_ok_msg(get_string('copiedblogpoststonewjournal', 'collection'));
        }
        catch (Exception $e) {
464
            $SESSION->add_error_msg(get_string('unabletosetmultipleblogs', 'error', $user->username, $viewid, get_config('wwwroot') . 'account/index.php'), false);
465
466
467
468
469
470
471
472
473
474
475
        }

        try {
            $USER->accountprefs = load_account_preferences($user->id);
        }
        catch (Exception $e) {
            $SESSION->add_error_msg(get_string('pleaseloginforjournals', 'error'));
        }

        return null;
    }
476
477
478
479
480
481
482
}

/**
 * BlogPost artefacts occur within Blog artefacts
 */
class ArtefactTypeBlogPost extends ArtefactType {

483
    /**
Alastair Pharo's avatar
Alastair Pharo committed
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
     * This defines whether the blogpost is published or not.
     *
     * @var boolean
     */
    protected $published = false;

    /**
     * We override the constructor to fetch the extra data.
     *
     * @param integer
     * @param object
     */
    public function __construct($id = 0, $data = null) {
        parent::__construct($id, $data);

499
500
501
502
503
        if ($this->id) {
            if ($bpdata = get_record('artefact_blog_blogpost', 'blogpost', $this->id)) {
                foreach($bpdata as $name => $value) {
                    if (property_exists($this, $name)) {
                        $this->$name = $value;
504
                    }
Alastair Pharo's avatar
Alastair Pharo committed
505
                }
506
507
508
509
            }
            else {
                // This should never happen unless the user is playing around with blog post IDs in the location bar or similar
                throw new ArtefactNotFoundException(get_string('blogpostdoesnotexist', 'artefact.blog'));
510
511
            }
        }
512
513
514
        else {
            $this->allowcomments = 1; // Turn comments on for new posts
        }
Alastair Pharo's avatar
Alastair Pharo committed
515
516
517
    }

    /**
518
     * This method extends ArtefactType::commit() by adding additional data
Alastair Pharo's avatar
Alastair Pharo committed
519
     * into the artefact_blog_blogpost table.
520
521
522
523
524
     *
     * This method also works out what blockinstances this blogpost is in, and 
     * informs them that they should re-check what artefacts they have in them.
     * The post content may now link to different artefacts. See {@link 
     * PluginBlocktypeBlogPost::get_artefacts for more information}
525
     */
526
    public function commit() {
Alastair Pharo's avatar
Alastair Pharo committed
527
528
529
530
        if (empty($this->dirty)) {
            return;
        }

531
        db_begin();
Alastair Pharo's avatar
Alastair Pharo committed
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
        $new = empty($this->id);
      
        parent::commit();

        $this->dirty = true;

        $data = (object)array(
            'blogpost'  => $this->get('id'),
            'published' => ($this->get('published') ? 1 : 0)
        );

        if ($new) {
            insert_record('artefact_blog_blogpost', $data);
        }
        else {
            update_record('artefact_blog_blogpost', $data, 'blogpost');
        }

550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
        // We want to get all blockinstances that contain this blog post. That is currently:
        // 1) All blogpost blocktypes with this post in it
        // 2) All blog blocktypes with this posts's blog in it
        //
        // With these, we tell them to rebuild what artefacts they have in them, 
        // since the post content could have changed and now have links to 
        // different artefacts in it
        $blockinstanceids = (array)get_column_sql('SELECT block
            FROM {view_artefact}
            WHERE artefact = ?
            OR artefact = ?', array($this->get('id'), $this->get('parent')));
        if ($blockinstanceids) {
            require_once(get_config('docroot') . 'blocktype/lib.php');
            foreach ($blockinstanceids as $id) {
                $instance = new BlockInstance($id);
                $instance->rebuild_artefact_list();
            }
        }

        db_commit();
Alastair Pharo's avatar
Alastair Pharo committed
570
        $this->dirty = false;
571
572
    }

573
    /**
Alastair Pharo's avatar
Alastair Pharo committed
574
575
     * This function extends ArtefactType::delete() by also deleting anything
     * that's in blogpost.
576
     */
577
    public function delete() {
Alastair Pharo's avatar
Alastair Pharo committed
578
579
580
        if (empty($this->id)) {
            return;
        }
581

582
        db_begin();
583
        $this->detach(); // Detach all file attachments
Alastair Pharo's avatar
Alastair Pharo committed
584
585
586
        delete_records('artefact_blog_blogpost', 'blogpost', $this->id);
      
        parent::delete();
587
        db_commit();
Alastair Pharo's avatar
Alastair Pharo committed
588
    }
589

590
591
592
593
594
595
596
597
598
599
600
601
602
603
    public static function bulk_delete($artefactids) {
        if (empty($artefactids)) {
            return;
        }

        $idstr = join(',', array_map('intval', $artefactids));

        db_begin();
        delete_records_select('artefact_blog_blogpost', 'blogpost IN (' . $idstr . ')');
        parent::bulk_delete($artefactids);
        db_commit();
    }


604
605
606
607
608
609
610
611
612
613
614
615
    /**
     * Checks that the person viewing this blog is the owner. If not, throws an 
     * AccessDeniedException. Used in the blog section to ensure only the 
     * owners of the blogs can view or change them there. Other people see 
     * blogs when they are placed in views.
     */
    public function check_permission() {
        global $USER;
        if ($USER->get('id') != $this->owner) {
            throw new AccessDeniedException(get_string('youarenottheownerofthisblogpost', 'artefact.blog'));
        }
    }
616
  
617
618
    public function describe_size() {
        return $this->count_attachments() . ' ' . get_string('attachments', 'artefact.blog');
619
620
    }

621
622
    public function render_self($options) {
        $smarty = smarty_core();
623
        $artefacturl = get_config('wwwroot') . 'artefact/artefact.php?artefact=' . $this->get('id');
624
625
626
627
        if (isset($options['viewid'])) {
            $artefacturl .= '&view=' . $options['viewid'];
        }
        $smarty->assign('artefacturl', $artefacturl);
628
629
        if (empty($options['hidetitle'])) {
            if (isset($options['viewid'])) {
630
                $smarty->assign('artefacttitle', '<a href="' . $artefacturl . '">' . hsc($this->get('title')) . '</a>');
631
632
            }
            else {
Richard Mansfield's avatar
Richard Mansfield committed
633
                $smarty->assign('artefacttitle', hsc($this->get('title')));
634
635
636
637
            }
        }

        // We need to make sure that the images in the post have the right viewid associated with them
638
        $postcontent = $this->get('description');
639
        if (isset($options['viewid'])) {
640
641
            safe_require('artefact', 'file');
            $postcontent = ArtefactTypeFolder::append_view_url($postcontent, $options['viewid']);
642
643
644
645
646
647
648
            if (isset($options['countcomments']) && $this->allowcomments) {
                safe_require('artefact', 'comment');
                $empty = array();
                $ids = array($this->id);
                $commentcount = ArtefactTypeComment::count_comments($empty, $ids);
                $smarty->assign('commentcount', $commentcount ? $commentcount[$this->id]->comments : 0);
            }
649
650
651
        }
        $smarty->assign('artefactdescription', $postcontent);
        $smarty->assign('artefact', $this);
652
653
654
655
656
657
658
        if (!empty($options['details']) and get_config('licensemetadata')) {
            $smarty->assign('license', render_license($this));
        }
        else {
            $smarty->assign('license', false);
        }

659
        $attachments = $this->get_attachments();
660
        if ($attachments) {
661
            require_once(get_config('docroot') . 'artefact/lib.php');
662
663
664
            foreach ($attachments as &$attachment) {
                $f = artefact_instance_from_id($attachment->id);
                $attachment->size = $f->describe_size();
665
                $attachment->iconpath = $f->get_icon(array('id' => $attachment->id, 'viewid' => isset($options['viewid']) ? $options['viewid'] : 0));
666
                $attachment->viewpath = get_config('wwwroot') . 'artefact/artefact.php?artefact=' . $attachment->id . '&view=' . (isset($options['viewid']) ? $options['viewid'] : 0);
667
668
                $attachment->downloadpath = get_config('wwwroot') . 'artefact/file/download.php?file=' . $attachment->id;
                if (isset($options['viewid'])) {
669
                    $attachment->downloadpath .= '&view=' . $options['viewid'];
670
671
672
673
674
675
676
677
678
679
680
681
                }
            }
            $smarty->assign('attachments', $attachments);
        }
        $smarty->assign('postedbyon', get_string('postedbyon', 'artefact.blog',
                                                 display_name($this->owner),
                                                 format_date($this->ctime)));
        return array('html' => $smarty->fetch('artefact:blog:render/blogpost_renderfull.tpl'),
                     'javascript' => '');
    }


682
683
    public function can_have_attachments() {
        return true;
Richard Mansfield's avatar
Richard Mansfield committed
684
685
686
    }


687
    public static function get_icon($options=null) {
688
        global $THEME;
689
        return $THEME->get_url('images/journal_entry.png', false);
690
691
    }

Nigel McNie's avatar
Nigel McNie committed
692
    public static function is_singular() {
Penny Leach's avatar
Penny Leach committed
693
694
695
        return false;
    }

Alastair Pharo's avatar
Alastair Pharo committed
696
    public static function collapse_config() {
697
698
    }

Alastair Pharo's avatar
Alastair Pharo committed
699
    /**
700
     * This function returns a list of posts in a given blog.
Alastair Pharo's avatar
Alastair Pharo committed
701
702
703
     *
     * @param integer
     * @param integer
704
     * @param integer
705
     * @param array
Alastair Pharo's avatar
Alastair Pharo committed
706
     */
707
    public static function get_posts($id, $limit, $offset, $viewoptions=null) {
Alastair Pharo's avatar
Alastair Pharo committed
708

709
710
711
712
        $results = array(
            'limit'  => $limit,
            'offset' => $offset,
        );
713

714
715
716
717
718
719
720
721
722
723
724
        // If viewoptions is null, we're getting posts for the my blogs area,
        // and we should get all posts & show drafts first.  Otherwise it's a
        // blog in a view, and we should only get published posts.

        $from = "
            FROM {artefact} a LEFT JOIN {artefact_blog_blogpost} bp ON a.id = bp.blogpost
            WHERE a.artefacttype = 'blogpost' AND a.parent = ?";

        if (!is_null($viewoptions)) {
            if (isset($viewoptions['before'])) {
                $from .= " AND a.ctime < '{$viewoptions['before']}'";
725
            }
726
727
            $from .= ' AND bp.published = 1';
        }
728

729
730
731
732
733
        $results['count'] = count_records_sql('SELECT COUNT(*) ' . $from, array($id));

        $data = get_records_sql_assoc('
            SELECT
                a.id, a.title, a.description, a.author, a.authorname, ' .
734
735
                db_format_tsfield('a.ctime', 'ctime') . ', ' . db_format_tsfield('a.mtime', 'mtime') . ',
                a.locked, bp.published, a.allowcomments ' . $from . '
736
            ORDER BY bp.published ASC, a.ctime DESC, a.id DESC',
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
            array($id),
            $offset, $limit
        );

        if (!$data) {
            $results['data'] = array();
            return $results;
        }

        // Get the attached files.
        $postids = array_map(create_function('$a', 'return $a->id;'), $data);
        $files = ArtefactType::attachments_from_id_list($postids);
        if ($files) {
            safe_require('artefact', 'file');
            foreach ($files as &$file) {
752
753
754
755
756
                $params = array('id' => $file->attachment);
                if (!empty($viewoptions['viewid'])) {
                    $params['viewid'] = $viewoptions['viewid'];
                }
                $file->icon = call_static_method(generate_artefact_class_name($file->artefacttype), 'get_icon', $params);
757
758
759
760
761
762
763
764
765
766
                $data[$file->artefact]->files[] = $file;
            }
        }

        if ($tags = ArtefactType::tags_from_id_list($postids)) {
            foreach($tags as &$at) {
                $data[$at->artefact]->tags[] = $at->tag;
            }
        }

767
768
769
770
771
772
773
        // Get comment counts
        if (!empty($viewoptions['countcomments'])) {
            safe_require('artefact', 'comment');
            $viewids = array();
            $commentcounts = ArtefactTypeComment::count_comments($viewids, array_keys($data));
        }

774
        foreach ($data as &$post) {
775
            // Format dates properly
776
            if (is_null($viewoptions)) {
777
778
                // My Blogs area: create forms for changing post status & deleting posts.
                $post->changepoststatus = ArtefactTypeBlogpost::changepoststatus_form($post->id, $post->published);
779
                $post->delete = ArtefactTypeBlogpost::delete_form($post->id, $post->title);
780
            }
781
782
783
            else {
                $by = $post->author ? display_default_name($post->author) : $post->authorname;
                $post->postedby = get_string('postedbyon', 'artefact.blog', $by, format_date($post->ctime));
784
785
786
                if (isset($commentcounts)) {
                    $post->commentcount = isset($commentcounts[$post->id]) ? $commentcounts[$post->id]->comments : 0;
                }
787
788
789
            }
            $post->ctime = format_date($post->ctime, 'strftimedaydatetime');
            $post->mtime = format_date($post->mtime);
790
791
792
793
794
795

            // Ensure images in the post have the right viewid associated with them
            if (!empty($viewoptions['viewid'])) {
                safe_require('artefact', 'file');
                $post->description = ArtefactTypeFolder::append_view_url($post->description, $viewoptions['viewid']);
            }
796
        }
Alastair Pharo's avatar
Alastair Pharo committed
797

798
799
800
        $results['data'] = array_values($data);

        return $results;
801
802
    }

803
804
805
806
807
808
809
810
811
    /**
     * This function renders a list of posts as html
     *
     * @param array posts
     * @param string template
     * @param array options
     * @param array pagination
     */
    public function render_posts(&$posts, $template, $options, $pagination) {
812
        $smarty = smarty_core();
813
        $smarty->assign('options', $options);
814
815
        $smarty->assign('posts', $posts['data']);

816
817
        $posts['tablerows'] = $smarty->fetch($template);

818
        if ($posts['limit'] && $pagination) {
819
            $pagination = build_pagination(array(
820
821
822
823
824
825
826
827
828
829
830
831
832
833
                'id' => $pagination['id'],
                'class' => 'center',
                'datatable' => $pagination['datatable'],
                'url' => $pagination['baseurl'],
                'jsonscript' => $pagination['jsonscript'],
                'count' => $posts['count'],
                'limit' => $posts['limit'],
                'offset' => $posts['offset'],
                'numbersincludefirstlast' => false,
                'resultcounttextsingular' => get_string('post', 'artefact.blog'),
                'resultcounttextplural' => get_string('posts', 'artefact.blog'),
            ));
            $posts['pagination'] = $pagination['html'];
            $posts['pagination_js'] = $pagination['javascript'];
834
        }
Alastair Pharo's avatar
Alastair Pharo committed
835
836
    }

837
    /** 
Alastair Pharo's avatar
Alastair Pharo committed
838
839
840
841
842
843
844
845
846
847
    /**
     * This function creates a new blog post.
     *
     * @param User
     * @param array
     */
    public static function new_post(User $user, array $values) {
        $artefact = new ArtefactTypeBlogPost();
        $artefact->set('title', $values['title']);
        $artefact->set('description', $values['description']);
Alastair Pharo's avatar
Alastair Pharo committed
848
        $artefact->set('published', $values['published']);
Alastair Pharo's avatar
Alastair Pharo committed
849
        $artefact->set('owner', $user->get('id'));
850
        $artefact->set('parent', $values['parent']);
Alastair Pharo's avatar
Alastair Pharo committed
851
        $artefact->commit();
852
        return true;
853
    }
Alastair Pharo's avatar
Alastair Pharo committed
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869

    /** 
     * This function updates an existing blog post.
     *
     * @param User
     * @param array
     */
    public static function edit_post(User $user, array $values) {
        $artefact = new ArtefactTypeBlogPost($values['id']);
        if ($user->get('id') != $artefact->get('owner')) {
            return false;
        }

        $artefact->set('title', $values['title']);
        $artefact->set('description', $values['description']);
        $artefact->set('published', $values['published']);
870
        $artefact->set('tags', $values['tags']);
871
872
873
874
875
        if (get_config('licensemetadata')) {
            $artefact->set('license', $values['license']);
            $artefact->set('licensor', $values['licensor']);
            $artefact->set('licensorurl', $values['licensorurl']);
        }
Alastair Pharo's avatar
Alastair Pharo committed
876
877
878
879
        $artefact->commit();
        return true;
    }

880
881
882
883
884
885
886
887
888
889
890
891
    public static function changepoststatus_form($id, $published = null) {
        //Get current post status from database
        if ($published === null) {
            $post = new ArtefactTypeBlogPost($id);
            $published = $post->published;
        }
        if ($published) {
            $strchangepoststatus = get_string('unpublish', 'artefact.blog');
        }
        else {
            $strchangepoststatus = get_string('publish', 'artefact.blog');
        }
892
        return pieform(array(
893
894
895
            'name' => 'changepoststatus_' . $id,
            'jssuccesscallback' => 'changepoststatus_success',
            'successcallback' => 'changepoststatus_submit',
896
897
898
            'jsform' => true,
            'renderer' => 'oneline',
            'elements' => array(
899
                'changepoststatus' => array(
900
901
902
                    'type' => 'hidden',
                    'value' => $id,
                ),
903
904
905
906
                'currentpoststatus' => array(
                    'type' => 'hidden',
                    'value' => $published,
                ),'submit' => array(
907
                    'type' => 'submit',
908
                    'class' => 'publish',
909
910
                    'value' => $strchangepoststatus,
                    'help' => true,
911
912
913
914
915
                ),
            ),
        ));
    }

916
    public static function delete_form($id, $title = '') {
917
        global $THEME;
918
919
920
921
922
923
924
925
926
927
928
929
930
        return pieform(array(
            'name' => 'delete_' . $id,
            'successcallback' => 'delete_submit',
            'jsform' => true,
            'jssuccesscallback' => 'delete_success',
            'renderer' => 'oneline',
            'elements' => array(
                'delete' => array(
                    'type' => 'hidden',
                    'value' => $id,
                    'help' => true,
                ),
                'submit' => array(
931
                    'type' => 'image',
932
                    'src' => $THEME->get_url('images/btn_deleteremove.png'),
933
934
                    'alt' => get_string('deletespecific', 'mahara', $title),
                    'elementtitle' => get_string('delete'),
935
                    'confirm' => get_string('deleteblogpost?', 'artefact.blog'),
936
                    'value' => get_string('delete'),
937
938
939
940
941
                ),
            ),
        ));
    }

Alastair Pharo's avatar
Alastair Pharo committed
942
    /**
943
     * This function changes the blog post status.
Alastair Pharo's avatar
Alastair Pharo committed
944
     *
945
     * @param $newpoststatus: boolean 1=published, 0=draft
Alastair Pharo's avatar
Alastair Pharo committed
946
947
     * @return boolean
     */
948
    public function changepoststatus($newpoststatus) {
Alastair Pharo's avatar
Alastair Pharo committed
949
950
951
        if (!$this->id) {
            return false;
        }
952

Alastair Pharo's avatar
Alastair Pharo committed
953
        $data = (object)array(
954
955
                'blogpost'  => $this->id,
                'published' => (int) $newpoststatus
Alastair Pharo's avatar
Alastair Pharo committed
956
957
958
959
960
961
962
963
964
965
        );

        if (get_field('artefact_blog_blogpost', 'COUNT(*)', 'blogpost', $this->id)) {
            update_record('artefact_blog_blogpost', $data, 'blogpost');
        }
        else {
            insert_record('artefact_blog_blogpost', $data);
        }
        return true;
    }
966

Martyn Smith's avatar
Martyn Smith committed
967
968
969
970
971
972
973
    public static function get_links($id) {
        $wwwroot = get_config('wwwroot');

        return array(
            '_default'                                  => $wwwroot . 'artefact/blog/post.php?blogpost=' . $id,
        );
    }
974
975
976
977
978
979
980
981
982
983

    public function update_artefact_references(&$view, &$template, &$artefactcopies, $oldid) {
        parent::update_artefact_references($view, $template, $artefactcopies, $oldid);
        // Attach copies of the files that were attached to the old post.
        // Update <img> tags in the post body to refer to the new image artefacts.
        $regexp = array();
        $replacetext = array();
        if (isset($artefactcopies[$oldid]->oldattachments)) {
            foreach ($artefactcopies[$oldid]->oldattachments as $a) {
                if (isset($artefactcopies[$a])) {
984
                    $this->attach($artefactcopies[$a]->newid);
985
986
987
988
989
990
991
992
                }
                $regexp[] = '#<img([^>]+)src="' . get_config('wwwroot') . 'artefact/file/download.php\?file=' . $a . '"#';
                $replacetext[] = '<img$1src="' . get_config('wwwroot') . 'artefact/file/download.php?file=' . $artefactcopies[$a]->newid . '"';
            }
            $this->set('description', preg_replace($regexp, $replacetext, $this->get('description')));
        }
    }

993
994
995
996
997
    /**
     * During the copying of a view, we might be allowed to copy
     * blogposts but not the containing blog.  We need to create a new
     * blog to hold the copied posts.
     */
998
    public function default_parent_for_copy(&$view, &$template, $artefactstoignore) {
999
        static $blogids;
1000
        global $USER, $SESSION;
1001

1002
1003
1004
1005
        $viewid = $view->get('id');

        if (isset($blogids[$viewid])) {
            return $blogids[$viewid];
1006
1007
        }

1008
        $blogname = get_string('viewposts', 'artefact.blog', $viewid);
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
        $data = (object) array(
            'title'       => $blogname,
            'description' => get_string('postscopiedfromview', 'artefact.blog', $template->get('title')),
            'owner'       => $view->get('owner'),
            'group'       => $view->get('group'),
            'institution' => $view->get('institution'),
        );
        $blog = new ArtefactTypeBlog(0, $data);
        $blog->commit();

1019
        $blogids[$viewid] = $blog->get('id');
1020

1021
1022
1023
1024
1025
1026
        try {
            $user = get_user($view->get('owner'));
            set_account_preference($user->id, 'multipleblogs', 1);
            $SESSION->add_ok_msg(get_string('copiedblogpoststonewjournal', 'collection'));
        }
        catch (Exception $e) {
1027
            $SESSION->add_error_msg(get_string('unabletosetmultipleblogs', 'error', $user->username, $viewid, get_config('wwwroot') . 'account/index.php'), false);
1028
1029
1030
1031
1032
1033
1034
1035
1036
        }

        try {
            $USER->accountprefs = load_account_preferences($user->id);
        }
        catch (Exception $e) {
            $SESSION->add_error_msg(get_string('pleaseloginforjournals', 'error'));
        }

1037
        return $blogids[$viewid];
1038
    }
1039
1040
1041
1042
1043
1044
1045
1046

    /**
     * Looks through the blog post text for links to download artefacts, and 
     * returns the IDs of those artefacts.
     */
    public function get_referenced_artefacts_from_postbody() {
        return artefact_get_references_in_html($this->get('description'));
    }
1047
1048
1049
1050

    public static function is_countable_progressbar() {
        return true;
    }
1051
}