lib.php 39.1 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
 *
 */

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

Aaron Wells's avatar
Aaron Wells committed
14
/**
15
16
17
18
19
20
21
22
23
24
 * Users can create blogs and blog posts using this plugin.
 */
class PluginArtefactBlog extends PluginArtefact {

    public static function get_artefact_types() {
        return array(
            'blog',
            'blogpost',
        );
    }
Aaron Wells's avatar
Aaron Wells committed
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
    public static function block_advanced_options_element($configdata, $artefacttype) {
71
        $strartefacttype = strtolower(get_string($artefacttype, 'artefact.blog'));
72
73
74
75
76
        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;
        }
    }

139
140
141
142
    public static function is_allowed_in_progressbar() {
        return false;
    }

Alastair Pharo's avatar
Alastair Pharo committed
143
    /**
144
145
146
     * 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
147
     */
148
    public function commit() {
149
150
151
152
        // Just forget the whole thing when we're clean.
        if (empty($this->dirty)) {
            return;
        }
Aaron Wells's avatar
Aaron Wells committed
153

154
155
        // We need to keep track of newness before and after.
        $new = empty($this->id);
Aaron Wells's avatar
Aaron Wells committed
156

157
158
159
160
        // Commit to the artefact table.
        parent::commit();

        $this->dirty = false;
161
162
    }

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

        // Delete the artefact and all children.
        parent::delete();
174
175
    }

176
    /**
Aaron Wells's avatar
Aaron Wells committed
177
178
179
     * 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
180
181
182
183
184
185
186
187
188
     * 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'));
        }
    }

189

190
191
    public function describe_size() {
        return $this->count_children() . ' ' . get_string('posts', 'artefact.blog');
192
193
    }

194
    /**
195
     * Renders a blog.
196
197
198
199
200
     *
     * @param  array  Options for rendering
     * @return array  A two key array, 'html' and 'javascript'.
     */
    public function render_self($options) {
201
202
203
204
205
206
207
208
209
210
211
        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;

212
213
214
215
216
        if (!isset($options['countcomments'])) {
            // Count comments if this is a view
            $options['countcomments'] = (!empty($options['viewid']));
        }

217
218
219
220
        $posts = ArtefactTypeBlogpost::get_posts($this->id, $limit, $offset, $options);

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

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

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

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

244
245
246
247
248
249
250
        if (!empty($options['details']) and get_config('licensemetadata')) {
            $smarty->assign('license', render_license($this));
        }
        else {
            $smarty->assign('license', false);
        }

251
        $options['hidetitle'] = true;
252
        $smarty->assign('options', $options);
253
        $smarty->assign('description', $this->get('description'));
254
255
        $smarty->assign('owner', $this->get('owner'));
        $smarty->assign('tags', $this->get('tags'));
256

257
        $smarty->assign_by_ref('posts', $posts);
258

259
        return array('html' => $smarty->fetch('artefact:blog:blog.tpl'), 'javascript' => '');
260
261
    }

Aaron Wells's avatar
Aaron Wells committed
262

263
    public static function get_icon($options=null) {
264
        global $THEME;
265
        return $THEME->get_url('images/journal.png', false);
266
267
    }

Nigel McNie's avatar
Nigel McNie committed
268
    public static function is_singular() {
Penny Leach's avatar
Penny Leach committed
269
270
271
        return false;
    }

Alastair Pharo's avatar
Alastair Pharo committed
272
    public static function collapse_config() {
273
274
    }

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

291
292
        foreach ($result as &$r) {
            if (!$r->locked) {
293
                $r->deleteform = ArtefactTypeBlog::delete_form($r->id, $r->title);
294
295
296
            }
        }

297
        $count = (int)get_field('artefact', 'COUNT(*)', 'owner', $USER->get('id'), 'artefacttype', 'blog');
Alastair Pharo's avatar
Alastair Pharo committed
298
299
300
301

        return array($count, $result);
    }

302
303
304
    public static function build_blog_list_html(&$blogs) {
        $smarty = smarty_core();
        $smarty->assign_by_ref('blogs', $blogs);
305
306
        $blogs->tablerows = $smarty->fetch('artefact:blog:bloglist.tpl');
        $pagination = build_pagination(array(
307
308
309
            'id' => 'bloglist_pagination',
            'class' => 'center',
            'url' => get_config('wwwroot') . 'artefact/blog/index.php',
310
311
            'jsonscript' => 'artefact/blog/index.json.php',
            'datatable' => 'bloglist',
312
313
314
315
316
317
318
319
320
321
322
            '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'),
        ));
