Skip to content
Snippets Groups Projects
WikiPage.class.php 9.84 KiB
Newer Older
<?php
/**
 * WikiPage.class.php
 * model class for table wiki
 *
 * 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 2 of
 * the License, or (at your option) any later version.
 *
 * @author    mlunzena
 * @copyright (c) Authors
 *
Jan-Hendrik Willms's avatar
Jan-Hendrik Willms committed
 * @property array $id alias for pk
 * @property string $course_id database column
Jan-Hendrik Willms's avatar
Jan-Hendrik Willms committed
 * @property string|null $user_id database column
 * @property string $name database column
 * @property string $content database column
Jan-Hendrik Willms's avatar
Jan-Hendrik Willms committed
 * @property string|null $ancestor database column
 * @property int|null $chdate database column
 * @property int $version database column
 * @property int|null $mkdate database column
 * @property User|null $user belongs_to User
Jan-Hendrik Willms's avatar
Jan-Hendrik Willms committed
 * @property Course $course belongs_to Course
 * @property WikiVersion[]|SimpleORMapCollection $versions
 * @property WikiOnlineEditingUser[]|SimpleORMapCollection $onlineeditingusers
 * @property-read WikiPage $parent additional field
 * @property-read WikiPage[] $children additional field
 * @property-read WikiVersion|null $predecessor additional field
 * @property-read int $versionnumber additional field
 */
