source: trunk/Modules/News/News.php@ 893

Last change on this file since 893 was 893, checked in by chronos, 4 years ago
  • Modified: More work on modules models initialization.
File size: 12.9 KB
Line 
1<?php
2
3include_once(dirname(__FILE__).'/NewsPage.php');
4include_once(dirname(__FILE__).'/NewsSource.php');
5include_once(dirname(__FILE__).'/Import/Vismo.php');
6
7function CategoryItemCompare($Item1, $Item2)
8{
9 if ($Item1['Index'] == $Item2['Index']) return 0;
10 return $Item1['Index'] > $Item2['Index'] ? -1 : 1;
11}
12
13class ModuleNews extends AppModule
14{
15 public int $NewsCountPerCategory = 3;
16 public string $UploadedFilesFolder = 'files/news/';
17
18 function __construct(System $System)
19 {
20 parent::__construct($System);
21 $this->Name = 'News';
22 $this->Version = '1.0';
23 $this->Creator = 'Chronos';
24 $this->License = 'GNU/GPL';
25 $this->Description = 'News and news groups management';
26 $this->Dependencies = array('User', 'Log', 'File');
27 $this->SupportedModules = array('Search');
28 }
29
30 function GetModels(): array
31 {
32 return array('NewsCategory', 'News');
33 }
34
35 function DoInstall(): void
36 {
37 foreach (self::GetModels() as $Model)
38 {
39 $this->InstallModel($Model::GetDesc());
40 }
41 }
42
43 function DoUnInstall(): void
44 {
45 foreach (array_reverse(self::GetModels()) as $Model)
46 {
47 $this->UninstallModel($Model::GetDesc());
48 }
49 }
50
51 function DoStart(): void
52 {
53 $this->System->RegisterPage(['aktuality'], 'PageNews');
54 $this->System->RegisterPage(['aktuality', 'subscription'], 'PageNewsSubscription');
55 $this->System->RegisterPage(['aktuality', 'rss'], 'PageNewsRss');
56 $this->System->RegisterPage(['aktuality', 'aktualizace'], 'PageNewsUpdate');
57 $this->System->FormManager->RegisterClass('News', array(
58 'Title' => 'Aktualita',
59 'Table' => 'News',
60 'DefaultSortColumn' => 'Date',
61 'DefaultSortOrder' => 1,
62 'Items' => array(
63 'Category' => array('Type' => 'TNewsCategory', 'Caption' => 'Kategorie', 'Default' => 0),
64 'Title' => array('Type' => 'String', 'Caption' => 'Nadpis', 'Default' => ''),
65 'Content' => array('Type' => 'Text', 'Caption' => 'Obsah', 'Default' => ''),
66 'Date' => array('Type' => 'Date', 'Caption' => 'Datum', 'Default' => ''),
67 'Author' => array('Type' => 'String', 'Caption' => 'Autor', 'Default' => ''),
68 'Enclosure' => array('Type' => 'String', 'Caption' => 'Přílohy', 'Default' => ''),
69 'User' => array('Type' => 'TUser', 'Caption' => 'Uživatel', 'Default' => ''),
70 'IP' => array('Type' => 'IPv4Address', 'Caption' => 'IP adresa', 'Default' => '', 'ReadOnly' => true),
71 'Link' => array('Type' => 'Hyperlink', 'Caption' => 'Odkaz', 'Default' => ''),
72 ),
73 ));
74 $this->System->FormManager->RegisterClass('NewsCategory', array(
75 'Title' => 'Kategorie aktualit',
76 'Table' => 'NewsCategory',
77 'Items' => array(
78 'Caption' => array('Type' => 'String', 'Caption' => 'Titulek', 'Default' => ''),
79 'RSS' => array('Type' => 'Hyperlink', 'Caption' => 'Zdroj RSS', 'Default' => ''),
80 'Permission' => array('Type' => 'Boolean', 'Caption' => 'Veřejné upravitelné', 'Default' => ''),
81 'Sequence' => array('Type' => 'Integer', 'Caption' => 'Pořadí', 'Default' => ''),
82 'Group' => array('Type' => 'Integer', 'Caption' => 'Skupina', 'Default' => ''),
83 'News' => array('Type' => 'TNewsList', 'Caption' => 'Aktuality', 'Default' => ''),
84 ),
85 ));
86 $this->System->FormManager->RegisterFormType('TNewsCategory', array(
87 'Type' => 'Reference',
88 'Table' => 'NewsCategory',
89 'Id' => 'Id',
90 'Name' => 'Caption',
91 'Filter' => '1',
92 ));
93 $this->System->FormManager->RegisterFormType('TNewsList', array(
94 'Type' => 'ManyToOne',
95 'Table' => 'News',
96 'Id' => 'Id',
97 'Ref' => 'Category',
98 'Filter' => '1',
99 ));
100
101 if ($this->System->ModuleManager->ModulePresent('Search'))
102 {
103 ModuleSearch::Cast($this->System->GetModule('Search'))->RegisterSearch('Novinky', 'News', array('Title', 'Content'));
104 }
105 }
106
107 function ShowNews(string $Category, int $ItemCount, int $DaysAgo): string
108 {
109 $ItemCount = abs($ItemCount);
110 $DaysAgo = abs($DaysAgo);
111 $DbResult = $this->Database->select('NewsCategory', '*', 'Id='.$Category);
112 $Row = $DbResult->fetch_array();
113 $Output = '<div class="NewsPanel"><div class="Title">'.$Row['Caption'];
114 $Output .= '<div class="Action"><a href="aktuality/?category='.$Category.'">Zobrazit</a>';
115 if (ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission('News', 'Insert', 'Group', $Category))
116 $Output .= ' <a href="aktuality/?action=add&amp;category='.$Category.'">Přidat</a>';
117 $Output .= '</div></div><div class="Content">';
118 $DbResult = $this->Database->query('SELECT `News`.*, `User`.`Name` FROM `News` LEFT JOIN `User` ON `User`.`Id`=`News`.`User` WHERE (`News`.`Category`='.$Category.') AND (DATE_SUB(NOW(), INTERVAL '.$DaysAgo.' DAY) < `News`.`Date`) ORDER BY `News`.`Date` DESC LIMIT 0,'.$ItemCount);
119
120 $Index = 0;
121 $FontSize = 12;
122 if ($DbResult->num_rows > 0)
123 {
124 $Output .= '<table class="NewsTable">';
125 while ($Row = $DbResult->fetch_array())
126 {
127 if ($Row['Name'] == '') $Author = $Row['Author'];
128 else $Author = $Row['Name'];
129 $Output .= '<tr><td onclick="window.location=\'aktuality/?action=view&amp;id='.$Row['Id'].
130 '\'" onmouseover="zobraz('."'new".$Category.$Index."'".')" style="cursor: pointer; margin: 0px;">'.
131 '<table class="NewsItemFrame"><tr><td style="font-size: '.$FontSize.'pt"><strong>'.$Row['Title'].'</strong></td>'.
132 '<td align="right" style="font-size: '.$FontSize.'pt">'.$Author.' ('.HumanDate($Row['Date']).')</td></tr></table>';
133 $Output .= '<div id="new'.$Category.$Index.'" class="NewsTableItem">'.$this->ModifyContent($Row['Content']);
134 if ($Row['Link'] != '') $Output .= '<br/><a href="'.$Row['Link'].'">Odkaz</a>';
135
136 if ($Row['Enclosure'] != '')
137 {
138 $Output .= '<br />Přílohy: ';
139 $Enclosures = explode(';', $Row['Enclosure']);
140 foreach ($Enclosures as $Enclosure)
141 {
142 if (file_exists($this->UploadedFilesFolder.$Enclosure))
143 $Output .= ' <a href="'.$this->UploadedFilesFolder.$Enclosure.'">'.$Enclosure.'</a>';
144 }
145 }
146 $Output .= '</div></td></tr>';
147 $Index = $Index + 1;
148 $FontSize = $FontSize - 1;
149 }
150 $Output .= '</table>';
151 }
152 $Output .= '</div></div>';
153 return $Output;
154 }
155
156 function LoadSettingsFromCookies(): void
157 {
158 // Initialize default news setting
159 $this->NewsSetting = array();
160 $I = 1;
161 $DbResult = $this->Database->select('NewsCategory', '*', '1 ORDER BY Sequence');
162 while ($NewsCategory = $DbResult->fetch_array())
163 {
164 $this->NewsSetting[] = array('CategoryId' => $NewsCategory['Id'], 'Index' => $I, 'Enabled' => 1,
165 'ItemCount' => $this->System->Config['Web']['News']['Count'], 'DaysAgo' => $this->System->Config['Web']['News']['DaysAgo'], 'Group' => $NewsCategory['Group']);
166 $I++;
167 }
168 // Merge defaults with user setting
169 if (array_key_exists('NewsSetting', $_COOKIE))
170 {
171 $NewsSettingCookie = unserialize($_COOKIE['NewsSetting']);
172 foreach ($this->NewsSetting as $Index => $this->NewSetting)
173 {
174 if (array_key_exists($Index, $NewsSettingCookie))
175 $this->NewsSetting[$Index] = array_merge($this->NewSetting, $NewsSettingCookie[$Index]);
176 }
177 }
178 }
179
180 function Show(): string
181 {
182 $Output = '';
183
184 $this->LoadSettingsFromCookies();
185
186 if (array_key_exists('Action', $_GET))
187 {
188 // Show news customize menu
189 if ($_GET['Action'] == 'CustomizeNews')
190 {
191 $Output .= $this->ShowCustomizeMenu();
192 }
193 }
194
195 $Output .= '<div onmouseout="skryj(predchozi)">';
196
197 $ColumnCount = 2;
198 $Output .= '<table style="width: 100%"><tr>';
199 for ($Column = 1; $Column <= $ColumnCount; $Column++)
200 {
201 $Output .= '<td style="vertical-align: top; width: '.round(100 / $ColumnCount).'%;">';
202 foreach ($this->NewsSetting as $SettingItem)
203 if (($SettingItem['Enabled'] == 1) and ($SettingItem['Group'] == $Column))
204 $Output .= $this->ShowNews($SettingItem['CategoryId'], $SettingItem['ItemCount'], $SettingItem['DaysAgo']);
205 $Output .= '</td>';
206 }
207 $Output .= '</tr></table>';
208
209 $Output .= '<a href="aktuality/subscription"><img class="RSSIcon" src="images/rss20.png" alt="Aktuality přes RSS" /></a> <a href="aktuality/subscription">Automatické sledování novinek</a>';
210 $Output .= '</div>';
211 return $Output;
212 }
213
214 function ShowCustomizeMenu(): string
215 {
216 $Output = '<form action="?Action=CustomizeNewsSave" method="post">';
217 $Output .= '<table width="100%" cellspacing="0" border="1"><tr><td><table cellspacing="0" width="100%">';
218 $Output .= '<tr><th>Kategorie</th><th>Pozice</th><th>Zobrazit</th><th>Max. počet</th><th>Posledních dnů</th><th>Sloupec</th></tr>';
219 $I = 0;
220 foreach ($this->NewsSetting as $SettingItem)
221 {
222 $DbResult = $this->Database->select('NewsCategory', '*', 'Id='.$SettingItem['CategoryId']);
223 $NewsCategory = $DbResult->fetch_array();
224 $Output .= '<tr><td>'.$NewsCategory['Caption'].'</td><td align="center"><input type="text" size="2" name="NewsCategoryIndex'.$I.'" value="'.$SettingItem['Index'].'" /></td><td align="center"><input type="checkbox" name="NewsCategoryEnabled'.$I.'"';
225 if ($SettingItem['Enabled'] == 1) $Output .= ' checked="checked"';
226 $Output .= ' /></td>'.
227 '<td align="center"><input type="text" size="2" name="NewsCategoryCount'.$I.'" value="'.$SettingItem['ItemCount'].'" />'.
228 '<input type="hidden" name="NewsCategoryId'.$I.'" value="'.$SettingItem['CategoryId'].'" /></td>'.
229 '<td align="center"><input type="text" size="3" name="NewsCategoryDaysAgo'.$I.'" value="'.$SettingItem['DaysAgo'].'" /></td>'.
230 '<td><input type="text" size="3" name="NewsColumn'.$I.'" value="'.$SettingItem['Group'].'"/></td></tr>';
231 $I++;
232 }
233 $Output .= '</table><input type="hidden" name="NewsCategoryCount" value="'.count($this->NewsSetting).'" /><input type="submit" value="Uložit" /></form></td></tr></table><br>';
234 return $Output;
235 }
236
237 function CustomizeSave(): void
238 {
239 $Checkbox = array('' => 0, 'on' => 1);
240 $Setting = array();
241 for ($I = 0; $I < $_POST['NewsCategoryCount']; $I++)
242 {
243 if (($_POST['NewsCategoryDaysAgo'.$I] * 1) < 0) $_POST['NewsCategoryIndex'.$I] = 0;
244 if (($_POST['NewsCategoryCount'.$I] * 1) < 0) $_POST['NewsCategoryCount'.$I] = 0;
245 if (($_POST['NewsColumn'.$I] * 1) < 1) $_POST['NewsColumn'.$I] = 1;
246 if (!array_key_exists('NewsCategoryEnabled'.$I, $_POST)) $_POST['NewsCategoryEnabled'.$I] = '';
247 $Setting[] = array('CategoryId' => $_POST['NewsCategoryId'.$I], 'Enabled' => $Checkbox[$_POST['NewsCategoryEnabled'.$I]], 'ItemCount' => ($_POST['NewsCategoryCount'.$I]*1), 'DaysAgo' => ($_POST['NewsCategoryDaysAgo'.$I]*1), 'Index' => ($_POST['NewsCategoryIndex'.$I]*1),
248 'Group' => $_POST['NewsColumn'.$I]);
249 }
250 // Sort indexes
251 usort($Setting, 'CategoryItemCompare');
252 $Setting = array_reverse($Setting);
253 // Normalize indexes
254 foreach ($Setting as $Index => $Item)
255 $Setting[$Index]['Index'] = $Index + 1;
256
257 // Store new cookie value
258 $_COOKIE['NewsSetting'] = serialize($Setting);
259 setcookie('NewsSetting', $_COOKIE['NewsSetting'], time() + 60 * 60 * 24 * 365);
260 }
261
262 function ModifyContent(string $Content): string
263 {
264 $Result = '';
265
266 // Make HTML link from URL
267 $I = 0;
268 while (strpos($Content, 'http://') !== false)
269 {
270 $I = strpos($Content, 'http://');
271 if (($I > 0) and ($Content[$I - 1] != '"'))
272 {
273 $Result .= substr($Content, 0, $I);
274 $Content = substr($Content, $I);
275 if (strpos($Content, ' ') !== false)
276 $URL = substr($Content, 0, strpos($Content, ' '));
277 else $URL = substr($Content, 0);
278 $Result .= '<a href="'.$URL.'">'.$URL.'</a>';
279 $Content = substr($Content, strlen($URL));
280 } else
281 {
282 $Result .= substr($Content, 0, $I + 1);
283 $Content = substr($Content, $I + 1);
284 }
285 }
286 $Result .= $Content;
287 return $Result;
288 }
289
290 static function Cast(AppModule $AppModule): ModuleNews
291 {
292 if ($AppModule instanceof ModuleNews)
293 {
294 return $AppModule;
295 }
296 throw new Exception('Expected ModuleNews type but got '.gettype($AppModule));
297 }
298}
299
300class News extends Model
301{
302 static function GetDesc(): ModelDesc
303 {
304 $Desc = new ModelDesc('News');
305 $Desc->AddReference('Category', 'NewsCategory', true);
306 $Desc->AddString('Title');
307 $Desc->AddText('Content');
308 $Desc->AddDate('Date');
309 $Desc->AddString('Author');
310 $Desc->AddString('Enclosure');
311 $Desc->AddReference('User', 'User');
312 $Desc->AddString('IP');
313 $Desc->AddString('Link');
314 return $Desc;
315 }
316}
317
318class NewsCategory extends Model
319{
320 static function GetDesc(): ModelDesc
321 {
322 $Desc = new ModelDesc('NewsCategory');
323 $Desc->AddString('Caption');
324 $Desc->AddString('RSS');
325 $Desc->AddBoolean('Permission');
326 $Desc->AddInteger('Sequence');
327 $Desc->AddInteger('Group');
328 return $Desc;
329 }
330}
Note: See TracBrowser for help on using the repository browser.