323
324
        $blogs->pagination = $pagination['html'];
        $blogs->pagination_js = $pagination['javascript'];
325
326
    }

Alastair Pharo's avatar
Alastair Pharo committed
327
328
329
330
331
332
    /**
     * This function creates a new blog.
     *
     * @param User
     * @param array
     */
Alastair Pharo's avatar
Alastair Pharo committed
333
    public static function new_blog(User $user, array $values) {
334
335
        require_once('embeddedimage.php');
        db_begin();
Alastair Pharo's avatar
Alastair Pharo committed
336
337
338
339
        $artefact = new ArtefactTypeBlog();
        $artefact->set('title', $values['title']);
        $artefact->set('description', $values['description']);
        $artefact->set('owner', $user->get('id'));
340
        $artefact->set('tags', $values['tags']);
341
342
343
344
345
        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
346
        $artefact->commit();
347
348
349
350
        $blogid = $artefact->get('id');
        $newdescription = EmbeddedImage::prepare_embedded_images($artefact->get('description'), 'blog', $blogid);
        $artefact->set('description', $newdescription);
        db_commit();
351
    }
Alastair Pharo's avatar
Alastair Pharo committed
352
353
354
355
356
357
358
359

    /**
     * This function updates an existing blog.
     *
     * @param User
     * @param array
     */
    public static function edit_blog(User $user, array $values) {
360
        require_once('embeddedimage.php');
Alastair Pharo's avatar
Alastair Pharo committed
361
362
363
364
365
        if (empty($values['id']) || !is_numeric($values['id'])) {
            return;
        }

        $artefact = new ArtefactTypeBlog($values['id']);
366
367
368
        if ($user->get('id') != $artefact->get('owner')) {
            return;
        }
369

Alastair Pharo's avatar
Alastair Pharo committed
370
        $artefact->set('title', $values['title']);
371
372
        $newdescription = EmbeddedImage::prepare_embedded_images($values['description'], 'blog', $values['id']);
        $artefact->set('description', $newdescription);
373
        $artefact->set('tags', $values['tags']);
374
375
376
377
378
        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
379
380
        $artefact->commit();
    }
381

Martyn Smith's avatar
Martyn Smith committed
382
383
    public static function get_links($id) {
        $wwwroot = get_config('wwwroot');
384

Martyn Smith's avatar
Martyn Smith committed
385
        return array(
386
387
            '_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
388
389
        );
    }
390
391
392
393
394

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

395
396
397
    /**
     * Returns the number of posts in this blog that have been published.
     *
Aaron Wells's avatar
Aaron Wells committed
398
     * The result of this function looked up from the database each time, so
399
400
401
402
403
404
405
406
407
408
409
410
411
     * 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')));
    }

412
    public static function delete_form($id, $title = '') {
413
        global $THEME;
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438

        $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);
            }
        }

439
440
441
442
443
444
445
446
447
448
449
        return pieform(array(
            'name' => 'delete_' . $id,
            'successcallback' => 'delete_blog_submit',
            'renderer' => 'oneline',
            'elements' => array(
                'delete' => array(
                    'type' => 'hidden',
                    'value' => $id,
                ),
                'submit' => array(
                    'type' => 'image',
450
                    'src' => $THEME->get_url('images/btn_deleteremove.png'),
451
452
                    'alt' => get_string('deletespecific', 'mahara', $title),
                    'elementtitle' => get_string('delete'),
453
                    'confirm' => $confirm,
454
                    'value' => get_string('delete'),
455
456
457
458
                ),
            ),
        ));
    }
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475

    /**
     * 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) {
476
            $SESSION->add_error_msg(get_string('unabletosetmultipleblogs', 'error', $user->username, $viewid, get_config('wwwroot') . 'account/index.php'), false);
477
478
479
480
481
482
483
484
485
486
487
        }

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

        return null;
    }
488
489
490
491
492
493
494
}

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

495
    /**
Alastair Pharo's avatar
Alastair Pharo committed
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
     * 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);

511
512
513
514
515
        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;
516
                    }
Alastair Pharo's avatar
Alastair Pharo committed
517
                }
518
519
520
521
            }
            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'));
522
523
            }
        }
524
525
526
        else {
            $this->allowcomments = 1; // Turn comments on for new posts
        }
Alastair Pharo's avatar
Alastair Pharo committed
527
528
529
    }

    /**
530
     * This method extends ArtefactType::commit() by adding additional data
Alastair Pharo's avatar
Alastair Pharo committed
531
     * into the artefact_blog_blogpost table.
532
     *
Aaron Wells's avatar
Aaron Wells committed
533
     * This method also works out what blockinstances this blogpost is in, and
534
     * informs them that they should re-check what artefacts they have in them.
Aaron Wells's avatar
Aaron Wells committed
535
     * The post content may now link to different artefacts. See {@link
536
     * PluginBlocktypeBlogPost::get_artefacts for more information}
537
     */
