['headline' => true], // Dictionary::translate('type_help'); 'help' => ['headline' => false], // Dictionary::translate('type_login-news'); 'login-news' => ['headline' => false], ]; private $pageType = false; /* * Member variables needed to represent a news entry. */ /** * @var int ID of the news entry attributed by the database. */ private $newsId = false; /** * @var string Title of the entry. */ private $newsTitle = false; /** * @var string HTML news content */ private $newsContent = false; /** * @var int Unix epoch date of the news' creation. */ private $newsDateline = false; /** * @var int Unix epoch date when the news expires. */ private $newsExpires = false; /** * Implementation of the abstract doPreprocess function. * * Checks if the user is logged in and processes any * action if one was specified in the request. */ protected function doPreprocess() { // load user, we will need it later User::load(); if (!User::isLoggedIn()) { Message::addError('main.no-permission'); Util::redirect('?do=Main'); } // check which action we need to do if (!Request::isPost()) { User::assertPermission('access-page'); /* and also the news (or help) with the given id */ $newsId = Request::get('newsid', false, 'int'); $pageType = Request::get('type', false, 'string'); if ($pageType === false && $newsId === false) { Util::redirect('?do=news&type=news'); } $this->pageType = $pageType === false ? 'news' : $pageType; $this->loadNews($newsId, $pageType); foreach (self::TYPES as $type => $entry) { Dashboard::addSubmenu('?do=news&type=' . $type, Dictionary::translate('type_' . $type, true)); } } else { $action = Request::post('action', false, 'string'); $pageType = Request::post('type', false, 'string'); if (!array_key_exists($pageType, self::TYPES)) { Message::addError('invalid-type', $pageType); Util::redirect('?do=news'); } if ($action === 'save') { // save to DB User::assertPermission("$pageType.save"); if (!$this->saveNews($pageType)) { Message::addError('save-error'); } else { Message::addSuccess('news-save-success'); } } elseif ($action === 'delete') { // delete it User::assertPermission("$pageType.delete"); $this->delNews(Request::post('newsid', false, 'int'), $pageType); } else { // unknown action, redirect user Message::addError('invalid-action', $action); } Util::redirect('?do=news&type=' . $pageType); } /* load summernote module if available */ $this->hasSummernote = Module::isAvailable('summernote'); } /** * Implementation of the abstract doRender function. * * Fetch the list of news from the database and paginate it. */ protected function doRender() { // fetch the list of the older news $NOW = time(); $lines = array(); $res = Database::simpleQuery("SELECT newsid, dateline, expires, title, content FROM vmchooser_pages WHERE type = :type ORDER BY dateline DESC LIMIT 20", ['type' => $this->pageType]); $foundActive = false; while ($row = $res->fetch(PDO::FETCH_ASSOC)) { $row['dateline_s'] = Util::prettyTime($row['dateline']); $row['expires_s'] = $this->formatExpires($row['expires']); if ($row['newsid'] == $this->newsId) { $row['active'] = true; } if ($row['expires'] < $NOW) { $row['muted'] = 'text-muted'; } elseif (!$foundActive) { $row['live'] = 'active'; $foundActive = true; } $row['content'] = substr(strip_tags(str_replace('>', '> ', $row['content'])), 0, 160); $lines[] = $row; } $data = array( 'withTitle' => self::TYPES[$this->pageType]['headline'], 'newsTypeName' => Dictionary::translate('type_' . $this->pageType, true), 'dateline_s' => Util::prettyTime($this->newsDateline), 'expires_s' => $this->formatExpires($this->newsExpires), 'currentContent' => $this->newsContent, 'currentTitle' => $this->newsTitle, 'type' => $this->pageType, 'list' => $lines, 'hasSummernote' => $this->hasSummernote, ); $validity = ceil(($this->newsExpires - $NOW) / 3600); if ($this->newsExpires === false || $validity > 24 * 365 * 5) { $data['infinite_checked'] = 'checked'; $this->newsExpires = strtotime('+7 days 00:00:00'); } $data['enddate'] = date('Y-m-d', $this->newsExpires); $data['endtime'] = date('H:i', $this->newsExpires); if (!User::hasPermission($this->pageType . '.save')) { $data['save'] = [ 'readonly' => 'readonly', 'disabled' => 'disabled', ]; } if (!User::hasPermission($this->pageType . '.delete')) { $data['delete'] = [ 'readonly' => 'readonly', 'disabled' => 'disabled', ]; } Render::addTemplate('page-news', $data); } private function formatExpires($ts) { if ($ts - 86400 * 365 * 5 > time()) return '-'; return Util::prettyTime($ts); } /** * Loads the news with the given ID into the form. * * @param int $newsId ID of the news to be shown. * @param string $pageType type if news id is not given. * * @return bool true if loading that news worked */ private function loadNews($newsId, $pageType) { // check to see if we need to request a specific newsid if ($newsId !== false) { $row = Database::queryFirst('SELECT newsid, title, content, dateline, expires, type FROM vmchooser_pages WHERE newsid = :newsid LIMIT 1', [ 'newsid' => $newsId, ]); if ($row === false) { Message::addError('news-empty'); } } else { $row = Database::queryFirst("SELECT newsid, title, content, dateline, expires, type FROM vmchooser_pages WHERE type = :type AND expires > UNIX_TIMESTAMP() ORDER BY dateline DESC LIMIT 1", [ 'type' => $pageType, ]); } if ($row === false) return false; // fetch the news to be shown if ($row !== false) { $this->newsId = $row['newsid']; $this->newsTitle = $row['title']; $this->newsContent = $row['content']; $this->newsDateline = (int)$row['dateline']; $this->newsExpires = (int)$row['expires']; $this->pageType = $row['type']; } return true; } /** * Save the given $newsTitle and $newsContent as POST'ed into the database. */ private function saveNews($pageType) { // check if news content were set by the user $newsTitle = Request::post('news-title', '', 'string'); $newsContent = Request::post('news-content', false, 'string'); $infinite = (Request::post('infinite', '', 'string') !== ''); if ($infinite) { $expires = strtotime('+10 years 0:00'); } else { $expires = strtotime(Request::post('enddate', 'today', 'string') . ' ' . Request::post('endtime', '23:59', 'string')); } if (!empty($newsContent)) { // we got title and content, save it to DB // dup check first $row = Database::queryFirst('SELECT newsid FROM vmchooser_pages WHERE content = :content AND type = :type LIMIT 1', [ 'content' => $newsContent, 'type' => $pageType, ]); if ($row !== false) { Database::exec('UPDATE vmchooser_pages SET dateline = :dateline, expires = :expires, title = :title WHERE newsid = :newsid LIMIT 1', [ 'newsid' => $row['newsid'], 'dateline' => time(), 'expires' => $expires, 'title' => $newsTitle, ]); return true; } // new one Database::exec("INSERT INTO vmchooser_pages (dateline, expires, title, content, type) VALUES (:dateline, :expires, :title, :content, :type)", array( 'dateline' => time(), 'expires' => $expires, 'title' => $newsTitle, 'content' => $newsContent, 'type' => $pageType, )); return true; } Message::addError('main.empty-field'); return false; } /** * Delete the news entry with ID $newsId. * * @param int $newsId ID of the entry to be deleted. * @param string $pageType type of news to be deleted. Must match the ID, otherwise do nothing. */ private function delNews($newsId, $pageType) { // sanity check: is newsId even numeric? if (!is_numeric($newsId)) { Message::addError('main.value-invalid', 'newsid', $newsId); } else { // check passed - do delete Database::exec('DELETE FROM vmchooser_pages WHERE newsid = :newsid AND type = :type LIMIT 1', array( 'newsid' => $newsId, 'type' => $pageType, )); Message::addSuccess('news-del-success'); } } }