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