538
    protected function postcommit_hook($new) {
539
540
        require_once(get_config('docroot') . 'blocktype/lib.php');
        require_once(get_config('docroot') . 'artefact/blog/blocktype/taggedposts/lib.php');
Alastair Pharo's avatar
Alastair Pharo committed
541
542
543
544
545
546
547
548
549
550
551
552
        $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');
        }

553
        // We want to get all blockinstances that may contain this blog post. That is currently:
554
555
        // 1) All blogpost blocktypes with this post in it
        // 2) All blog blocktypes with this posts's blog in it
556
557
        // 3) All recentposts blocktypes with this post's blog in it
        // 4) All taggedposts blocktypes with this post's tags
558
        $blocks = (array)get_column_sql('SELECT block
559
560
561
            FROM {view_artefact}
            WHERE artefact = ?
            OR artefact = ?', array($this->get('id'), $this->get('parent')));
562
563
564
565
566
567
568
569
570
571
        if (!$blocks) {
            $blocks = array();
        }

        // Get all "tagged blog entries" blocks that may contain this block
        // (we'll just check for a single matching tag here, and let each block
        // instance further down decide whether or not it matches
        $tags = $this->get('tags');
        if ($tags) {
            $blocks = array_merge($blocks, PluginBlocktypeTaggedposts::find_matching_blocks($tags));
572
573
574
575
        }

        // Now rebuild the list of which artefacts these blocks contain
        // in the view_artefacts table. (This is used for watchlist notifications)
576
577
        if ($blocks) {
            foreach ($blocks as $id) {
578
579
580
581
                $instance = new BlockInstance($id);
                $instance->rebuild_artefact_list();
            }
        }
582
583
    }

584
    /**
Alastair Pharo's avatar
Alastair Pharo committed
585
586
     * This function extends ArtefactType::delete() by also deleting anything
     * that's in blogpost.
587
     */
588
    public function delete() {
Alastair Pharo's avatar
Alastair Pharo committed
589
590
591
        if (empty($this->id)) {
            return;
        }
592

593
        require_once('embeddedimage.php');
594
        db_begin();
595
        $this->detach(); // Detach all file attachments
Alastair Pharo's avatar
Alastair Pharo committed
596
        delete_records('artefact_blog_blogpost', 'blogpost', $this->id);
597
        EmbeddedImage::delete_embedded_images('blogpost', $this->id);
Alastair Pharo's avatar
Alastair Pharo committed
598
        parent::delete();
599
        db_commit();
Alastair Pharo's avatar
Alastair Pharo committed
600
    }
601

602
603
604
605
606
607
608
609
610
611
612
613
614
615
    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();
    }


