summaryrefslogblamecommitdiffstats
path: root/modules-available/news/page.inc.php
blob: 7a09d437abf22ed0badec08e7bc118617ede314b (plain) (tree)
1
2
3
4



                            












                                                            












                                                                    
                                        




                                                          





                                                          
 







                                                                






                                                                
 
                                                   

                                         
                                                              
 
                                                                           









                                                                                                                              
                         
 






                                                                             
                         
 




                                                                         

                                                                                 
                                 
 






                                                                                                 
                         

                                                                     
                 


                                                                         









                                                                    
                              
                                 

                                                                                                                   
                                     
                                                              

                                                                                  


                                                              

                                                             


                                                        
                         
 
                                                                                                              

                                        
 
                              






                                                                                                 
                                         

                                                                






                                                                               













                                                                        
 




                                                   
         
 



                                                          
                                                                


                                                        
                                                     


                                                                       

                                                                                                                                
                                                    



                                                                
                        



                                                                                                                                
                 

                                     
 

                                             





                                                                    
                 
                            
         
 


                                                                                   
                                            

                                                             

                                                                              


                                                                             
                        

                                                                                              

                                           
                                                                  










                                                                                                                                   
                                                              






                                                                                                             
                                                     
                                                      

                                                          
                                                    
                           
 
                                    
                 
 

                                                      
         
 



                                                            
                                                                                                       
           
                                                    





                                                                                   
                                                                                                                            
                                                    
                                                    



                                                                
 
<?php

class Page_News extends Page
{

	private $hasSummernote = false;

	const TYPES = [
		// Dictionary::translate('type_news');
		'news' => ['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');
		}
	}
}