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

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

/**
Francois Marier's avatar
Francois Marier committed
31
 * Implements Leap2A import of blog related entries into Mahara
32
 *
Francois Marier's avatar
Francois Marier committed
33
 * For more information about Leap blog importing, see:
34
 * http://wiki.mahara.org/Developer_Area/Import//Export/LEAP_Import/Blog_Artefact_Plugin
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 *
 * TODO:
 * - Get entries that feel they're part of the blog, not just entries the blog feels are part of it
 * - Import raw ATOM feed entries as blog posts
 */
class LeapImportBlog extends LeapImportArtefactPlugin {

    /**
     * Import an entry as a blog, with associated blog posts and attachments
     */
    const STRATEGY_IMPORT_AS_BLOG = 1;

    /**
     * Import entry as an simple blog post into a catch-all blog
     */
    const STRATEGY_IMPORT_AS_ENTRY = 2;

52
53
54
55
56
57
58
59
60
61
62
63
    private static $firstblogid = null;
    private static $importedablog = false;

    /**
     * Users get a default blog when they're created. We don't want this user
     * to have one if their import includes a blog. So we remember the default
     * blog ID here in order to delete it later if necessary.
     */
    public static function setup(PluginImportLeap $importer) {
        self::$firstblogid = get_field('artefact', 'id', 'owner', $importer->get('usr'), 'artefacttype', 'blog');
    }

64
    public static function get_import_strategies_for_entry(SimpleXMLElement $entry, PluginImportLeap $importer) {
65
66
        $strategies = array();

67
68
69
70
71
72
73
74
75
76
        if (PluginImportLeap::is_rdf_type($entry, $importer, 'selection')) {
            if (PluginImportLeap::is_correct_category_scheme($entry, $importer, 'selection_type', 'Blog')) {
                $score = 100;
            } else {
                // the blog plugin can either fall back to importing single entries
                // or handle the case where things are a selection that have no other strategies either.
                // however, in the case where the otherrequiredentries for the selection have a higher strategy elsewhere,
                // we need to still fallback to importing a selection post as a blog post by itself, to avoid dataloss.
                $score = 20; // other things *can* be imported as blogs
            }
77
78
            $otherrequiredentries = array();

79
            // Get entries that this blog/selection feels are a part of it
80
            foreach ($entry->link as $link) {
81
                if ($importer->curie_equals($link['rel'], $importer->get_leap2a_namespace(), 'has_part') && isset($link['href'])) {
82
83
84
85
                    $otherrequiredentries[] = (string)$link['href'];
                }
            }

86
            // TODO: Get entries that feel they should be a part of this blog/selection
87
88
89
90
91
92
            // We can compare the lists and perhaps warn if they're different
            //    $otherentries = $importer->xml->xpath('//a:feed/a:entry/a:link[@rel="leap:is_part_of" and @href="' . $entryid . '"]/../a:id');

            $otherrequiredentries = array_unique($otherrequiredentries);
            $strategies[] = array(
                'strategy' => self::STRATEGY_IMPORT_AS_BLOG,
93
                'score'    => $score,
94
95
                'other_required_entries' => $otherrequiredentries,
            );
96
97
98
99
100
101
102
            if ($score == 20) {
                $strategies[] = array(
                    'strategy' => self::STRATEGY_IMPORT_AS_ENTRY,
                    'score'    => 10,
                    'other_required_entries' => array(),
                );
            }
103
104
105
        }
        else {
            // The blog can import any entry as a literal blog post
106
107
108
109
110
111
112
            // Get files that this blogpost/catchall feels are a part of it
            $otherrequiredentries = array();
            foreach ($entry->link as $link) {
                if ($importer->curie_equals($link['rel'], '', 'enclosure') && isset($link['href'])) {
                    $otherrequiredentries[] = (string)$link['href'];
                }
            }
113
114
115
            $strategies[] = array(
                'strategy' => self::STRATEGY_IMPORT_AS_ENTRY,
                'score'    => 10,
116
                'other_required_entries' => $otherrequiredentries,
117
118
119
120
121
122
            );
        }

        return $strategies;
    }

123
    public static function import_using_strategy(SimpleXMLElement $entry, PluginImportLeap $importer, $strategy, array $otherentries) {
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
        $artefactmapping = array();
        switch ($strategy) {
        case self::STRATEGY_IMPORT_AS_BLOG:
            // First, the blog
            $blog = new ArtefactTypeBlog();
            $blog->set('title', (string)$entry->title);
            $blog->set('description', PluginImportLeap::get_entry_content($entry, $importer));
            $blog->set('owner', $importer->get('usr'));
            if ($published = strtotime((string)$entry->published)) {
                $blog->set('ctime', $published);
            }
            if ($updated = strtotime((string)$entry->updated)) {
                $blog->set('mtime', $updated);
            }
            $blog->set('tags', PluginImportLeap::get_entry_tags($entry));
            $blog->commit();
            $artefactmapping[(string)$entry->id] = array($blog->get('id'));
141
            self::$importedablog = true;
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

            // Then, the blog posts
            foreach ($otherentries as $entryid) {
                $blogentry = $importer->get_entry_by_id($entryid);
                if (!$blogentry) {
                    // TODO: what to do here? Also - should this be checked here or earlier?
                    $importer->trace("WARNING: Blog $entry->id claims to have part $entryid which doesn't exist");
                    continue;
                }

                $artefactmapping[$entryid] = self::create_blogpost($blogentry, $importer, $blog->get('id'));
            }
            break;
        case self::STRATEGY_IMPORT_AS_ENTRY:
            $blogid = self::ensure_catchall_blog($importer);
            $artefactmapping[(string)$entry->id] = self::create_blogpost($entry, $importer, $blogid);
            break;
        default:
            throw new ImportException($importer, 'TODO: get_string: unknown strategy chosen for importing entry');
        }
        return $artefactmapping;
    }