616
    /**
Aaron Wells's avatar
Aaron Wells committed
617
618
619
     * 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
620
621
622
623
624
625
626
627
     * 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'));
        }
    }
Aaron Wells's avatar
Aaron Wells committed
628

629
630
    public function describe_size() {
        return $this->count_attachments() . ' ' . get_string('attachments', 'artefact.blog');
631
632
    }

633
    public function render_self($options) {
634
635
        global $USER;

636
        $smarty = smarty_core();
637
638
639
640
641
642
643
644
        $smarty->assign('published', $this->get('published'));
        if (!$this->get('published')) {
            $notpublishedblogpoststr = get_string('notpublishedblogpost', 'artefact.blog');
            if ($this->get('owner') == $USER->get('id')) {
                $notpublishedblogpoststr .= ' <a href="' . get_config('wwwroot') . 'artefact/blog/post.php?id=' . $this->get('id') . '">' . get_string('publishit', 'artefact.blog') . '</a>';
            }
            $smarty->assign('notpublishedblogpost', $notpublishedblogpoststr);
        }
645
        $artefacturl = get_config('wwwroot') . 'artefact/artefact.php?artefact=' . $this->get('id');
646
647
648
649
        if (isset($options['viewid'])) {
            $artefacturl .= '&view=' . $options['viewid'];
        }
        $smarty->assign('artefacturl', $artefacturl);
650
651
        if (empty($options['hidetitle'])) {
            if (isset($options['viewid'])) {
652
                $smarty->assign('artefacttitle', '<a href="' . $artefacturl . '">' . hsc($this->get('title')) . '</a>');
653
654
            }
            else {
Richard Mansfield's avatar
Richard Mansfield committed
655
                $smarty->assign('artefacttitle', hsc($this->get('title')));
656
657
658
659
            }
        }

        // We need to make sure that the images in the post have the right viewid associated with them
660
        $postcontent = $this->get('description');
661
        if (isset($options['viewid'])) {
662
663
            safe_require('artefact', 'file');
            $postcontent = ArtefactTypeFolder::append_view_url($postcontent, $options['viewid']);
664
665
        }
        $smarty->assign('artefactdescription', $postcontent);
666
667
        $smarty->assign('artefacttags', $this->get('tags'));
        $smarty->assign('artefactowner', $this->get('owner'));
668
669
670
671
672
673
674
        if (!empty($options['details']) and get_config('licensemetadata')) {
            $smarty->assign('license', render_license($this));
        }
        else {
            $smarty->assign('license', false);
        }

675
        $attachments = $this->get_attachments();
676
        if ($attachments) {
677
            require_once(get_config('docroot') . 'artefact/lib.php');
678
679
680
            foreach ($attachments as &$attachment) {
                $f = artefact_instance_from_id($attachment->id);
                $attachment->size = $f->describe_size();
681
                $attachment->iconpath = $f->get_icon(array('id' => $attachment->id, 'viewid' => isset($options['viewid']) ? $options['viewid'] : 0));
682
                $attachment->viewpath = get_config('wwwroot') . 'artefact/artefact.php?artefact=' . $attachment->id . '&view=' . (isset($options['viewid']) ? $options['viewid'] : 0);
683
684
                $attachment->downloadpath = get_config('wwwroot') . 'artefact/file/download.php?file=' . $attachment->id;
                if (isset($options['viewid'])) {
685
                    $attachment->downloadpath .= '&view=' . $options['viewid'];
686
687
688
                }
            }
            $smarty->assign('attachments', $attachments);
689
690
691
692
            if (isset($options['blockid'])) {
                $smarty->assign('blockid', $options['blockid']);
            }
            $smarty->assign('postid', $this->get('id'));
693
694
695
696
697
698
699
700
701
        }
        $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' => '');
    }


702
703
    public function can_have_attachments() {
        return true;
Richard Mansfield's avatar
Richard Mansfield committed
704
705
706
    }


707
    public static function get_icon($options=null) {
708
        global $THEME;
709
        return $THEME->get_url('images/journal_entry.png', false);
710
711
    }

Nigel McNie's avatar
Nigel McNie committed
712
    public static function is_singular() {
Penny Leach's avatar
Penny Leach committed
713
714
715
        return false;
    }

Alastair Pharo's avatar
Alastair Pharo committed
716
    public static function collapse_config() {
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
744
745
746
747
748
749
750
751
752
753
754
755
    /**
     * This function returns the blog id and offset for a given post.
     *
     * @param integer $postid The id of the required blog post
     * @return object An object containing the required data
     */
    public static function get_post_data($postid) {
        $post = new stdClass();

        $post->blogid = get_field('artefact', 'parent', 'id', $postid, 'artefacttype', 'blogpost');

        if (is_postgres()) {
            $rownum = get_field_sql("SELECT rownum
                                    FROM (SELECT id, ROW_NUMBER() OVER (ORDER BY id DESC) AS rownum
                                        FROM {artefact}
                                        WHERE parent = ?
                                        ORDER BY id DESC) AS posts
                                    WHERE id = ?",
                    array($post->blogid, $postid));
        }
        else if (is_mysql()) {
            $initvar = execute_sql("SET @row_num = 0");
            if ($initvar) {
                $rownum = get_field_sql("SELECT rownum
                                        FROM (SELECT id, @row_num := @row_num + 1 AS rownum
                                            FROM {artefact}
                                            WHERE parent = ?
                                            ORDER BY id DESC) AS posts
                                        WHERE id = ?",
                        array($post->blogid, $postid));
            }
        }
        $post->offset = $rownum - 1;

        return $post;
    }

