Skip to content
Snippets Groups Projects
jsupdater.php 14.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • <?php
    /*
     * Copyright (c) 2011  Rasmus Fuhse
     *
     * 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.
     */
    
    /**
     * Controller called by the main periodical ajax-request. It collects data,
     * converts the textstrings to utf8 and returns it as a json-object to the
     * internal javascript-function "STUDIP.JSUpdater.process(json)".
     */
    class JsupdaterController extends AuthenticatedController
    {
        // Allow nobody to prevent login screen
        // Refers to http://develop.studip.de/trac/ticket/4771
        protected $allow_nobody = true;
    
        /**
         * Checks whether we have a valid logged in user,
         * send "Forbidden" otherwise.
         *
         * @param String $action The action to perform
         * @param Array  $args   Potential arguments
         */
        public function before_filter(&$action, &$args)
        {
            parent::before_filter($action, $args);
    
            // Check for a valid logged in user (only when an ajax request occurs)
            if (Request::isXhr() && (!is_object($GLOBALS['user']) || $GLOBALS['user']->id === 'nobody')) {
                $this->response->set_status(403);
                $action = 'nop';
            }
        }
    
        /**
         * Does and renders absolute nothing.
         */
        public function nop_action()
        {
            $this->render_nothing();
        }
    
        /**
         * Main action that returns a json-object like
         * {
         *  'js_function.sub_function': data,
         *  'anotherjs_function.sub_function': moredata
         * }
         * This action is called by STUDIP.JSUpdater.poll and the result processed
         * the internal STUDIP.JSUpdater.process method
         */
        public function get_action()
        {
            UpdateInformation::setInformation("server_timestamp", time());
            $data = UpdateInformation::getInformation();
            $data = array_merge($data, $this->coreInformation());
    
    
        }
    
        /**
         * Marks a personal notification as read by the user so it won't be displayed
         * in the list in the header.
         * @param string $id : hash-id of the notification
         */
        public function mark_notification_read_action($id)
        {
            if ($id === 'all') {
                PersonalNotifications::markAllAsRead();
            } else {
                PersonalNotifications::markAsRead($id);
            }
    
            $url = false;
            if ($id === 'all') {
                $url = Request::get('return_to');
            } elseif (!Request::isXhr() || Request::isDialog()) {
                $notification = new PersonalNotifications($id);
                $url = $notification->url;
            }
    
            if ($url) {
                $this->redirect(URLHelper::getURL(TransformInternalLinks($url)));
            } else {
                $this->render_nothing();
            }
        }
    
        /**
         * Sets the background-color of the notification-number to blue, so it does
         * not annoy the user anymore. But he/she is still able to see the notificaion-list.
         * Just sets a unix-timestamp in the user-config NOTIFICATIONS_SEEN_LAST_DATE.
         */
        public function notifications_seen_action()
        {
            UserConfig::get($GLOBALS['user']->id)->store('NOTIFICATIONS_SEEN_LAST_DATE', time());
            $this->render_text(time());
        }
    
        /**
         * SystemPlugins may call UpdateInformation::setInformation to set information
         * to be sent via ajax to the main request. Core-functionality-data should be
         * collected and set here.
         * @return array: array(array('index' => $data), ...)
         */
        protected function coreInformation()
        {
    
                'coursewareclipboard' => $this->getCoursewareClipboardUpdates($pageInfo['coursewareclipboard'] ?? null),
                'blubber' => $this->getBlubberUpdates($pageInfo['blubber'] ?? null),
                'messages' => $this->getMessagesUpdates($pageInfo['messages'] ?? null),
                'personalnotifications' => $this->getPersonalNotificationUpdates(),
                'questionnaire' => $this->getQuestionnaireUpdates($pageInfo['questionnaire'] ?? null),
                'wiki_page_content' => $this->getWikiPageContents($pageInfo['wiki_page_content'] ?? null),
                'wiki_editor_status' => $this->getWikiEditorStatus($pageInfo['wiki_editor_status'] ?? null),
    
            ];
    
            return array_filter($data);
        }
    
        private function getBlubberUpdates($pageInfo)
        {
            $data = [];
    
            if (isset($pageInfo['threads']) && is_array($pageInfo['threads'])) {
    
                $blubber_data = [];
    
                    $thread = new BlubberThread($thread_id);
                    if ($thread->isReadable()) {
    
                        $comments = BlubberComment::findBySQL(
                            "thread_id = :thread_id AND chdate >= :time ORDER BY mkdate ASC",
                            ['thread_id' => $thread_id, 'time' => UpdateInformation::getTimestamp()]
                        );
    
                        foreach ($comments as $comment) {
                            $blubber_data[$thread_id][] = $comment->getJSONdata();
                        }
                    }
                }
                if (count($blubber_data)) {
                    $data['addNewComments'] = $blubber_data;
                }
                $statement = DBManager::get()->prepare("
                    SELECT blubber_events_queue.item_id
                    FROM blubber_events_queue
                    WHERE blubber_events_queue.event_type = 'delete'
                ");
    
                $comment_ids = $statement->fetchAll(PDO::FETCH_COLUMN, 0);
                if (count($comment_ids)) {
                    $data['removeDeletedComments'] = $comment_ids;
                }
                $statement = DBManager::get()->prepare("
                    DELETE FROM blubber_events_queue
                    WHERE mkdate <= UNIX_TIMESTAMP() - 60 * 15
                ");
                $statement->execute();
            }
            if (mb_stripos(Request::get("page"), "dispatch.php/blubber") !== false) {
                //collect updated threads for the widget
                $threads = BlubberThread::findMyGlobalThreads(30, UpdateInformation::getTimestamp());
    
                $thread_widget_data = [];
    
                foreach ($threads as $thread) {
    
                    $thread_widget_data[] = [
    
                        'thread_id' => $thread->getId(),
                        'avatar' => $thread->getAvatar(),
                        'name' => $thread->getName(),
                        'timestamp' => (int) $thread->getLatestActivity()
    
                }
                if (count($thread_widget_data)) {
                    $data['updateThreadWidget'] = $thread_widget_data;
                }
            }
    
            return $data;
        }
    
        /**
         * @SuppressWarnings(PHPMD.Superglobals)
         */
        private function getMessagesUpdates($pageInfo)
        {
            $data = [];
            if (mb_stripos(Request::get("page"), "dispatch.php/messages") !== false) {
                $messages = Message::findNew(
                    $GLOBALS["user"]->id,
    
                    $pageInfo['received'],
                    $pageInfo['since'],
                    $pageInfo['tag']
    
                );
                $templateFactory = $this->get_template_factory();
                foreach ($messages as $message) {
                    $attributes = [
                        'message' => $message,
    
                        'controller' => $this,
                    ];
                    $html = $templateFactory->open("messages/_message_row.php")
                                             ->render($attributes);
                    $data['messages'][$message->getId()] = $html;
                }
            }
    
            return $data;
        }
    
        /**
         * @SuppressWarnings(UnusedFormalParameter)
         */
    
        private function getPersonalNotificationUpdates()
    
            if (PersonalNotifications::isActivated()) {
    
                $data['notifications'] = array_map(
                    function ($notification) {
    
                        $info = $notification->toArray();
                        $info['html'] = $notification->getLiElement();
    
                        return $info;
                    },
                    PersonalNotifications::getMyNotifications()
                );
    
        }
    
        private function getQuestionnaireUpdates($pageInfo)
        {
    
                !isset($pageInfo['questionnaire_ids'])
                || !is_array($pageInfo['questionnaire_ids'])
    
            Questionnaire::findEachMany(
                function (Questionnaire $questionnaire) use ($pageInfo, &$data) {
    
                    if ($questionnaire->latestAnswerTimestamp() > $pageInfo['last_update']) {
    
    Jan-Hendrik Willms's avatar
    Jan-Hendrik Willms committed
                        $template = $this->get_template_factory()->open('questionnaire/evaluate');
                        $template->questionnaire = $questionnaire;
    
                        $template->filtered = $pageInfo['filtered'] ?? [];
    
                        $template->set_layout(null);
    
                        $data[$questionnaire->id] = [
    
                            'html' => $template->render()
                        ];
                    }
    
        private function getWikiPageContents($pageInfo): array
        {
            $data = [];
    
            if (!empty($pageInfo)) {
                foreach ($pageInfo as $page_id) {
    
                    $page = WikiPage::find($page_id);
                    if ($page && $page->isReadable() && ($page->chdate >= Request::int('server_timestamp'))) {
                        $data['contents'][$page_id] = wikiReady($page->content, true, $page->range_id, $page->id);
                    }
                }
            }
            return $data;
        }
    
        private function getWikiEditorStatus($pageInfo): array
        {
            $data = [];
    
                $user = User::findCurrent();
    
                foreach ((array) $pageInfo['page_ids'] as $page_id) {
    
                    WikiOnlineEditingUser::deleteBySQL(
                        "`page_id` = :page_id AND `chdate` < UNIX_TIMESTAMP() - :threshold",
                        [
                            'page_id' => $page_id,
                            'threshold' => WikiOnlineEditingUser::$threshold
                        ]
                    );
                    $page = WikiPage::find($page_id);
    
    David Siegfried's avatar
    David Siegfried committed
                    if ($page) {
                        if ($page->isEditable()) {
                            if (
    
                                $pageInfo['focussed'] == $page_id
                                && !empty($pageInfo['page_content'])
    
    David Siegfried's avatar
    David Siegfried committed
                            ) {
                                $page->content = \Studip\Markup::markAsHtml(
    
    David Siegfried's avatar
    David Siegfried committed
                                );
    
                                if ($page->isDirty()) {
                                    $page['user_id'] = User::findCurrent()->id;
                                    $page->store();
                                }
    
    David Siegfried's avatar
    David Siegfried committed
                            }
                            $onlineData = [
                                'user_id' => $user->id,
                                'page_id' => $page_id
                            ];
                            $online     = WikiOnlineEditingUser::findOneBySQL(
                                "`user_id` = :user_id AND `page_id` = :page_id",
                                $onlineData
    
    David Siegfried's avatar
    David Siegfried committed
                            if (!$online) {
                                $online = WikiOnlineEditingUser::build($onlineData);
    
    David Siegfried's avatar
    David Siegfried committed
                            $editingUsers = WikiOnlineEditingUser::countBySQL(
                                "`page_id` = ? AND `editing` = 1 AND `user_id` != ?",
                                [$page->id, $user->id]
                            );
                            if ($editingUsers > 0) {
                                $online->editing = 0;
                            } else if ($online->editing && $online->editing_request) {
                                // this is the mode that this user requested the editing mode and was granted to get it:
                                $online->editing_request = 0;
                            } else if ($online->editing_request) {
                                $other_requests = WikiOnlineEditingUser::countBySql("`page_id` = ? AND `editing_request` = 1 AND `user_id` != ?", [
    
                                    $page->id,
                                    $user->id,
                                ]);
    
    David Siegfried's avatar
    David Siegfried committed
                                if ($other_requests === 0) {
                                    $online->editing_request = 0;
                                    $online->editing         = 1;
                                }
                            } else {
    
                                    $online->editing = 1;
                                } else {
    
    David Siegfried's avatar
    David Siegfried committed
                                    $other_users = WikiOnlineEditingUser::countBySql("`page_id` = ? AND `user_id` != ?", [
                                        $page->id,
                                        $user->id,
                                    ]);
                                    if ($other_users === 0) {
                                        // if I'm the only user I don't need to lose the edit mode
                                        $online->editing = 1;
                                    } else {
                                        $online->editing = 0;
                                    }
    
    David Siegfried's avatar
    David Siegfried committed
                            $online->chdate = time();
                            $online->store();
                            $data['contents'][$page_id]         = wikiReady($page->content, true, $page->range_id, $page_id);
                            $data['wysiwyg_contents'][$page_id] = $page->content;
                            $data['pages'][$page_id]['editing'] = $online->editing;
                        }
                        else {
                            $data['pages'][$page_id]['editing'] = 0;
    
    David Siegfried's avatar
    David Siegfried committed
                        $data['pages'][$page_id]['chdate'] = $page->chdate;
                        $data['users'][$page_id] = $page->getOnlineUsers();
    
        private function getCoursewareClipboardUpdates($pageInfo)
        {
    
            if (!isset($pageInfo['counter'])) {
                return null;
            }
    
            $counter = $pageInfo['counter'] ?? 0;
    
            return \Courseware\Clipboard::countByUser_id($GLOBALS['user']->id) != $counter;