diff options
Diffstat (limited to 'app/routes')
| -rw-r--r-- | app/routes/Activity.php | 168 | ||||
| -rw-r--r-- | app/routes/Blubber.php | 321 | ||||
| -rw-r--r-- | app/routes/Clipboard.php | 193 | ||||
| -rw-r--r-- | app/routes/Contacts.php | 302 | ||||
| -rw-r--r-- | app/routes/Course.php | 242 | ||||
| -rw-r--r-- | app/routes/Discovery.php | 27 | ||||
| -rw-r--r-- | app/routes/Events.php | 186 | ||||
| -rw-r--r-- | app/routes/Feedback.php | 271 | ||||
| -rw-r--r-- | app/routes/FileSystem.php | 684 | ||||
| -rw-r--r-- | app/routes/Forum.php | 419 | ||||
| -rw-r--r-- | app/routes/Messages.php | 301 | ||||
| -rw-r--r-- | app/routes/News.php | 375 | ||||
| -rw-r--r-- | app/routes/ResourceBooking.php | 192 | ||||
| -rw-r--r-- | app/routes/ResourceCategories.php | 349 | ||||
| -rw-r--r-- | app/routes/ResourcePermissions.php | 585 | ||||
| -rw-r--r-- | app/routes/ResourceProperties.php | 224 | ||||
| -rw-r--r-- | app/routes/ResourceRequest.php | 138 | ||||
| -rw-r--r-- | app/routes/Resources.php | 950 | ||||
| -rw-r--r-- | app/routes/RoomClipboard.php | 322 | ||||
| -rw-r--r-- | app/routes/Schedule.php | 71 | ||||
| -rw-r--r-- | app/routes/Semester.php | 115 | ||||
| -rw-r--r-- | app/routes/Studip.php | 65 | ||||
| -rw-r--r-- | app/routes/User.php | 300 | ||||
| -rw-r--r-- | app/routes/UserConfig.php | 99 | ||||
| -rw-r--r-- | app/routes/Wiki.php | 148 |
25 files changed, 0 insertions, 7047 deletions
diff --git a/app/routes/Activity.php b/app/routes/Activity.php deleted file mode 100644 index fadca0f..0000000 --- a/app/routes/Activity.php +++ /dev/null @@ -1,168 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author Till Glöggler <tgloeggl@uos.de> - * @author André Klaßen <klassen@elan-ev.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition user_id ^[a-f0-9]{1,32}$ - */ -class Activity extends \RESTAPI\RouteMap -{ - /** - * List activities for an user - * - * @get /user/:user_id/activitystream - * - * @param string $user_id the user to get the activities for - * - * @return array the activities as array('collection' => array(...), 'pagination' => array()) - */ - public function getActivities($user_id) - { - // only root can retrieve arbitrary streams - if (!$GLOBALS['perm']->have_perm('root') && $GLOBALS['user']->id != $user_id) { - $this->error(401); - } - - // failsafe einbauen - falls es keine älteren Aktivitäten mehr im System gibt, Abbruch! - - $oldest_activity = \Studip\Activity\Activity::getOldestActivity(); - $max_age = $oldest_activity ? $oldest_activity->mkdate : time(); - - - $contexts = []; - - $user = \User::find($user_id); - - // create system context - $system_context = new \Studip\Activity\SystemContext($user); - $contexts[] = $system_context; - - $contexts[] = new \Studip\Activity\UserContext($user, $user); - $user->contacts->each(function($another_user) use (&$contexts, $user) { - $contexts[] = new \Studip\Activity\UserContext($another_user, $user); - }); - - if (!in_array($user->perms, ['admin','root'])) { - // create courses and institutes context - foreach (\Course::findMany($user->course_memberships->pluck('seminar_id')) as $course) { - $contexts[] = new \Studip\Activity\CourseContext($course, $user); - } - foreach (\Institute::findMany($user->institute_memberships->pluck('institut_id')) as $institute) { - $contexts[] = new \Studip\Activity\InstituteContext($institute, $user); - } - } - - - // add filters - $filter = new \Studip\Activity\Filter(); - - $start = \Request::int('start', strtotime('-1 days')); - $end = \Request::int('end', time()); - - - $scrollfrom = \Request::int('scrollfrom', false); - $filtertype = \Request::get('filtertype', ''); - - $objectType = \Request::get('object_type'); - $filter->setObjectType($objectType); - - $objectId = \Request::get('object_id'); - $filter->setObjectId($objectId); - - $context = \Request::get('context_type'); - $filter->setContext($context); - - $contextId = \Request::get('context_id'); - $filter->setContextId($contextId); - - if (!empty($filtertype)) { - $filter->setType(json_decode($filtertype)); - } - - if ($scrollfrom) { - // shorten "watch-window" by one second to prevent duplication of activities - $scrollfrom -= 1; - - if ($scrollfrom > $max_age){ - $end = $scrollfrom; - $start = strtotime('-1 day', $end); - $data = []; - - $backtrack = 1; - - while (empty($data)) { - $filter->setStartDate($start); - $filter->setEndDate($end); - - $data = $this->getStreamData($contexts, $filter); - - if ($start < $max_age) { - break; - } - - // move "watch-window" back one day at a time - $end = $start - 1; - $start = strtotime('-'. $backtrack . ' days', $start); - - // enforce maximum "watch-window", currently 2 weeks - $backtrack = min (14, $backtrack + 1); - } - } else { - $data = false; - } - } else { - - $filter->setStartDate($start); - $filter->setEndDate($end); - $data = $this->getStreamData($contexts, $filter); - - } - - // set etag for preventing resending the same stuff over and over again - $this->etag(md5(serialize($data))); - - return $data; - } - - /** - * private helper function to get stream data for given contexts and filter - * - * @param $contexts - * @param $filter - * @return array - */ - - private function getStreamData($contexts, $filter) - { - $stream = new \Studip\Activity\Stream($contexts, $filter); - $data = $stream->toArray(); - - foreach ($data as $key => $act) { - $actor = [ - 'type' => $data[$key]['actor_type'], - 'id' => $data[$key]['actor_id'] - ]; - - if ($data[$key]['actor_type'] == 'user') { - $a_user = \User::findFull($data[$key]['actor_id']); - $actor['details'] = User::getMiniUser($this, $a_user ?: new \User()); - } elseif ($data[$key]['actor_type'] === 'anonymous') { - $actor['details'] = [ - 'name' => _('Anonym'), - ]; - } - - unset($data[$key]['actor_type']); - unset($data[$key]['actor_id']); - - $data[$key]['actor'] = $actor; - } - - return $data; - - } -} diff --git a/app/routes/Blubber.php b/app/routes/Blubber.php deleted file mode 100644 index 1445088..0000000 --- a/app/routes/Blubber.php +++ /dev/null @@ -1,321 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition course_id ^[a-f0-9]{1,32}$ - * @condition stream_id ^(global|[a-f0-9]{1,32})$ - * @condition user_id ^[a-f0-9]{1,32}$ - * @condition blubber_id ^[a-f0-9]{1,32}$ - */ -class Blubber extends \RESTAPI\RouteMap -{ - - /** - * Get content and some comments for a blubber-thread or for the "global" thread all "public" threads. - * - * @get /blubber/threads/:thread_id - * @param string $thread_id id of the blubber thread or "global" if you want public threads (not comments). Remind the global thread is a virtual thread with a special behaviour. - * @return array the blubber as array - */ - public function getThreadData($thread_id) - { - if (!$GLOBALS['perm']->have_perm('autor')) { - $this->error(401); - } - $GLOBALS['user']->cfg->store('BLUBBER_DEFAULT_THREAD', $thread_id); - - $thread = new \BlubberThread($thread_id); - $thread = \BlubberThread::upgradeThread($thread); - if (!$thread->isReadable()) { - $this->error(401); - } - - $json = $thread->getJSONData(50, null, \Request::get("search")); - $thread->markAsRead(); - - $this->etag(md5(serialize($json))); - - return $json; - } - - /** - * Get threads - * - * @get /blubber/threads - * @return array the stream as array - */ - public function getMyThreads() - { - $threads_data = [ - 'threads' => [], - 'more_down' => 0, - ]; - $limit = \Request::int('limit', 50); - - $threads = \BlubberThread::findMyGlobalThreads( - $limit + 1, - null, - \Request::int('timestamp'), - null, - \Request::get("search") ?: null - ); - if (count($threads) > $limit) { - array_pop($threads); - $threads_data['more_down'] = 1; - } - foreach ($threads as $thread) { - $threads_data['threads'][] = [ - 'thread_id' => $thread->getId(), - 'avatar' => $thread->getAvatar(), - 'name' => $thread->getName(), - 'timestamp' => (int) $thread->getLatestActivity(), - ]; - } - return $threads_data; - } - - /** - * Write a comment to a thread - * - * @post /blubber/threads/:thread_id/comments - * @param string $thread_id id of the blubber thread - * @return array the comment as array - */ - public function postComment($thread_id) - { - if (!$GLOBALS['perm']->have_perm('autor')) { - $this->error(401); - } - - if (!trim($this->data['content'])) { - $this->error(406); - } - - $thread = \BlubberThread::find($thread_id); - if (!$thread->isCommentable()) { - $this->error(401); - } - - $comment = new \BlubberComment(); - $comment['thread_id'] = $thread_id; - $comment['content'] = $this->data['content']; - $comment['user_id'] = $GLOBALS['user']->id; - $comment['external_contact'] = 0; - $comment->store(); - - $thread->setLastVisit(); - - return $comment->getJSONData(); - } - - /** - * Write a comment to a thread - * - * @put /blubber/threads/:thread_id/comments/:comment_id - * - * @param string $thread_id id of the blubber thread - * @param string $comment id of the comment - * - * @return array the comment as array - */ - public function editComment($thread_id, $comment_id) - { - $comment = \BlubberComment::find($comment_id); - if (!$comment->isWritable()) { - $this->error(401); - } - $old_content = $comment['content']; - $comment['content'] = $this->data['content']; - - if ($comment['user_id'] !== $GLOBALS['user']->id) { - $messaging = new \messaging(); - $message = sprintf( - _("%s hat als Moderator gerade Ihren Beitrag in Blubber editiert.\n\nDie alte Version des Beitrags lautete:\n\n%s\n\nDie neue lautet:\n\n%s\n"), - get_fullname(), $old_content, $comment['content'] - ); - - $message .= "\n\n"; - - $message .= '[' . _('Link zu diesem Beitrag') . ']'; - $message .= \URLHelper::getURL( - "{$GLOBALS['ABSOLUTE_URI_STUDIP']}dispatch.php/blubber/index/{$comment->thread_id}", - [], - true - ); - - $messaging->insert_message( - $message, - get_username($comment['user_id']), - $GLOBALS['user']->id, - null, null, null, null, - _("Änderungen an Ihrem Blubber.") - ); - } - - if (!trim($this->data['content'])) { - $data = $comment->getJSONData(); - $comment->delete(); - } else { - $comment->store(); - $data = $comment->getJSONData(); - } - return $data; - } - - /** - * Write a comment to a thread - * - * @get /blubber/threads/:thread_id/comments - * - * @param string $thread_id id of the blubber thread - * - * @return array the comments as array - */ - public function getComments($thread_id) - { - if (!$GLOBALS['perm']->have_perm('autor')) { - $this->error(401); - } - - $thread = new \BlubberThread($thread_id); - if (!$thread->isReadable()) { - $this->error(401); - } - - $modifier = \Request::get('modifier'); - if ($modifier === 'olderthan') { - $limit = \Request::int('limit', 50); - - $query = "SELECT blubber_comments.* - FROM blubber_comments - WHERE blubber_comments.thread_id = :thread_id - AND blubber_comments.mkdate <= :timestamp - ORDER BY mkdate DESC - LIMIT :limit"; - $result = \DBManager::get()->fetchAll($query, [ - 'thread_id' => $thread_id, - 'timestamp' => \Request::int('timestamp', time()), - 'limit' => $limit + 1, - ]); - - $output = ['comments' => []]; - - if (count($result) > $limit) { - array_pop($result); - $output['more_up'] = 1; - } else { - $output['more_up'] = 0; - } - foreach ($result as $data) { - $comment = \BlubberComment::buildExisting($data); - $output['comments'][] = $comment->getJSONData(); - } - return $output; - } - - if ($modifier === 'newerthan') { - $limit = \Request::int('limit', 50); - - $query = "SELECT blubber_comments.* - FROM blubber_comments - WHERE blubber_comments.thread_id = :thread_id - AND blubber_comments.mkdate >= :timestamp - ORDER BY mkdate - LIMIT :limit"; - $comments = \DBManager::get()->fetchAll($query, [ - 'thread_id' => $thread_id, - 'timestamp' => \Request::int('timestamp', time()), - 'limit' => $limit + 1, - ], function ($comment) { - return \BlubberComment::buildExisting($comment)->getJSONData(); - }); - - $output = ['comments' => $comments]; - - if (count($comments) > $limit) { - array_pop($output['comments']); - $output['more_down'] = 1; - } else { - $output['more_down'] = 0; - } - - return $output; - } - - $query = "SELECT blubber_comments.* - FROM blubber_comments - WHERE blubber_comments.thread_id = :thread_id "; - $parameters = ['thread_id' => $thread_id]; - - if (\Request::get('search')) { - $query .= " AND blubber_comments.content LIKE :search "; - $parameters['search'] = '%'.\Request::get('search').'%'; - } - $query .= " ORDER BY mkdate ASC "; - - $output['comments'] = \DBManager::get()->fetchAll($query, $parameters, function ($comment) { - return \BlubberComment::buildExisting($comment)->getJSONData(); - }); - $output['more_up'] = 0; - $output['more_down'] = 0; - - return $output; - } - - /** - * Does the current user follow the thread? - * - * @get /blubber/threads/:thread_id/follow - */ - public function threadIsFollowed($thread_id) - { - return $this->requireThread($thread_id)->isFollowedByUser(); - } - - /** - * User follows a thread. - * - * @post /blubber/threads/:thread_id/follow - * - * @param string $thread_id id of the blubber thread - */ - public function followThread($thread_id) - { - $this->requireThread($thread_id)->addFollowingByUser(); - } - - /** - * User unfollows a thread. - * - * @delete /blubber/threads/:thread_id/follow - * - * @param string $thread_id id of the blubber thread - */ - public function unfollowThread($thread_id) - { - $this->requireThread($thread_id)->removeFollowingByUser(); - } - - /** - * Returns a blubber thread and checks permissions. - * - * @param string $thread_id Id of the blubber thread - * @return \BlubberThread - */ - private function requireThread($thread_id) - { - if (!$GLOBALS['perm']->have_perm('autor')) { - $this->error(401); - } - - $thread = new \BlubberThread($thread_id); - if (!$thread->isReadable()) { - $this->error(401); - } - - return \BlubberThread::upgradeThread($thread); - } -} diff --git a/app/routes/Clipboard.php b/app/routes/Clipboard.php deleted file mode 100644 index dfe22e0..0000000 --- a/app/routes/Clipboard.php +++ /dev/null @@ -1,193 +0,0 @@ -<?php -namespace RESTAPI\Routes; - - -/** - * This file contains the REST class for the clipboard system. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017-2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @since 4.5 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class Clipboard extends \RESTAPI\RouteMap -{ - /** - * Adds a new clipboard. - * - * @post /clipboard/add - */ - public function addClipboard() - { - $name = \Request::get('name'); - - if (!$name) { - $this->halt(400, _('Es wurde kein Name angegeben!')); - } - - $clipboard = new \Clipboard(); - $clipboard->user_id = $GLOBALS['user']->id; - $clipboard->name = $name; - if (!$clipboard->store()) { - $this->halt(500, _('Fehler beim Speichern des Merkzettels!')); - } - - $result = $clipboard->toRawArray(); - //A special treatment for the widget_id parameter: - //It is passed through: - $widget_id = \Request::get('widget_id'); - if ($widget_id) { - $result['widget_id'] = $widget_id; - } - - return $result; - } - - - /** - * Edits a clipboard. - * - * @put /clipboard/:clipboard_id - */ - public function editCliboard($clipboard_id = null) - { - $clipboard = \Clipboard::find($clipboard_id); - if (!$clipboard) { - $this->notFound(_('Ungültige Merkzettel-ID!')); - } - - if ($clipboard->user_id != $GLOBALS['user']->id) { - //Thou shalt not delete clipboards - //which don't belong to you! - throw new \AccessDeniedException(); - } - - $name = $this->data['name']; - if (!$name) { - $this->halt(400, _('Es wurde kein Name angegeben!')); - } - - $clipboard->name = $name; - - if ($clipboard->isDirty()) { - $success = $clipboard->store(); - } else { - $success = true; - } - - if (!$success) { - $this->halt(500, _('Fehler beim Bearbeiten des Merkzettels!')); - } - - $result = $clipboard->toRawArray(); - - //A special treatment for the widget_id parameter: - //It is passed through: - $widget_id = \Request::get('widget_id'); - if ($widget_id) { - $result['widget_id'] = $widget_id; - } - - return $result; - } - - - /** - * Deletes a clipboard. - * - * @delete /clipboard/:clipboard_id - */ - public function deleteClipboard($clipboard_id = null) - { - $clipboard = \Clipboard::find($clipboard_id); - if (!$clipboard) { - $this->notFound(_('Ungültige Merkzettel-ID!')); - } - - if ($clipboard->user_id !== $GLOBALS['user']->id) { - //Thou shalt not delete items of clipboards - //which don't belong to you! - throw new \AccessDeniedException(); - } - - if (!$clipboard->delete()) { - $this->halt(500, _('Fehler beim Löschen des Merkzettels!')); - } - - return ""; - } - - - /** - * Adds an item to a clipboard. - * - * @post /clipboard/:clipboard_id/item - */ - public function addClipboardItem($clipboard_id = null) - { - $clipboard = \Clipboard::find($clipboard_id); - if (!$clipboard) { - $this->notFound(_('Ungültige Merkzettel-ID!')); - } - - if ($clipboard->user_id != $GLOBALS['user']->id) { - //Thou shalt not add items to clipboards - //which don't belong to you! - throw new \AccessDeniedException(); - } - - $range_id = \Request::get('range_id'); - $range_type = \Request::get('range_type'); - $widget_id = \Request::get('widget_id'); - - if (!is_a($range_type, $clipboard->allowed_item_class, true)) { - $this->halt( - 400, - sprintf( - _('Die Klasse %s ist in dieser Merkzettel-Klasse nicht erlaubt!'), - $range_type - ) - ); - } - - try { - $item = $clipboard->addItem($range_id, $range_type); - - $result = $item->toRawArray(); - $result['name'] = $item->__toString(); - if ($widget_id) { - $result['widget_id'] = $widget_id; - } - return $result; - } catch (\Exception $e) { - $this->halt(500, $e->getMessage()); - } - } - - - /** - * Removes an item (selected by its range-ID) from a clipboard. - * - * @delete /clipboard/:clipboard_id/item/:range_id - */ - public function removeClipboardItem($clipboard_id = null, $range_id = null) - { - $clipboard = \Clipboard::find($clipboard_id); - if (!$clipboard) { - $this->notFound(_('Ungültige Merkzettel-ID!')); - } - - if ($clipboard->user_id != $GLOBALS['user']->id) { - //Thou shalt not delete items of clipboards - //which don't belong to you! - throw new \AccessDeniedException(); - } - - if ($clipboard->removeItem($range_id)) { - return ['range_id' => $range_id]; - } else { - $this->halt(500, _('Fehler beim Löschen des Eintrags!')); - } - } -} diff --git a/app/routes/Contacts.php b/app/routes/Contacts.php deleted file mode 100644 index d7fd010..0000000 --- a/app/routes/Contacts.php +++ /dev/null @@ -1,302 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition user_id ^[a-f0-9]{1,32}$ - * @condition friend_id ^[a-f0-9]{1,32}$ - * @condition group_id ^[a-f0-9]{1,32}$ - */ -class Contacts extends \RESTAPI\RouteMap -{ - - public static function before() - { - require_once 'User.php'; - require_once 'lib/statusgruppe.inc.php'; - } - - /** - * Lists all contacts of a user - * - * @get /user/:user_id/contacts - */ - public function getUserContacts($user_id) - { - if ($GLOBALS['user']->id !== $user_id) { - $this->error(401); - } - - // quite degenerated as long as we can only see our own contacts - $user = $this->requireUser($user_id); - - $total = count($user->contacts); - $contacts = $user->contacts->limit($this->offset, $this->limit); - - $contacts_json = $this->contactsToJSON($contacts); - $this->etag(md5(serialize($contacts_json))); - - return $this->paginated($contacts_json, - $total, compact('user_id')); - } - - /** - * Adds/Updates a contact to user's list of contacts - * - * @put /user/:user_id/contacts/:friend_id - */ - public function addUserContact($user_id, $buddy_user_id) - { - if ($GLOBALS['user']->id !== $user_id) { - $this->error(401); - } - - $user = $this->requireUser($user_id); - $friend = $this->requireUser($buddy_user_id); - - // prevent duplicates - if ($user->isFriendOf($friend)) { - $this->error(409, sprintf('User "%s" is already a contact', htmlReady($friend->id))); - } - - $user->contacts[] = $friend; - $user->store(); - - $this->status(201); - } - - /** - * Deletes a contact - * - * @delete /user/:user_id/contacts/:friend_id - */ - public function removeUserContact($user_id, $buddy_user_id) - { - if ($GLOBALS['user']->id !== $user_id) { - $this->error(401); - } - - $user = $this->requireUser($user_id); - $friend = $this->requireUser($buddy_user_id); - - if (!$user->isFriendOf($friend)) { - $this->notFound("Contact not found"); - } - - $user->contacts->unsetByPK($friend->id); - $user->store(); - - $this->status(204); - } - - - /** - * List all contact groups of a user - * - * @get /user/:user_id/contact_groups - */ - public function getUserContactGroups($user_id) - { - if ($GLOBALS['user']->id !== $user_id) { - $this->error(401); - } - - $contact_groups = \SimpleCollection::createFromArray( - \Statusgruppen::findByRange_id($GLOBALS['user']->id)) - ->orderBy('name ASC'); - - $total = count($contact_groups); - $contact_groups = $contact_groups->limit($this->offset, $this->limit); - - $contact_groups_json = $this->contactGroupsToJSON($contact_groups); - $this->etag(md5(serialize($contact_groups_json))); - - return $this->paginated($contact_groups_json, - $total, compact('user_id')); - } - - /** - * Create a new contact group for a user. - * - * @post /user/:user_id/contact_groups - */ - public function createContactGroup($user_id) - { - if ($GLOBALS['user']->id !== $user_id) { - $this->error(401); - } - - if (!isset($this->data['name']) || !mb_strlen($name = trim($this->data['name']))) { - $this->error(400, 'Contact group name required.'); - } - - $group = new \Statusgruppen(); - $group->range_id = $GLOBALS['user']->id; - $group->name = $name; - $group->size = 0; - $group->selfassign = 0; - $group->calendar_group = 0; - $group->store(); - $this->redirect('contact_group/' . $group->id, 201, 'ok'); - } - - /** - * Show a single contact group - * - * @get /contact_group/:group_id - */ - public function showContactGroup($group_id) - { - $group = $this->requireContactGroup($group_id); - $contact_group_json = $this->contactGroupToJSON($group); - $this->etag(md5(serialize($contact_group_json))); - return $contact_group_json; - } - - /** - * Remove a contact group - * - * @delete /contact_group/:group_id - */ - public function destroyContactGroup($group_id) - { - $group = $this->requireContactGroup($group_id); - - $group->remove(); - - $this->status(204); - } - - /** - * List all members of a contact group - * - * @get /contact_group/:group_id/members - */ - public function indexOfContactGroupMembers($group_id) - { - $group = $this->requireContactGroup($group_id); - $contacts = $group->members->limit($this->offset, $this->limit); - - $json = []; - foreach ($contacts as $contact) { - $url = $this->urlf('/contact_group/%s/members/%s', [$group_id, $contact->user_id]); - $json[$url] = User::getMiniUser($this, $contact->user); - } - - $this->etag(md5(serialize($json))); - - return $this->paginated($json, count($group->members), compact('group_id')); - } - - /** - * Add a user to a contact group - * - * @put /contact_group/:group_id/members/:user_id - */ - public function addToContactGroup($group_id, $user_id) - { - $group = $this->requireContactGroup($group_id); - $user = $this->requireUser($user_id); - - // prevent duplicates - $exists = $group->members->findBy('user_id', $user_id)->first(); - if ($exists) { - $this->halt(204); - } - - $new_contact = [ - 'owner_id' => $GLOBALS['user']->id, - 'user_id' => $user->id]; - - $new_contact['group_assignments'][] = ['statusgruppe_id' => $group->id, - 'user_id' => $user->id]; - - $success = (bool)\Contact::import($new_contact)->store(); - - - if (!$success) { - $this->error(500); - } - - $this->status(201); - } - - /** - * Remove a user from a contact group - * - * @delete /contact_group/:group_id/members/:user_id - */ - public function removeFromContactGroup($group_id, $user_id) - { - $group = $this->requireContactGroup($group_id); - $membership = $group->members->findBy('user_id', $user_id)->first(); - if (!$membership) { - $this->notFound(); - } - - $membership->delete(); - - $this->status(204); - } - - - /**************************************************/ - /* PRIVATE HELPER METHODS */ - /**************************************************/ - - private function requireUser($user_id) - { - $user = \User::find($user_id); - // TODO: checks visibility using the global perm object! - if (!$user || !get_visibility_by_id($user_id)) { - $this->notFound(sprintf("Could not find user with id: %s", htmlReady($user_id))); - } - - return $user; - } - - private function requireContactGroup($group_id) - { - $group = \Statusgruppen::find($group_id); - if (!$group) { - $this->notFound(); - } - - if ($group->range_id !== $GLOBALS['user']->id) { - $this->error(401); - } - return $group; - } - - private function contactsToJSON($contacts) { - $result = []; - foreach ($contacts as $contact) { - $result[] = User::getMiniUser($this, $contact); - } - return $result; - } - - private function contactGroupsToJSON($contact_groups) - { - $result = []; - foreach ($contact_groups as $cg) { - $url = $this->urlf('/contact_group/%s', [htmlReady($cg->id)]); - $result[$url] = $this->contactGroupToJSON($cg); - } - return $result; - } - - private function contactGroupToJSON($group) - { - $json = [ - 'id' => $group->id, - 'name' => (string) $group->name, - 'contacts' => $this->urlf('/contact_group/%s/members', [htmlReady($group->id)]), - 'contacts_count' => sizeof($group->members) - ]; - return $json; - } -} diff --git a/app/routes/Course.php b/app/routes/Course.php deleted file mode 100644 index d1fad96..0000000 --- a/app/routes/Course.php +++ /dev/null @@ -1,242 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition course_id ^[a-f0-9]{1,32}$ - * @condition user_id ^[a-f0-9]{1,32}$ - */ -class Course extends \RESTAPI\RouteMap -{ - - public function before() - { - require_once 'User.php'; - } - - /** - * Lists all courses of a user including the semesters in which - * that course is active. - * Optionally filtered by a URL parameter 'semester'. - * - * @get /user/:user_id/courses - */ - public function getUserCourses($user_id) - { - if (($GLOBALS['user']->id !== $user_id) && !$GLOBALS['perm']->have_perm("root")) { - $this->error(401); - } - - // setting up semester to filter by - $semester = null; - $semester_id = \Request::get('semester'); - if ($semester_id) { - $semester = \Semester::find($semester_id); - if (!$semester) { - $this->error(400, "Semester not found."); - } - } - - $memberships = $this->findMembershipsByUserId($user_id, $semester); - - $total = count($memberships); - $memberships = $memberships->limit($this->offset, $this->limit); - $memberships_json = $this->membershipsToJSON($memberships); - $this->etag(md5(serialize($memberships_json))); - return $this->paginated( - $memberships_json, - $total, - compact('user_id'), - ['semester' => $semester_id] - ); - } - - /** - * Show a single course - * - * @get /course/:course_id - */ - public function getCourse($course_id) - { - if (!$course = \Course::find($course_id)) { - $this->notFound("Course not found"); - } - - $course = $this->requireCourse($course_id); - $this->lastmodified($course->chdate); - $course_json = $this->courseToJSON($course); - $this->etag(md5(serialize($course_json))); - return $course_json; - } - - /** - * List all members of a course. - * Optionally filtered by a URL parameter 'status'. - * - * @get /course/:course_id/members - */ - public function getMembers($course_id) - { - $status_filter = \Request::get('status'); - if ($status_filter && !in_array($status_filter, words("user autor tutor dozent"))) { - $this->error(400, "Status may be one of: user, autor, tutor, dozent"); - } - - $course = $this->requireCourse($course_id); - $members = $course->members; - if ($status_filter) { - $members = $members->findBy('status', $status_filter); - } - - $total = count($members); - $members = $members->limit($this->offset, $this->limit); - $members_json = $this->membersToJSON($course, $members); - $this->etag(md5(serialize($members_json))); - return $this->paginated( - $members_json, - $total, - compact('course_id'), - ['status' => $status_filter] - ); - } - - /** - * Get the root file folder of a course. - * - * @get /course/:course_id/top_folder - */ - public function getTopFolder($course_id) - { - $top_folder = \Folder::findTopFolder( - $this->requireCourse($course_id)->id, - 'course' - ); - - if (!$top_folder) { - $this->notFound("No folder found for course with id {$course_id}!"); - } - - return (new FileSystem())->getFolder($top_folder->id); - } - - /**************************************************/ - /* PRIVATE HELPER METHODS */ - /**************************************************/ - - private function findMembershipsByUserId($user_id, $semester) - { - $memberships = \SimpleORMapCollection::createFromArray( - \CourseMember::findBySQL('user_id = ? ORDER BY mkdate ASC', [$user_id]) - ); - - // filter by semester - if ($semester) { - - $memberships = $memberships->filter(function ($m) use ($semester) { - return $m->course->isInSemester($semester); - }); - } - - return $memberships; - } - - private function membershipsToJSON($memberships) - { - $json = []; - - foreach ($memberships as $membership) { - $course_json = $this->courseToJSON($course = $membership->course); - - $json[$this->urlf("/course/%s", [$course->id])] = $course_json; - } - return $json; - } - - private function courseToJSON($course) - { - $json = []; - - $json['course_id'] = $course->id; - $json['number'] = $course->VeranstaltungsNummer; - $json['title'] = (string) $course->Name; - $json['subtitle'] = (string) $course->Untertitel; - $json['type'] = $course->status; - $json['description'] = (string) $course->Beschreibung; - $json['location'] = (string) $course->Ort; - - // lecturers - foreach ($course->getMembersWithStatus('dozent') as $lecturer) { - $url = $this->urlf('/user/%s', [htmlReady($lecturer->user_id)]); - $json['lecturers'][$url] = User::getMiniUser($this, $lecturer->user); - } - - // other members - foreach (words("user autor tutor dozent") as $status) { - $json['members'][$status] = $this->urlf('/course/%s/members?status=%s', [$course->id, $status]); - $json['members'][$status . '_count'] = $course->countMembersWithStatus($status); - } - - foreach (words("start_semester end_semester") as $key) { - $json[$key] = $course->$key ? $this->urlf('/semester/%s', [htmlReady($course->$key->id)]) : null; - } - - $activated = array_map('get_class', $course->getActivatedTools()); - - $json['modules'] = []; - foreach (['forum' => 'forum_categories', - 'documents' => 'top_folder', - 'wiki' => 'wiki'] as $module => $uri) - { - if (in_array('Core' . ucfirst($module), $activated)) { - $json['modules'][$module] = $this->urlf('/course/%s/%s', [htmlReady($course->id), $uri]); - } - } - - // Add group if current user is member of the group - $json['group'] = null; - - $member = \CourseMember::find([$course->id, $GLOBALS['user']->id]); - if ($member) { - $json['group'] = (int) $member->gruppe; - } - - - return $json; - } - - private function requireCourse($id) - { - if (!$course = \Course::find($id)) { - $this->notFound("Course not found"); - } - - //This route is used in the room management system. - //Therefore, we need not only to check if the user is in the course, - //but also, if the user is a global resource admin. In the latter case, - //access shall also be granted. - if (!$GLOBALS['perm']->have_studip_perm('user', $id, $GLOBALS['user']->id) - && !\ResourceManager::userHasGlobalPermission(\User::findCurrent(), 'admin')) { - $this->error(401); - } - - return $course; - } - - private function membersToJSON($course, $members) - { - $json = []; - - foreach ($members as $member) { - $url = $this->urlf('/user/%s', [$member->user_id]); - $avatar = \Avatar::getAvatar($member->user_id); - $json[$url] = [ - 'member' => User::getMiniUser($this, $member->user), - 'status' => $member->status - ]; - } - return $json; - } -} diff --git a/app/routes/Discovery.php b/app/routes/Discovery.php deleted file mode 100644 index c83f524..0000000 --- a/app/routes/Discovery.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author Jan-Hendrik Willms <tleilax+studip@gmail.com> - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class Discovery extends \RESTAPI\RouteMap -{ - /** - * Schnittstellenbeschreibung - * - * @get /discovery - */ - public function getDiscovery() - { - $routes = $this->router->getRoutes(true); - foreach ($routes as $uri_template => $methods) { - foreach ($methods as $method => $route) { - $routes[$uri_template][$method] = $route['description']; - } - } - return $routes; - } -} diff --git a/app/routes/Events.php b/app/routes/Events.php deleted file mode 100644 index 368d615..0000000 --- a/app/routes/Events.php +++ /dev/null @@ -1,186 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -use Config; -use Resource; -use Room; -use Seminar; -use Issue; - - -/** - * @author André Klaßen <andre.klassen@elan-ev.de> - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition course_id ^[a-f0-9]{1,32}$ - * @condition user_id ^[a-f0-9]{1,32}$ - * @condition semester_id ^[a-f0-9]{1,32}$ - */ -class Events extends \RESTAPI\RouteMap -{ - - /** - * returns all upcoming events within the next two weeks for a given user - * - * @get /user/:user_id/events - */ - public function getEvents($user_id) - { - if ($user_id !== $GLOBALS['user']->id) { - $this->error(401); - } - - $start = new \DateTime(); - $end = clone $start; - $end = $end->add(new \DateInterval('P2W')); - - $list = array_merge( - \CalendarCourseDate::getEvents($start, $end, $user_id), - \CalendarCourseExDate::getEvents($start, $end, $user_id) - ); - - $json = []; - $events = array_slice($list, $this->offset, $this->limit); ; - foreach ($events as $event) { - - $course_uri = $this->urlf('/course/%s', [htmlReady($event->range_id)]); - - $json[] = [ - 'event_id' => $event->id, - 'course' => $course_uri, - 'start' => $event->date, - 'end' => $event->end_time, - 'title' => $event->getTitle(), - 'description' => $event->getDescription() ?: '', - 'categories' => $event->getTypeName(), - 'room' => $event->getRoomName(), - 'canceled' => $event instanceof \CourseExDate || holiday($event->date), - ]; - } - - $this->etag(md5(serialize($json))); - - return $this->paginated($json, count($list), compact('user_id')); - } - - /** - * returns an iCAL Export of all events for a given user - * - * @get /user/:user_id/events.ics - */ - public function getEventsICAL($user_id) - { - if ($user_id !== $GLOBALS['user']->id) { - $this->error(401); - } - $end = new \DateTime(); - $end->setTimestamp(\CalendarDate::NEVER_ENDING); - $start = new \DateTime(); - $start->modify('-4 week'); - $ical_export = new \ICalendarExport(); - $ical = $ical_export->exportCalendarDates($user_id, $start, $end) - . $ical_export->exportCourseDates($user_id, $start, $end) - . $ical_export->exportCourseExDates($user_id, $start, $end); - $content = $ical_export->writeHeader() . $ical . $ical_export->writeFooter(); - - $this->contentType('text/calendar'); - $this->headers([ - 'Content-Length' => strlen($content), - 'Content-Disposition' => 'attachment; ' . encode_header_parameter('filename', 'studip.ics'), - ]); - $this->halt(200, $this->response->headers, function () use ($content) { - echo $content; - }); - } - - - /** - * returns events for a given course - * - * @get /course/:course_id/events - */ - public function getEventsForCourse($course_id) - { - if (!$GLOBALS['perm']->have_studip_perm('user', $course_id, $GLOBALS['user']->id)) { - $this->error(401); - } - - $seminar = new Seminar($course_id); - $dates = getAllSortedSingleDates($seminar); - $total = sizeof($dates); - - $events = []; - foreach (array_slice($dates, $this->offset, $this->limit) as $date) { - - // get issue titles - $issue_titles = []; - if (is_array($issues = $date->getIssueIDs())) { - foreach ($issues as $is) { - $issue = new Issue(['issue_id' => $is]); - $issue_titles[] = $issue->getTitle(); - } - } - - $room = self::getRoomForSingleDate($date); - $events[] = [ - 'event_id' => $date->getSingleDateID(), - 'start' => $date->getStartTime(), - 'end' => $date->getEndTime(), - 'title' => $date->toString(), - 'description' => implode(', ', $issue_titles), - 'categories' => $date->getTypeName() ?: '', - 'room' => $room ?: '', - 'deleted' => $date->isExTermin(), - 'canceled' => $date->isHoliday() ?: false, - ]; - } - - $this->etag(md5(serialize($events))); - - return $this->paginated($events, $total, compact('course_id')); - } - - private static function getRoomForSingleDate($val) { - - /* css-Klasse auswählen, sowie Template-Feld für den Raum mit Text füllen */ - if (Config::get()->RESOURCES_ENABLE) { - - if ($val->getResourceID()) { - $resObj = Resource::find($val->getResourceID()); - if ($resObj) { - $room_object = $resObj->getDerivedClassInstance(); - if ($room_object instanceof Room) { - $room = _("Raum: "); - $room .= $room_object->getActionURL('booking_plan'); - } - } - } else { - $room = _("keine Raumangabe"); - - if ($val->isExTermin()) { - if ($name = $val->isHoliday()) { - $room = '('.$name.')'; - } else { - $room = '('._('fällt aus').')'; - } - } - - else { - if ($val->getFreeRoomText()) { - $room = '('.htmlReady($val->getFreeRoomText()).')'; - } - } - } - } else { - $room = ''; - if ($val->getFreeRoomText()) { - $room = '('.htmlReady($val->getFreeRoomText()).')'; - } - } - - return html_entity_decode(strip_tags($room)); - } - -} diff --git a/app/routes/Feedback.php b/app/routes/Feedback.php deleted file mode 100644 index 9a28347..0000000 --- a/app/routes/Feedback.php +++ /dev/null @@ -1,271 +0,0 @@ -<?php - -namespace RESTAPI\Routes; - -/** - * @author Nils Gehrke <nils.gehrke@uni-goettingen.de> - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition feedback_id ^\d*$ - * @condition course_id ^[a-f0-9]{32}$ - * - */ -class Feedback extends \RESTAPI\RouteMap -{ - /** - * Create feedback element for a range - * - * @post /feedback/range/:range_id/:range_type - * - */ - public function createFeedbackElement($range_id, $range_type) - { - $course_id = $range_type::find($range_id)->getRangeCourseId(); - if (!\Feedback::hasRangeAccess($range_id, $range_type) || !\Feedback::hasCreatePerm($course_id)) { - $this->error(403); - } - $feedback = \FeedbackElement::build([ - 'range_id' => $range_id, - 'range_type' => $range_type, - 'user_id' => $GLOBALS['user']->id, - 'course_id' => $course_id, - 'question' => $this->data['question'], - 'description' => $this->data['description'], - 'results_visible' => intval($this->data['results_visible']), - 'commentable' => intval($this->data['commentable']), - 'mode' => $this->data['mode'] - ]); - $feedback->store(); - return $feedback->toArray(); - } - - /** - * Get a feedback element - * - * @get /feedback/:feedback_id - * - */ - public function getFeedbackElement($feedback_id) - { - if (!$feedback = \FeedbackElement::find($feedback_id)) { - $this->error(404); - } - if (!\Feedback::hasRangeAccess($feedback->range_id, $feedback->range_type)) { - $this->error(403); - } - return $feedback->toArray(); - } - - - /** - * Get all entries of a feedback element - * - * @get /feedback/:feedback_id/entries - * - */ - public function getFeedbackEntries($feedback_id) - { - if (!$feedback = \FeedbackElement::find($feedback_id)) { - $this->error(404); - } - if (!\Feedback::hasRangeAccess($feedback->range_id, $feedback->range_type)) { - $this->error(403); - } - if ($feedback->results_visible == 1 && !$feedback->isFeedbackable()) { - foreach($feedback->entries as $entry) { - $result['entries'][] = $entry->toArray(); - } - } elseif (!$feedback->isFeedbackable()) { - $result['entries'][] = $feedback->getOwnEntry()->toArray(); - } else { - $result = []; - } - - return $result; - } - - /** - * Edit a feedback element - * - * @put /feedback/:feedback_id - * - */ - public function editFeedbackElement($feedback_id) - { - if (!$feedback = \FeedbackElement::find($feedback_id)) { - $this->error(404); - } - $course_id = $feedback->course_id; - if (!\Feedback::hasRangeAccess($feedback->range_id, $feedback->range_type) || !\Feedback::hasAdminPerm($course_id)) { - $this->error(403); - } - $feedback->question = $this->data['question'] !== null ? $this->data['question'] : $feedback->question; - $feedback->description = $this->data['description'] !== null ? $this->data['description'] : $feedback->description; - $feedback->results_visible = $this->data['results_visible'] !== null ? - intval($this->data['results_visible']) : $feedback->results_visible; - $feedback->store(); - return $feedback->toArray(); - } - - /** - * Delete a feedback element - * - * @delete /feedback/:feedback_id - * - */ - public function deleteFeedbackElement($feedback_id) - { - if (!$feedback = \FeedbackElement::find($feedback_id)) { - $this->error(404); - } - $course_id = $feedback->course_id; - if (!\Feedback::hasRangeAccess($feedback->range_id, $feedback->range_type) || !\Feedback::hasAdminPerm($course_id)) { - $this->error(403); - } - $feedback->delete(); - $this->halt(200); - } - - /** - * List all feedback elements for a range - * - * @get /feedback/range/:range_id/:range_type - * - * @param string $range_id - * @param string $range_type - */ - public function getFeedbackElementsForRange($range_id, $range_type) - { - if (!\Feedback::hasRangeAccess($range_id, $range_type)) { - $this->error(403, 'You may not access the given range object.'); - } - $feedback_elements = \FeedbackElement::findBySQL('range_id = ? AND range_type = ? ORDER BY mkdate DESC', [$range_id, $range_type]); - foreach($feedback_elements as $feedback) { - $result['feedback_elements'][] = $feedback->toArray(); - } - return $result; - } - - /** - * List all feedback elements of a course - * - * @get /course/:course_id/feedback - * - */ - public function getFeedbackElementsForCourse($course_id) - { - if (!\Feedback::hasAdminPerm($course_id)) { - $this->error(403, 'You may not list all feedback elements of the course. Only feedback admins can.'); - } - $feedback_elements = \FeedbackElement::findBySQL('course_id = ? ORDER BY mkdate DESC', [$course_id]); - foreach($feedback_elements as $feedback) { - $result['feedback_elements'][] = $feedback->toArray(); - } - return $result; - } - - /** - * add an entry for a feedback element - * - * @post /feedback/:feedback_id/entry - * - */ - public function addFeedbackEntry($feedback_id) - { - if (!$feedback = \FeedbackElement::find($feedback_id)) { - $this->error(404); - } - if (!$feedback->isFeedbackable()) { - $this->error(403, 'You may not add an entry here. Maybe you have already given feedback or you are the author of the feedback element.'); - } - $entry = \FeedbackEntry::build([ - 'feedback_id' => $feedback->id, - 'user_id' => $GLOBALS['user']->id - ]); - - $entry->rating = $this->getRating( - $feedback->mode, - (int) $this->data['rating'] - ); - - if ($feedback->commentable) { - $entry->comment = $this->data['comment']; - } - - $entry->store(); - return $entry->toArray(); - } - - /** - * edit an entry of a feedback element - * - * @put /feedback/entry/:entry_id - * - */ - public function editFeedbackEntry($entry_id) - { - $entry = \FeedbackEntry::find($entry_id); - - if (!$entry) { - $this->notFound(); - } - - if (!$entry->isEditable()) { - $this->error(403); - } - - $entry->rating = $this->getRating( - $entry->feedback->mode, - (int) $this->data['rating'] - ); - - if ($entry->feedback->commentable) { - $entry->comment = $this->data['comment'] ?? $entry->comment; - } - - $entry->store(); - return $entry->toArray(); - } - - /** - * delete an entry of a feedback element - * - * @delete /feedback/entry/:entry_id - * - */ - public function deleteFeedbackEntry($entry_id) - { - if (!$entry = \FeedbackEntry::find($entry_id)) { - $this->error(404); - } - if ($entry->delete()){ - $this->halt(200); - } - } - - /** - * @param int $mode - * @param int $rating - * @return int - */ - private function getRating(int $mode, int $rating): int - { - if ($mode === 0) { - return 0; - } - - if ($rating === 0) { - return 1; - } - - if ($mode === 1) { - return min(5, $rating); - } - - if ($mode === 2) { - return min(10, $rating); - } - - throw new \InvalidArgumentException("Invalid mode {$mode}"); - } -} diff --git a/app/routes/FileSystem.php b/app/routes/FileSystem.php deleted file mode 100644 index 9abd713..0000000 --- a/app/routes/FileSystem.php +++ /dev/null @@ -1,684 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * This class implements REST routes for the new Stud.IP file system. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @license GNU General Public License Version 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * Partially based upon the Files.php source code from Jan-Hendrik Willms - * (tleilax+studip@gmail.com) and mluzena@uos.de which is also - * licensed under the terms of the GNU General Public License Version 2 - * or later. - */ - -class FileSystem extends \RESTAPI\RouteMap -{ - // FILE REFERENCE AND FILE ROUTES: - - /** - * Get a file reference object (metadata) - * @get /file/:file_ref_id - */ - public function getFileRef($file_ref_id) - { - return $this->filerefToJSON( - $this->requireFileRef($file_ref_id), - (bool) \Request::int('extended') - ); - } - - /** - * Get the data of a file by the ID of an associated FileRef object - * - * @get /file/:file_ref_id/download - */ - public function getFileRefData($file_ref_id) - { - $file_ref = $this->requireFileRef($file_ref_id); - - // check if the current user has the permissions to read this file reference: - $user = \User::findCurrent(); - if (!$file_ref->folder->getTypedFolder()->isFileDownloadable($file_ref_id, $user->id)) { - $this->error(403, "You may not download the file reference with the id {$file_ref_id}"); - } - - // check if file exists: - if (!$file_ref->file) { - $this->error(500, 'File reference has no associated file object!'); - } - - $data_path = $file_ref->file->getPath(); - if (!file_exists($data_path)) { - $this->error(500, "File was not found in the operating system's file system!"); - } - - $this->lastModified($file_ref->file->chdate); - $this->sendFile($data_path, ['filename' => $file_ref->name]); - } - - /** - * Update file data using a FileReference to it. - * - * @post /file/:file_ref_id/update - */ - public function updateFileData($file_ref_id) - { - // We only update the first file: - $uploaded_file = array_shift($this->data['_FILES']); - - // FileManager::updateFileRef handles the whole file upload - // and does all the necessary security checks: - $result = \FileManager::updateFileRef( - $this->requireFileRef($file_ref_id), - \User::findCurrent(), - $uploaded_file, - true, - false - ); - - if (!$result instanceof \FileRef) { - $this->error(500, 'Error while updating a file reference: ' . implode(' ', $result)); - } - - return $this->filerefToJSON($result); - } - - /** - * Edit a file reference. - * - * @put /file/:file_ref_id - */ - public function editFileRef($file_ref_id) - { - $result = \FileManager::editFileRef( - $this->requireFileRef($file_ref_id), - \User::findCurrent(), - $this->data['name'], - $this->data['description'], - $this->data['content_term_of_use_id'], - $this->data['license'] - ); - - if (!$result instanceof \FileRef) { - $this->error(500, 'Error while editing a file reference: ' . implode(' ', $result)); - } - - return $this->filerefToJSON($result); - } - - /** - * Copies a file reference. - * - * @post /file/:file_ref_id/copy/:destination_folder_id - */ - public function copyFileRef($file_ref_id, $destination_folder_id) - { - $result = \FileManager::copyFile( - $this->requireFileRef($file_ref_id)->getFileType(), - $this->requireFolder($destination_folder_id)->getTypedFolder(), - \User::findCurrent() - ); - - if (!($result instanceof \FileType)) { - $this->error(500, 'Error while copying a file reference: ' . implode(' ', $result)); - } - - return $this->filerefToJSON($result->getFileRef()); - } - - /** - * Moves a file reference. - * - * @post /file/:file_ref_id/move/:destination_folder_id - */ - public function moveFileRef($file_ref_id, $destination_folder_id) - { - $result = \FileManager::moveFile( - $this->requireFileRef($file_ref_id)->getFileType(), - $this->requireFolder($destination_folder_id)->getTypedFolder(), - \User::findCurrent() - ); - - if (!($result instanceof \FileType)) { - $this->error(500, 'Error while moving a file reference: ' . implode(' ', $result)); - } - - return $this->filerefToJSON($result->getFileRef()); - } - - /** - * Deletes a file reference. - * - * @delete /file/:file_ref_id - */ - public function deleteFileRef($file_ref_id) - { - $result = \FileManager::deleteFileRef( - $this->requireFileRef($file_ref_id), - \User::findCurrent() - ); - - if (!$result instanceof \FileRef) { - $this->error(500, 'Error while deleting a file reference: ' . implode(' ', $result)); - } - - $this->halt(200); - } - - /** - * Upload file to given folder. - * file data has to be attached as multipart/form-data - * - * @post /file/:folder_id - */ - public function uploadFile($folder_id) - { - $typed_folder = $this->requireFolder($folder_id)->getTypedFolder(); - if (isset($this->data['_FILES'])) { - $file_data = array_map(function ($a) { - return is_array($a) ? $a : [$a]; - }, array_shift($this->data['_FILES'])); - } - if (is_array($file_data)) { - $validated_files = \FileManager::handleFileUpload( - $file_data, - $typed_folder, - $this->requireUser()->id - ); - - if (count($validated_files['error']) > 0) { - $this->error(500, 'Error while uploading files: ' . implode(' ', $validated_files['error'])); - } - - $uploaded_files = \SimpleCollection::createFromArray($validated_files['files']); - $default_license = \ContentTermsOfUse::findDefault(); - $uploaded_files->setValue('content_terms_of_use_id', $default_license->id); - $uploaded_files->store(); - if (count($uploaded_files) === 1) { - $result = $this->filerefToJSON($uploaded_files->first()); - } else { - $result = $uploaded_files->map(function ($f) { - return $this->filerefToJSON($f); - }); - } - $this->halt(201, [], $result); - } else { - $this->error(400, 'No files found in request.'); - } - } - - // FOLDER ROUTES: - - /** - * Returns a list of defined folder types, separated by range type. - * @get /studip/file_system/folder_types - */ - public function getDefinedFolderTypes() - { - return \FileManager::getFolderTypes(); - } - - /** - * Get a folder object with its file references, subdirectories and the permissions for the user who has made the API call. - * @get /folder/:folder_id - */ - public function getFolder($folder_id) - { - return $this->folderToJSON( - $this->requireFolder($folder_id), - true - ); - } - - /** - * Creates a new folder inside of another folder and returns the new object on success. - * @post /folder/:parent_folder_id/new_folder - */ - public function createNewFolder($parent_folder_id) - { - $user = \User::findCurrent(); - $parent = $this->requireTypedFolder($parent_folder_id); - - if (!$parent->isWritable($user->id)) { - $this->error(403, 'You are not permitted to create a subfolder in the parent folder!'); - } - - $result = \FileManager::createSubFolder( - $parent, - $user, - 'StandardFolder', //to be extended - $this->data['name'], - $this->data['description'] - ); - - if (!$result instanceof \FolderType) { - $this->error(500, 'Error while creating a folder: ' . implode(' ', $result)); - } - - return $this->folderToJSON( - $this->requireFolder($result->getId()) - ); - } - - /** - * Get a list with all FileRef objects of a folder. - * @get /folder/:folder_id/files - */ - public function getFileRefsOfFolder($folder_id) - { - $folder = $this->requireFolder($folder_id); - - $query = "folder_id = :folder_id ORDER BY name ASC"; - $parameters[':folder_id'] = $folder->id; - - if ($this->limit || $this->offset) { - $query .= " LIMIT :limit OFFSET :offset"; - $parameters[':limit'] = $this->limit; - $parameters[':offset'] = $this->offset; - } - - $file_refs = \FileRef::findAndMapBySql(function (\FileRef $ref) { - return $this->filerefToJSON($ref); - }, $query, $parameters); - - return $this->paginated( - $file_refs, - \FileRef::countByFolder_id($folder->id), - ['folder_id' => $folder->id] - ); - } - - - /** - * Get a list with all FileRef objects of a folder. - * @get /folder/:folder_id/subfolders - */ - public function getSubfoldersOfFolder($folder_id) - { - $user = $this->requireUser(); - $folder = $this->requireFolder($folder_id); - - $query = "parent_id = :parent_id ORDER BY name ASC"; - $parameters = [':parent_id' => $folder->id]; - - if ($this->limit || $this->offset) { - $query .= " LIMIT :limit OFFSET :offset"; - $parameters[':limit'] = $this->limit; - $parameters[':offset'] = $this->offset; - } - - $subfolders = \Folder::findAndMapBySql(function (\Folder $subfolder) use ($user) { - $type = $subfolder->getTypedFolder(); - if (!$type || !$type->isVisible($user->id)) { - return false; - } - return $this->folderToJSON($subfolder); - }, $query, $parameters); - - return $this->paginated( - array_filter($subfolders), - \Folder::countByParent_id($folder_id), - ['folder_id' => $folder_id] - ); - } - - /** - * Get a list with permissions the current user has for a folder. - * @get /folder/:folder_id/permissions - */ - public function getFolderPermissions($folder_id) - { - $user = $this->requireUser(); - $folder = $this->requireFolder($folder_id); - - // read permissions of the user and return them: - return array_merge([ - 'folder_id' => $folder->id, - 'user_id' => $user->id, - ], $this->folderPermissionsToJSON($folder)); - } - - /** - * Allows editing the name or the description (or both) of a folder. - * - * @put /folder/:folder_id - */ - public function editFolder($folder_id) - { - if (isset($this->data['name']) && !$this->data['name']) { - $this->error(400, "The name for the folder with the id {$folder_id} must not be empty!"); - } - - $user = $this->requireUser(); - $typed_folder = $this->requireTypedFolder($folder_id); - - if (!$typed_folder->isEditable($user->id)) { - $this->error(403, "You may not edit the folder with id {$folder_id}!"); - } - - if (!$typed_folder instanceof \StandardFolder) { - $this->error(501, "Editing is only allowed for folders of type StandardFolder for now!"); - } - - if ($this->data['name']) { - $typed_folder->name = $this->data['name']; - } - if (isset($this->data['description'])) { - $typed_folder->description = $this->data['description'] ?: ''; - } - - if (!$typed_folder->store()) { - $this->error(500, "Could not store folder with id {$folder_id}!"); - } - - return $this->folderToJSON( - $this->requireFolder($folder_id) - ); - } - - /** - * Copies a folder into another folder. - * - * @post /folder/:folder_id/copy/:destination_folder_id - */ - public function copyFolder($folder_id, $destination_folder_id) - { - $result = \FileManager::copyFolder( - $this->requireTypedFolder($folder_id), - $this->requireTypedFolder($destination_folder_id), - \User::findCurrent() - ); - - if (!$result instanceof \FolderType) { - $this->error(500, 'Error while copying a folder: ' . implode(' ', $result)); - } - - return $this->folderToJSON( - $this->requireFolder($result->getId()) - ); - } - - - /** - * Move a folder into another folder. - * @post /folder/:folder_id/move/:destination_folder_id - */ - public function moveFolder($folder_id, $destination_folder_id) - { - $result = \FileManager::moveFolder( - $this->requireTypedFolder($folder_id), - $this->requireTypedFolder($destination_folder_id), - \User::findCurrent() - ); - - if (!$result instanceof \FolderType) { - $this->error(500, 'Error while moving a folder: ' . implode(' ', $result)); - } - - return $this->folderToJSON( - $this->requireFolder($folder_id) - ); - } - - - /** - * Deletes a folder. - * - * @delete /folder/:folder_id - */ - public function deleteFolder($folder_id) - { - $result = \FileManager::deleteFolder( - $this->requireTypedFolder($folder_id), - \User::findCurrent() - ); - - if (!$result instanceof \FolderType) { - $this->error(500, 'Error while deleting a folder: ' . implode(' ', $result)); - } - - $this->halt(200); - } - - // RELATED OBJECT ROUTES: - - /** - * Get a collection of all ContentTermsOfUse objects - * - * @get /studip/content_terms_of_use_list - */ - public function getContentTermsOfUseList() - { - $objects = \ContentTermsOfUse::findBySql( - '1 ORDER BY name ASC LIMIT :limit OFFSET :offset', - ['limit' => $this->limit, 'offset' => $this->offset] - ); - - return $this->paginated( - array_map([$this, 'termsOfUseToJSON'], $objects), - \ContentTermsOfUse::countBySql('1') - ); - } - - // UTILITY METHODS - - /** - * Requires a valid user object. - * @return \User object - */ - private function requireUser() - { - return \User::findCurrent(); - } - - /** - * Requires a valid file reference object - * @param mixed $id_or_object Either a file reference id or object - * @return \FileRef object - */ - private function requireFileRef($id_or_object) - { - if ($id_or_object instanceof \FileRef) { - $file_ref = $id_or_object; - } else { - //check if the file_id references a file reference object: - $file_ref = \FileRef::find($id_or_object); - if (!$file_ref) { - $this->notFound("File reference with id {$id_or_object} not found!"); - } - } - - // check if the file reference is placed inside a folder. - // (must be present to check for permissions) - if (!$file_ref->folder) { - $this->error(500, "File reference with id {$file_ref->id} has no folder!"); - } - - $typed_folder = $file_ref->folder->getTypedFolder(); - if (!$typed_folder) { - $this->error(500, "The folder of file reference with id {$file_ref->id} has no folder type!"); - } - - //check if the current user has the permissions to read this file reference: - if (!$typed_folder->isReadable($this->requireUser()->id)) { - $this->error(403, "You are not permitted to read the file reference with id {$file_ref->id}!"); - } - - return $file_ref; - } - - /** - * Converts a file reference object to JSON. - * @param \FileRef $ref File reference object - * @param boolean $extended Extended output? (includes folder, owner and terms of use) - * @return array representation for json encoding - */ - private function filerefToJSON(\FileRef $ref, $extended = false) - { - $user = $this->requireUser(); - $typed_folder = $ref->folder->getTypedFolder(); - $filetype = $ref->getFileType(); - - $result = array_merge($ref->toRawArray(), [ - 'size' => (int) $ref->file->size, - 'mime_type' => $ref->file->mime_type, - 'storage' => $ref->file->filetype === "URLFile" ? "url" : "disk", - - 'is_readable' => $typed_folder->isReadable($user->id), - 'is_downloadable' => $filetype->isDownloadable($user->id), - 'is_editable' => $filetype->isEditable($user->id), - 'is_writable' => $filetype->isWritable($user->id), - ]); - - $result['downloads'] = (int) $result['downloads']; - $result['mkdate'] = (int) $result['mkdate']; - $result['chdate'] = (int) $result['chdate']; - - if ($result['storage'] === 'url') { - $result['url'] = $ref->getFileType()->getDownloadURL(); - } - - if ($extended) { - //folder does exist (since we checked for its existence above) - $result['folder'] = $this->folderToJSON($ref->folder); - - if ($ref->owner) { - $result['owner'] = User::getMiniUser($this, $ref->owner); - } - - //$result['license'] = $file_ref->license; //to be activated when licenses are defined - - if ($ref->terms_of_use) { - $result['terms_of_use'] = $this->termsOfUseToJSON($ref->terms_of_use); - } - } - - return $result; - } - - /** - * Requires a valid folder object - * @param mixed $id_or_object Either a folder id or object - * @return Folder object - */ - private function requireFolder($id_or_object) - { - if ($id_or_object instanceof \Folder) { - $folder = $id_or_object; - } else { - $folder = \Folder::find($id_or_object); - if (!$folder) { - $this->notFound("Folder with id {$id_or_object} not found!"); - } - } - - $typed_folder = $folder->getTypedFolder(); - if (!$typed_folder) { - $this->error(500, "Cannot find folder type of folder with id {$folder->id}!"); - return; - } - - if (!$typed_folder->isReadable($this->requireUser()->id)) { - $this->error(403, "You are not allowed to read the contents of the folder with the id {$folder->id}!"); - } - - return $folder; - } - - /** - * Requires a valid typed folder object - * @param mixed $id_or_object Either a folder id or object - * @return FolderType instance - */ - private function requireTypedFolder($id_or_object) - { - return $this->requireFolder($id_or_object)->getTypedFolder(); - } - - /** - * Converts a given folder to JSON. - * @param Folder $folder Folder object - * @param boolean $extended Extended output? (includes subfolders and file references) - * @return array representation for json encoding - */ - private function folderToJSON(\Folder $folder, $extended = false) - { - $result = $this->folderPermissionsToJSON($folder); - - if ($result['is_readable']) { - $result = array_merge($folder->toRawArray(), $result); - - $result['mkdate'] = (int) $result['mkdate']; - $result['chdate'] = (int) $result['chdate']; - - //The field "data_content" must be handled differently - //than the other fields since it contains JSON data. - $data_content = json_decode($folder->data_content); - $result['data_content'] = $data_content; - - if ($extended) { - $user = $this->requireUser(); - - $result['subfolders'] = []; - foreach ($folder->subfolders as $subfolder) { - if (!$subfolder->getTypedFolder()->isVisible($user->id)) { - continue; - } - $result['subfolders'][] = $this->folderToJSON($subfolder); - } - - $result['file_refs'] = []; - foreach ($folder->getTypedFolder()->getFiles() as $file) { - if (method_exists($file,"getFileRef")) { - $result['file_refs'][] = $this->filerefToJSON( - $file->getFileRef() - ); - } - } - } - } - - return $result; - } - - /** - * Converts permissions of a folder to JSON. - * @param Folder $folder Folder object - * @param User $user User object to check permissions against - * @return array representation for json encoding - */ - private function folderPermissionsToJSON(\Folder $folder) - { - $user = $this->requireUser(); - $type = $folder = $folder->getTypedFolder(); - if (!$type) { - $this->error(500, 'Folder type not found!'); - } - - return [ - 'is_visible' => $type->isVisible($user->id), - 'is_readable' => $type->isReadable($user->id), - 'is_writable' => $type->isWritable($user->id), - ]; - } - - /** - * Converts a terms of use object to JSON. - * @param ContentTermsOfUse $object Object - * @return array representation for json encoding - */ - private function termsOfUseToJSON(\ContentTermsOfUse $object) - { - $result = $object->toRawArray(); - - $result['is_default'] = (bool) $result['is_default']; - - $result['mkdate'] = (int) $result['mkdate']; - $result['chdate'] = (int) $result['chdate']; - - return $result; - } -} diff --git a/app/routes/Forum.php b/app/routes/Forum.php deleted file mode 100644 index 35aad91..0000000 --- a/app/routes/Forum.php +++ /dev/null @@ -1,419 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition course_id ^[a-f0-9]{1,32}$ - */ -class Forum extends \RESTAPI\RouteMap -{ - /** - * List all categories of a forum - * - * @get /course/:course_id/forum_categories - */ - public function getForumCategories($course_id) - { - if (!\ForumPerm::has('view', $course_id)) { - $this->error(401); - } - - $categories = \ForumCat::findBySeminar_id($course_id, 'ORDER BY pos ASC'); - $total = sizeof($categories); - $categories = array_splice($categories, (int)$this->offset, (int)$this->limit ?: 10); - - $json = []; - foreach ($categories as $cat) { - $json_cat = $cat->toArray(); - $uri = $this->urlf('/forum_category/%s', [htmlReady($json_cat['category_id'])]); - $json_cat['course_id'] = $json_cat['seminar_id']; - $json[$uri] = $this->categoryToJson($json_cat); - } - - $this->etag(md5(serialize($json))); - - return $this->paginated($json, $total, compact('course_id')); - } - - /** - * Create a new category - * - * @post /course/:course_id/forum_categories - */ - public function createForumCategory($course_id) - { - if (!\ForumPerm::has("add_category", $course_id)) { - $this->error(401); - } - - if (!isset($this->data['name']) || !mb_strlen($name = trim($this->data['name']))) { - $this->error(400, 'Category name required.'); - } - - $category_id = \ForumCat::add($course_id, $name); - if (!$category_id) { - $this->error(500, 'Error creating the forum category.'); - } - - $this->redirect('forum_category/' . $category_id, 201, 'ok'); - } - - /** - * Read a category - * - * @get /forum_category/:category_id - */ - public function getForumCategory($category_id) - { - $category = $this->findCategory($category_id); - $cid = $category['course_id']; - - if (!\ForumPerm::has('view', $cid)) { - $this->error(401); - } - - $category_json = $this->categoryToJson($category); - $this->etag(md5(serialize($category_json))); - return $category_json; - } - - /** - * Update a category - * - * @put /forum_category/:category_id - */ - public function updateForumCategory($category_id) - { - $category = $this->findCategory($category_id); - - if (!\ForumPerm::has("edit_category", $category['course_id'])) { - $this->error(401); - } - - if (!isset($this->data['name']) || !mb_strlen($name = trim($this->data['name']))) { - $this->error(400, 'Category name required.'); - } - - \ForumCat::setName($category_id, $this->data['name']); - - $this->status(204); - } - - /** - * Delete a category - * - * @delete /forum_category/:category_id - */ - public function deleteForumCategory($category_id) - { - $category = $this->findCategory($category_id); - $cid = $category['course_id']; - - if (!\ForumPerm::has("remove_category", $cid)) { - $this->error(401); - } - - \ForumCat::remove($category_id, $cid); - - $this->status(204); - } - - /** - * Show entries of a category - * - * @get /forum_category/:category_id/areas - */ - public function getCategoryEntries($category_id) - { - $category = $this->findCategory($category_id); - - if (!\ForumPerm::has('view', $category['course_id'])) { - $this->error(401); - } - - $areas = $this->getAreas($category_id, $this->offset, $this->limit); - - $this->etag(md5(serialize($areas))); - return $this->paginated($areas, $this->countAreas($category_id), compact('category_id')); - } - - - - /** - * Add a new forum entry to an existing one - * - * @post /forum_category/:category_id/areas - */ - public function appendForumEntry($category_id) - { - $category = $this->findCategory($category_id); - $cid = $category['course_id']; - - if (!\ForumPerm::has('add_area', $cid)) { - $this->error(401); - } - - if (!isset($this->data['subject']) || !mb_strlen($subject = trim($this->data['subject']))) { - $this->error(400, 'Subject required.'); - } - - if (!isset($this->data['content'])) { - $this->error(400, 'Content required.'); - } - $content = trim($this->data['content']); - - $anonymous = isset($this->data['anonymous']) ? intval($this->data['anonymous']) : 0; - - $entry_id = $this->createEntry($cid, $cid, $subject, $content, $anonymous); - - \ForumCat::addArea($category_id, $entry_id); - - $this->redirect('forum_entry/' . $entry_id, 201, "ok"); - } - - /** - * Get a forum entry - * - * @get /forum_entry/:entry_id - */ - public function getForumEntry($entry_id) - { - $entry = \ForumEntry::getConstraints($entry_id); - $cid = $entry['seminar_id']; - - if (!\ForumPerm::has('view', $cid)) { - $this->error(401); - } - - $entry = $this->findEntry($entry_id); - $this->lastmodified($entry->chdate); - $this->etag(md5(serialize($entry))); - return $entry; - } - - /** - * Add a new forum entry to an existing one - * - * @post /forum_entry/:entry_id - */ - public function addForumEntry($parent_id) - { - $parent = \ForumEntry::getConstraints($parent_id); - $cid = $parent['seminar_id']; - - $perm = self::isArea($parent) ? 'add_area' : 'add_entry'; - - if (!\ForumPerm::has($perm, $cid)) { - $this->error(401); - } - - $subject = (string) trim($this->data['subject']); - $content = (string) trim($this->data['content']); - - // areas and threads need a subject, postings do not - if ($parent['depth'] < 3 && !$subject) { - $this->error(400, 'Subject required.'); - } - - // all entries besides the area need content - if ($parent['depth'] > 1 && !$content) { - $this->error(400, 'Content required.'); - } - - if ($parent['depth'] >= 3 && $subject) { - $this->error(400, 'Must not have subject here.'); - } - - $anonymous = isset($this->data['anonymous']) ? (int) $this->data['anonymous'] : 0; - - $entry_id = $this->createEntry($parent_id, $cid, $subject, $content, $anonymous); - - $this->redirect('forum_entry/' . $entry_id, 201, "ok"); - } - - /** - * Update an existing one forum entry - * - * @put /forum_entry/:entry_id - */ - public function updateForumEntry($entry_id) - { - $entry = \ForumEntry::getConstraints($entry_id); - $cid = $entry['seminar_id']; - - $perm = self::isArea($entry) ? 'edit_area' : 'edit_entry'; - - if (!\ForumPerm::hasEditPerms($entry_id) || !\ForumPerm::has($perm, $cid)) { - $this->error(401); - } - - $subject = (string) trim($this->data['subject']); - $content = (string) trim($this->data['content']); - - // areas and threads need a subject, postings do not - if ($entry['depth'] < 3 && !$subject) { - $this->error(400, 'Subject required.'); - } - - // all entries besides the area need content - if ($entry['depth'] > 1 && !$content) { - $this->error(400, 'Content required.'); - } - - if ($entry['depth'] >= 3 && $subject) { - $this->error(400, 'Must not have subject here.'); - } - - \ForumEntry::update($entry_id, $subject, $content); - - $this->status(204); - } - - /** - * Delete an entry - * - * @delete /forum_entry/:entry_id - */ - public function deleteForumEntry($entry_id) - { - $entry = \ForumEntry::getConstraints($entry_id); - $cid = $entry['seminar_id']; - - if (!\ForumPerm::hasEditPerms($entry_id) || !\ForumPerm::has('remove_entry', $cid)) { - $this->error(401); - } - - \ForumEntry::delete($entry_id); - - $this->status(204); - } - - /********************* - * * - * PRIVATE FUNCTIONS * - * * - *********************/ - - - private function findEntry($entry_id) - { - $raw = \ForumEntry::getConstraints($entry_id); - if ($raw === false) { - $this->notFound(); - } - - $entry = $this->convertEntry($raw); - - $children = \ForumEntry::getEntries($entry_id, \ForumEntry::WITHOUT_CHILDS, '', 'ASC', 0, false); - - if (isset($children['list'][$entry_id])) { - unset($children['list'][$entry_id]); - } - - $entry['children'] = []; - foreach (array_values($children['list']) as $childentry) { - $entry['children'][] = $this->convertEntry($childentry); - } - - return $entry; - } - - public function convertEntry($raw) - { - $entry = []; - foreach(words("topic_id mkdate chdate anonymous depth") as $key) { - $entry[$key] = $raw[$key]; - } - - $hide_user = $entry['anonymous'] && $raw['user_id'] !== $GLOBALS['user']->id; - - $entry['subject'] = $raw['name']; - $entry['user'] = $hide_user ? null : $this->urlf('/user/%s', [$raw['user_id']]); - $entry['course'] = $this->urlf('/course/%s', [$raw['seminar_id']]); - $entry['content_html'] = \ForumEntry::getContentAsHtml($raw['content']); - $entry['content'] = \ForumEntry::killEdit($raw['content']); - - return $entry; - } - - - private static function isArea($entry) - { - return 1 === $entry['depth']; - } - - private function createEntry($parent_id, $course_id, $subject, $content, $anonymous) - { - $topic_id = self::generateID(); - - $data = [ - 'topic_id' => $topic_id, - 'seminar_id' => $course_id, - 'user_id' => $GLOBALS['user']->id, - 'name' => $subject, - 'content' => $content, - 'author' => $GLOBALS['user']->getFullName(), - 'author_host' => $_SERVER['REMOTE_ADDR'], - 'anonymous' => (int) $anonymous - ]; - \ForumEntry::insert($data, $parent_id); - - return $topic_id; - } - - private function findCategory($category_id) - { - $result = []; - - if ($cat = \ForumCat::get($category_id)) { - $result = $cat; - $result['course_id'] = $cat['seminar_id']; - $result['name'] = $cat['entry_name']; - } else { - $this->error(404); - } - - return $result; - } - - private function categoryToJson($category) - { - $json = $category; - - $json['course'] = $this->urlf('/course/%s', [htmlReady($json['course_id'])]); - unset($json['course_id']); - - $json['areas'] = $this->urlf('/forum_category/%s/areas', [$json['category_id']]); - $json['areas_count'] = $this->countAreas($json['category_id']); - - return $json; - } - - private function countAreas($category_id) - { - return sizeof(\ForumCat::getAreas($category_id)); - } - - private function getAreas($category_id, $offset = 0, $limit = 10) - { - $offset = (int) $offset; - $limit = (int) $limit; - - $areas = []; - - foreach (\ForumCat::getAreas($category_id, $offset, $limit) as $area) { - $url = $this->urlf('/forum_entry/%s', [htmlReady($area['topic_id'])]); - $areas[$url] = $this->convertEntry($area); - } - - return $areas; - } - - private static function generateID() - { - return md5(uniqid(rand())); - } -} diff --git a/app/routes/Messages.php b/app/routes/Messages.php deleted file mode 100644 index db9cb2e..0000000 --- a/app/routes/Messages.php +++ /dev/null @@ -1,301 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition message_id ^[a-f0-9]{1,32}$ - * @condition user_id ^[a-f0-9]{1,32}$ - * @condition box ^(inbox|outbox)$ - */ -class Messages extends \RESTAPI\RouteMap -{ - /** - * Liefert die Anzahl der vorhandenen Nachrichten des autorisierten Nutzers - * zurück. Der Parameter bestimmt je nach Wert, auf welchen Bereich - * (Posteingang bzw. Postausgang) zugegriffen werden soll. - * Die Rückgabe beinhaltet jeweils die Anzahl aller Nachrichten sowie die - * Anzahl der ungelesenen Nachrichten. - * - * @head /user/:user_id/:box - */ - public function indexOfMessages($user_id, $box) - { - if ($user_id !== self::currentUser()) { - $this->error(401); - } - - $count = $this->countMessages($user_id, $box); - - $this->headers([ - 'X-Messages-Total' => $count['total'], - 'X-Messages-Unread' => $count['unread'], - ]); - - return null; - } - - /** - * Liefert die vorhandenen Nachrichten des autorisierten Nutzers zurück. - * - * @get /user/:user_id/:box - */ - public function getMessages($user_id, $box) - { - if ($user_id !== self::currentUser()) { - $this->error(401); - } - - $ids = $this->getMessageIds($user_id, $box); - $total = count($ids); - - $ids = array_slice($ids, $this->offset, $this->limit); - - $messages = []; - if (count($ids) > 0) { - \Message::findEachMany(function ($message) use (&$messages) { - $url = $this->urlf('/message/%s', $message->id); - $messages[$url] = $this->messageToJSON($message); - }, $ids, 'ORDER BY mkdate DESC'); - } - - return $this->paginated($messages, $total, compact('user_id', 'box')); - } - - /** - * Liefert die Daten der angegebenen Nachricht zurück. - * - * @get /message/:message_id - */ - public function showMessage($message_id) - { - $message = $this->requireMessage($message_id); - $message_json = $this->messageToJSON($message); - $this->etag(md5(serialize($message_json))); - return $message_json; - } - - - /** - * Get the root file folder of a message. The root file folder contains all - * files that were appended to the message. - * - * @get /message/:message_id/file_folder - */ - public function getTopFolder($message_id) - { - //first we check if the user exists: - $message = \Message::find($message_id); - - $user = \User::findCurrent(); - - if (!$user) { - $this->halt(404, 'User not found!'); - } - - if(!$message->permissionToRead($user->id)) { - $this->halt(403, 'You are not allowed to read this message or its appended files!'); - } - - //we can get the top folder: - $top_folder = \Folder::findTopFolder($message->id, 'message'); - - if($top_folder) { - $file_system_api = new FileSystem(); - return $file_system_api->getFolder($top_folder->id); - } else { - $this->halt(404, 'Folder not found!'); - } - } - - - /** - * Schreibt eine neue Nachricht. - * - * @post /messages - */ - public function createMessage() - { - if (!mb_strlen($subject = trim($this->data['subject'] ?: ''))) { - $this->error(400, 'No subject provided'); - } - - if (!mb_strlen($message = trim($this->data['message'] ?: ''))) { - $this->error(400, 'No message provided'); - } - - $recipients = (array) ($this->data['recipients'] ?: null); - if (!sizeof($recipients)) { - $this->error(400, 'No recipient(s) provided'); - } - - $usernames = array_map(function ($id) { $user = \User::find($id); return @$user['username']; }, $recipients); - - if (sizeof($usernames) !== sizeof(array_filter($usernames))) { - $this->error(400, "Some recipients do not exist."); - } - - $message = \Message::send($GLOBALS['user']->id, $usernames, $subject, $message); - if (!$message) { - $this->error(500, 'Could not create message'); - } - - $this->redirect('message/' . $message->id, 201, "ok"); - } - - - /** - * Eine Nachricht als (un)gelesen markieren. - * - * @put /message/:message_id - */ - public function updateMessage($message_id) - { - - $message = $this->requireMessage($message_id); - $user_id = $this->currentUser(); - - if (isset($this->data['unread'])) { - if ($this->data['unread']) { - $message->markAsUnread($user_id); - } else { - $message->markAsRead($user_id); - } - } - - $this->halt(204); - } - - /** - * Löscht eine Nachricht. - * - * @delete /message/:message_id - */ - public function destroyMessage($message_id) - { - $message = $this->requireMessage($message_id); - - $msgin = new \messaging(); - if (!$msgin->delete_message($message_id, self::currentUser(), true)) { - $this->error(500); - } - - $this->status(204); - } - - /**************************************************/ - /* PRIVATE HELPER METHODS */ - /**************************************************/ - - private static function currentUser() - { - return $GLOBALS['user']->id; - } - - private function requireMessage($message_id) - { - if (!$message = \Message::find($message_id)) { - $this->notFound("Message not found"); - } - - $current_user = self::currentUser(); - $message_user = $message->originator->user_id === $current_user - ? $message->originator - : $message->receivers->findOneBy('user_id', $current_user); - - if (!$message_user) { - $this->error(401); - } - - if ($message_user->deleted) { - $this->notFound("Message not found"); - } - - return $message; - } - - private function messageToJSON($message) - { - $user_id = self::currentUser(); - - $my_mu = $message->receivers->filter(function ($mu) use ($user_id) { - return $mu->user_id === $user_id; - }); - if ($message->originator->user_id === $user_id) { - $my_mu[] = $message->originator; - } - - $my_roles = [ - 'snd' => $message->autor_id === $user_id, - 'rec' => in_array('rec', $my_mu->pluck('snd_rec')), - ]; - - $json = $message->toArray(words('message_id subject message mkdate priority')); - - // formatted message - $json['message_html'] = formatReady($json['message']) ?: ''; - - // Tags - $json['tags'] = $message->getTags($user_id); - - // sender - $sender = $message->getSender(); - $json['sender'] = $this->urlf('/user/%s', [$message->author->id]); - - // recipients - if ($my_roles['snd']) { - $json['recipients'] = []; - foreach ($message->getRecipients() as $r) { - $json['recipients'][] = $this->urlf('/user/%s', [$r->user_id]); - } - } else { - $json['recipients'] = [$this->urlf('/user/%s', [$user_id])]; - } - - // attachments - if ($message->attachment_folder && count($message->attachment_folder->file_refs) > 0) { - $json['attachments'] = []; - foreach ($message->attachment_folder->file_refs as $ref) { - $json['attachments'][] = $this->urlf('/file/%s', [$ref->id]); - } - } - - // unread only if in inbox - if ($my_roles['rec']) { - foreach ($my_mu as $mu) { - if ($mu->snd_rec === 'rec') { - $json['unread'] = !$mu->readed; - break; - } - } - } - - return $json; - } - - private function countMessages($user_id, $box) - { - $condition = 'user_id = ? AND snd_rec = ? AND deleted = 0'; - $params = [$user_id, $box === 'inbox' ? 'rec' : 'snd']; - - $total = \MessageUser::countBySQL($condition, $params); - $unread = \MessageUser::countBySQL( - $condition . ' AND readed = 0', - $params - ); - - return compact('total', 'unread'); - } - - private function getMessageIds($user_id, $box) - { - return \MessageUser::findAndMapBySQL(function ($row) { - return $row->message_id; - }, 'user_id = ? AND snd_rec = ? AND deleted = 0 ORDER BY mkdate DESC', [ - $user_id, $box === 'inbox' ? 'rec' : 'snd' - ]); - } - -} diff --git a/app/routes/News.php b/app/routes/News.php deleted file mode 100644 index c9b258b..0000000 --- a/app/routes/News.php +++ /dev/null @@ -1,375 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition news_id ^[0-9a-f]{1,32}$ - * @condition course_id ^[0-9a-f]{1,32}$ - * @condition user_id ^[0-9a-f]{1,32}$ - * @condition comment_id ^[0-9a-f]{1,32}$ - */ -class News extends \RESTAPI\RouteMap -{ - public static function before() - { - require_once 'lib/models/StudipNews.class.php'; - } - - /** - * Globale News auslesen - * - * @get /studip/news - */ - public function getGlobalNews() - { - list($json, $total) = $this->getRangedNews('studip'); - - $this->etag(md5(serialize($json))); - return $this->paginated($json, $total); - } - - /** - * News einer Veranstaltung auslesen - * - * @get /course/:course_id/news - */ - public function getCourseNews($course_id) - { - list($json, $total) = $this->getRangedNews($course_id); - - $this->etag(md5(serialize($json))); - return $this->paginated($json, $total, compact('course_id')); - } - - /** - * News eines Nutzers auslesen - * - * @get /user/:user_id/news - */ - public function getUserNews($user_id) - { - list($json, $total) = $this->getRangedNews($user_id); - - $this->etag(md5(serialize($json))); - return $this->paginated($json, $total, compact('user_id')); - } - - - /** - * News auslesen - * - * @get /news/:news_id - */ - public function getNews($news_id) - { - $news = $this->requireNews($news_id); - $news_json = $this->newsToJson($news); - - $this->lastmodified($news->chdate); - $this->expires($news->expire); - $this->etag(md5(serialize($news_json))); - - return $news_json; - } - - /** - * News löschen - * - * @delete /news/:news_id - */ - public function destroyNews($news_id) - { - $news = $this->requireNews($news_id); - - if (!$news->havePermission('delete', '', $GLOBALS['user']->id)) { - $this->error(401); - } - - $news->delete(); - $this->status(204); - } - - - /** - * News updaten - * - * @put /news/:news_id - */ - public function updateNews($news_id) - { - $news = $this->requireNews($news_id); - if (!$news->havePermission('edit', '', $GLOBALS['user']->id)) { - $this->error(401); - } - - if (isset($this->data['topic'])) { - if (!mb_strlen(trim($topic = $this->data['topic']))) { - $this->error(400, 'Topic must not be empty.'); - } - $news->topic = $topic; - } - - if (isset($this->data['body'])) { - if (!mb_strlen(trim($body = $this->data['body']))) { - $this->error(400, 'Body must not be empty.'); - } - $news->body = $body; - } - - if (isset($this->data['expire'])) { - $news->expire = (int) $this->data['expire']; - } - - if (isset($this->data['allow_comments'])) { - $news->allow_comments = (int) $this->data['allow_comments']; - } - - $news->chdate_uid = $GLOBALS['user']->id; - - if (!$news->store()) { - $this->error(500, 'Could not update news'); - - } - $this->status(204); - } - - /** - * News anlegen - * - * @post /course/:course_id/news - * @post /user/:user_id/news - * @post /studip/news - */ - public function createNews($range_id = 'studip') - { - - if (!\StudipNews::haveRangePermission('edit', $range_id, $GLOBALS['user']->id)) { - $this->error(401, "Not authorized to create a news here."); - } - - $news = new \StudipNews(); - $news->setData([ - 'user_id' => $GLOBALS['user']->id, - 'author' => $GLOBALS['user']->getFullName(), - 'topic' => trim(@$this->data['topic']), - 'body' => trim(@$this->data['body']), - 'date' => time(), - 'expire' => isset($this->data['expire']) ? intval($this->data['expire']) : 2 * 7 * 24 * 60 * 60, - 'allow_comments' => isset($this->data['allow_comments']) ? intval($this->data['allow_comments']) : 0 - ]); - $news->addRange($range_id); - - if ($errors = $this->validateNews($news)) { - $this->error(400, compact('errors')); - } - - if (!$news->store()) { - $this->error(500); - } - - $news->storeRanges(); - - $this->redirect('news/' . $news->id, 201, "ok"); - } - - /** - * News-Comments auslesen - * - * @get /news/:news_id/comments - */ - public function getNewsComments($news_id) - { - $comments = $this->requireNews($news_id)->comments->orderBy("mkdate asc"); - - $total = count($comments); - $json = []; - foreach ($comments->limit($this->offset, $this->limit) as $comment) { - $tmp = $comment->toArray("comment_id object_id user_id content mkdate chdate"); - $tmp['content_html'] = htmlReady($comment->content); - $json[$this->urlf('/comment/%s', [htmlReady($comment->id)])] = $tmp; - } - - $this->etag(md5(serialize($json))); - - return $this->paginated($json, $total, compact('news_id')); - } - - /** - * News-Comment auslesen - * - * @get /comment/:comment_id - */ - public function getComment($comment_id) - { - $comment = $this->requireComment($comment_id); - $comment_json = $this->commentToJson($comment); - - $this->lastmodified($comment->chdate); - $this->etag(md5(serialize($comment_json))); - - return $comment_json; - } - - /** - * News-Comment anlegen - * - * @post /news/:news_id/comments - */ - public function appendComment($news_id) - { - $news = $this->requireNews($news_id); - - if (!$news->allow_comments) { - $this->error(409, 'Comments are not allowed'); - } - - if (!isset($this->data['content']) || !mb_strlen($content = trim($this->data['content']))) { - $this->error(400, 'Content required.'); - } - - $comment = new \StudipComment(); - $comment->setData( - [ - 'object_id' => $news_id, - 'user_id' => $GLOBALS['user']->id, - 'content' => $content - ]); - - if (!$comment->store()) { - $this->halt(500, 'Could not create comment.'); - } - - $this->redirect('comment/' . $comment->id, 201, "ok"); - } - - /** - * News-Comment löschen - * - * @delete /comment/:comment_id - */ - public function destroyComment($comment_id) - { - $comment = $this->requireComment($comment_id); - - if (!$comment->delete()) { - $this->error(500, 'Comment could not be deleted.'); - } - - $this->halt(204); - } - - - /**************************************************/ - /* PRIVATE HELPER METHODS */ - /**************************************************/ - - private function getRangedNews($range_id) - { - - $news = \StudipNews::getNewsByRange($range_id, true, true); - - if (!self::checkRangePermission($range_id, $GLOBALS['user']->id)) { - $this->error(401); - } - - $total = count($news); - $news = array_slice($news, $this->offset, $this->limit); - - $json = []; - foreach ($news as $n) { - $json[$this->urlf('/news/%s', [$n->id])] = $this->newsToJson($n); - } - - return [$json, $total]; - } - - private function validateNews($news) - { - $errors = []; - - $retain = $_SESSION['messages']; - $_SESSION['messages'] = []; - - if (!$news->validate()) { - foreach ($_SESSION['messages'] as $message_box) { - $errors[] = $message_box->message; - } - } - - $_SESSION['messages'] = $retain; - return $errors; - } - - private static function checkRangePermission($range_id, $user_id) - { - return \StudipNews::haveRangePermission('view', $range_id, $user_id); - } - - - private function requireNews($id) - { - if (!$news = \StudipNews::find($id)) { - $this->notFound("News not found"); - } - - if (!$news->havePermission('view', '', $GLOBALS['user']->id)) { - $this->error(401); - } - - return $news; - } - - private function newsToJson($news) - { - $json = $news->toArray(words("news_id topic body date user_id expire allow_comments chdate chdate_uid mkdate")); - - $json['topic'] = (string) $news->topic; - $json['body_html'] = formatReady((string) $news->body); - $json['chdate_uid'] = trim($json['chdate_uid']); - - if ($news->allow_comments) { - $json['comments'] = $this->urlf('/news/%s/comments', [$news->id]); - $json['comments_count'] = sizeof($news->comments); - } - - $json['ranges'] = []; - foreach ($news->news_ranges as $range) { - if (self::checkRangePermission($range->range_id, $GLOBALS['user']->id)) { - switch ($range->type) { - case 'global': $url = $this->url('/studip/news'); break; - case 'sem': $url = $this->urlf('/course/%s/news', [$range->range_id]); break; - case 'user': $url = $this->urlf('/user/%s/news', [$range->range_id]); break; - case 'inst': $url = $this->urlf('/TODO/%s/news', [$range->range_id]); break; - case 'fak': $url = $this->urlf('/TODO/%s/news', [$range->range_id]); break; - } - - $json['ranges'][] = $url; - } - } - return $json; - } - - private function requireComment($id) - { - if (!$comment = \StudipComment::find($id)) { - $this->notFound("Comment not found"); - } - if (!$comment->news->havePermission('view', '', $GLOBALS['user']->id)) { - $this->error(401); - } - - return $comment; - } - - private function commentToJson($comment) - { - $json = $comment->toArray(words("comment_id mkdate chdate content")); - $json['content_html'] = formatReady($json['content']); - $json['author'] = $this->urlf('/user/%s', [$comment->user_id]); - $json['news'] = $this->urlf('/news/%s', [$comment->object_id]); - return $json; - } -} diff --git a/app/routes/ResourceBooking.php b/app/routes/ResourceBooking.php deleted file mode 100644 index a5d027f..0000000 --- a/app/routes/ResourceBooking.php +++ /dev/null @@ -1,192 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * This file contains the REST class for the - * room and resource management system. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017-2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @since 4.5 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class ResourceBooking extends \RESTAPI\RouteMap -{ - - /** - * Helper method that either returns the specified data - * or simply an empty string in case that no request result - * is requested. - */ - protected function sendReturnData($data) - { - if (\Request::submitted('quiet')) { - //Return nothing. - return ''; - } - - //Return data. - return $data; - } - - - /** - * Moves a resource booking, if permitted. - * - * @post /resources/booking/:booking_id/move - */ - public function move($booking_id) - { - $booking = \ResourceBooking::find($booking_id); - if (!$booking) { - $this->notFound('Resource booking object not found!'); - } - - $current_user = \User::findCurrent(); - - if ($booking->isReadOnlyForUser($current_user)) { - throw new \AccessDeniedException(); - } - - $resource_id = \Request::get('resource_id'); - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); - $interval_id = \Request::get('interval_id'); - - //Try the ISO format first: YYYY-MM-DDTHH:MM:SS±ZZ:ZZ - $begin = \DateTime::createFromFormat(\DateTime::RFC3339, $begin_str); - $end = \DateTime::createFromFormat(\DateTime::RFC3339, $end_str); - if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) { - $tz = new \DateTime(); - $tz = $tz->getTimezone(); - //Try the ISO format without timezone: - $begin = \DateTime::createFromFormat('Y-m-d\TH:i:s', $begin_str, $tz); - $end = \DateTime::createFromFormat('Y-m-d\TH:i:s', $end_str, $tz); - } - - //Check if a specific interval has been moved: - if ($interval_id) { - $interval = \ResourceBookingInterval::findOneBySql( - 'interval_id = :interval_id AND booking_id = :booking_id', - [ - 'interval_id' => $interval_id, - 'booking_id' => $booking->id - ] - ); - if (!$interval) { - $this->notFound('Resource booking interval not found!'); - } - $interval_begin = new \DateTime(); - $interval_begin->setTimestamp($interval->begin); - $interval_end = new \DateTime(); - $interval_end->setTimestamp($interval->end); - - //Calculate the difference from the interval time range - //to the time range from the request. That difference - //is then applied to the booking. - $begin_diff = $interval_begin->diff($begin); - $end_diff = $interval_end->diff($end); - - $new_booking_begin = new \DateTime(); - $new_booking_begin->setTimestamp($booking->begin); - $new_booking_end = new \DateTime(); - $new_booking_end->setTimestamp($booking->end); - - $new_booking_begin = $new_booking_begin->add($begin_diff); - $new_booking_end = $new_booking_end->add($end_diff); - //We must substract the preparation time to the begin timestamp - //to get the real begin: - $real_begin = clone $new_booking_begin; - if ($booking->preparation_time > 0) { - $real_begin->sub(new \DateInterval('PT' . ($booking->preparation_time / 60 ) . 'M')); - } - $booking->begin = $real_begin->getTimestamp(); - $booking->end = $new_booking_end->getTimestamp(); - } else { - //We must substract the preparation time to the begin timestamp - //to get the real begin: - $real_begin = clone $begin; - if ($booking->preparation_time > 0) { - $real_begin->sub(new \DateInterval('PT' . ($booking->preparation_time / 60 ) . 'M')); - } - $booking->begin = $real_begin->getTimestamp(); - $booking->end = $end->getTimestamp(); - } - if ($resource_id) { - //The resource-ID has changed: - //The booking was moved from one resource to another. - $booking->resource_id = $resource_id; - } - - //Update the booking_user_id field: - $booking->booking_user_id = \User::findCurrent()->id; - - try { - $booking->store(); - return $this->sendReturnData($booking->toRawArray()); - } catch (\Exception $e) { - $this->halt(500, $e->getMessage()); - } - } - - - /** - * Retrieves the intervals of the resource booking. - * These can be filtered by a time range. - * - * @get /resources/booking/:booking_id/intervals - */ - public function getIntervals($booking_id) - { - $booking = \ResourceBooking::find($booking_id); - if (!$booking) { - $this->notFound('Resource booking object not found!'); - } - - $current_user = \User::findCurrent(); - - $resource = $booking->resource->getDerivedClassInstance(); - if (!$resource->bookingPlanVisibleForUser($current_user)) { - throw new \AccessDeniedException(); - } - - //Get begin and end: - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); - $begin = null; - $end = null; - if ($begin_str && $end_str) { - //Try the ISO format first: YYYY-MM-DDTHH:MM:SS±ZZ:ZZ - $begin = \DateTime::createFromFormat(\DateTime::RFC3339, $begin_str); - $end = \DateTime::createFromFormat(\DateTime::RFC3339, $end_str); - if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) { - $tz = new \DateTime(); - $tz = $tz->getTimezone(); - //Try the ISO format without timezone: - $begin = \DateTime::createFromFormat('Y-m-d\TH:i:s', $begin_str, $tz); - $end = \DateTime::createFromFormat('Y-m-d\TH:i:s', $end_str, $tz); - } - } - - $sql = "booking_id = :booking_id "; - $sql_data = ['booking_id' => $booking->id]; - if (($begin instanceof \DateTime) && ($end instanceof \DateTime)) { - $sql .= "AND begin >= :begin AND end <= :end "; - $sql_data['begin'] = $begin->getTimestamp(); - $sql_data['end'] = $end->getTimestamp(); - } - if (\Request::submitted('exclude_cancelled_intervals')) { - $sql .= "AND takes_place = '1' "; - } - $sql .= "ORDER BY begin ASC, end ASC"; - $intervals = \ResourceBookingInterval::findBySql($sql, $sql_data); - - $result = []; - foreach ($intervals as $interval) { - $result[] = $interval->toRawArray(); - } - - return $result; - } -} diff --git a/app/routes/ResourceCategories.php b/app/routes/ResourceCategories.php deleted file mode 100644 index bdd3d15..0000000 --- a/app/routes/ResourceCategories.php +++ /dev/null @@ -1,349 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * This file contains API routes related to ResourceCategory objects. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017-2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @since 4.5 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class ResourceCategories extends \RESTAPI\RouteMap -{ - /** - * Validate access to each route. - */ - public function before() - { - if (!\ResourceManager::userHasGlobalPermission(\User::findCurrent(), 'admin')) { - throw new \AccessDeniedException(); - } - } - - /** - * Returns all defined resource categories. - * - * @get /resources/categories - */ - public function getAllResourceCategories() - { - return \ResourceCategory::findAndMapBySql( - function (\ResourceCategory $category) { - return $category->toRawArray(); - }, - 'TRUE ORDER BY name ASC' - ); - } - - - /** - * Get a resource category object. - * - * @get /resources/category/:category_id - */ - public function getResourceCategory($category_id) - { - $category = \ResourceCategory::find($category_id); - if (!$category) { - $this->notFound('ResourceCategory object not found!'); - } - - return $category->toRawArray(); - } - - - /** - * Creates a resource category object. - * - * @post /resources/new_category - */ - public function addResourceCategory() - { - $name = \Request::get('name'); - $description = \Request::get('description'); - $class_name = \Request::get('class_name'); - $iconnr = \Request::int('iconnr'); - - $properties_name = \Request::getArray('properties_name'); - $properties_type = \Request::getArray('properties_type'); - $properties_requestable = \Request::getArray('properties_requestable'); - $properties_protected = \Request::getArray('properties_protected'); - - $set_properties = []; - foreach ($properties_name as $key => $property_name) { - $set_properties[] = [ - 'name' => $property_name, - 'type' => $properties_type[$key], - 'requestable' => $properties_requestable[$key], - 'protected' => $properties_protected[$key] - ]; - } - - //validation: - if (!$name) { - $this->halt( - 400, - _('Der Name der Kategorie ist leer!') - ); - } - - if (!is_a($class_name, 'Resource', true)) { - $this->halt( - 400, - _('Es wurde keine gültige Ressourcen-Datenklasse ausgewählt!') - ); - } - - switch ($class_name) { - case 'Location': - $category = \ResourceManager::createLocationCategory( - $name, - $description - ); - break; - case 'Building': - $category = \ResourceManager::createBuildingCategory( - $name, - $description - ); - break; - case 'Room': - $category = \ResourceManager::createRoomCategory( - $name, - $description - ); - break; - default: - $category = \ResourceManager::createCategory( - $name, - $description, - $class_name, - false, - $iconnr - ); - } - - if ($category->store() === false) { - $this->halt( - 500, - _('Fehler beim Speichern der Kategorie!') - ); - } - - //After we have stored the category we must store - //the properties or create them, if necessary: - - foreach ($set_properties as $set_property) { - $category->addProperty( - $set_property['name'], - $set_property['type'], - $set_property['requestable'], - $set_property['protected'] - ); - } - - return $category->toRawArray(); - } - - /** - * Modifies a resource category. - * - * @put /resources/category/:category_id - */ - public function editResourceCategory($category_id) - { - $category = \ResourceCategory::find($category_id); - if (!$category) { - $this->notFound('ResourceCategory object not found!'); - } - - if ($category->system) { - $this->halt(403, 'System categories must not be modified!'); - return; - } - - $name = $this->data['name']; - $description = $this->data['description']; - $iconnr = intval($this->data['iconnr']); - - //validation: - if ($name) { - $category->name = $name; - } - if ($description) { - $category->description = $description; - } - if ($iconnr) { - $category->iconnr = $iconnr; - } - - if ($category->store() === false) { - $this->halt( - 500, - 'Error while saving the category!' - ); - } - - return $category->toRawArray(); - } - - - /** - * Deletes a resource category. - * - * @delete /resources/category/:category_id - */ - public function deleteResourceCategory($category_id) - { - $category = \ResourceCategory::find($category_id); - if (!$category) { - $this->notFound('ResourceCategory object not found!'); - } - - if ($category->system) { - $this->halt(403,'System resource categories must not be deleted!'); - return; - } - - if ($category->delete()) { - return 'OK'; - } else { - $this->halt( - 500, - 'Error while deleting the resource category!' - ); - } - } - - - /** - * Get all resource category property objects for a resource category. - * - * @get /resources/category/:category_id/properties - */ - public function getResourceCategoryProperties($category_id) - { - $category = \ResourceCategory::find($category_id); - if (!$category) { - $this->notFound('ResourceCategory object not found!'); - } - - $result = []; - $properties = \ResourceCategoryProperty::findBySql( - 'INNER JOIN resource_property_definitions rpd - USING (property_id) - WHERE category_id = :category_id ORDER BY rpd.name ASC', - [ - 'category_id' => $category->id - ] - ); - - if ($properties) { - foreach ($properties as $property) { - $data = $property->toRawArray(); - $data['name'] = $property->definition->name; - $data['type'] = $property->definition->type; - $result[] = $data; - } - } - - return $result; - } - - - /** - * Returns all resources which belong to the specified category. - * The result set can be limited by the parameters 'offset' and 'limit'. - * If the parameter 'with_full_name' is set to 1, the resources full name - * as provided by its responsible class, is added to the result set. - * - * @get /resources/category/:category_id/resources - */ - public function getResourceCategoryResources($category_id) - { - $category = \ResourceCategory::find($category_id); - if (!$category) { - $this->notFound('ResourceCategory object not found!'); - } - - $offset = \Request::int('offset'); - $limit = \Request::int('limit'); - $with_full_name = \Request::get('with_full_name'); - - $result = []; - - $sql = 'category_id = :category_id ORDER BY name ASC '; - $sql_array = ['category_id' => $category->id]; - - if ($limit > 0) { - $sql .= 'limit :limit '; - $sql_array['limit'] = $limit; - if ($offset > 0) { - $sql .= 'offset :offset '; - $sql_array['offset'] = $offset; - } - } - - $resources = \Resource::findBySql($sql, $sql_array); - - if ($resources) { - foreach ($resources as $r) { - if ($with_full_name) { - $r = $r->getDerivedClassInstance(); - $data = $r->toRawArray(); - $data['full_name'] = $r->getFullName(); - $result[] = $data; - } else { - $result[] = $r->toRawArray(); - } - } - } - - return $result; - } - - - /** - * Creates a resource. - * - * @post /resources/category/:category_id/create_resource - */ - public function createResource($category_id) - { - $category = \ResourceCategory::find($category_id); - if (!$category) { - $this->notFound('ResourceCategory object not found!'); - } - - - $name = \Request::get('name'); - $description = \Request::get('description'); - $parent_id = \Request::get('parent_id'); - $properties = \Request::getArray('properties'); - - if (!$name) { - $this->halt( - 400, - 'The parameter \'name\' is not set!' - ); - } - - try { - $resource = $category->createResource( - $name, - $description, - $parent_id, - $properties - ); - - return $resource; - } catch (\Exception $e) { - $this->halt( - 400, - $e->getMessage() - ); - } - } -} diff --git a/app/routes/ResourcePermissions.php b/app/routes/ResourcePermissions.php deleted file mode 100644 index be5c647..0000000 --- a/app/routes/ResourcePermissions.php +++ /dev/null @@ -1,585 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * This file contains API routes related to ResourcePermission - * and ResourceTemporaryPermission objects. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017-2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @since 4.5 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class ResourcePermissions extends \RESTAPI\RouteMap -{ - - //Methods for permanent permissions: - - - /** - * Get the permission levels of users for the specified resource. - * - * @param levels: Limit the result set to the specified permission levels. - * Allowed permission levels: user, autor, tutor, admin. - * The permission levels have to be comma separated like in the - * following example: "autor,tutor,admin". - * - * @get /resources/permissions/:resource_id - */ - public function getResourcePermissions($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'admin')) { - throw new \AccessDeniedException(); - } - - $levels_str = \Request::get('levels'); - $levels = []; - if ($levels_str) { - $levels = explode(',', $levels_str); - } - - $sql = 'resource_id = :resource_id '; - $sql_array = [ - 'resource_id' => $resource->id - ]; - - if ($levels) { - $sql .= 'AND perms IN ( :levels ) '; - $sql_array['levels'] = $levels; - } - - $permissions = \ResourcePermission::findBySql($sql, $sql_array); - - $result = []; - if ($permissions) { - foreach ($permissions as $permission) { - $result[] = $permission->toRawArray(); - } - } - - return $result; - } - - - /** - * Returns the permissions a specific user has on a specified resource. - * - * @get /resources/permissions/:resource_id/:user:_id - */ - public function getPermission($resource_id, $user_id) - { - if ($resource_id !== 'global') { - if (!\Resource::exists($resource_id)) { - $this->halt( - 404, - 'Resource not found!' - ); - } - } - - $user = \User::find($user_id); - if (!$user) { - $this->halt( - 400, - 'No user was provided!' - ); - } - - $current_user = \User::findCurrent(); - - if (!\ResourceManager::userHasGlobalPermission($current_user, 'admin')) { - if ($resource_id !== 'global') { - $resource = \Resource::find($resource_id); - $resource = $resource->getDerivedClassInstance(); - if (!$resource->userHasPermission($current_user, 'admin')) { - $this->halt(403); - } - } else { - //$resource_id == 'global': One must be admin - //to perform this action! - $this->halt(403); - } - } - - $permission = \ResourcePermission::findOneBySql( - "resource_id = :resource_id AND user_id = :user_id", - [ - 'resource_id' => $resource_id, - 'user_id' => $user->id - ] - ); - - if ($permission) { - return $permission->toRawArray(); - } else { - //The user already had no global permissions! - return NULL; - } - } - - - /** - * @post /resources/permissions/:resource_id/:user_id - */ - public function setPermission($resource_id, $user_id) - { - if ($resource_id !== 'global') { - if (!\Resource::exists($resource_id)) { - $this->halt( - 404, - 'Resource not found!' - ); - return; - } - } - - $user = \User::find($user_id); - if (!$user) { - $this->halt( - 400, - 'No user was provided!' - ); - } - - $current_user = \User::findCurrent(); - - if (!\ResourceManager::userHasGlobalPermission($current_user, 'admin')) { - if ($resource_id !== 'global') { - $resource = \Resource::find($resource_id); - $resource = $resource->getDerivedClassInstance(); - if (!$resource->userHasPermission($current_user, 'admin')) { - $this->halt(403); - } - } else { - //$resource_id == 'global': One must be admin - //to perform this action! - $this->halt(403); - } - } - - //Verify permission level: - $perms = \Request::get('perms'); - - if (!in_array($perms, ['user', 'autor', 'tutor', 'admin'])) { - $this->halt( - 400, - 'Invalid permission level specified!' - ); - } - - //Check if permissions are already present for the user. - //If not, create a new permission object. - $permission = \ResourcePermission::findOneBySql( - "resource_id = :resource_id AND user_id = :user_id", - [ - 'resource_id' => $resource_id, - 'user_id' => $user->id - ] - ); - - if (!$permission) { - $permission = new \ResourcePermission(); - $permission->resource_id = $resource_id; - $permission->user_id = $user->id; - } - - $permission->perms = $perms; - - if ($permission->store() === false) { - $this->halt( - 500, - 'Error while saving permissions!' - ); - } - - return $permission->toRawArray(); - } - - - /** - * @delete /resources/permissions/:resource_id/:user_id - */ - public function deletePermission($resource_id, $user_id) - { - if ($resource_id !== 'global' && !\Resource::exists($resource_id)) { - $this->notFound('Resource not found!'); - } - - $user = \User::find($user_id); - if (!$user) { - $this->halt( - 400, - 'No user was provided!' - ); - } - - $current_user = \User::findCurrent(); - - if (!\ResourceManager::userHasGlobalPermission($current_user, 'admin')) { - if ($resource_id !== 'global') { - $resource = \Resource::find($resource_id); - $resource = $resource->getDerivedClassInstance(); - if (!$resource->userHasPermission($current_user, 'admin')) { - $this->halt(403); - } - } else { - //$resource_id == 'global': One must be admin - //to perform this action! - $this->halt(403); - } - } - - $permission = \ResourcePermission::findOneBySql( - "resource_id = :resource_id AND user_id = :user_id", - [ - 'resource_id' => $resource_id, - 'user_id' => $user->id - ] - ); - - if (!$permission) { - //The user already had no global permissions! - return 'OK'; - } - - if ($permission->delete()) { - return 'OK'; - } else { - $this->halt( - 500, - 'Error while deleting global permissions!' - ); - } - } - - - //Methods for temporary permissions: - - - /** - * Get the temporary permission levels of users for the specified resource. - * The begin and end parameters are mandatory to determine a time range - * to collect the temporary permissions in that range. - * - * @param begin: The begin timestamp of the time range. - * @param end: The end timestamp of the time range. - * @param levels: Limit the result set to the specified temporary permission - * levels. Allowed permission levels: user, autor, tutor, admin. - * The permission levels have to be comma separated like in the - * following example: "autor,tutor,admin". - * - * @get /resources/temporary_permissions/:resource_id - */ - public function getTemporaryResourcePermissions($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'admin')) { - throw new \AccessDeniedException(); - } - - $begin = \Request::get('begin'); - $end = \Request::get('end'); - $levels_str = \Request::get('levels'); - $levels = []; - if ($levels_str) { - $levels = explode(',', $levels_str); - } - - if (!$begin or !$end) { - //Use the current day: - $begin = strtotime('today 0:00:00'); - $end = strtotime('today 23:59:59'); - } - - $sql = 'resource_id = :resource_id - AND - ((begin >= :begin AND begin <= :end) - OR - (end >= :begin AND end <= :end)) - OR - (begin < :begin AND end > :end)'; - $sql_array = [ - 'resource_id' => $resource->id, - 'begin' => $begin, - 'end' => $end - ]; - - if ($levels) { - $sql .= 'AND perms IN ( :levels ) '; - $sql_array['levels'] = $levels; - } - - return \ResourceTemporaryPermission::findAndMapBySql( - function (\ResourceTemporaryPermission $permission) { - return $permission->toRawArray(); - }, - $sql, - $sql_array - ); - } - - - /** - * Returns the permissions a specific user has on a specified resource. - * - * @get /resources/temporary_permissions/:resource_id/:user:_id - */ - public function getTemporaryPermission($resource_id, $user_id) - { - if ($resource_id !== 'global') { - if (!\Resource::exists($resource_id)) { - $this->notFound('Resource not found!'); - } - } - - $user = \User::find($user_id); - if (!$user) { - $this->halt( - 400, - 'No user was provided!' - ); - } - - $current_user = \User::findCurrent(); - - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); - $begin = null; - $end = null; - $with_time_range = false; - if ($begin_str && $end_str) { - $with_time_range = true; - $begin = new \DateTime(); - $begin->setTimestamp($begin_str); - $end = new \DateTime(); - $end->setTimestamp($end_str); - } - - if (!\ResourceManager::userHasGlobalPermission($current_user, 'admin')) { - if ($resource_id !== 'global') { - $resource = \Resource::find($resource_id); - $resource = $resource->getDerivedClassInstance(); - if (!$resource->userHasPermission($current_user, 'admin')) { - $this->halt(403); - } - } else { - //$resource_id == 'global': One must be admin - //to perform this action! - $this->halt(403); - } - } - - $permissions = null; - if ($with_time_range) { - $permissions = \ResourceTemporaryPermission::findBySql( - "resource_id = :resource_id AND user_id = :user_id - AND ( - (begin >= :begin AND begin <= :end) - OR - (end >= :begin AND end <= :end) - )", - [ - 'resource_id' => $resource_id, - 'user_id' => $user->id, - 'begin' => $begin->getTimestamp(), - 'end' => $end->getTimestamp() - ] - ); - } else { - $permissions = \ResourceTemporaryPermission::findBySql( - "resource_id = :resource_id AND user_id = :user_id", - [ - 'resource_id' => $resource_id, - 'user_id' => $user->id - ] - ); - } - - if ($permissions) { - $result = []; - foreach ($permissions as $permission) { - $result[] = $permission->toRawArray(); - } - return $result; - } else { - //The user already had no global permissions! - return NULL; - } - } - - - /** - * Sets temporary permissions for a user. - * - * @param begin The begin timestamp for the temporary permisssion. - * @param end The end timestamp for the temporary permission. - * @param perms The permission level for the temporary permission. - * - * @post /resources/temporary_permissions/:resource_id/:user_id - */ - public function setTemporaryPermission($resource_id, $user_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource not found!'); - } - - $user = \User::find($user_id); - if (!$user) { - $this->notFound('User not found!'); - } - - $current_user = \User::findCurrent(); - - if (!\ResourceManager::userHasGlobalPermission($current_user, 'admin') - && !$resource->userHasPermission($current_user, 'admin')) { - $this->halt(403); - } - - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); - if (!$begin_str || !$end_str) { - $this->halt( - 400, - 'No time range specified for temporary permission!' - ); - } - - $begin = new \DateTime(); - $begin->setTimestamp($begin_str); - $end = new \DateTime(); - $end->setTimestamp($end_str); - - //Verify permission level: - $perms = \Request::get('perms'); - - if (!in_array($perms, ['user', 'autor', 'tutor', 'admin'])) { - $this->halt( - 400, - 'Invalid permission level specified!' - ); - } - - //Check if permissions are already present for the user. - //If not, create a new permission object. - $permission = \ResourceTemporaryPermission::findOneBySql( - "resource_id = :resource_id AND user_id = :user_id - AND begin = :begin AND end = :end", - [ - 'resource_id' => $resource_id, - 'user_id' => $user->id, - 'begin' => $begin->getTimestamp(), - 'end' => $end->getTimestamp() - ] - ); - - if (!$permission) { - $permission = new \ResourceTemporaryPermission(); - $permission->resource_id = $resource_id; - $permission->user_id = $user->id; - $permission->begin = $begin->getTimestamp(); - $permission->end = $end->getTimestamp(); - } - - $permission->perms = $perms; - - if ($permission->store() === false) { - $this->halt( - 500, - 'Error while saving permissions!' - ); - } - - return $permission->toRawArray(); - } - - - /** - * Deletes all temporary permissions of a user. - * If a time interval is given all permissions inside the interval - * are deleted. - * - * @delete /resources/temporary_permissions/:resource_id/:user_id - */ - public function deleteTemporaryPermission($resource_id, $user_id) - { - if ($resource_id !== 'global') { - if (!\Resource::exists($resource_id)) { - $this->notFound('Resource not found!'); - } - } - - $user = \User::find($user_id); - if (!$user) { - $this->notFound('User not found!'); - } - - $current_user = \User::findCurrent(); - - if (!\ResourceManager::userHasGlobalPermission($current_user, 'admin')) { - if ($resource_id !== 'global') { - $resource = \Resource::find($resource_id); - $resource = $resource->getDerivedClassInstance(); - if (!$resource->userHasPermission($current_user, 'admin')) { - $this->halt(403); - } - } else { - //$resource_id == 'global': One must be admin - //to perform this action! - $this->halt(403); - } - } - - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); - $begin = null; - $end = null; - $with_time_range = false; - if ($begin_str and $end_str) { - $with_time_range = true; - $begin = new \DateTime(); - $begin->setTimestamp($begin_str); - $end = new \DateTime(); - $end->setTimestamp($end_str); - } - - if ($with_time_range) { - \ResourceTemporaryPermission::deleteBySql( - "resource_id = :resource_id AND user_id = :user_id - AND ( - (begin >= :begin AND end <= :end) - )", - [ - 'resource_id' => $resource_id, - 'user_id' => $user->id, - 'begin' => $begin->getTimestamp(), - 'end' => $end->getTimestamp() - ] - ); - } else { - \ResourceTemporaryPermission::deleteBySql( - "resource_id = :resource_id AND user_id = :user_id", - [ - 'resource_id' => $resource_id, - 'user_id' => $user->id - ] - ); - } - - return 'OK'; - } -} diff --git a/app/routes/ResourceProperties.php b/app/routes/ResourceProperties.php deleted file mode 100644 index 2ddbbaf..0000000 --- a/app/routes/ResourceProperties.php +++ /dev/null @@ -1,224 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * This file contains API routes related to ResourceProperty objects. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017-2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @since 4.5 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class ResourceProperties extends \RESTAPI\RouteMap -{ - /** - * Validate access to each route. - */ - public function before() - { - if (!\ResourceManager::userHasGlobalPermission(\User::findCurrent(), 'admin')) { - throw new \AccessDeniedException(); - } - } - - /** - * Returns all resource property definitions. - * - * @get /resources/properties - */ - public function getAllResourcePropertyDefinitions() - { - $properties = \ResourcePropertyDefinition::findBySql('TRUE ORDER BY name ASC'); - - $result = []; - - if ($properties) { - foreach ($properties as $p) { - $result[] = $p->toRawArray(); - } - } - - return $result; - } - - - /** - * Creates a new resource property definition. - * - * @post /resources/add_property - */ - public function addResourcePropertyDefinition() - { - $name = \Request::get('name'); - $description = \Request::i18n('description'); - $type = \Request::get('type'); - $write_permission_level = \Request::get('write_permission_level'); - $options = \Request::get('options', ''); - $range_search = \Request::bool('range_search'); - - if (!$name) { - $this->halt( - 400, - 'The field \'name\' must not be empty!' - ); - } - if (!in_array($type, \ResourcePropertyDefinition::getDefinedTypes())) { - $this->halt( - 400, - 'Invalid property type specified!' - ); - } - if (!in_array($write_permission_level, ['user', 'autor', 'tutor', 'admin'])) { - $this->halt( - 400, - 'Invalid permission level in field \'write_permission_level\'!' - ); - } - - $property = new \ResourcePropertyDefinition(); - $property->name = $name; - $property->description = $description; - $property->type = $type; - $property->options = $options ?: ''; - $property->range_search = $range_search; - $property->write_permission_level = $write_permission_level; - - if (!$property->store()) { - $this->halt( - 500, - 'Error while saving the property!' - ); - } - return $property->toRawArray(); - } - - - /** - * Get a resource property definition object. - * - * @get /resources/property/:property_id - */ - public function getResourcePropertyDefinition($property_id) - { - $property = \ResourcePropertyDefinition::find($property_id); - if (!$property) { - $this->notFound('ResourcePropertyDefinition object not found!'); - } - - return $property->toRawArray(); - } - - - /** - * Modifies a resource property definition. - * - * @put /resources/property/:property_id - */ - public function editResourcePropertyDefinition($property_id) - { - $property = \ResourcePropertyDefinition::find($property_id); - if (!$property) { - $this->notFound('ResourcePropertyDefinition object not found!'); - } - - if ($property->system) { - $this->halt( - 403, - 'System properties must not be edited!' - ); - } - - $name = $this->data['name']; - $description = $this->data['description']; - $type = $this->data['type']; - $write_permission_level = $this->data['write_permission_level']; - $options = $this->data['options']; - $range_search = $this->data['range_search']; - - if ($name) { - $property->name = $name; - } - - if ($description) { - $property->description = $description; - } - - if ($type) { - if (!in_array($type, \ResourcePropertyDefinition::getDefinedTypes())) { - $this->halt( - 400, - 'Invalid property type specified!' - ); - } - $property->type = $type; - } - - if ($write_permission_level) { - if (!in_array($write_permission_level, ['user', 'autor', 'tutor', 'admin'])) { - $this->halt( - 400, - 'Invalid permission level in field \'write_permission_level\'!' - ); - } - $property->write_permission_level = $write_permission_level; - } - - if ($options) { - $property->options = $options; - } - - if ($range_search) { - $property->range_search = $range_search; - } - - if ($property->isDirty()) { - if ($property->store()) { - return $property->toRawArray(); - } else { - $this->halt( - 500, - 'Error while saving the property!' - ); - } - } - - return $property->toRawArray(); - } - - - /** - * Deletes a resource property definition object. - * - * @delete /resources/property/:property_id - */ - public function deleteResourcePropertyDefinition($property_id) - { - $property = \ResourcePropertyDefinition::find($property_id); - if (!$property) { - $this->notFound('ResourcePropertyDefinition object not found!'); - } - - if (!\ResourceManager::userHasGlobalPermission(\User::findCurrent(), 'admin')) { - $this->halt(403); - } - - //Check if the property is in use: - - if ($property->isInUse()) { - $this->halt( - 403, - 'The property is in use and can therefore not be deleted!' - ); - } - - if ($property->delete()) { - return "OK"; - } else { - $this->halt( - 500, - 'Error while deleting resource property definition!' - ); - } - } -} diff --git a/app/routes/ResourceRequest.php b/app/routes/ResourceRequest.php deleted file mode 100644 index 24dfd2e..0000000 --- a/app/routes/ResourceRequest.php +++ /dev/null @@ -1,138 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * This file contains the REST class for resource requests from the - * room and resource management system. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017-2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @since 4.5 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class ResourceRequest extends \RESTAPI\RouteMap -{ - - /** - * Helper method that either returns the specified data - * or simply an empty string in case that no request result - * is requested. - */ - protected function sendReturnData($data) - { - if (\Request::submitted('quiet')) { - //Return nothing. - return ''; - } - - //Return data. - return $data; - } - - - /** - * Moves a resource request, if permitted. - * - * @post /resources/request/:request_id/move - */ - public function move($request_id) - { - $request = \ResourceRequest::find($request_id); - if (!$request) { - $this->notFound('Resource request object not found!'); - } - - $current_user = \User::findCurrent(); - - if ($request->isReadOnlyForUser($current_user)) { - throw new \AccessDeniedException(); - } - - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); - - //Try the ISO format first: YYYY-MM-DDTHH:MM:SS±ZZ:ZZ - $begin = \DateTime::createFromFormat(\DateTime::RFC3339, $begin_str); - $end = \DateTime::createFromFormat(\DateTime::RFC3339, $end_str); - if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) { - $tz = new \DateTime(); - $tz = $tz->getTimezone(); - $begin = \DateTime::createFromFormat('Y-m-d\TH:i:s', $begin_str, $tz); - $end = \DateTime::createFromFormat('Y-m-d\TH:i:s', $end_str, $tz); - } - - $request->begin = $begin->getTimestamp(); - $request->end = $end->getTimestamp(); - - try { - $request->store(); - return $this->sendReturnData($request->toRawArray()); - } catch (\Exception $e) { - $this->halt(500, $e->getMessage()); - } - } - - - /** - * Changes the reply comment of a request. - * - * @post /resources/request/:request_id/edit_reply_comment - */ - public function editReplyComment($request_id) - { - $request = \ResourceRequest::find($request_id); - if (!$request) { - $this->notFound('Resource request object not found!'); - } - - $current_user = \User::findCurrent(); - - if ($request->isReadOnlyForUser($current_user)) { - throw new \AccessDeniedException(); - } - - $request->reply_comment = \Request::get('reply_comment'); - - try { - if ($request->store() === false) { - throw new \RuntimeException('Could not store comment'); - } - } catch (\Exception $e) { - $this->halt(500, $e->getMessage()); - } - - return $this->sendReturnData($request->toRawArray()); - } - - - /** - * Changes the reply comment of a request. - * - * @post /resources/request/:request_id/toggle_marked - */ - public function toggleMarkedFlag($request_id) - { - $request = \ResourceRequest::find($request_id); - if (!$request) { - $this->notFound('Resource request object not found!'); - } - - $current_user = \User::findCurrent(); - - if ($request->isReadOnlyForUser($current_user)) { - throw new \AccessDeniedException(); - } - - //Switch to the next marking state or return to the unmarked state - //if the next marking state would be after the last defined - //marking state. - $request->marked = (++$request->marked % \ResourceRequest::MARKING_STATES); - - if ($request->isDirty()) { - $request->store(); - } - - return $request; - } -} diff --git a/app/routes/Resources.php b/app/routes/Resources.php deleted file mode 100644 index 7117546..0000000 --- a/app/routes/Resources.php +++ /dev/null @@ -1,950 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * This file contains the REST class for the - * room and resource management system. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017-2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @since 4.5 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class Resources extends \RESTAPI\RouteMap -{ - - //Resource routes: - - - /** - * Get a resource object. - * @param derived_class: If the URL parameter derived_class is set - * the resource object is converted to an instance of the - * class that does correct handling of the resource object. - * - * @get /resources/resource/:resource_id - */ - public function getResource($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'user')) { - throw new \AccessDeniedException(); - } - - if (\Request::submitted('derived_classes')) { - $resource = $resource->getDerivedClassInstance(); - } - - $result = $resource->toRawArray(); - - $result['full_name'] = $resource->getFullName(); - $result['has_children'] = $resource->children ? true : false; - - return $result; - } - - - /** - * Modifies a resource object. - * - * @put /resources/resource/:resource_id - */ - public function editResource($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'autor')) { - $this->halt(403); - return; - } - - $name = $this->data['name']; - $description = $this->data['description']; - $parent_id = $this->data['parent_id']; - $properties = $this->data['properties']; - - if ($name) { - $resource->name = $name; - } - if ($description) { - $resource->description = $description; - } - if ($parent_id) { - if (!\Resource::exists($parent_id)) { - $this->halt( - 400, - 'No resource exists with the ID \'' . $parent_id . '\'!' - ); - } - $resource->parent_id = $parent_id; - } - if ($properties) { - foreach ($properties as $name => $value) { - try { - $resource->setProperty($name, $value, $GLOBALS['user']->id); - } catch (\AccessDeniedException $e) { - $this->halt( - 403, - $e->getMessage() - ); - } catch (\Exception $e) { - $this->halt( - 500, - $e->getMessage() - ); - } - } - } - - if ($resource->isDirty()) { - if ($resource->store()) { - return $resource->toRawArray(); - } else { - $this->halt( - 500, - 'Error while saving the resource object!' - ); - } - } - return $resource->toRawArray(); - } - - - /** - * Deletes a resource object. - * - * @delete /resources/resource/:resource_id - */ - public function deleteResource($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'admin')) { - $this->halt(403); - return; - } - - if (\Request::submitted('derived_classes')) { - $resource = $resource->getDerivedClassInstance(); - } - - if ($resource->delete()) { - return 'OK'; - } else { - $this->halt( - 500, - 'Error while deleting the resource object!' - ); - } - } - - - /** - * Returns the child resources of a resource object, if they exist. - * - * @get /resources/resource/:resource_id/children - */ - public function getResourceChildren($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'user')) { - throw new \AccessDeniedException(); - } - - $use_derived_classes = (bool) \Request::submitted('derived_classes'); - - $result = []; - - $children = \Resource::findBySql( - 'parent_id = :resource_id - ORDER BY name ASC', - [ - 'resource_id' => $resource->id - ] - ); - if ($children) { - foreach ($children as $child) { - if ($use_derived_classes) { - $child = $child->getDerivedClassInstance(); - } - $result[] = $child->toRawArray(); - } - } - return $result; - } - - - /** - * Returns the parent resource of a resource object, if it exists. - * - * @get /resources/resource/:resource_id/parent - */ - public function getResourceParent($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'user')) { - throw new \AccessDeniedException(); - } - - if (!$resource->parent) { - $this->notFound('This resource has no parent!'); - } - - $use_derived_classes = (bool) \Request::submitted('derived_classes'); - - if ($use_derived_classes) { - $parent = $resource->parent->getDerivedClassInstance(); - return $parent->toRawArray(); - } - - return $resource->parent->toRawArray(); - } - - - /** - * Get all property objects of a resource. - * - * @get /resources/resource/:resource_id/properties - */ - public function getResourceProperties($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'user')) { - throw new \AccessDeniedException(); - } - - $result = []; - $properties = \ResourceProperty::findBySql( - 'INNER JOIN resource_property_definitions rpd - ON resource_properties.property_id = rpd.property_id - WHERE - resource_properties.resource_id = :resource_id - ORDER BY rpd.name ASC', - [ - 'resource_id' => $resource->id - ] - ); - - if ($properties) { - foreach ($properties as $property) { - $data = $property->toRawArray(); - $data['name'] = $property->definition->name; - $data['type'] = $property->definition->type; - if ($data['type'] == 'position') { - //position properties also get the map-URL: - $data['map_url'] = \ResourceManager::getMapUrlForResourcePosition( - $property - ); - } - $result[] = $data; - } - } - - return $result; - } - - - /** - * Returns the booking plan of a resource for a week specified - * by the parameters begin and end. - * - * @param begin: The begin timestamp of the time range for the booking plan. - * @param end: The end timestamp of the time range for the booking plan. - * - * @allow_nobody - * - * @get /resources/resource/:resource_id/booking_plan - */ - public function getResourceBookingPlan($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - $current_user = \User::findCurrent(); - $nobody_access = true; - - if ($current_user instanceof \User) { - $nobody_access = false; - if (!$resource->bookingPlanVisibleForUser($current_user)) { - throw new \AccessDeniedException(); - } - } elseif ($resource instanceof \Room) { - if (!$resource->bookingPlanVisibleForUser($current_user)) { - throw new \AccessDeniedException(); - } - } - $user_is_resource_user = false; - if ($current_user instanceof \User) { - $user_is_resource_user = $resource->userHasPermission( - $current_user, - 'user' - ); - } - - $display_requests = false; - if ($current_user instanceof \User) { - $display_requests = \Request::get('display_requests'); - } - $display_all_requests = \Request::get('display_all_requests'); - - if ($display_all_requests && !$user_is_resource_user) { - //The user is not allowed to see all requests. - throw new \AccessDeniedException(); - } - - $begin_date = \Request::get('start'); - $end_date = \Request::get('end'); - if (!$begin_date || !$end_date) { - //No time range specified. - $this->halt(400, 'The parameters "start" and "end" are missing!'); - return; - } - - //Try the ISO format first: YYYY-MM-DDTHH:MM:SS±ZZ:ZZ - $begin = \DateTime::createFromFormat(\DateTime::RFC3339, $begin_date); - $end = \DateTime::createFromFormat(\DateTime::RFC3339, $end_date); - - if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) { - $begin = new \DateTime(); - $end = new \DateTime(); - //Assume the local timezone and use the Y-m-d format: - $date_regex = '/[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1])/'; - if (preg_match($date_regex, $begin_date)) { - //$begin is specified in the date formay YYYY-MM-DD: - $begin_str = explode('-', $begin_date); - $begin->setDate( - intval($begin_str[0]), - intval($begin_str[1]), - intval($begin_str[2]) - ); - $begin->setTime(0,0,0); - } else { - $begin->setTimestamp($begin_date); - } - //Now we do the same for $end_timestamp: - if (preg_match($date_regex, $end_date)) { - //$begin is specified in the date formay YYYY-MM-DD: - $end_str = explode('-', $end_date); - $end->setDate( - intval($end_str[0]), - intval($end_str[1]), - intval($end_str[2]) - ); - $end->setTime(23,59,59); - } else { - $end->setTimestamp($end_date); - } - } - - //Get parameters: - $booking_types = []; - if (!$nobody_access) { - $booking_types = explode(',', \Request::get('booking_types')); - } - - $begin_timestamp = $begin->getTimestamp(); - $end_timestamp = $end->getTimestamp(); - - //Get the event data sources: - $bookings = \ResourceBooking::findByResourceAndTimeRanges( - $resource, - [ - [ - 'begin' => $begin_timestamp, - 'end' => $end_timestamp - ] - ], - $booking_types - ); - $requests = []; - if ($display_all_requests) { - $requests = \ResourceRequest::findByResourceAndTimeRanges( - $resource, - [ - [ - 'begin' => $begin_timestamp, - 'end' => $end_timestamp - ] - ], - 0 - ); - } elseif ($display_requests) { - //Get the users own request only: - $requests = \ResourceRequest::findByResourceAndTimeRanges( - $resource, - [ - [ - 'begin' => $begin_timestamp, - 'end' => $end_timestamp - ] - ], - 0, - [], - 'user_id = :user_id', - ['user_id' => $current_user->id] - ); - } - - $objects = array_merge($bookings, $requests); - $event_data = \Studip\Fullcalendar::createData($objects, $begin_timestamp, $end_timestamp); - - if ($nobody_access) { - //For nobody users, the code stops here since - //nobody users are not allowed to include additional objects. - return $event_data; - } - - //Check if there are additional objects to be displayed: - $additional_objects = \Request::getArray('additional_objects'); - $additional_object_colours = \Request::getArray('additional_object_colours'); - if ($additional_objects) { - foreach ($additional_objects as $object_class => $object_ids) { - if (!is_a($object_class, '\SimpleORMap', true)) { - continue; - } - if (!is_a($object_class, '\Studip\Calendar\EventSource', true)) { - continue; - } - - $special_colours = []; - if ($additional_object_colours[$object_class]) { - $special_colours = $additional_object_colours[$object_class]; - } - - $additional_objects = $object_class::findMany($object_ids); - foreach ($additional_objects as $additional_object) { - $event_data = $additional_object->getFilteredEventData( - $current_user->id, - null, - null, - $begin, - $end - ); - - if ($special_colours) { - foreach ($event_data as $data) { - $data->text_colour = $special_colours['fg']; - $data->background_colour = $special_colours['bg']; - $data->editable = false; - $event_data[] = $data->toFullcalendarEvent(); - } - } - } - } - } - return $event_data; - } - - - /** - * Returns the booking plan of a resource for a selected semester. - * - * @param semester_id: The ID of the semester. Defaults to the current - * semester, if not set. - * - * @get /resources/resource/:resource_id/semester_plan - */ - public function getResourceSemesterBookingPlan($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - $current_user = \User::findCurrent(); - - if (!$resource->bookingPlanVisibleForUser($current_user)) { - throw new \AccessDeniedException(); - } - - $user_is_resource_user = $resource->userHasPermission( - $current_user, - 'user' - ); - - $display_requests = \Request::get('display_requests'); - $display_all_requests = \Request::get('display_all_requests'); - - $begin = new \DateTime(); - $end = new \DateTime(); - - $semester_id = \Request::get('semester_id'); - $semester = null; - - if ($semester_id) { - $semester = \Semester::find($semester_id); - if (!$semester) { - $this->halt(404, 'Specified semester not found!'); - } - } else { - $semester = \Semester::findCurrent(); - if (!$semester) { - $this->halt(500, 'Current semester not available!'); - } - } - - if (\Request::get('semester_timerange') != 'fullsem') { - $begin->setTimestamp($semester->vorles_beginn); - $end->setTimestamp($semester->vorles_ende); - } else { - $begin->setTimestamp($semester->beginn); - $end->setTimestamp($semester->ende); - } - - //Get parameters: - $booking_types = \Request::getArray('booking_types'); - - $begin_timestamp = $begin->getTimestamp(); - $end_timestamp = $end->getTimestamp(); - - //Get the event data sources: - $bookings = \ResourceBooking::findByResourceAndTimeRanges( - $resource, - [ - [ - 'begin' => $begin_timestamp, - 'end' => $end_timestamp - ] - ], - $booking_types - ); - - $requests = []; - if ($display_all_requests || $display_requests) { - $requests_sql = "INNER JOIN seminar_cycle_dates scd - USING (metadate_id) - WHERE - resource_id = :resource_id - AND - closed = '0' "; - $requests_sql_params = [ - 'begin' => $begin_timestamp, - 'end' => $end_timestamp, - 'resource_id' => $resource->id - ]; - if (!$display_all_requests) { - $requests_sql .= "AND user_id = :user_id "; - $requests_sql_params['user_id'] = $current_user->id; - } - - $requests = \ResourceRequest::findBySql( - $requests_sql, - $requests_sql_params - ); - } - - $merged_objects = []; - $metadates = []; - - foreach ($bookings as $booking) { - $booking->resource = $resource; - $irrelevant_booking = false; - if ($booking->getRepetitionType() != 'weekly') { - if (!\Request::get('display_single_bookings')) { - $irrelevant_booking = true; - } else if ($booking->end < strtotime('today')) { - $irrelevant_booking = true; - } - } - if ($booking->getAssignedUserType() === 'course' && in_array($booking->assigned_course_date->metadate_id, $metadates)) { - $irrelevant_booking = true; - }; - if (!$irrelevant_booking) { - //It is an booking with repetitions that has to be included - //in the semester plan. - if (in_array($booking->getRepetitionType(), ['single','weekly'])) { - $event_list = $booking->convertToEventData([\ResourceBookingInterval::build(['interval_id' => md5(uniqid()), 'begin' => $booking->begin - $booking->preparation_time, 'end' => $booking->end])], $current_user); - } else { - $event_list = $booking->getFilteredEventData(null,null,null,strtotime('today'), $end_timestamp); - } - foreach ($event_list as $event_data) { - if ($booking->getAssignedUserType() === 'course' && $booking->assigned_course_date->metadate_id) { - $index = sprintf( - '%1$s_%2$s_%3$s', - $booking->assigned_course_date->metadate_id, - $event_data->begin->format('NHis'), - $event_data->end->format('NHis') - ); - $metadates[] = $booking->assigned_course_date->metadate_id; - } else { - $index = sprintf( - '%1$s_%2$s_%3$s', - $booking->id, - $event_data->begin->format('NHis'), - $event_data->end->format('NHis') - ); - } - - //Strip some data that cannot be used effectively in here: - $event_data->api_urls = []; - $event_data->editable = false; - - $merged_objects[$index] = $event_data; - } - } - } - - foreach ($requests as $request) { - if ($request->cycle instanceof \SeminarCycleDate) { - $cycle_dates = $request->cycle->getAllDates(); - foreach ($cycle_dates as $cycle_date) { - $relevant_request = $semester->beginn <= $cycle_date->date - && $semester->ende >= $cycle_date->date; - if ($relevant_request) { - //We have found a date for the current semester - //that makes the request relevant. - break; - } - } - if (!$relevant_request) { - continue; - } - $event_data_list = $request->getFilteredEventData( - $current_user->id - ); - - foreach ($event_data_list as $event_data) { - $index = sprintf( - '%1$s_%2$s_%3$s', - $request->metadate_id, - $event_data->begin->format('NHis'), - $event_data->end->format('NHis') - ); - - //Strip some data that cannot be used effectively in here: - $event_data->view_urls = []; - $event_data->api_urls = []; - - $merged_objects[$index] = $event_data; - } - } - } - - //Convert the merged events to Fullcalendar events: - $data = []; - foreach ($merged_objects as $obj) { - $data[] = $obj->toFullCalendarEvent(); - } - - return $data; - } - - - /** - * Gets request of a resource. At your option the requests can be - * limited to a specific time range, specified by the parameters - * begin and end. Furthermore the requests can be filtered by user-ID. - * - * @param begin: A timestamp specifying the begin of the time range. - * @param end: A timestamp specifying the end of the time range. - * @param user_id: This parameter limits the result set to requests - * of the user specified by the user-ID provided in this parameter. - * - * @get /resources/resource/:resource_id/requests - */ - public function getResourceRequests($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'user')) { - throw new \AccessDeniedException(); - } - - $begin = $this->data['begin']; - $end = $this->data['end']; - $user_id = $this->data['user_id']; - - $sql = 'resource_id = :resource_id '; - $sql_array = [ - 'resource_id' => $resource->id - ]; - - if ($begin and $end) { - $sql .= 'AND ((begin >= :begin AND begin <= :end) - OR - (end >= :begin AND end <= :end)) '; - $sql_array['begin'] = $begin; - $sql_array['end'] = $end; - } - - if ($user_id) { - $sql .= 'AND user_id = :user_id '; - $sql_array['user_id'] = $user_id; - } - - $sql .= 'ORDER BY mkdate ASC'; - - $requests = \ResourceRequest::findBySql($sql, $sql_array); - - $result = []; - foreach ($requests as $request) { - $result[] = $request->toRawArray(); - } - - return $result; - } - - - /** - * - * @param begin: A timestamp specifying the begin of the time range. - * @param end: A timestamp specifying the end of the time range. - * @param user_id: This parameter limits the result set to bookings - * of the user specified by the user-ID provided in this parameter. - * @param types: Limits the result to booking types specified in this - * parameter. The allowed types are comma separated like this: "1,2,3". - * The defined types are: - * 0 = normal booking, 1 = reservation, 2 = lock. - * - * @get /resources/resource/:resource_id/bookings - */ - public function getResourceBookings($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'user')) { - throw new \AccessDeniedException(); - } - - $begin = \Request::get('begin'); - $end = \Request::get('end'); - $user_id = \Request::get('user_id'); - $types = []; - $types_str = \Request::get('types'); - if ($types_str) { - $types = explode(',', $types_str); - } - - $sql = 'resource_id = :resource_id '; - $sql_array = [ - 'resource_id' => $resource->id - ]; - - if ($begin and $end) { - $sql .= 'AND ((begin >= :begin AND begin <= :end) - OR - (end >= :begin AND end <= :end)) '; - $sql_array['begin'] = $begin; - $sql_array['end'] = $end; - } - - if ($user_id) { - $sql .= 'AND user_id = :user_id '; - $sql_array['user_id'] = $user_id; - } - if ($types) { - $sql .= 'AND booking_type IN ( :types ) '; - $sql_array['types'] = $types; - } - - $sql .= 'ORDER BY mkdate ASC'; - - $bookings = \ResourceBooking::findBySql($sql, $sql_array); - - $result = []; - if ($bookings) { - foreach ($bookings as $booking) { - $result[] = $booking->toRawArray(); - } - } - - return $result; - } - - - /** - * Creates a booking/reservation/lock for a resource. - * - * @param begin: The begin timestamp for the booking. - * @param end: The end timestamp for the booking. - * @param preparation_time: The amount of seconds for preparation time - * before the begin timestamp. - * @param internal_comment: A comment that is only visible for some - * parts of the staff. - * @param booking_type: The booking type: - * 0 = normal booking - * 1 = reservation - * 2 = lock - * - * @post /resources/resource/:resource_id/assign - */ - public function createResourceBooking($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'user')) { - throw new \AccessDeniedException(); - } - - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); - $preparation_time = \Request::int('preparation_time'); - $internal_comment = \Request::get('internal_comment'); - $booking_type = \Request::int('booking_type'); - - $begin = new \DateTime(); - $begin->setTimestamp($begin_str); - $end = new \DateTime(); - $end->setTimestamp($end_str); - - try { - $booking = $resource->createSimpleBooking( - \User::findCurrent(), - $begin, - $end, - $preparation_time, - $internal_comment, - $booking_type - ); - return $booking; - } catch (\Exception $e) { - $this->halt( - 400, - $e->getMessage() - ); - } - } - - - /** - * Creates a resource request. - * - * @post /resources/resource/:resource_id/request_simple - */ - public function createSimpleResourceRequest($resource_id) - { - $resource = \Resource::find($resource_id); - if (!$resource) { - $this->notFound('Resource object not found!'); - } - - $resource = $resource->getDerivedClassInstance(); - - $user = \User::findCurrent(); - if (!$resource->userHasPermission($user, 'user')) { - throw new \AccessDeniedException(); - } - - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); - $comment = \Request::get('comment'); - - $begin = new \DateTime(); - $begin->setTimestamp($begin_str); - $end = new \DateTime(); - $end->setTimestamp($end_str); - - try { - $request = $resource->createSimpleRequest( - $user, - $begin, - $end, - $comment - ); - return $request; - } catch (\Exception $e) { - $this->halt( - 400, - $e->getMessage() - ); - } - } - - - /** - * Change the status of a resource booking interval: - * @post /resources/booking_interval/:interval_id/toggle_takes_place - */ - public function toggleResourceBookingIntervalTakesPlaceField($interval_id) - { - $interval = \ResourceBookingInterval::find($interval_id); - if (!$interval) { - $this->notFound('ResourceBookingInterval object not found!'); - } - - //Get the resource and check the permissions of the user: - $resource = $interval->resource; - if (!$resource) { - $this->halt(500, 'ResourceBookingInterval not linked with a resource!'); - } - - $resource = $resource->getDerivedClassInstance(); - - if (!$resource->userHasPermission(\User::findCurrent(), 'autor', [$interval->begin, $interval->end])) { - $this->halt(403, 'You do not have sufficient permissions to modify the interval!'); - } - - if ( - !$interval->takes_place - && $resource->isAssigned(new \DateTime('@' . $interval->begin), new \DateTime('@' . $interval->end)) - ) { - $this->halt(409, 'Already booked'); - } - //Switch the takes_place field: - $interval->takes_place = $interval->takes_place ? '0' : '1'; - - if ($interval->store()) { - return [ - 'takes_place' => $interval->takes_place - ]; - } else { - $this->halt(500, 'Error while storing the interval!'); - } - } -} diff --git a/app/routes/RoomClipboard.php b/app/routes/RoomClipboard.php deleted file mode 100644 index ffcafe6..0000000 --- a/app/routes/RoomClipboard.php +++ /dev/null @@ -1,322 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * This file contains the REST class for room clipboards - * (clipboards containing room resources). - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017-2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @since 4.5 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class RoomClipboard extends \RESTAPI\RouteMap -{ - //Room clipboard routes: - - /** - * Returns the request/booking plan for a room clipboard. - * - * @get /room_clipboard/:clipboard_id/booking_plan - */ - public function getPlan($clipboard_id = null) - { - if (!$clipboard_id) { - $this->notFound('ID of clipboard has not been provided!'); - } - - $clipboard = \Clipboard::find($clipboard_id); - if (!$clipboard) { - $this->notFound('Clipboard object not found!'); - } - - $current_user = \User::findCurrent(); - - //Permission check: - if ($clipboard->user_id !== $current_user->id) { - throw new \AccessDeniedException(); - } - - $display_requests = \Request::bool('display_requests'); - $display_all_requests = \Request::bool('display_all_requests'); - - $begin_date = \Request::get('start'); - $end_date = \Request::get('end'); - if (!$begin_date || !$end_date) { - //No time range specified. - $this->halt(400, 'The parameters "start" and "end" are missing!'); - return; - } - - //Try the ISO format first: YYYY-MM-DDTHH:MM:SS±ZZ:ZZ - $begin = \DateTime::createFromFormat(\DateTime::RFC3339, $begin_date); - $end = \DateTime::createFromFormat(\DateTime::RFC3339, $end_date); - - if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) { - $begin = new \DateTime(); - $end = new \DateTime(); - //Assume the local timezone and use the Y-m-d format: - $date_regex = '/[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1])/'; - if (preg_match($date_regex, $begin_date)) { - //$begin is specified in the date formay YYYY-MM-DD: - $begin_str = explode('-', $begin_date); - $begin->setDate( - intval($begin_str[0]), - intval($begin_str[1]), - intval($begin_str[2]) - ); - $begin->setTime(0,0,0); - } else { - $begin->setTimestamp($begin_date); - } - //Now we do the same for $end_timestamp: - if (preg_match($date_regex, $end_date)) { - //$begin is specified in the date formay YYYY-MM-DD: - $end_str = explode('-', $end_date); - $end->setDate( - intval($end_str[0]), - intval($end_str[1]), - intval($end_str[2]) - ); - $end->setTime(23,59,59); - } else { - $end->setTimestamp($end_date); - } - } - - //Check if a clipboard is selected: - $selected_clipboard_id = $_SESSION['selected_clipboard_id']; - - $rooms = []; - if ($clipboard_id) { - $clipboard = \Clipboard::find($clipboard_id); - } elseif ($selected_clipboard_id) { - $clipboard = \Clipboard::find($selected_clipboard_id); - } else { - $this->halt(400, 'No clipboard selected!'); - } - if ($clipboard) { - $rooms = \Room::findMany($clipboard->getAllRangeIds('Room')); - } else { - $this->halt(404, 'Clipboard not found!'); - } - - $booking_types = \Request::getArray('booking_types'); - - //Room permission check: - $plan_objects = []; - foreach ($rooms as $room) { - if ($room->bookingPlanVisibleForuser($current_user)) { - $plan_objects = array_merge( - $plan_objects, - \ResourceManager::getBookingPlanObjects( - $room, - [ - [ - 'begin' => $begin->getTimestamp(), - 'end' => $end->getTimestamp() - ] - ], - $booking_types, - $display_all_requests ? 'all' : $display_requests - ) - ); - } - } - - $data = \Studip\Fullcalendar::createData($plan_objects, $begin, $end); - - return $data; - } - - - /** - * Returns the semester plan for a room clipboard. - * - * @get /room_clipboard/:clipboard_id/semester_plan - */ - public function getSemeterPlan($clipboard_id = null) - { - if (!$clipboard_id) { - $this->notFound('ID of clipboard has not been provided!'); - } - - $clipboard = \Clipboard::find($clipboard_id); - if (!$clipboard) { - $this->notFound('Clipboard object not found!'); - } - - $current_user = \User::findCurrent(); - - //Permission check: - if ($clipboard->user_id !== $current_user->id) { - throw new \AccessDeniedException(); - } - - $display_requests = \Request::bool('display_requests'); - $display_all_requests = \Request::bool('display_all_requests'); - - $begin = new \DateTime(); - $end = new \DateTime(); - - $semester_id = \Request::get('semester_id'); - $semester = null; - - if ($semester_id) { - $semester = \Semester::find($semester_id); - if (!$semester) { - $this->halt(404, 'Specified semester not found!'); - } - } else { - $semester = \Semester::findCurrent(); - if (!$semester) { - $this->halt(500, 'Current semester not available!'); - } - } - - if (\Request::get('semester_timerange') == 'vorles') { - $begin->setTimestamp($semester->vorles_beginn); - $end->setTimestamp($semester->vorles_ende); - } else { - $begin->setTimestamp($semester->beginn); - $end->setTimestamp($semester->ende); - } - - //Check if a clipboard is selected: - $selected_clipboard_id = $_SESSION['selected_clipboard_id']; - - $rooms = []; - if ($clipboard_id) { - $clipboard = \Clipboard::find($clipboard_id); - } elseif ($selected_clipboard_id) { - $clipboard = \Clipboard::find($selected_clipboard_id); - } else { - $this->halt(400, 'No clipboard selected!'); - } - if ($clipboard) { - $rooms = \Room::findMany($clipboard->getAllRangeIds('Room')); - } else { - $this->halt(404, 'Clipboard not found!'); - } - - //Get parameters: - $booking_types = \Request::getArray('booking_types'); - - //Get the event data sources: - $plan_objects = []; - - foreach ($rooms as $room) { - if ($room->bookingPlanVisibleForuser($current_user)) { - $plan_objects = array_merge( - $plan_objects, - \ResourceManager::getBookingPlanObjects( - $room, - [ - [ - 'begin' => $begin->getTimestamp(), - 'end' => $end->getTimestamp() - ] - ], - $booking_types, - $display_all_requests ? 'all' : $display_requests - ) - ); - } - } - - $merged_objects = []; - $metadates = []; - foreach ($plan_objects as $plan_object) { - if ($plan_object instanceof \ResourceBooking) { - $irrelevant_booking = - $plan_object->getRepetitionType() != 'weekly' || - ($plan_object->getAssignedUserType() === 'course' && in_array($plan_object->assigned_course_date->metadate_id, $metadates)); - if ($irrelevant_booking) { - continue; - } - - //It is a booking with repetitions that has to be included - //in the semester plan. - - $real_begin = $plan_object->begin; - if ($plan_object->preparation_time > 0) { - $real_begin -= $plan_object->preparation_time; - } - $event_data = $plan_object->convertToEventData([\ResourceBookingInterval::build(['interval_id' => md5(uniqid()), 'begin' => $real_begin, 'end' => $plan_object->end])], $current_user); - - //Merge event data from the same booking that have the - //same weekday and begin and end time into one event. - //If no repetition interval is set and the booking belongs - //to a course date, use the corresponding metadate ID or the - //course date ID in the index. Otherwise use the booking's - //ID (specified by event_data->object_id). - foreach ($event_data as $event) { - if ($plan_object->getAssignedUserType() === 'course') { - $index = sprintf( - '%1$s_%2$s_%3$s', - $plan_object->assigned_course_date->metadate_id, - $event->begin->format('NHis'), - $event->end->format('NHis') - ); - $metadates[] = $plan_object->assigned_course_date->metadate_id; - } else { - $index = sprintf( - '%1$s_%2$s_%3$s', - $plan_object->id, - $event->begin->format('NHis'), - $event->end->format('NHis') - ); - } - - //Strip some data that cannot be used effectively in here: - $event->api_urls = []; - - $merged_objects[$index] = $event; - } - } elseif ($plan_object instanceof \ResourceRequest) { - if ($plan_object->cycle instanceof \SeminarCycleDate) { - $cycle_dates = $plan_object->cycle->getAllDates(); - foreach ($cycle_dates as $cycle_date) { - $relevant_request = $semester->beginn <= $cycle_date->date - && $semester->ende >= $cycle_date->date; - if ($relevant_request) { - //We have found a date for the current semester - //that makes the request relevant. - break; - } - } - if (!$relevant_request) { - continue; - } - $event_data_list = $plan_object->getFilteredEventData( - $current_user->id - ); - - foreach ($event_data_list as $event_data) { - $index = sprintf( - '%1$s_%2$s_%3$s', - $plan_object->metadate_id, - $event_data->begin->format('NHis'), - $event_data->end->format('NHis') - ); - - //Strip some data that cannot be used effectively in here: - $event_data->view_urls = []; - $event_data->api_urls = []; - - $merged_objects[$index] = $event_data; - } - } - } - } - - //Convert the merged events to Fullcalendar events: - $data = []; - foreach ($merged_objects as $obj) { - $data[] = $obj->toFullCalendarEvent(); - } - - return $data; - } -} diff --git a/app/routes/Schedule.php b/app/routes/Schedule.php deleted file mode 100644 index 2341f73..0000000 --- a/app/routes/Schedule.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author André Klaßen <andre.klassen@elan-ev.de> - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition user_id ^[a-f0-9]{1,32}$ - * @condition semester_id ^[a-f0-9]{1,32}$ - */ -class Schedule extends \RESTAPI\RouteMap -{ - /** - * returns schedule for a given user and semester - * - * @get /user/:user_id/schedule/:semester_id - * @get /user/:user_id/schedule - */ - public function getSchedule($user_id, $semester_id = null) - { - if ($user_id !== $GLOBALS['user']->id) { - $this->error(401); - } - - $current_semester = isset($semester_id) - ? \Semester::find($semester_id) - : \Semester::findCurrent(); - - if (!$current_semester) { - $this->notFound('No such semester.'); - } - - $schedule_settings = \UserConfig::get($user_id)->SCHEDULE_SETTINGS; - $days = \CalendarScheduleModel::getDisplayedDays($schedule_settings['glb_days']); - - $entries = \CalendarScheduleModel::getEntries( - $user_id, $current_semester, - $schedule_settings['glb_start_time'], $schedule_settings['glb_end_time'], - $days, - $visible = false - ); - - $json = []; - foreach ($entries as $number_of_day => $schedule_of_day) { - $entries = []; - foreach ($schedule_of_day->entries as $entry) { - $entries[$entry['id']] = self::entryToJson($entry); - } - $json[$number_of_day] = $entries; - } - - $this->etag(md5(serialize($json))); - - return array_reverse($json, true); - } - - - private static function entryToJson($entry) - { - $json = []; - foreach (['start', 'end', 'content', 'title', 'color', 'type'] as $key) { - $json[$key] = in_array($key, ['start', 'end']) - ? (int) $entry[$key] - : $entry[$key]; - } - - return $json; - } -} diff --git a/app/routes/Semester.php b/app/routes/Semester.php deleted file mode 100644 index bdb1ee7..0000000 --- a/app/routes/Semester.php +++ /dev/null @@ -1,115 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author Jan-Hendrik Willms <tleilax+studip@gmail.com> - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition semester_id ^[0-9a-f]{1,32}$ - */ -class Semester extends \RESTAPI\RouteMap -{ - public function __construct() - { - parent::__construct(); - if (!\Request::int('limit')) { - $this->limit = count(\Semester::getAll()); - } - } - - /** - * Returns a list of all semesters. - * - * @get /semesters - * @allow_nobody - */ - public function getSemesters() - { - $semesters = \Semester::getAll(); - - // paginate - $total = count($semesters); - $semesters = array_slice($semesters, $this->offset, $this->limit); - - $json = []; - foreach ($semesters as $semester) { - $url = $this->urlf('/semester/%s', $semester['semester_id']); - $json[$url] = $this->semesterToJSON($semester); - } - - return $this->paginated($json, $total); - } - - /** - * Returns the semester week as string for a given string - * - * @get /semester/:timestamp/week - * @allow_nobody - */ - public function getSemesterWeek(int $timestamp) - { - $semester = \Semester::findByTimestamp($timestamp); - if (!$semester) { - return null; - } - $timestamp = strtotime('today', $timestamp); - $week_begin_timestamp = strtotime('monday this week', $semester->vorles_beginn); - $end_date = $semester->vorles_ende; - - $i = 0; - $result = [ - 'semester_name' => (string)$semester->name, - 'week_number' => sprintf(_('KW %u'), date('W', $timestamp)), - 'current_day' => strftime('%x', $timestamp) - ]; - while ($week_begin_timestamp < $end_date) { - $next_week_timestamp = strtotime('+1 week', $week_begin_timestamp); - if ($week_begin_timestamp <= $timestamp && $timestamp < $next_week_timestamp) { - $result['sem_week'] = sprintf( - _('%u. Vorlesungswoche (ab %s)'), - $i + 1, - strftime('%x', $week_begin_timestamp)); - break; - } - $i += 1; - - $week_begin_timestamp = $next_week_timestamp; - } - - return $result; - } - - /** - * Returns a single semester. - * - * @get /semester/:semester_id - */ - public function getSemester($id) - { - $semester = \Semester::find($id); - if (!$semester) { - $this->notFound(); - } - - $semester_json = $this->semesterToJSON($semester); - $this->etag(md5(serialize($semester_json))); - - return $semester_json; - } - - private function semesterToJSON($semester) - { - return [ - 'id' => $semester['semester_id'], - 'title' => (string) $semester['name'], - 'token' => (string) $semester['semester_token'], - 'begin' => (int) $semester['beginn'], - 'end' => (int) $semester['ende'], - 'seminars_begin' => (int) $semester['vorles_beginn'], - 'seminars_end' => (int) $semester['vorles_ende'], - 'visible' => (int) $semester['visible'], - ]; - } -} diff --git a/app/routes/Studip.php b/app/routes/Studip.php deleted file mode 100644 index 749a53a..0000000 --- a/app/routes/Studip.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -use Config; -use SemClass; -use SemType; - -/** - * @author Jan-Hendrik Willms <tleilax+studip@gmail.com> - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - */ -class Studip extends \RESTAPI\RouteMap -{ - /** - * Grundlegende Systemeinstellungen - * - * @get /studip/settings - */ - public function getSettings() - { - $sem_types = array_map(function ($item) { - return [ - 'name' => $item['name'], - 'class' => $item['class'], - ]; - }, SemType::getTypes()); - - $sem_classes = array_map(function ($item) { - $item = (array) $item; - return reset($item); - }, SemClass::getClasses()); - - return [ - 'ALLOW_CHANGE_USERNAME' => Config::get()->ALLOW_CHANGE_USERNAME, - 'ALLOW_CHANGE_EMAIL' => Config::get()->ALLOW_CHANGE_EMAIL, - 'ALLOW_CHANGE_NAME' => Config::get()->ALLOW_CHANGE_NAME, - 'ALLOW_CHANGE_TITLE' => Config::get()->ALLOW_CHANGE_TITLE, - 'INST_TYPE' => $GLOBALS['INST_TYPE'], - 'SEM_TYPE' => $sem_types, - 'SEM_CLASS' => $sem_classes, - 'TERMIN_TYP' => $GLOBALS['TERMIN_TYP'], - 'PERS_TERMIN_KAT' => $GLOBALS['PERS_TERMIN_KAT'], - 'SUPPORT_EMAIL' => $GLOBALS['UNI_CONTACT'], - 'TITLES' => $GLOBALS['DEFAULT_TITLE_FOR_STATUS'], - 'UNI_NAME_CLEAN' => Config::get()->UNI_NAME_CLEAN, - ]; - } - - /** - * Farbeinstellungen - * - * @get /studip/colors - */ - public function getColors() - { - // TODO: Move these definitions somewhere else (but where!?) - return [ - 'background' => '#e1e4e9', - 'dark' => '#34578c', - 'light' => '#899ab9', - ]; - } -} diff --git a/app/routes/User.php b/app/routes/User.php deleted file mode 100644 index d3cce26..0000000 --- a/app/routes/User.php +++ /dev/null @@ -1,300 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author André Klaßen <andre.klassen@elan-ev.de> - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition user_id ^[0-9a-f]{1,32}$ - */ -class User extends \RESTAPI\RouteMap -{ - /**************************************************/ - /* PUBLIC STATIC HELPER METHODS */ - /**************************************************/ - - public static function getMiniUser($routemap, $user) - { - $avatar = \Avatar::getAvatar($user->id); - - return [ - 'id' => $user->id, - 'href' => $routemap->urlf('/user/%s', [htmlReady($user->id)]), - 'name' => self::getNamesOfUser($user), - 'avatar_small' => $avatar->getURL(\Avatar::SMALL), - 'avatar_medium' => $avatar->getURL(\Avatar::MEDIUM), - 'avatar_normal' => $avatar->getURL(\Avatar::NORMAL), - 'avatar_original' => $avatar->getURL(\Avatar::NORMAL) - ]; - } - - public static function getNamesOfUser($user) - { - $name = [ - 'username' => $user->username, - 'formatted' => $user->getFullName(), - 'family' => $user->nachname, - 'given' => $user->vorname, - 'prefix' => $user->title_front, - 'suffix' => $user->title_rear - ]; - return $name; - } - - - /**************************************************/ - /* ROUTES */ - /**************************************************/ - - /** - * Searches for users by a given keyword. - * - * @get /users - */ - public function searchUsers() - { - $needle = \Request::get('q') ?? \Request::get('needle'); - if (!$needle) { - $this->halt(400, 'Missing search paramter ?q='); - } - - $query = \GlobalSearchUsers::getSQL($needle, [], $this->offset + $this->limit); - $result = \DBManager::get()->fetchAll($query); - $total = (int) \DBManager::get()->fetchColumn('SELECT FOUND_ROWS() as found_rows'); - - $user_ids = array_column($result, 'user_id'); - $users = \User::findMany($user_ids); - - return $this->paginated( - array_map(function ($user) { - return self::getMiniUser($this, $user); - }, $users), - $total - ); - } - - - /** - * getUser - retrieves data of a user - * - * @get /user/:user_id - * @get /user - */ - public function getUser($user_id = '') - { - $user_id = $user_id ?: $GLOBALS['user']->id; - - $user = \User::findFull($user_id); - if (!$user) { - $this->halt(404, sprintf('User %s not found', $user_id)); - } - - $visibilities = get_local_visibility_by_id($user_id, 'homepage'); - if (is_array(json_decode($visibilities, true))) { - $visibilities = json_decode($visibilities, true); - } else { - $visibilities = []; - } - - $get_field = function ($field, $visibility) use ($user_id, $user, $visibilities) { - if (!$user[$field] - || !is_element_visible_for_user($GLOBALS['user']->id, $user_id, $visibilities[$visibility])) - { - return ''; - } - return $user[$field]; - }; - - $avatar = \Avatar::getAvatar($user_id); - - $user = [ - 'user_id' => $user_id, - 'username' => $user['username'], - 'name' => self::getNamesOfUser($user), - 'perms' => $user['perms'], - 'email' => get_visible_email($user_id), - 'avatar_small' => $avatar->getURL(\Avatar::SMALL), - 'avatar_medium' => $avatar->getURL(\Avatar::MEDIUM), - 'avatar_normal' => $avatar->getURL(\Avatar::NORMAL), - 'avatar_original' => $avatar->getURL(\Avatar::NORMAL), - 'phone' => $get_field('privatnr', 'private_phone'), - 'homepage' => $get_field('Home', 'homepage'), - 'privadr' => strip_tags($get_field('privadr', 'privadr')), - ]; - - // Data fields - $datafields = []; - foreach (\DataFieldEntry::getDataFieldEntries($user_id, 'user') as $entry) { - if (!$entry->isVisible()) { - continue; - } - if (!\Visibility::verify($entry->getID(), $user_id)) { - continue; - } - $datafields[] = [ - 'type' => $entry->getType(), - 'id' => $entry->getId(), - 'name' => (string) $entry->getName(), - 'value' => $entry->getValue(), - ]; - } - $user['datafields'] = $datafields; - - $this->etag(md5(serialize($user))); - - return $user; - - } - - - /** - * deleteUser - deletes a user - * - * @delete /user/:user_id - */ - public function deleteUser($user_id) - { - if (!$GLOBALS['perm']->have_perm('root')) { - $this->error(401); - } - - if (!$GLOBALS['user']->id === $user_id) { - $this->error(400, 'Must not delete yourself'); - } - - $user = \User::find($user_id); - $user->delete(); - - $this->status(204); - } - - - /** - * returns institutes for a given user - * - * @get /user/:user_id/institutes - */ - public function getInstitutes($user_id) - { - $user = \User::find($user_id); - if (!$user) { - $this->notFound(sprintf('User %s not found', $user_id)); - } - - $query = "SELECT i0.Institut_id AS institute_id, i0.Name AS name, - inst_perms AS perms, sprechzeiten AS consultation, - raum AS room, ui.telefon AS phone, ui.fax, - i0.Strasse AS street, i0.Plz AS city, - i1.Name AS faculty_name, i1.Strasse AS faculty_street, - i1.Plz AS faculty_city - FROM user_inst AS ui - JOIN Institute AS i0 USING (Institut_id) - LEFT JOIN Institute AS i1 ON (i0.fakultaets_id = i1.Institut_id) - WHERE visible = 1 AND user_id = :user_id - ORDER BY priority ASC"; - $statement = \DBManager::get()->prepare($query); - $statement->bindValue(':user_id', $user_id); - $statement->execute(); - - $institutes = [ - 'work' => [], - 'study' => [], - ]; - - foreach ($statement->fetchAll(\PDO::FETCH_ASSOC) as $row) { - if ($row['perms'] === 'user') { - $institutes['study'][] = $row; - } else { - $institutes['work'][] = $row; - } - } - - $this->etag(md5(serialize($institutes))); - - $result = array_slice($institutes, $this->offset, $this->limit); - return $this->paginated( - $result, - count($institutes['study']) + count($institutes['work']), - compact('user_id') - ); - } - - - /** - * Get the root file folder of a user's file area. - * - * @get /user/:user_id/top_folder - */ - public function getTopFolder($user_id) - { - $user = \User::find($user_id); - if (!$user) { - $this->notFound("User with id {$user_id} not found!"); - } - - if ($user->id !== \User::findCurrent()->id) { - $this->error(403, 'You are not allowed to see another user\'s personal file area!'); - } - - $top_folder = \Folder::findTopFolder($user->id, 'user'); - - if (!$top_folder) { - $this->notFound("No folder found for user with id {$user_id}!"); - } - - return (new FileSystem())->getFolder($top_folder->id); - } - - /** - * Patches the course member data of a user and course. Pass data to be - * patched via a valid json object in the body. Fields that my be patched: - * - * - group - the associated group in the overview of the users's courses - * - visibility - visible state of the course - * - * @patch /user/:user_id/courses/:course_id - * - * @todo more patchable fields? - */ - public function patchCourseGroup($user_id, $course_id) - { - $user = \User::find($user_id); - if (!$user) { - $this->notFound('User not found'); - } - - if ($user->id !== $GLOBALS['user']->id) { - $this->halt(403, "You may not alter this user's data"); - } - - $member = \CourseMember::find([$course_id, $user->id]); - if (!$member) { - $this->notFound('You are not a member of the course'); - } - - if (isset($this->data['group'])) { - if (!is_numeric($this->data['group']) || $this->data['group'] < 0 || $this->data['group'] > 8) { - $this->halt(400, 'Given group is not inside the valid range 0..8'); - } - $member->gruppe = $this->data['group']; - } - - if (isset($this->data['visibility'])) { - if (in_array($member->status, ['tutor', 'dozent'])) { - $this->halt(400, 'You may not change the visibility status for this course since you are a teacher.'); - } - if (!in_array($this->data['visibility'], ['yes', 'no'])) { - $this->halt(400, 'Visibility may only be "yes" or "no".'); - } - $member->visible = $this->data['visibility']; - } - - if ($member->isDirty()) { - $member->store(); - } - - $this->halt(204); - } -} diff --git a/app/routes/UserConfig.php b/app/routes/UserConfig.php deleted file mode 100644 index ba01538..0000000 --- a/app/routes/UserConfig.php +++ /dev/null @@ -1,99 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -use RESTAPI\RouteMap; -use RESTAPI\Router; - -/** - * API routes for accessing user config values. - * - * @author Jan-Hendrik Willms <tleilax+studip@gmail.com> - * @license GPL2 or any later version - * @since Stud.IP 3.4 - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition user_id ^[0-9a-f]{1,32}$ - * - * @status 404 if user does not exist - * @status 403 if user may access the request config item - */ -class UserConfig extends RouteMap -{ - // Stores the user's config instance - private $config; - - /** - * Performs checks if the user exists and may actually access the - * requested config. - * - * @param Router $router Instance of the api router - * @param array $handler Detected handler router - * @param array $parameters Parameters of the called route - */ - public function before(Router $router, array $handler, array $parameters) - { - // Check whether user exist - if (\User::find($parameters['user_id']) === null) { - $this->error(404, sprintf('User %s not found', $parameters['user_id'])); - } - - // Check whether user accesses own config or user is root - if ($parameters['user_id'] !== $GLOBALS['user']->id && $GLOBALS['user']->perms !== 'root') { - $this->error(403, 'User may only access own config'); - } - - $this->config = \UserConfig::get($parameters['user_id']); - } - - /** - * Returns the value of a specific config entry for a given user - * - * @get /user/:user_id/config/:field - * - * @return mixed Value for the request config item - * @status 404 if config item does not exist - */ - public function getConfig($user_id, $field) - { - // Check whether key exists in config - if (!isset($this->config[$field])) { - $this->error(404, sprintf('No config item for field %s and user %s', - $field, $user_id)); - } - - return $this->config[$field]; - } - - /** - * Stored the value of a specific config entry for a given user - * - * @put /user/:user_id/config/:field - * - * @status 204 on success - * @status 400 if no value is given - */ - public function setConfig($user_id, $field) - { - if (!isset($this->data['value'])) { - $this->error(400, 'No value given in request'); - } - - $this->config->store($field, $this->data['value']); - - $this->status(204); - } - - /** - * Removes a specific config entry for a given user - * - * @delete /user/:user_id/config/:field - * - * @status 204 on success - */ - public function deleteConfig($user_id, $field) - { - $this->config->delete($field); - - $this->status(204); - } -} diff --git a/app/routes/Wiki.php b/app/routes/Wiki.php deleted file mode 100644 index 7f54628..0000000 --- a/app/routes/Wiki.php +++ /dev/null @@ -1,148 +0,0 @@ -<?php -namespace RESTAPI\Routes; - -/** - * @author <mlunzena@uos.de> - * @license GPL 2 or later - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - * - * @condition range_id ^[0-9a-f]{1,32}$ - */ -class Wiki extends \RESTAPI\RouteMap -{ - public function before() - { - require_once 'User.php'; - } - - /** - * Wikiseitenindex einer Veranstaltung - * - * @get /course/:range_id/wiki - */ - public function getCourseWiki($range_id) - { - $pages = \WikiPage::findBySQL("`range_id` = ? ORDER BY `name` ASC", [$range_id]); - - if (!$pages[0]->isReadable()) { - $this->error(401); - } - - $total = sizeof($pages); - $pages = $pages->limit($this->offset, $this->limit); - - $linked_pages = []; - foreach ($pages as $page) { - $url = $this->urlf('/course/%s/wiki/%s', [$range_id, htmlReady($page['keyword'])]); - $linked_pages[$url] = $this->wikiPageToJson($page, ["content"]); - } - - $this->etag(md5(serialize($linked_pages))); - - return $this->paginated($linked_pages, $total, compact('range_id')); - } - - /** - * Wikiseite auslesen - * - * @get /course/:range_id/wiki/:keyword - * @get /course/:range_id/wiki/:keyword/:version - */ - public function getCourseWikiKeyword($range_id, $keyword, $version = null) - { - $page = $this->requirePage($range_id, $keyword, $version); - $wiki_json = $this->wikiPageToJson($page); - $this->etag(md5(serialize($wiki_json))); - $this->lastmodified($page->chdate); - return $wiki_json; - } - - /** - * Wikiseite ändern/hinzufügen - * - * @put /course/:range_id/wiki/:keyword - */ - public function putCourseWikiKeyword($range_id, $keyword) - { - if (!isset($this->data['content'])) { - $this->error(400, 'No content provided'); - } - - $page =\WikiPage::findOneBySQL("`range_id` = ? AND `name` = ?", [$range_id, $keyword]); - if (!$page) { - $page = new \WikiPage(); - $page->range_id = $range_id; - $page->name = $keyword; - } - - if (!$page->isEditable()) { - $this->error(401); - } - - $page->content = $this->data['content']; - $page->store(); - - $url = sprintf('course/%s/wiki/%s/%d', htmlReady($range_id), htmlReady($keyword), count($page->versions) + 1); - $this->redirect($url, 201, 'ok'); - } - - /**************************************************/ - /* PRIVATE HELPER METHODS */ - /**************************************************/ - - private function requirePage($range_id, $keyword, $version = null) - { - $page = \WikiPage::findOneBySQL("`range_id` = ? AND `name` = ?", [$range_id, $keyword]); - - if (!$page) { - $this->notFound(); - } - - if (!$page->isReadable($GLOBALS['user']->id)) { - $this->error(401); - } - if ($version !== null && $version !== count($page->versions) + 1) { - return $page->versions[count($page->versions) - 1 - $version]; - } else { - return $page; - } - } - - private function wikiPageToJson($page, $without = []) - { - $json = [ - 'range_id' => $page->range_id, - 'keyword' => $page->name, - 'chdate' => $page->chdate, - 'version' => 1 - ]; - - // (pre-rendered) content - if (!in_array('content', $without)) { - $json['content'] = $page->content; - $json['content_html'] = wikiReady($page->content, true, $page->range_id, $page->id); - } - if (!in_array('user', $without)) { - if ($page->author) { - $json['user'] = User::getMiniUser($this, $page->user_id); - } - } - - foreach ($without as $key) { - if (isset($json[$key])) { - unset($json[$key]); - } - } - - // string to int conversions as SORM does not know about ints - foreach (['chdate', 'mkdate', 'filesize', 'downloads'] as $key) { - if (isset($json[$key])) { - $json[$key] = (int) $json[$key]; - } - } - - return $json; - } - - -} |