Alastair Pharo's avatar
Alastair Pharo committed
756
    /**
757
     * This function returns a list of posts in a given blog.
Alastair Pharo's avatar
Alastair Pharo committed
758
759
760
     *
     * @param integer
     * @param integer
761
     * @param integer
762
     * @param array
Alastair Pharo's avatar
Alastair Pharo committed
763
     */
764
    public static function get_posts($id, $limit, $offset, $viewoptions=null) {
Alastair Pharo's avatar
Alastair Pharo committed
765

766
767
768
769
        $results = array(
            'limit'  => $limit,
            'offset' => $offset,
        );
770

771
772
773
774
775
776
777
778
779
780
781
        // 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']}'";
782
            }
783
784
            $from .= ' AND bp.published = 1';
        }
785

786
787
788
789
790
        $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, ' .
791
792
                db_format_tsfield('a.ctime', 'ctime') . ', ' . db_format_tsfield('a.mtime', 'mtime') . ',
                a.locked, bp.published, a.allowcomments ' . $from . '
793
            ORDER BY bp.published ASC, a.ctime DESC, a.id DESC',
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
            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) {
809
810
811
812
813
                $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);
814
815
816
817
818
819
820
821
822
823
824
                $data[$file->artefact]->files[] = $file;
            }
        }

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

        foreach ($data as &$post) {
825
            // Format dates properly
826
            if (is_null($viewoptions)) {
827
828
                // My Blogs area: create forms for changing post status & deleting posts.
                $post->changepoststatus = ArtefactTypeBlogpost::changepoststatus_form($post->id, $post->published);
829
                $post->delete = ArtefactTypeBlogpost::delete_form($post->id, $post->title);
830
            }
831
832
833
            else {
                $by = $post->author ? display_default_name($post->author) : $post->authorname;
                $post->postedby = get_string('postedbyon', 'artefact.blog', $by, format_date($post->ctime));
834
835
836
837
838
839
                // Get comment counts
                if (!empty($viewoptions['countcomments'])) {
                    safe_require('artefact', 'comment');
                    require_once(get_config('docroot') . 'lib/view.php');
                    $view = new View($viewoptions['viewid']);
                    $artefact = artefact_instance_from_id($post->id);
840
841
842
                    list($commentcount, $comments) = ArtefactTypeComment::get_artefact_comments_for_view($artefact, $view, null, false);
                    $post->commentcount = $commentcount;
                    $post->comments = $comments;
843
                }
844
845
846
            }
            $post->ctime = format_date($post->ctime, 'strftimedaydatetime');
            $post->mtime = format_date($post->mtime);
847
848
849
850
851
852

            // 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']);
            }
853
        }
Alastair Pharo's avatar
Alastair Pharo committed
854

855
856
857
        $results['data'] = array_values($data);

        return $results;
858
859
    }

