1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2018 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16declare(strict_types=1); 17 18namespace Fisharebest\Webtrees\Module; 19 20use Fisharebest\Webtrees\Auth; 21use Fisharebest\Webtrees\Database; 22use Fisharebest\Webtrees\I18N; 23use Fisharebest\Webtrees\Tree; 24use Symfony\Component\HttpFoundation\RedirectResponse; 25use Symfony\Component\HttpFoundation\Request; 26use Symfony\Component\HttpFoundation\Response; 27use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; 28 29/** 30 * Class FamilyTreeNewsModule 31 */ 32class FamilyTreeNewsModule extends AbstractModule implements ModuleBlockInterface 33{ 34 // How to update the database schema for this module 35 const SCHEMA_TARGET_VERSION = 3; 36 const SCHEMA_SETTING_NAME = 'NB_SCHEMA_VERSION'; 37 const SCHEMA_MIGRATION_PREFIX = '\Fisharebest\Webtrees\Module\FamilyTreeNews\Schema'; 38 39 /** 40 * Create a new module. 41 * 42 * @param string $directory Where is this module installed 43 */ 44 public function __construct(string $directory) 45 { 46 parent::__construct($directory); 47 48 // Create/update the database tables. 49 Database::updateSchema(self::SCHEMA_MIGRATION_PREFIX, self::SCHEMA_SETTING_NAME, self::SCHEMA_TARGET_VERSION); 50 } 51 52 /** 53 * How should this module be labelled on tabs, menus, etc.? 54 * 55 * @return string 56 */ 57 public function getTitle(): string 58 { 59 /* I18N: Name of a module */ 60 return I18N::translate('News'); 61 } 62 63 /** 64 * A sentence describing what this module does. 65 * 66 * @return string 67 */ 68 public function getDescription(): string 69 { 70 /* I18N: Description of the “News” module */ 71 return I18N::translate('Family news and site announcements.'); 72 } 73 74 /** 75 * Generate the HTML content of this block. 76 * 77 * @param Tree $tree 78 * @param int $block_id 79 * @param bool $template 80 * @param string[] $cfg 81 * 82 * @return string 83 */ 84 public function getBlock(Tree $tree, int $block_id, bool $template = true, array $cfg = []): string 85 { 86 $articles = Database::prepare( 87 "SELECT news_id, user_id, gedcom_id, UNIX_TIMESTAMP(updated) + :offset AS updated, subject, body FROM `##news` WHERE gedcom_id = :tree_id ORDER BY updated DESC" 88 )->execute([ 89 'offset' => WT_TIMESTAMP_OFFSET, 90 'tree_id' => $tree->id(), 91 ])->fetchAll(); 92 93 $content = view('modules/gedcom_news/list', [ 94 'articles' => $articles, 95 'block_id' => $block_id, 96 'limit' => 5, 97 ]); 98 99 if ($template) { 100 return view('modules/block-template', [ 101 'block' => str_replace('_', '-', $this->getName()), 102 'id' => $block_id, 103 'config_url' => '', 104 'title' => $this->getTitle(), 105 'content' => $content, 106 ]); 107 } 108 109 return $content; 110 } 111 112 /** {@inheritdoc} */ 113 public function loadAjax(): bool 114 { 115 return false; 116 } 117 118 /** {@inheritdoc} */ 119 public function isUserBlock(): bool 120 { 121 return false; 122 } 123 124 /** {@inheritdoc} */ 125 public function isGedcomBlock(): bool 126 { 127 return true; 128 } 129 130 /** 131 * Update the configuration for a block. 132 * 133 * @param Request $request 134 * @param int $block_id 135 * 136 * @return void 137 */ 138 public function saveBlockConfiguration(Request $request, int $block_id) 139 { 140 } 141 142 /** 143 * An HTML form to edit block settings 144 * 145 * @param Tree $tree 146 * @param int $block_id 147 * 148 * @return void 149 */ 150 public function editBlockConfiguration(Tree $tree, int $block_id) 151 { 152 } 153 154 /** 155 * @param Request $request 156 * @param Tree $tree 157 * 158 * @return Response 159 */ 160 public function getEditNewsAction(Request $request, Tree $tree): Response 161 { 162 if (!Auth::isManager($tree)) { 163 throw new AccessDeniedHttpException(); 164 } 165 166 $news_id = $request->get('news_id'); 167 168 if ($news_id > 0) { 169 $row = Database::prepare( 170 "SELECT subject, body FROM `##news` WHERE news_id = :news_id AND gedcom_id = :tree_id" 171 )->execute([ 172 'news_id' => $news_id, 173 'tree_id' => $tree->id(), 174 ])->fetchOneRow(); 175 } else { 176 $row = (object) [ 177 'body' => '', 178 'subject' => '', 179 ]; 180 } 181 182 $title = I18N::translate('Add/edit a journal/news entry'); 183 184 return $this->viewResponse('modules/gedcom_news/edit', [ 185 'body' => $row->body, 186 'news_id' => $news_id, 187 'subject' => $row->subject, 188 'title' => $title, 189 ]); 190 } 191 192 /** 193 * @param Request $request 194 * @param Tree $tree 195 * 196 * @return RedirectResponse 197 */ 198 public function postEditNewsAction(Request $request, Tree $tree): RedirectResponse 199 { 200 if (!Auth::isManager($tree)) { 201 throw new AccessDeniedHttpException(); 202 } 203 204 $news_id = $request->get('news_id'); 205 $subject = $request->get('subject'); 206 $body = $request->get('body'); 207 208 if ($news_id > 0) { 209 Database::prepare( 210 "UPDATE `##news` SET subject = :subject, body = :body, updated = CURRENT_TIMESTAMP" . 211 " WHERE news_id = :news_id AND gedcom_id = :tree_id" 212 )->execute([ 213 'subject' => $subject, 214 'body' => $body, 215 'news_id' => $news_id, 216 'tree_id' => $tree->id(), 217 ]); 218 } else { 219 Database::prepare( 220 "INSERT INTO `##news` (gedcom_id, subject, body, updated) VALUES (:tree_id, :subject ,:body, CURRENT_TIMESTAMP)" 221 )->execute([ 222 'body' => $body, 223 'subject' => $subject, 224 'tree_id' => $tree->id(), 225 ]); 226 } 227 228 $url = route('tree-page', [ 229 'ged' => $tree->name(), 230 ]); 231 232 return new RedirectResponse($url); 233 } 234 235 /** 236 * @param Request $request 237 * @param Tree $tree 238 * 239 * @return RedirectResponse 240 */ 241 public function postDeleteNewsAction(Request $request, Tree $tree): RedirectResponse 242 { 243 $news_id = $request->get('news_id'); 244 245 if (!Auth::isManager($tree)) { 246 throw new AccessDeniedHttpException(); 247 } 248 249 Database::prepare( 250 "DELETE FROM `##news` WHERE news_id = :news_id AND gedcom_id = :tree_id" 251 )->execute([ 252 'news_id' => $news_id, 253 'tree_id' => $tree->id(), 254 ]); 255 256 $url = route('tree-page', [ 257 'ged' => $tree->name(), 258 ]); 259 260 return new RedirectResponse($url); 261 } 262} 263