summaryrefslogblamecommitdiffstats
path: root/modules-available/news/page.inc.php
blob: 291f15fcc61e540efbd2de69f654e2b89c141b3c (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;
	/**
	 * @var int location id
	 */
	private $locationId = 0;


	/**
	 * 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', null, 'int');
			$pageType = Request::get('type', null, 'string');
			$this->locationId = Request::get('locationid', 0, 'int');
			if ($pageType === null && $newsId === null) {
				Util::redirect('?do=news&type=news&locationid=' . $this->locationId);
			}
			$this->pageType = $pageType ?? 'news';
			$this->loadNews($newsId);

			foreach (self::TYPES as $type => $entry) {
				Dashboard::addSubmenu('?do=news&type=' . $type . '&locationid=' . $this->locationId,
					Dictionary::translate('type_' . $type));
			}

		} else {

			$action = Request::post('action', false, 'string');
			$pageType = Request::post('type', false, 'string');
			$this->locationId = Request::post('locationid', Request::REQUIRED_EMPTY, 'int');
			if (!array_key_exists($pageType, self::TYPES)) {
				Message::addError('invalid-type', $pageType);
				Util::redirect('?do=news&locationid=' . $this->locationId);
			}

			if ($action === 'save') {
				// save to DB
				User::assertPermission("$pageType.save", $this->locationId);
				if (!$this->saveNews($pageType)) {
					Message::addError('save-error');
				} else {
					Message::addSuccess('news-save-success');
				}

			} elseif ($action === 'delete') {
				// delete it
				User::assertPermission("$pageType.delete", $this->locationId);
				$this->delNews(Request::post('newsid', Request::REQUIRED, 'int'), $pageType);
			} else {
				// unknown action, redirect user
				Message::addError('invalid-action', $action);
			}

			Util::redirect('?do=news&type=' . $pageType . '&locationid=' . $this->locationId);
		}

		/* 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();
		$str = $this->locationId === 0 ? 'IS NULL' : ' = ' . $this->locationId;
		$res = Database::simpleQuery("SELECT newsid, dateline, expires, title, content FROM vmchooser_pages
				WHERE type = :type AND locationid $str ORDER BY dateline DESC LIMIT 20", ['type' => $this->pageType]);
		$foundActive = false;
		foreach ($res as $row) {
			$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),
			'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',
			];
		}
		$data['locationid'] = $this->locationId;
		if ($this->locationId > 0) {
			$data['location_name'] = Location::getName($this->locationId);
		} else {
			// Superadmin can see all overridden locations
			$data['overridden'] = Database::queryAll("SELECT DISTINCT l.locationid, l.locationname FROM vmchooser_pages
				INNER JOIN location l USING (locationid)
				WHERE expires > UNIX_TIMESTAMP() ORDER BY locationname ASC");
		}
		Render::addTemplate('page-news', $data);
	}

	private function formatExpires(int $ts): string
	{
		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, or latest if null
	 */
	private function loadNews(?int $newsId): void
	{
		// check to see if we need to request a specific newsid
		if ($newsId !== null) {
			$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 {
			$str = $this->locationId === 0 ? 'IS NULL' : ' = ' . $this->locationId;
			$row = Database::queryFirst("SELECT newsid, title, content, dateline, expires, type FROM vmchooser_pages
					WHERE type = :type AND locationid $str AND expires > UNIX_TIMESTAMP() ORDER BY dateline DESC LIMIT 1", [
				'type' => $this->pageType,
			]);
		}
		if ($row === false)
			return;

		// fetch the news to be shown
		$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'];
	}

	/**
	 * Save the given $newsTitle and $newsContent as POST'ed into the database.
	 */
	private function saveNews(string $pageType): bool
	{
		// check if news content were set by the user
		$newsTitle = Request::post('news-title', '', 'string');
		$newsContent = Request::post('news-content', Request::REQUIRED, 'string');
		$test = trim(html_entity_decode(strip_tags($newsContent), ENT_QUOTES, 'UTF-8'));
		if (empty($test)) {
			Message::addError('main.empty-field');
			return false;
		}
		$infinite = (Request::post('infinite', '', 'string') !== '');
		if ($infinite) {
			$expires = strtotime('+20 years 0:00');
		} else {
			$expires = strtotime(Request::post('enddate', 'today', 'string') . ' '
				. Request::post('endtime', '23:59', 'string'));
		}
		$str = $this->locationId === 0 ? 'IS NULL' : ' = ' . $this->locationId;
		// 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 AND locationid $str 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, locationid, title, content, type)
				VALUES (:dateline, :expires, :locationid, :title, :content, :type)", array(
			'dateline' => time(),
			'expires' => $expires,
			'locationid' => $this->locationId === 0 ? null : $this->locationId,
			'title' => $newsTitle,
			'content' => $newsContent,
			'type' => $pageType,
		));

		return true;
	}

	/**
	 * 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(int $newsId, string $pageType): void
	{
		Database::exec('DELETE FROM vmchooser_pages WHERE newsid = :newsid AND type = :type LIMIT 1', array(
			'newsid' => $newsId,
			'type' => $pageType,
		));
		Message::addSuccess('news-del-success');
	}
}