860
861
862
863
864
865
866
867
868
    /**
     * 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) {
869
        $smarty = smarty_core();
870
        $smarty->assign('options', $options);
871
872
        $smarty->assign('posts', $posts['data']);

873
874
        $posts['tablerows'] = $smarty->fetch($template);

875
876
        $setlimit = isset($pagination['setlimit']) ? $pagination['setlimit'] : false;

877
        if ($posts['limit'] && $pagination) {
878
            $pagination = build_pagination(array(
879
880
881
882
883
884
885
                'id' => $pagination['id'],
                'class' => 'center',
                'datatable' => $pagination['datatable'],
                'url' => $pagination['baseurl'],
                'jsonscript' => $pagination['jsonscript'],
                'count' => $posts['count'],
                'limit' => $posts['limit'],
886
                'setlimit' => $setlimit,
887
888
889
890
891
892
893
                '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'];
894
        }
Alastair Pharo's avatar
Alastair Pharo committed
895
896
    }

Aaron Wells's avatar
Aaron Wells committed
897
    /**
Alastair Pharo's avatar
Alastair Pharo committed
898
899
900
901
902
903
904
905
906
907
    /**
     * 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
908
        $artefact->set('published', $values['published']);
Alastair Pharo's avatar
Alastair Pharo committed
909
        $artefact->set('owner', $user->get('id'));
910
        $artefact->set('parent', $values['parent']);
Alastair Pharo's avatar
Alastair Pharo committed
911
        $artefact->commit();
912
        return true;
913
    }
Alastair Pharo's avatar
Alastair Pharo committed
914

Aaron Wells's avatar
Aaron Wells committed
915
    /**
Alastair Pharo's avatar
Alastair Pharo committed
916
917
918
919
920
921
922
923
924
925
926
927
928
929
     * 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']);
930
        $artefact->set('tags', $values['tags']);
931
932
933
934
935
        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
936
937
938
939
        $artefact->commit();
        return true;
    }

940
941
942
943
944
945
946
947
948
949
950
951
    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');
        }
952
        return pieform(array(
953
954
955
            'name' => 'changepoststatus_' . $id,
            'jssuccesscallback' => 'changepoststatus_success',
            'successcallback' => 'changepoststatus_submit',
956
957
958
            'jsform' => true,
            'renderer' => 'oneline',
            'elements' => array(
959
                'changepoststatus' => array(
960
961
962
                    'type' => 'hidden',
                    'value' => $id,
                ),
963
964
965
966
                'currentpoststatus' => array(
                    'type' => 'hidden',
                    'value' => $published,
                ),'submit' => array(
967
                    'type' => 'submit',
968
                    'class' => 'publish',
969
970
                    'value' => $strchangepoststatus,
                    'help' => true,
971
972
973
974
975
                ),
            ),
        ));
    }

976
    public static function delete_form($id, $title = '') {
977
        global $THEME;
978
979
980
981
982
983
984
985
986
987
988
989
990
        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(
991
                    'type' => 'image',
992
                    'src' => $THEME->get_url('images/btn_deleteremove.png'),
993
994
                    'alt' => get_string('deletespecific', 'mahara', $title),
                    'elementtitle' => get_string('delete'),
995
                    'confirm' => get_string('deleteblogpost?', 'artefact.blog'),
996
                    'value' => get_string('delete'),
997
998
999
1000
1001
                ),
            ),
        ));
    }

Alastair Pharo's avatar
Alastair Pharo committed
1002
    /**
1003
     * This function changes the blog post status.
Alastair Pharo's avatar
Alastair Pharo committed
1004
     *
1005
     * @param $newpoststatus: boolean 1=published, 0=draft
Alastair Pharo's avatar
Alastair Pharo committed
1006
1007
     * @return boolean
     */
1008
    public function changepoststatus($newpoststatus) {
Alastair Pharo's avatar
Alastair Pharo committed
1009
1010
1011
        if (!$this->id) {
            return false;
        }
1012

1013
1014
        $this->set('published', (int) $newpoststatus);
        $this->commit();
Alastair Pharo's avatar
Alastair Pharo committed
1015
1016
1017

        return true;
    }
1018

Martyn Smith's avatar
Martyn Smith committed
1019
1020
1021
1022
    public static function get_links($id) {
        $wwwroot = get_config('wwwroot');

        return array(
1023
            '_default' => $wwwroot . 'artefact/blog/view/index.php?blogpost=' . $id,
Martyn Smith's avatar
Martyn Smith committed
1024
1025
        );
    }
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035

    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])) {
1036
                    $this->attach($artefactcopies[$a]->newid);
1037
1038
1039
1040
1041
1042
1043
1044
                }
                $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')));
        }
    }

1045
1046
1047
1048
1049
    /**
     * 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.
     */
1050
    public function default_parent_for_copy(&$view, &$template, $artefactstoignore) {
1051
        static $blogids;
1052
        global $USER, $SESSION;
1053

1054
1055
1056
1057
        $viewid = $view->get('id');

        if (isset($blogids[$viewid])) {
            return $blogids[$viewid];
1058
1059
        }

1060
        $blogname = get_string('viewposts', 'artefact.blog', $viewid);
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
        $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();

1071
        $blogids[$viewid] = $blog->get('id');
1072

1073
1074
1075
1076
1077
1078
        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) {
1079
            $SESSION->add_error_msg(get_string('unabletosetmultipleblogs', 'error', $user->username, $viewid, get_config('wwwroot') . 'account/index.php'), false);
1080
1081
1082
1083
1084
1085
1086
1087
1088
        }

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

1089
        return $blogids[$viewid];
1090
    }
1091
1092

    /**
Aaron Wells's avatar
Aaron Wells committed
1093
     * Looks through the blog post text for links to download artefacts, and
1094
1095
1096
1097
1098
     * returns the IDs of those artefacts.
     */
    public function get_referenced_artefacts_from_postbody() {
        return artefact_get_references_in_html($this->get('description'));
    }
1099
1100
1101
1102

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