    /**
     * Attaches files to blog posts
     *
     * We look at the leap relationships to add attachments. Currently this 
     * looks explicitly for the has_attachment relationship.
     *
     * If importing an entry resulted in importing a new file (caused by the 
     * entry having out-of-line content), we attach that file to the entry.
     */
174
    public static function setup_relationships(SimpleXMLElement $entry, PluginImportLeap $importer, $strategy, array $otherentries) {
175
        $newartefactmapping = array();
176
177
178
179
180
        switch ($strategy) {
        case self::STRATEGY_IMPORT_AS_BLOG:
            foreach ($otherentries as $entryid) {
                $blogpostentry = $importer->get_entry_by_id($entryid);
                // Get all attachments this blogpost things are attached to it
181
                if (!isset($blogpostentry->link)) {
182
183
                    continue;
                }
184
                $blogpost = null;
185
                foreach ($blogpostentry->link as $blogpostlink) {
186
187
188
189
190
191
                    if (!$blogpost) {
                        $artefactids = $importer->get_artefactids_imported_by_entryid((string)$blogpostentry->id);
                        $blogpost = new ArtefactTypeBlogPost($artefactids[0]);
                    }
                    if ($id = $importer->create_attachment($entry, $blogpostlink, $blogpost)) {
                        $newartefactmapping[$link['href']][] = $id;
192
193
194
195
196
197
198
199
200
201
                    }
                    if ($blogpost) {
                        $blogpost->commit();
                    }
                }

                self::setup_outoflinecontent_relationship($blogpostentry, $importer);
            }
            break;
        case self::STRATEGY_IMPORT_AS_ENTRY:
202
203
204
205
206
207
208
            $blogpostids = $importer->get_artefactids_imported_by_entryid((string)$entry->id);
            if (!isset($blogpostids[0])) {
                // weird!
                break;
            }
            $blogpost = new ArtefactTypeBlogPost($blogpostids[0]);
            foreach ($entry->link as $link) {
209
210
                if ($id = $importer->create_attachment($entry, $link, $blogpost)) {
                    $newartefactmapping[$link['href']][] = $id;
211
212
213
                }
            }
            $blogpost->commit();
214
            self::setup_outoflinecontent_relationship($entry, $importer);
215
216
217
218
            break;
        default:
            throw new ImportException($importer, 'TODO: get_string: unknown strategy chosen for importing entry');
        }
219
220
221
222
        return $newartefactmapping;
    }

    /**
Francois Marier's avatar
Francois Marier committed
223
224
     * Attaches a file to a blogpost entry that was just linked directly, rather than having a Leap2a entry
     * See http://wiki.leapspecs.org/2A/files
225
226
227
228
229
230
231
232
233
     *
     * @param SimpleXMLElement $blogpostentry
     * @param SimpleXMLElement $blogpostlink
     * @param PluginImportLeap $importer
     */
    private static function attach_linked_file($blogpostentry, $blogpostlink, PluginImportLeap $importer) {
        $importer->trace($blogpostlink);
        $pathname = urldecode((string)$blogpostlink['href']);
        $dir = dirname($importer->get('filename'));
234
        $pathname = $dir . '/' . $pathname;
235
236
237
238
239
        if (!file_exists($pathname)) {
            return false;
        }
        // Note: this data is passed (eventually) to ArtefactType->__construct,
        // which calls strtotime on the dates for us
240
        require_once('file.php');
241
242
243
        $data = (object)array(
            'title' => (string)$blogpostentry->title . ' ' . get_string('attachment', 'artefact.blog'),
            'owner' => $importer->get('usr'),
244
            'filetype' => file_mime_type($pathname),
245
246
        );
        return ArtefactTypeFile::save_file($pathname, $data, $importer->get('usrobj'), true);
247
248
    }

249
250
251
252
253
254
    /**
     * Deletes the default blog that is created for all users
     */
    public static function cleanup(PluginImportLeap $importer) {
        if (self::$importedablog && self::$firstblogid) {
            $blog = artefact_instance_from_id(self::$firstblogid);
255
256
257
            if (!$blog->has_children()) { // TODO see #544160
                $blog->delete();
            }
258
        }
259
260
261
262
        $userid = $importer->get('usr');
        if (count_records('artefact', 'artefacttype', 'blog', 'owner', $userid) != 1) {
            set_account_preference($userid, 'multipleblogs', 1);
        }
263
264
    }

265
266
267
268
269
270
271
272
273
274
275
276
    /**
     * Creates a catch-all blog if one doesn't exist already
     *
     * @param PluginImportLeap $importer The importer
     * @return int The artefact ID of the catch-all blog
     */
    private static function ensure_catchall_blog(PluginImportLeap $importer) {
        static $blogid = null;
        if (is_null($blogid)) {
            $time = time(); // TODO maybe the importer will get a time field to record time of import
            $blog = new ArtefactTypeBlog();
            $title = $importer->get('xml')->xpath('//a:feed/a:title');
Nigel McNie's avatar
Nigel McNie committed
277
278
            $blog->set('title', get_string('dataimportedfrom', 'artefact.blog', (string)$title[0]));
            $blog->set('description', get_string('entriesimportedfromleapexport', 'artefact.blog'));
279
280
281
282
283
            $blog->set('owner', $importer->get('usr'));
            $blog->set('ctime', $time);
            $blog->set('mtime', $time);
            $blog->commit();
            $blogid = $blog->get('id');
284
            self::$importedablog = true;
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
        }

        return $blogid;
    }