class WikiPage extends SimpleORMap implements PrivacyObject
{
    /**
     * Configures the model
     * @param  array  $config Configuration
     */
    protected static function configure($config = [])
    {
        $config['db_table'] = 'wiki_pages';
        $config['belongs_to']['user'] = [
            'class_name'  => User::class,
            'foreign_key' => 'user_id'
        ];
        $config['belongs_to']['course'] = [
            'class_name'  => Course::class,
            'foreign_key' => 'range_id',
        ];
        $config['has_many']['versions'] = [
            'class_name'  => WikiVersion::class,
            'foreign_key' => 'page_id',
            'order_by'    => 'ORDER BY mkdate DESC',
            'on_delete'   => 'delete',
        ];
        $config['has_many']['onlineeditingusers'] = [
            'class_name' => WikiOnlineEditingUser::class,
            'foreign_key' => 'page_id',
            'on_delete'   => 'delete',
        ];

        $config['additional_fields']['parent'] = [
            'get' => function (WikiPage $page): ?WikiPage {
                return self::find($page->parent_id);
            }
        ];

        $config['additional_fields']['children'] = [
            'get' => function (WikiPage $page): array {
                return self::findBySQL('parent_id = ?', [
                    $page->id
                ]);
        $config['additional_fields']['predecessor'] = [
            'get' => function (WikiPage $page): ?WikiVersion {
                return $page->versions ? $page->versions[0] : null;
            }
        ];
        $config['additional_fields']['versionnumber'] = [
            'get' => function (WikiPage $page): int {
                return count($page->versions) + 1;
        $config['registered_callbacks']['before_store'][] = 'createVersion';
        $config['default_values']['last_author'] = 'nobody';

        parent::configure($config);
    }


    protected function createVersion()
    {
        $last_version = $this->versions[0];
        if (
            !$this->isNew()
            && $this->content['content'] !== $this->content_db['content']
            && (
                $this->content_db['user_id'] !== $this->content['user_id']
                || $this->content_db['chdate'] < time() - 60 * 30
            )
            && (!$last_version || $last_version['content'] !== $this['content'])
        ) {
            //Neue Version anlegen:
            WikiVersion::create([
                'page_id' => $this->id,
                'name'    => $this->content_db['name'],
                'content' => $this->content_db['content'],
                'user_id' => $this->content_db['user_id'],
                'mkdate'  => $this->content_db['chdate'],
            ]);
        return true;
    public static function findByName($range_id, $name)
        return self::findOneBySQL('name = :name AND range_id = :range_id', [
            'range_id' => $range_id,
            'name' => $name
        ]);
    /**
     * Returns whether this page is visible to the given user.
     * @param  string|null $user_id User id
     * @return boolean indicating whether the page is visible
     */
    public function isReadable(?string $user_id = null): bool
        if ($this->isNew()) {
            return true;
        }
        // anyone can see this page if it belongs to a free course
        if (
            $this->read_permission === 'all'
            && Config::get()->ENABLE_FREE_ACCESS
            && $this->course
            && !$this->course->lesezugriff
        ) {
            return true;
        }
Jan-Hendrik Willms's avatar
Jan-Hendrik Willms committed
        if ($user_id === null && User::findCurrent()) {
            $user_id = User::findCurrent()->id;
        }

        if (
            $this->read_permission === 'all'
            && $GLOBALS['perm']->have_studip_perm('user', $this->range_id, $user_id)
        ) {
        if ($GLOBALS['perm']->have_studip_perm(
            'dozent',
            $this->range_id,
            $user_id
        )) {
            return true;
        }

        if (in_array($this->read_permission, ['tutor', 'dozent'])) {
            return $GLOBALS['perm']->have_studip_perm($this->read_permission, $this->range_id, $user_id);
        } else {
            return StatusgruppeUser::exists([$this->read_permission, $user_id]);
        }
    }

    /**
     * Returns whether this page is editable to the given user.
     * @param  string|null  $user_id the ID of the user
     * @return boolean indicating whether the page is editable
     */
    public function isEditable(?string $user_id = null): bool
Jan-Hendrik Willms's avatar
Jan-Hendrik Willms committed
        if ($user_id === null && User::findCurrent()) {
            $user_id = User::findCurrent()->id;
        }
        if ($GLOBALS['perm']->have_studip_perm(
            'dozent',
            $this->range_id,
            $user_id
        )) {
            return true;
        }
        if ($this->write_permission === 'all') {
            return true;
        }
        if (in_array($this->write_permission, ['tutor', 'dozent'])) {
            return $GLOBALS['perm']->have_studip_perm(
                $this->write_permission,
                $this->range_id,
                $user_id
            );
        } else {
            return StatusgruppeUser::exists([$this->write_permission, $user_id]);
        }
    }


    /**
     * Returns the start page of a wiki for a given course. The start page has
     * the keyword 'WikiWikiWeb'.
     *
     * @param  string $range_id Course id
     * @return WikiPage
     */
    public static function getStartPage($range_id): WikiPage
        $page_id = CourseConfig::get($range_id)->WIKI_STARTPAGE_ID;
        if ($page_id) {
            return self::find($page_id);
        $page = new WikiPage();
        $page->content = _('Dieses Wiki ist noch leer.');
        if ($page->isEditable()) {
            $page->content .=  ' ' . _("Bearbeiten Sie es!\nNeue Seiten oder Links werden einfach durch Eingeben von [nop][[Wikinamen]][/nop] in doppelten eckigen Klammern angelegt.");
        }
        return $page;
    }

    /**
     * Export available data of a given user into a storage object
     * (an instance of the StoredUserData class) for that user.
     *
     * @param StoredUserData $storage object to store data into
     */
    public static function exportUserData(StoredUserData $storage)
    {
        $sorm = self::findBySQL("user_id = ?", [$storage->user_id]);
        if ($sorm) {
            $field_data = [];
            foreach ($sorm as $row) {
                $field_data[] = $row->toRawArray();
            }
            if ($field_data) {
                $storage->addTabularData(_('Wiki Einträge'), 'wiki', $field_data);
            }
        }
    }


    /**
     * Tests if a given Wikipage name (keyword) is a valid ancestor for this page.
     *
     * @param   string   $ancestor Wikipage name to be tested to be an ancestor
     * @return  boolean  true if ok, false if not
     *
     */
    public function isValidAncestor($ancestor): bool
        if ($this->name === 'WikiWikiWeb' || $this->name === $ancestor) {
            return false;
        }

        $keywords = array_map(
            function ($descendant) {
                return $descendant->name;
            },
            $this->getDescendants()
        );

        return !in_array($ancestor, $keywords);
    }

    /**
     * Retrieve an array of all descending WikiPages (recursive).
     *
     * @return WikiPage[] Array of all descendant WikiPages
    public function getDescendants(): array
    {
        $descendants = [];

        foreach ($this->children as $child) {
            array_push($descendants, $child, ...$child->getDescendants());
        }

        return $descendants;
    }

    public function getOnlineUsers(): array
        $users = [];
        WikiOnlineEditingUser::deleteBySQL(
            "`page_id` = :page_id AND `chdate` < UNIX_TIMESTAMP() - :threshold",
            [
                'page_id' => $this->id,
                'threshold' => WikiOnlineEditingUser::$threshold
            ]
        );
        return $this->onlineeditingusers->map(function (WikiOnlineEditingUser $editing_user) {
            return [
                'user_id' => $editing_user->user_id,
                'username' => $editing_user->user->username,
                'fullname' => $editing_user->user->getFullName(),
                'avatar' => Avatar::getAvatar($editing_user->user_id)->getURL(Avatar::SMALL),
                'editing' => (bool) $editing_user->editing,
                'editing_request' => (bool) $editing_user->editing_request,
            ];
        });