public function comment_action() { $context = Request::option("context"); $thread = new ForumPosting(Request::option("thread")); if ($thread['context_type'] === "course") { $seminar = new Seminar($context); if ($seminar->write_level > 0 && !$GLOBALS['perm']->have_studip_perm("autor", $context)) { throw new AccessDeniedException("Kein Zugriff"); } } ForumPosting::$course_hashes = $thread['context_type'] === "course" ? $thread['Seminar_id'] : false; if (Request::option("thread") && $thread['Seminar_id'] === $context) { $output = array(); $posting = new ForumPosting(); ForumPosting::$mention_thread_id = $thread->getId(); StudipTransformFormat::addStudipMarkup("mention1", '@\\"[^\\n\\"]*\\"', "", "ForumPosting::mention"); StudipTransformFormat::addStudipMarkup("mention2", '@[^\\s]*[\\d\\w_]+', "", "ForumPosting::mention"); $content = transformBeforeSave(studip_utf8decode(Request::get("content"))); //mentions einbauen: $content = preg_replace("/(@\"[^\n\"]*\")/e", "ForumPosting::mention('\\1', '" . $thread->getId() . "')", $content); $content = preg_replace("/(@[^\\s]+)/e", "ForumPosting::mention('\\1', '" . $thread->getId() . "')", $content); $posting['description'] = $content; $posting['context_type'] = $thread['context_type']; $posting['seminar_id'] = $thread['Seminar_id']; $posting['root_id'] = $posting['parent_id'] = Request::option("thread"); $posting['name'] = "Re: " . $thread['name']; if ($GLOBALS['user']->id !== "nobody") { $posting['user_id'] = $GLOBALS['user']->id; $posting['author'] = get_fullname(); } else { if (Request::get("anonymous_security") === $_SESSION['blubber_anonymous_security']) { $contact_user = BlubberExternalContact::findByEmail(Request::get("anonymous_email")); $_SESSION['anonymous_email'] = Request::get("anonymous_email"); $_SESSION['anonymous_name'] = $contact_user['name'] = Request::get("anonymous_name"); $contact_user->store(); $posting['user_id'] = $contact_user->getId(); $posting['external_contact'] = 1; $posting['author'] = Request::get("anonymous_name"); } else { throw new AccessDeniedException("No permission to write posting."); } } $posting['author_host'] = $_SERVER['REMOTE_ADDR']; if ($posting->store()) { $factory = new Flexi_TemplateFactory($this->plugin->getPluginPath() . "/views/forum"); $template = $factory->open("comment.php"); $template->set_attribute('posting', $posting); $template->set_attribute('course_id', $thread['Seminar_id']); $output['content'] = studip_utf8encode($template->render($template->render())); $output['mkdate'] = time(); $output['posting_id'] = $posting->getId(); //Notifications: if (class_exists("PersonalNotifications")) { $user_ids = array(); if ($thread['user_id'] && $thread['user_id'] !== $GLOBALS['user']->id) { $user_ids[] = $thread['user_id']; } foreach ((array) $thread->getChildren() as $comment) { if ($comment['user_id'] && $comment['user_id'] !== $GLOBALS['user']->id && !$comment['external_contact']) { $user_ids[] = $comment['user_id']; } } $user_ids = array_unique($user_ids); PersonalNotifications::add($user_ids, PluginEngine::getURL($this->plugin, array('cid' => $thread['context_type'] === "course" ? $thread['Seminar_id'] : null), "forum/thread/" . $thread->getId()), get_fullname() . " hat einen Kommentar geschrieben", "posting_" . $posting->getId(), Avatar::getAvatar($GLOBALS['user']->id)->getURL(Avatar::MEDIUM)); } } $this->render_json($output); } else { $this->render_json(array('error' => "Konnte thread nicht zuordnen.")); } }
/** * update the passed topic * * @param type $topic_id the id of the topic to update * @param type $name the new name * @param type $content the new content * * @return void */ static function update($topic_id, $name, $content) { $topic = ForumEntry::getConstraints($topic_id); if (time() - $topic['mkdate'] > 5 * 60) { $content = ForumEntry::appendEdit($content); } $stmt = DBManager::get()->prepare("UPDATE forum_entries\n SET name = ?, content = ?, chdate = UNIX_TIMESTAMP(), latest_chdate = UNIX_TIMESTAMP()\n WHERE topic_id = ?"); $stmt->execute(array($name, transformBeforeSave($content), $topic_id)); // update "latest_chdate" for easier sorting of actual threads $parent_id = ForumEntry::getParentTopicId($topic_id); DBManager::get()->exec("UPDATE forum_entries SET latest_chdate = UNIX_TIMESTAMP()\n WHERE topic_id = '" . $parent_id . "'"); }
/** * Edits the content of a blubber. Sends a message of the change to the author, if the editing user is not * the author of the blubber, to inform him/her about the change. * If the content is empty the blubber is going to be deleted, because we don't want empty * blubber in the system. * * @put /blubber/posting/:blubber_id * @put /blubber/comment/:blubber_id * * @param string $blubber_id * * @param string content new content for the blubber */ public function editBlubberPosting($blubber_id) { if (!strlen(trim($this->data['content']))) { $this->error(400, 'No content provided'); } $blubber = new \BlubberPosting($blubber_id); $this->requireWriteAccessTo($blubber); if ($this->requestedRouteMatches('/posting/') xor $blubber->isThread()) { $this->notFound(); } $old_content = $blubber['description']; \BlubberPosting::$mention_posting_id = $blubber->getId(); \StudipTransformFormat::addStudipMarkup("mention1", '@\\"[^\\n\\"]*\\"', "", "\\BlubberPosting::mention"); \StudipTransformFormat::addStudipMarkup("mention2", '@[^\\s]*[\\d\\w_]+', "", "\\BlubberPosting::mention"); $content = \transformBeforeSave($this->data['content']); $blubber['name'] = $blubber['description'] = $content; $blubber->store(); if ($blubber['user_id'] !== $GLOBALS['user']->id) { $this->sendEditMail($blubber, sprintf(_("%s hat als Moderator gerade Ihren Beitrag im Blubberforum editiert.\n\nDie alte Version des Beitrags lautete:\n\n%s\n\nDie neue lautet:\n\n%s\n"), get_fullname(), $old_content, $blubber['description']), _("Änderungen an Ihrem Posting.")); } $this->status(204); }
/** * this action renders a preview of the submitted text */ function preview_action() { if (Request::isXhr()) { $this->set_content_type('text/html; charset=UTF-8'); $this->render_text(studip_utf8encode(formatReady(transformBeforeSave(studip_utf8decode(Request::get('posting')))))); } else { $this->render_text(ForumEntry::getContentAsHtml(transformBeforeSave(Request::get('posting')))); } }
/** * Writes a comment on a thread and outputs the metadata of new comment as json. * @throws AccessDeniedException */ public function comment_action() { if (!Request::isPost()) { throw new Exception("GET not supported"); } $context = Request::option("context"); $thread = new BlubberPosting(Request::option("thread")); if ($thread['context_type'] === "course" && $GLOBALS['SessSemName']['class'] === "sem") { $seminar = new Seminar($context); if ($seminar->write_level > 0 && !$GLOBALS['perm']->have_studip_perm("autor", $context)) { throw new AccessDeniedException(); } } BlubberPosting::$course_hashes = $thread['context_type'] === "course" ? $thread['Seminar_id'] : false; if (!$thread->isNew() && $thread['Seminar_id'] === $context) { $output = array(); $posting = new BlubberPosting(); $posting['context_type'] = $thread['context_type']; $posting['seminar_id'] = $thread['Seminar_id']; $posting['root_id'] = $posting['parent_id'] = $thread->getId(); $posting['name'] = "Re: " . $thread['name']; if ($GLOBALS['user']->id !== "nobody") { $posting['user_id'] = $GLOBALS['user']->id; } else { if (Request::get("anonymous_security") === $_SESSION['blubber_anonymous_security']) { $contact_user = BlubberExternalContact::findByEmail(Request::get("anonymous_email")); $_SESSION['anonymous_email'] = Request::get("anonymous_email"); $_SESSION['anonymous_name'] = $contact_user['name'] = Request::get("anonymous_name"); $contact_user->store(); $posting['user_id'] = $contact_user->getId(); $posting['external_contact'] = 1; } else { throw new AccessDeniedException("No permission to write posting."); } } $posting['author_host'] = $_SERVER['REMOTE_ADDR']; $posting['description'] = studip_utf8decode(Request::get("content")); $posting->store(); BlubberPosting::$mention_posting_id = $posting->getId(); StudipTransformFormat::addStudipMarkup("mention1", '@\\"[^\\n\\"]*\\"', null, "BlubberPosting::mention"); StudipTransformFormat::addStudipMarkup("mention2", '@[^\\s]*[\\d\\w_]+', null, "BlubberPosting::mention"); $content = transformBeforeSave(studip_utf8decode(Request::get("content"))); $posting['description'] = $content; $posting->store(); $factory = new Flexi_TemplateFactory($this->plugin->getPluginPath() . "/views/streams"); $template = $factory->open("comment.php"); $template->set_attribute('posting', $posting); $template->set_attribute('course_id', $thread['Seminar_id']); $output['content'] = $template->render($template->render()); $output['mkdate'] = time(); $output['posting_id'] = $posting->getId(); //Notifications: $user_ids = array(); if ($thread['user_id'] && $thread['user_id'] !== $GLOBALS['user']->id) { $user_ids[] = $thread['user_id']; } foreach ((array) $thread->getChildren() as $comment) { if ($comment['user_id'] && $comment['user_id'] !== $GLOBALS['user']->id && !$comment['external_contact']) { $user_ids[] = $comment['user_id']; } } $user_ids = array_unique($user_ids); foreach ($user_ids as $user_id) { setTempLanguage($user_id); $avatar = Visibility::verify('picture', $GLOBALS['user']->id, $user_id) ? Avatar::getAvatar($GLOBALS['user']->id) : Avatar::getNobody(); PersonalNotifications::add($user_id, PluginEngine::getURL($this->plugin, array('cid' => $thread['context_type'] === "course" ? $thread['Seminar_id'] : null), "streams/thread/" . $thread->getId()), sprintf(_("%s hat einen Kommentar geschrieben"), get_fullname()), "posting_" . $posting->getId(), $avatar->getURL(Avatar::MEDIUM)); restoreLanguage(); } $this->render_json($output); } else { $this->render_json(array('error' => "Konnte thread nicht zuordnen.")); } }
/** * Builds news dialog for editing / adding news * * @param string $id news id (in case news already exists; otherwise set to "new") * @param string $context_range range id (only for new news; set to 'template' for copied news) * @param string $template_id template id (source of news template) * */ function edit_news_action($id = '', $context_range = '', $template_id = '') { // initialize $this->news_isvisible = array('news_basic' => true, 'news_comments' => false, 'news_areas' => false); $ranges = array(); $this->ranges = array(); $this->area_options_selectable = array(); $this->area_options_selected = array(); $this->may_delete = false; $this->route = "news/edit_news/{$id}"; if ($context_range) { $this->route .= "/{$context_range}"; if ($template_id) { $this->route .= "/{$template_id}"; } } $msg_object = new messaging(); if ($id == "new") { unset($id); $this->title = _("Ankündigung erstellen"); } else { $this->title = _("Ankündigung bearbeiten"); } // user has to have autor permission at least if (!$GLOBALS['perm']->have_perm(autor)) { $this->set_status(401); return $this->render_nothing(); } // Output as dialog (Ajax-Request) or as Stud.IP page? if (Request::isXhr()) { $this->set_layout(null); header('X-Title: ' . $this->title); } else { $this->set_layout($GLOBALS['template_factory']->open('layouts/base')); } // load news and comment data and check if user has permission to edit $news = new StudipNews($id); if (!$news->isNew()) { $this->comments = StudipComment::GetCommentsForObject($id); } if (!$news->havePermission('edit') and !$news->isNew()) { $this->set_status(401); PageLayout::postMessage(MessageBox::error(_('Keine Berechtigung!'))); return $this->render_nothing(); } // if form sent, get news data by post vars if (Request::get('news_isvisible')) { // visible categories, selected areas, topic, and body are utf8 encoded when sent via ajax $this->news_isvisible = unserialize(Request::get('news_isvisible')); if (Request::isXhr()) { $this->area_options_selected = unserialize(studip_utf8decode(Request::get('news_selected_areas'))); $this->area_options_selectable = unserialize(studip_utf8decode(Request::get('news_selectable_areas'))); $topic = studip_utf8decode(Request::get('news_topic')); $body = transformBeforeSave(Studip\Markup::purifyHtml(studip_utf8decode(Request::get('news_body')))); } else { $this->area_options_selected = unserialize(Request::get('news_selected_areas')); $this->area_options_selectable = unserialize(Request::get('news_selectable_areas')); $topic = Request::get('news_topic'); $body = transformBeforeSave(Studip\Markup::purifyHtml(Request::get('news_body'))); } $date = $this->getTimeStamp(Request::get('news_startdate'), 'start'); $expire = $this->getTimeStamp(Request::get('news_enddate'), 'end') ? $this->getTimeStamp(Request::get('news_enddate'), 'end') - $this->getTimeStamp(Request::get('news_startdate'), 'start') : ''; $allow_comments = Request::get('news_allow_comments') ? 1 : 0; if (Request::submitted('comments_status_deny')) { $this->anker = 'news_comments'; $allow_comments = 0; } elseif (Request::submitted('comments_status_allow')) { $this->anker = 'news_comments'; $allow_comments = 1; } if ($news->getValue('topic') != $topic or $news->getValue('body') != $body or $news->getValue('date') != $date or $news->getValue('allow_comments') != $allow_comments or $news->getValue('expire') != $expire) { $changed = true; } $news->setValue('topic', $topic); $news->setValue('body', $body); $news->setValue('date', $date); $news->setValue('expire', $expire); $news->setValue('allow_comments', $allow_comments); } elseif ($id) { // if news id given check for valid id and load ranges if ($news->isNew()) { PageLayout::postMessage(MessageBox::error(_('Die Ankündigung existiert nicht!'))); return $this->render_nothing(); } $ranges = $news->news_ranges->toArray(); } elseif ($template_id) { // otherwise, load data from template $news_template = new StudipNews($template_id); if ($news_template->isNew()) { PageLayout::postMessage(MessageBox::error(_('Die Ankündigung existiert nicht!'))); return $this->render_nothing(); } // check for permission if (!$news_template->havePermission('edit')) { $this->set_status(401); return $this->render_nothing(); } $ranges = $news_template->news_ranges->toArray(); // remove those ranges for which user doesn't have permission foreach ($ranges as $key => $news_range) { if (!$news->haveRangePermission('edit', $news_range['range_id'])) { $changed_areas++; $this->news_isvisible['news_areas'] = true; unset($ranges[$key]); } } if ($changed_areas == 1) { PageLayout::postMessage(MessageBox::info(_('1 zugeordneter Bereich wurde nicht übernommen, weil Sie dort keine Ankündigungen erstellen dürfen.'))); } elseif ($changed_areas) { PageLayout::postMessage(MessageBox::info(sprintf(_('%s zugeordnete Bereiche wurden nicht übernommen, weil Sie dort keine Ankündigungen erstellen dürfen.'), $changed_areas))); } $news->setValue('topic', $news_template->getValue('topic')); $news->setValue('body', $news_template->getValue('body')); $news->setValue('date', $news_template->getValue('date')); $news->setValue('expire', $news_template->getValue('expire')); $news->setValue('allow_comments', $news_template->getValue('allow_comments')); } else { // for new news, set startdate to today and range to dialog context $news->setValue('date', strtotime(date('Y-m-d'))); // + 12*60*60; $news->setValue('expire', 604800); if ($context_range != '' and $context_range != 'template') { $add_range = new NewsRange(array('', $context_range)); $ranges[] = $add_range->toArray(); } } // build news var for template $this->news = $news->toArray(); // treat faculties and institutes as one area group (inst) foreach ($ranges as $range) { switch ($range['type']) { case 'fak': $this->area_options_selected['inst'][$range['range_id']] = $range['name']; break; default: $this->area_options_selected[$range['type']][$range['range_id']] = $range['name']; } } // define search presets $this->search_presets['user'] = _('Meine Profilseite'); if ($GLOBALS['perm']->have_perm('autor') and !$GLOBALS['perm']->have_perm('admin')) { $my_sem = $this->search_area('__THIS_SEMESTER__'); if (count($my_sem['sem'])) { $this->search_presets['sem'] = _('Meine Veranstaltungen im aktuellen Semester') . ' (' . count($my_sem['sem']) . ')'; } } if ($GLOBALS['perm']->have_perm('dozent') and !$GLOBALS['perm']->have_perm('root')) { $my_inst = $this->search_area('__MY_INSTITUTES__'); if (count($my_inst)) { $this->search_presets['inst'] = _('Meine Einrichtungen') . ' (' . count($my_inst['inst']) . ')'; } } if ($GLOBALS['perm']->have_perm('root')) { $this->search_presets['global'] = $this->area_structure['global']['title']; } // perform search if (Request::submitted('area_search') or Request::submitted('area_search_preset')) { $this->anker = 'news_areas'; $this->search_term = studip_utf8decode(Request::get('area_search_term')); if (Request::submitted('area_search')) { $this->area_options_selectable = $this->search_area($this->search_term); } else { $this->current_search_preset = Request::option('search_preset'); if ($this->current_search_preset == 'inst') { $this->area_options_selectable = $my_inst; } elseif ($this->current_search_preset == 'sem') { $this->area_options_selectable = $my_sem; } elseif ($this->current_search_preset == 'user') { $this->area_options_selectable = array('user' => array($GLOBALS['auth']->auth['uid'] => get_fullname())); } elseif ($this->current_search_preset == 'global') { $this->area_options_selectable = array('global' => array('studip' => _('Stud.IP'))); } } if (!count($this->area_options_selectable)) { unset($this->search_term); } else { // already assigned areas won't be selectable foreach ($this->area_options_selected as $type => $data) { foreach ($data as $id => $title) { unset($this->area_options_selectable[$type][$id]); } } } } // delete comment(s) if (Request::submitted('delete_marked_comments')) { $this->anker = 'news_comments'; $this->flash['question_text'] = delete_comments(Request::optionArray('mark_comments')); $this->flash['question_param'] = array('mark_comments' => Request::optionArray('mark_comments'), 'delete_marked_comments' => 1); // reload comments if (!$this->flash['question_text']) { $this->comments = StudipComment::GetCommentsForObject($id); $changed = true; } } if ($news->havePermission('delete')) { $this->comments_admin = true; } if (is_array($this->comments)) { foreach ($this->comments as $key => $comment) { if (Request::submitted('news_delete_comment_' . $comment['comment_id'])) { $this->anker = 'news_comments'; $this->flash['question_text'] = delete_comments($comment['comment_id']); $this->flash['question_param'] = array('mark_comments' => array($comment['comment_id']), 'delete_marked_comments' => 1); } } } // open / close category foreach ($this->news_isvisible as $category => $value) { if (Request::submitted('toggle_' . $category) or Request::get($category . '_js')) { $this->news_isvisible[$category] = $this->news_isvisible[$category] ? false : true; $this->anker = $category; } } // add / remove areas if (Request::submitted('news_add_areas') and is_array($this->area_options_selectable)) { $this->anker = 'news_areas'; foreach (Request::optionArray('area_options_selectable') as $range_id) { foreach ($this->area_options_selectable as $type => $data) { if (isset($data[$range_id])) { $this->area_options_selected[$type][$range_id] = $data[$range_id]; unset($this->area_options_selectable[$type][$range_id]); } } } } if (Request::submitted('news_remove_areas') and is_array($this->area_options_selected)) { $this->anker = 'news_areas'; foreach (Request::optionArray('area_options_selected') as $range_id) { foreach ($this->area_options_selected as $type => $data) { if (isset($data[$range_id])) { $this->area_options_selectable[$type][$range_id] = $data[$range_id]; unset($this->area_options_selected[$type][$range_id]); } } } } // prepare to save news if (Request::submitted('save_news') and Request::isPost()) { CSRFProtection::verifySecurityToken(); //prepare ranges array for already assigned news_ranges foreach ($news->getRanges() as $range_id) { $this->ranges[$range_id] = get_object_type($range_id, array('global', 'fak', 'inst', 'sem', 'user')); } // check if new ranges must be added foreach ($this->area_options_selected as $type => $area_group) { foreach ($area_group as $range_id => $area_title) { if (!isset($this->ranges[$range_id])) { if ($news->haveRangePermission('edit', $range_id)) { $news->addRange($range_id); $changed = true; } else { PageLayout::postMessage(MessageBox::error(sprintf(_('Sie haben keine Berechtigung zum Ändern der Bereichsverknüpfung für "%s".'), htmlReady($area_title)))); $error++; } } } } // check if assigned ranges must be removed foreach ($this->ranges as $range_id => $range_type) { if ($range_type === 'fak' && !isset($this->area_options_selected['inst'][$range_id]) || $range_type !== 'fak' && !isset($this->area_options_selected[$range_type][$range_id])) { if ($news->havePermission('unassign', $range_id)) { $news->deleteRange($range_id); $changed = true; } else { PageLayout::postMessage(MessageBox::error(_('Sie haben keine Berechtigung zum Ändern der Bereichsverknüpfung.'))); $error++; } } } // save news if ($news->validate() and !$error) { if ($news->getValue('user_id') != $GLOBALS['auth']->auth['uid']) { $news->setValue('chdate_uid', $GLOBALS['auth']->auth['uid']); setTempLanguage($news->getValue('user_id')); $msg = sprintf(_('Ihre Ankündigung "%s" wurde von %s verändert.'), $news->getValue('topic'), get_fullname() . ' (' . get_username() . ')') . "\n"; $msg_object->insert_message($msg, get_username($news->getValue('user_id')), "____%system%____", FALSE, FALSE, "1", FALSE, _("Systemnachricht:") . " " . _("Ankündigung geändert")); restoreLanguage(); } else { $news->setValue('chdate_uid', ''); } $news->store(); PageLayout::postMessage(MessageBox::success(_('Die Ankündigung wurde gespeichert.'))); // in fallback mode redirect to edit page with proper news id if (!Request::isXhr() and !$id) { $this->redirect('news/edit_news/' . $news->getValue('news_id')); } elseif (Request::isXhr()) { $this->render_nothing(); } } } // check if user has full permission on news object if ($news->havePermission('delete')) { $this->may_delete = true; } }
/** * Write a new/edited wiki page to database * * @param string keyword WikiPage name * @param string version WikiPage version * @param string body WikiPage text * @param string user_id Internal user id of editor * @param string range_id Internal id of seminar/einrichtung * **/ function submitWikiPage($keyword, $version, $body, $user_id, $range_id) { releasePageLocks($keyword, $user_id); // kill lock that was set when starting to edit // write changes to db, show new page $latestVersion=getWikiPage($keyword,false); if ($latestVersion) { $date=time(); $lastchange = $date - $latestVersion['chdate']; } StudipTransformFormat::addStudipMarkup('wiki-comments', '(\[comment\])', null, function(){return sprintf('[comment=%s]', get_fullname());}); //TODO: Die $message Texte klingen fürchterlich. Halbsätze, Denglisch usw... if ($latestVersion && ($latestVersion['body'] == $body)) { $message = MessageBox::info(_('Keine Änderung vorgenommen.')); PageLayout::postMessage($message); } else if ($latestVersion && ($version !== null) && ($lastchange < 30*60) && ($user_id == $latestVersion['user_id'])) { // if same author changes again within 30 minutes, no new verison is created NotificationCenter::postNotification('WikiPageWillUpdate', array($range_id, $keyword)); // apply replace-before-save transformations $body = transformBeforeSave($body); $query = "UPDATE wiki SET body = ?, chdate = UNIX_TIMESTAMP() WHERE keyword = ? AND range_id = ? AND version = ?"; $statement = DBManager::get()->prepare($query); $statement->execute(array($body, $keyword, $range_id, $version)); NotificationCenter::postNotification('WikiPageDidUpdate', array($range_id, $keyword)); } else { if ($version === null) { $version=0; } else { $version=$latestVersion['version']+1; } NotificationCenter::postNotification('WikiPageWillCreate', array($range_id, $keyword)); // apply replace-before-save transformations $body = transformBeforeSave($body); $query = "INSERT INTO wiki (range_id, user_id, keyword, body, chdate, version) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(), ?)"; $statement = DBManager::get()->prepare($query); $statement->execute(array($range_id, $user_id, $keyword, $body, $version)); NotificationCenter::postNotification('WikiPageDidCreate', array($range_id, $keyword)); } StudipTransformFormat::removeStudipMarkup('wiki-comments'); refreshBacklinks($keyword, $body); }