    /**
     * Creates a blogpost from the given entry
     *
     * @param SimpleXMLElement $entry    The entry to create the blogpost from
     * @param PluginImportLeap $importer The importer
     * @param int $blogid                The blog in which to put the post
     * @return array A list of artefact IDs created, to be used with the artefact mapping. 
     *               There will either be one (the blogpost ID), or two. If there is two, the 
     *               second one will be the ID of the file created to hold the out-of-line 
     *               content associated with the blogpost
     */
    private static function create_blogpost(SimpleXMLElement $entry, PluginImportLeap $importer, $blogid) {
        $createdartefacts = array();
        $blogpost = new ArtefactTypeBlogPost();
        $blogpost->set('title', (string)$entry->title);
        // If the entry has out of line content, we import that separately as a 
        // file and set the content to refer to it
307
        if (LeapImportFile::is_file($entry, $importer)) {
308
309
310
            $file = LeapImportFile::create_file($entry, $importer);
            $createdartefacts[] = $file->get('id');

311
            $content = '<a href="' . get_config('wwwroot') . 'artefact/file/download.php?file=' . $file->get('id') . '"'
312
313
314
315
316
317
318
319
320
321
                . ' title="' . hsc($file->get('title')) . '">';
            if (is_image_mime_type($file->get('filetype'))) {
                $content .= '<img src="' . get_config('wwwroot') 
                    . 'artefact/file/download.php?file=' . $file->get('id') . '&amp;maxwidth=500&amp;maxheight=500"'
                    . ' alt="' . hsc($file->get('title')) . '">';
            }
            $content .= '</a>';
            $blogpost->set('description', $content);
        }
        else {
322
323
324
325
326
327
            $description = PluginImportLeap::get_entry_content($entry, $importer);
            $type = isset($entry->content['type']) ? (string)$entry->content['type'] : 'text';
            if ($type == 'text') {
                $description = format_whitespace($description);
            }
            $blogpost->set('description', $description);
328
329
330
331
332
333
334
335
        }
        if ($published = strtotime((string)$entry->published)) {
            $blogpost->set('ctime', $published);
        }
        if ($updated = strtotime((string)$entry->updated)) {
            $blogpost->set('mtime', $updated);
        }

336
        $draftpost = PluginImportLeap::is_correct_category_scheme($entry, $importer, 'readiness', 'Unready');
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
        $blogpost->set('published', $draftpost ? 0 : 1);

        $blogpost->set('owner', $importer->get('usr'));
        $blogpost->set('parent', $blogid);
        $blogpost->set('tags', PluginImportLeap::get_entry_tags($entry));
        $blogpost->commit();
        array_unshift($createdartefacts, $blogpost->get('id'));

        return $createdartefacts;
    }

    /**
     * Checks to see if a blogpost had out-of-line content, and if it did, 
     * attaches the generated file to it
     *
     * @param SimpleXMLElement $entry    The entry to check
     * @param PluginImportLeap $importer The importer
     */
    private static function setup_outoflinecontent_relationship(SimpleXMLElement $entry, PluginImportLeap $importer) {
        $artefactids = $importer->get_artefactids_imported_by_entryid((string)$entry->id);
        if (count($artefactids) == 2) {
            // In this case, a file was created as a result of 
            // importing a blog entry with out-of-line content. We 
            // attach the file to this post.
            $blogpost = new ArtefactTypeBlogPost($artefactids[0]);
362
            $blogpost->attach($artefactids[1]);
363
364
365
366
367
368
369
            $blogpost->commit();
        }
    }

}

?>