|
1
|
|
|
<?php declare(strict_types=1); defined('BASEPATH') OR exit('No direct script access allowed'); |
|
2
|
|
|
|
|
3
|
|
|
class Tracker_Model extends CI_Model { |
|
4
|
|
|
public $sites; |
|
5
|
|
|
public $enabledCategories; |
|
6
|
|
|
|
|
7
|
121 |
|
public function __construct() { |
|
8
|
121 |
|
parent::__construct(); |
|
9
|
|
|
|
|
10
|
121 |
|
$this->load->database(); |
|
11
|
|
|
|
|
12
|
121 |
|
$this->enabledCategories = [ |
|
13
|
|
|
'reading' => 'Reading', |
|
14
|
|
|
'on-hold' => 'On-Hold', |
|
15
|
|
|
'plan-to-read' => 'Plan to Read' |
|
16
|
|
|
]; |
|
17
|
121 |
|
if($this->User_Options->get('category_custom_1') == 'enabled') { |
|
18
|
|
|
$this->enabledCategories['custom1'] = $this->User_Options->get('category_custom_1_text'); |
|
19
|
|
|
} |
|
20
|
121 |
|
if($this->User_Options->get('category_custom_2') == 'enabled') { |
|
21
|
|
|
$this->enabledCategories['custom2'] = $this->User_Options->get('category_custom_2_text'); |
|
22
|
|
|
} |
|
23
|
121 |
|
if($this->User_Options->get('category_custom_3') == 'enabled') { |
|
24
|
|
|
$this->enabledCategories['custom3'] = $this->User_Options->get('category_custom_3_text'); |
|
25
|
|
|
} |
|
26
|
|
|
|
|
27
|
121 |
|
require_once(APPPATH.'models/Site_Model.php'); |
|
28
|
121 |
|
$this->sites = new Sites_Model; |
|
29
|
121 |
|
} |
|
30
|
|
|
|
|
31
|
|
|
/****** GET TRACKER *******/ |
|
32
|
|
|
public function get_tracker_from_user_id(int $userID) { |
|
33
|
|
|
$query = $this->db |
|
34
|
|
|
->select('tracker_chapters.*, |
|
35
|
|
|
tracker_titles.site_id, tracker_titles.title, tracker_titles.title_url, tracker_titles.latest_chapter, tracker_titles.last_updated AS title_last_updated, tracker_titles.status AS title_status, tracker_titles.last_checked > DATE_SUB(NOW(), INTERVAL 1 WEEK) AS title_active, |
|
36
|
|
|
tracker_sites.site, tracker_sites.site_class, tracker_sites.status AS site_status') |
|
37
|
|
|
->from('tracker_chapters') |
|
38
|
|
|
->join('tracker_titles', 'tracker_chapters.title_id = tracker_titles.id', 'left') |
|
39
|
|
|
->join('tracker_sites', 'tracker_sites.id = tracker_titles.site_id', 'left') |
|
40
|
|
|
->where('tracker_chapters.user_id', $userID) |
|
41
|
|
|
->where('tracker_chapters.active', 'Y') |
|
42
|
|
|
->get(); |
|
43
|
|
|
|
|
44
|
|
|
$arr = ['series' => [], 'has_inactive' => FALSE]; |
|
45
|
|
|
foreach($this->enabledCategories as $category => $name) { |
|
46
|
|
|
$arr['series'][$category] = [ |
|
47
|
|
|
'name' => $name, |
|
48
|
|
|
'manga' => [], |
|
49
|
|
|
'unread_count' => 0 |
|
50
|
|
|
]; |
|
51
|
|
|
} |
|
52
|
|
|
if($query->num_rows() > 0) { |
|
53
|
|
|
foreach ($query->result() as $row) { |
|
54
|
|
|
$is_unread = intval($row->latest_chapter == $row->current_chapter ? '1' : '0'); |
|
55
|
|
|
$arr['series'][$row->category]['unread_count'] = (($arr['series'][$row->category]['unread_count'] ?? 0) + !$is_unread); |
|
56
|
|
|
$data = [ |
|
57
|
|
|
'id' => $row->id, |
|
58
|
|
|
'generated_current_data' => $this->sites->{$row->site_class}->getChapterData($row->title_url, $row->current_chapter), |
|
59
|
|
|
'generated_latest_data' => $this->sites->{$row->site_class}->getChapterData($row->title_url, $row->latest_chapter), |
|
60
|
|
|
'full_title_url' => $this->sites->{$row->site_class}->getFullTitleURL($row->title_url), |
|
61
|
|
|
|
|
62
|
|
|
'new_chapter_exists' => $is_unread, |
|
63
|
|
|
'tag_list' => $row->tags, |
|
64
|
|
|
'has_tags' => !empty($row->tags), |
|
65
|
|
|
|
|
66
|
|
|
'title_data' => [ |
|
67
|
|
|
'id' => $row->title_id, |
|
68
|
|
|
'title' => $row->title, |
|
69
|
|
|
'title_url' => $row->title_url, |
|
70
|
|
|
'latest_chapter' => $row->latest_chapter, |
|
71
|
|
|
'current_chapter' => $row->current_chapter, |
|
72
|
|
|
'last_updated' => $row->title_last_updated, |
|
73
|
|
|
//NOTE: active is used to warn the user if a title hasn't updated (Maybe due to nobody active tracking it or other reasons). |
|
74
|
|
|
// This will ONLY be false when an actively updating series (site enabled & title status = 0) hasn't updated within the past week. |
|
75
|
|
|
'active' => ($row->site_status == 'disabled' || in_array($row->title_status, [/*complete*/ 1, /* one-shot */ 2, /* ignored */ 255]) || $row->title_active == 1) |
|
76
|
|
|
], |
|
77
|
|
|
'site_data' => [ |
|
78
|
|
|
'id' => $row->site_id, |
|
79
|
|
|
'site' => $row->site, |
|
80
|
|
|
'status' => $row->site_status |
|
81
|
|
|
] |
|
82
|
|
|
]; |
|
83
|
|
|
$arr['series'][$row->category]['manga'][] = $data; |
|
84
|
|
|
|
|
85
|
|
|
if(!$arr['has_inactive']) $arr['has_inactive'] = !$data['title_data']['active']; |
|
86
|
|
|
} |
|
87
|
|
|
|
|
88
|
|
|
//CHECK: Is this good for speed? |
|
89
|
|
|
//NOTE: This does not sort in the same way as tablesorter, but it works better. |
|
90
|
|
|
switch($this->User_Options->get('list_sort_type')) { |
|
91
|
|
|
case 'unread': |
|
|
|
|
|
|
92
|
|
|
foreach (array_keys($arr['series']) as $category) { |
|
93
|
|
|
usort($arr['series'][$category]['manga'], function ($a, $b) { |
|
94
|
|
|
$a_text = strtolower("{$a['new_chapter_exists']} - {$a['title_data']['title']}"); |
|
95
|
|
|
$b_text = strtolower("{$b['new_chapter_exists']} - {$b['title_data']['title']}"); |
|
96
|
|
|
|
|
97
|
|
|
if($this->User_Options->get('list_sort_order') == 'asc') { |
|
98
|
|
|
return $a_text <=> $b_text; |
|
99
|
|
|
} else { |
|
100
|
|
|
return $b_text <=> $a_text; |
|
101
|
|
|
} |
|
102
|
|
|
}); |
|
103
|
|
|
} |
|
104
|
|
|
break; |
|
105
|
|
|
|
|
106
|
|
View Code Duplication |
case 'alphabetical': |
|
|
|
|
|
|
107
|
|
|
foreach (array_keys($arr['series']) as $category) { |
|
108
|
|
|
usort($arr['series'][$category]['manga'], function ($a, $b) { |
|
109
|
|
|
$a_text = strtolower("{$a['title_data']['title']}"); |
|
110
|
|
|
$b_text = strtolower("{$b['title_data']['title']}"); |
|
111
|
|
|
|
|
112
|
|
|
if($this->User_Options->get('list_sort_order') == 'asc') { |
|
113
|
|
|
return $a_text <=> $b_text; |
|
114
|
|
|
} else { |
|
115
|
|
|
return $b_text <=> $a_text; |
|
116
|
|
|
} |
|
117
|
|
|
}); |
|
118
|
|
|
} |
|
119
|
|
|
break; |
|
120
|
|
|
|
|
121
|
|
View Code Duplication |
case 'my_status': |
|
122
|
|
|
foreach (array_keys($arr['series']) as $category) { |
|
123
|
|
|
usort($arr['series'][$category]['manga'], function ($a, $b) { |
|
124
|
|
|
$a_text = strtolower("{$a['generated_current_data']['number']}"); |
|
125
|
|
|
$b_text = strtolower("{$b['generated_current_data']['number']}"); |
|
126
|
|
|
|
|
127
|
|
|
if($this->User_Options->get('list_sort_order') == 'asc') { |
|
128
|
|
|
return $a_text <=> $b_text; |
|
129
|
|
|
} else { |
|
130
|
|
|
return $b_text <=> $a_text; |
|
131
|
|
|
} |
|
132
|
|
|
}); |
|
133
|
|
|
} |
|
134
|
|
|
break; |
|
135
|
|
|
|
|
136
|
|
View Code Duplication |
case 'latest': |
|
137
|
|
|
foreach (array_keys($arr['series']) as $category) { |
|
138
|
|
|
usort($arr['series'][$category]['manga'], function ($a, $b) { |
|
139
|
|
|
$a_text = strtolower("{$a['generated_latest_data']['number']}"); |
|
140
|
|
|
$b_text = strtolower("{$b['generated_latest_data']['number']}"); |
|
141
|
|
|
|
|
142
|
|
|
if($this->User_Options->get('list_sort_order') == 'asc') { |
|
143
|
|
|
return $a_text <=> $b_text; |
|
144
|
|
|
} else { |
|
145
|
|
|
return $b_text <=> $a_text; |
|
146
|
|
|
} |
|
147
|
|
|
}); |
|
148
|
|
|
} |
|
149
|
|
|
break; |
|
150
|
|
|
|
|
151
|
|
|
default: |
|
152
|
|
|
break; |
|
153
|
|
|
} |
|
154
|
|
|
} |
|
155
|
|
|
return $arr; |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
|
|
public function getSiteDataFromURL(string $site_url) { |
|
159
|
|
|
$query = $this->db->select('id, site_class') |
|
160
|
|
|
->from('tracker_sites') |
|
161
|
|
|
->where('site', $site_url) |
|
162
|
|
|
->get(); |
|
163
|
|
|
|
|
164
|
|
|
if($query->num_rows() > 0) { |
|
165
|
|
|
$siteData = $query->row(); |
|
166
|
|
|
} |
|
167
|
|
|
|
|
168
|
|
|
return $siteData ?? FALSE; |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
public function getTitleID(string $titleURL, int $siteID, bool $create = TRUE, bool $returnData = FALSE) { |
|
172
|
|
|
$query = $this->db->select('tracker_titles.id, tracker_titles.title, tracker_titles.title_url, tracker_titles.latest_chapter, tracker_titles.status, tracker_sites.site_class, (tracker_titles.last_checked > DATE_SUB(NOW(), INTERVAL 3 DAY)) AS active', FALSE) |
|
173
|
|
|
->from('tracker_titles') |
|
174
|
|
|
->join('tracker_sites', 'tracker_sites.id = tracker_titles.site_id', 'left') |
|
175
|
|
|
->where('tracker_titles.title_url', $titleURL) |
|
176
|
|
|
->where('tracker_titles.site_id', $siteID) |
|
177
|
|
|
->get(); |
|
178
|
|
|
|
|
179
|
|
|
if($query->num_rows() > 0) { |
|
180
|
|
|
$id = (int) $query->row('id'); |
|
181
|
|
|
|
|
182
|
|
|
//This updates inactive series if they are newly added, as noted in https://github.com/DakuTree/manga-tracker/issues/5#issuecomment-247480804 |
|
183
|
|
|
if(((int) $query->row('active')) === 0 && $query->row('status') === 0) { |
|
184
|
|
|
$titleData = $this->sites->{$query->row('site_class')}->getTitleData($query->row('title_url')); |
|
185
|
|
|
if(!is_null($titleData['latest_chapter'])) { |
|
186
|
|
View Code Duplication |
if($this->updateTitleById((int) $id, $titleData['latest_chapter'])) { |
|
187
|
|
|
//Make sure last_checked is always updated on successful run. |
|
188
|
|
|
//CHECK: Is there a reason we aren't just doing this in updateTitleById? |
|
189
|
|
|
$this->db->set('last_checked', 'CURRENT_TIMESTAMP', FALSE) |
|
190
|
|
|
->where('id', $id) |
|
191
|
|
|
->update('tracker_titles'); |
|
192
|
|
|
} |
|
193
|
|
|
} else { |
|
194
|
|
|
log_message('error', "{$query->row('title')} failed to update successfully"); |
|
195
|
|
|
} |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
$titleID = $id; |
|
199
|
|
|
} else { |
|
200
|
|
|
//TODO: Check if title is valid URL! |
|
201
|
|
|
if($create) $titleID = $this->addTitle($titleURL, $siteID); |
|
202
|
|
|
} |
|
203
|
|
|
if(!isset($titleID) || !$titleID) $titleID = 0; |
|
204
|
|
|
|
|
205
|
|
|
return ($returnData && $titleID !== 0 ? $query->row_array() : $titleID); |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
public function updateTracker(int $userID, string $site, string $title, string $chapter) : bool { |
|
209
|
|
|
$success = FALSE; |
|
210
|
|
|
if($siteData = $this->Tracker->getSiteDataFromURL($site)) { |
|
211
|
|
|
//Validate user input |
|
212
|
|
|
if(!$this->sites->{$siteData->site_class}->isValidTitleURL($title)) { |
|
213
|
|
|
//Error is already logged via isValidTitleURL |
|
214
|
|
|
return FALSE; |
|
215
|
|
|
} |
|
216
|
|
|
if(!$this->sites->{$siteData->site_class}->isValidChapter($chapter)) { |
|
217
|
|
|
//Error is already logged via isValidChapter |
|
218
|
|
|
return FALSE; |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
//NOTE: If the title doesn't exist it will be created. This maybe isn't perfect, but it works for now. |
|
222
|
|
|
$titleID = $this->Tracker->getTitleID($title, (int) $siteData->id); |
|
223
|
|
|
if($titleID === 0) { |
|
224
|
|
|
//Something went wrong. |
|
225
|
|
|
log_message('error', "TitleID = 0 for {$title} @ {$siteData->id}"); |
|
226
|
|
|
return FALSE; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
$idQuery = $this->db->select('id') |
|
230
|
|
|
->where('user_id', $userID) |
|
231
|
|
|
->where('title_id', $titleID) |
|
232
|
|
|
->get('tracker_chapters'); |
|
233
|
|
|
if($idQuery->num_rows() > 0) { |
|
234
|
|
|
$success = (bool) $this->db->set(['current_chapter' => $chapter, 'active' => 'Y', 'last_updated' => NULL]) |
|
235
|
|
|
->where('user_id', $userID) |
|
236
|
|
|
->where('title_id', $titleID) |
|
237
|
|
|
->update('tracker_chapters'); |
|
238
|
|
|
|
|
239
|
|
|
if($success) { |
|
240
|
|
|
$idQueryRow = $idQuery->row(); |
|
241
|
|
|
$this->History->userUpdateTitle((int) $idQueryRow->id, $chapter); |
|
242
|
|
|
} |
|
243
|
|
|
} else { |
|
244
|
|
|
$category = $this->User_Options->get_by_userid('default_series_category', $userID); |
|
245
|
|
|
$success = (bool) $this->db->insert('tracker_chapters', [ |
|
246
|
|
|
'user_id' => $userID, |
|
247
|
|
|
'title_id' => $titleID, |
|
248
|
|
|
'current_chapter' => $chapter, |
|
249
|
|
|
'category' => $category |
|
250
|
|
|
]); |
|
251
|
|
|
|
|
252
|
|
|
if($success) { |
|
253
|
|
|
$this->History->userAddTitle((int) $this->db->insert_id(), $chapter, $category); |
|
|
|
|
|
|
254
|
|
|
} |
|
255
|
|
|
} |
|
256
|
|
|
} |
|
257
|
|
|
return $success; |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
public function updateTrackerByID(int $userID, int $chapterID, string $chapter) : bool { |
|
261
|
|
|
$success = (bool) $this->db->set(['current_chapter' => $chapter, 'active' => 'Y', 'last_updated' => NULL]) |
|
262
|
|
|
->where('user_id', $userID) |
|
263
|
|
|
->where('id', $chapterID) |
|
264
|
|
|
->update('tracker_chapters'); |
|
265
|
|
|
|
|
266
|
|
|
if($success) { |
|
267
|
|
|
$this->History->userUpdateTitle($chapterID, $chapter); |
|
268
|
|
|
} |
|
269
|
|
|
return $success; |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
View Code Duplication |
public function deleteTrackerByID(int $userID, int $chapterID) { |
|
273
|
|
|
//Series are not fully deleted, they are just marked as inactive as to hide them from the user. |
|
274
|
|
|
//This is to allow user history to function properly. |
|
275
|
|
|
|
|
276
|
|
|
$success = $this->db->set(['active' => 'N', 'last_updated' => NULL]) |
|
277
|
|
|
->where('user_id', $userID) |
|
278
|
|
|
->where('id', $chapterID) |
|
279
|
|
|
->update('tracker_chapters'); |
|
280
|
|
|
|
|
281
|
|
|
return (bool) $success; |
|
282
|
|
|
} |
|
283
|
|
|
private function updateTitleById(int $id, string $latestChapter) { |
|
284
|
|
|
//FIXME: Really not too happy with how we're doing history stuff here, it just feels messy. |
|
285
|
|
|
$query = $this->db->select('latest_chapter AS current_chapter') |
|
286
|
|
|
->from('tracker_titles') |
|
287
|
|
|
->where('id', $id) |
|
288
|
|
|
->get(); |
|
289
|
|
|
$row = $query->row(); |
|
290
|
|
|
|
|
291
|
|
|
$success = $this->db->set(['latest_chapter' => $latestChapter]) //last_updated gets updated via a trigger if something changes |
|
292
|
|
|
->where('id', $id) |
|
293
|
|
|
->update('tracker_titles'); |
|
294
|
|
|
|
|
295
|
|
|
//Update History |
|
296
|
|
|
//NOTE: To avoid doing another query to grab the last_updated time, we just use time() which <should> get the same thing. |
|
297
|
|
|
//FIXME: The <preferable> solution here is we'd just check against the last_updated time, but that can have a few issues. |
|
298
|
|
|
$this->History->updateTitleHistory($id, $row->current_chapter, $latestChapter, date('Y-m-d H:i:s')); |
|
299
|
|
|
|
|
300
|
|
|
return (bool) $success; |
|
301
|
|
|
} |
|
302
|
|
|
private function updateTitleDataById(int $id, array $titleData) { |
|
|
|
|
|
|
303
|
|
|
$success = $this->db->set($titleData) |
|
304
|
|
|
->where('id', $id) |
|
305
|
|
|
->update('tracker_titles'); |
|
306
|
|
|
|
|
307
|
|
|
return (bool) $success; |
|
308
|
|
|
} |
|
309
|
|
|
private function addTitle(string $titleURL, int $siteID) { |
|
310
|
|
|
$query = $this->db->select('site, site_class') |
|
311
|
|
|
->from('tracker_sites') |
|
312
|
|
|
->where('id', $siteID) |
|
313
|
|
|
->get(); |
|
314
|
|
|
|
|
315
|
|
|
$titleData = $this->sites->{$query->row()->site_class}->getTitleData($titleURL, TRUE); |
|
316
|
|
|
|
|
317
|
|
|
//FIXME: getTitleData can fail, which will in turn cause the below to fail aswell, we should try and account for that |
|
318
|
|
|
if($titleData) { |
|
319
|
|
|
$this->db->insert('tracker_titles', array_merge($titleData, ['title_url' => $titleURL, 'site_id' => $siteID])); |
|
320
|
|
|
$titleID = $this->db->insert_id(); |
|
|
|
|
|
|
321
|
|
|
|
|
322
|
|
|
$this->History->updateTitleHistory((int) $titleID, NULL, $titleData['latest_chapter'], $titleData['last_updated']); |
|
323
|
|
|
} else { |
|
324
|
|
|
log_message('error', "getTitleData failed for: {$query->row()->site_class} | {$titleURL}"); |
|
325
|
|
|
} |
|
326
|
|
|
return $titleID ?? 0; |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
|
/** |
|
330
|
|
|
* Checks for any titles that haven't updated in 16 hours and updates them. |
|
331
|
|
|
* This is ran every 6 hours via a cron job. |
|
332
|
|
|
*/ |
|
333
|
|
|
public function updateLatestChapters() { |
|
334
|
|
|
$query = $this->db->select(' |
|
335
|
|
|
tracker_titles.id, |
|
336
|
|
|
tracker_titles.title, |
|
337
|
|
|
tracker_titles.title_url, |
|
338
|
|
|
tracker_titles.status, |
|
339
|
|
|
tracker_sites.site, |
|
340
|
|
|
tracker_sites.site_class, |
|
341
|
|
|
tracker_sites.status, |
|
342
|
|
|
tracker_titles.latest_chapter, |
|
343
|
|
|
tracker_titles.last_updated, |
|
344
|
|
|
from_unixtime(MAX(auth_users.last_login)) AS timestamp |
|
345
|
|
|
') |
|
346
|
|
|
->from('tracker_titles') |
|
347
|
|
|
->join('tracker_sites', 'tracker_sites.id = tracker_titles.site_id', 'left') |
|
348
|
|
|
->join('tracker_chapters', 'tracker_titles.id = tracker_chapters.title_id', 'left') |
|
349
|
|
|
->join('auth_users', 'tracker_chapters.user_id = auth_users.id', 'left') |
|
350
|
|
|
->where('tracker_sites.status', 'enabled') |
|
351
|
|
|
->where('tracker_chapters.active', 'Y') //CHECK: Does this apply BEFORE the GROUP BY/HAVING is done? |
|
352
|
|
|
//Check if title is marked as on-going, and update if latest_chapter isn't set or hasn't updated within last 12 hours |
|
353
|
|
|
->where('(tracker_titles.status = 0 AND (`latest_chapter` = NULL OR `last_checked` < DATE_SUB(NOW(), INTERVAL 12 HOUR)))', NULL, FALSE) //TODO: Each title should have specific interval time? |
|
354
|
|
|
//Check if title is marked as complete, and update if it hasn't updated in the last week. |
|
355
|
|
|
->or_where('(tracker_titles.status = 1 AND `last_checked` < DATE_SUB(NOW(), INTERVAL 1 WEEK))', NULL, FALSE) |
|
356
|
|
|
//Status 2 (One-shot) & 255 (Ignore) are both not updated intentionally. |
|
357
|
|
|
->group_by('tracker_titles.id') |
|
358
|
|
|
->having('timestamp IS NOT NULL') |
|
359
|
|
|
->having('timestamp > DATE_SUB(NOW(), INTERVAL 120 HOUR)') |
|
360
|
|
|
->order_by('tracker_titles.title', 'ASC') |
|
361
|
|
|
->get(); |
|
362
|
|
|
|
|
363
|
|
|
if($query->num_rows() > 0) { |
|
364
|
|
|
foreach ($query->result() as $row) { |
|
365
|
|
|
print "> {$row->title} <{$row->site_class}>"; //Print this prior to doing anything so we can more easily find out if something went wrong |
|
366
|
|
|
$titleData = $this->sites->{$row->site_class}->getTitleData($row->title_url); |
|
367
|
|
|
if(is_array($titleData) && !is_null($titleData['latest_chapter'])) { |
|
368
|
|
|
//FIXME: "At the moment" we don't seem to be doing anything with TitleData['last_updated']. |
|
369
|
|
|
// Should we even use this? Y/N |
|
370
|
|
View Code Duplication |
if($this->updateTitleById((int) $row->id, $titleData['latest_chapter'])) { |
|
371
|
|
|
//Make sure last_checked is always updated on successful run. |
|
372
|
|
|
//CHECK: Is there a reason we aren't just doing this in updateTitleById? |
|
373
|
|
|
$this->db->set('last_checked', 'CURRENT_TIMESTAMP', FALSE) |
|
374
|
|
|
->where('id', $row->id) |
|
375
|
|
|
->update('tracker_titles'); |
|
376
|
|
|
|
|
377
|
|
|
print " - ({$titleData['latest_chapter']})\n"; |
|
378
|
|
|
} |
|
379
|
|
|
} else { |
|
380
|
|
|
log_message('error', "{$row->title} failed to update successfully"); |
|
381
|
|
|
print " - FAILED TO PARSE\n"; |
|
382
|
|
|
} |
|
383
|
|
|
} |
|
384
|
|
|
} |
|
385
|
|
|
} |
|
386
|
|
|
|
|
387
|
|
|
public function updateCustom() { |
|
388
|
|
|
$sites = $this->getSites(); |
|
389
|
|
|
foreach ($sites as $site) { |
|
390
|
|
|
if($titleDataList = $this->sites->{$site['site_class']}->doCustomUpdate()) { |
|
391
|
|
|
foreach ($titleDataList as $titleURL => $titleData) { |
|
392
|
|
|
print "> {$titleData['title']} <{$site['site_class']}>"; //Print this prior to doing anything so we can more easily find out if something went wrong |
|
393
|
|
|
if(is_array($titleData) && !is_null($titleData['latest_chapter'])) { |
|
394
|
|
|
if($dbTitleData = $this->getTitleID($titleURL, (int) $site['id'], FALSE, TRUE)) { |
|
395
|
|
|
if($this->sites->{$site['site_class']}->doCustomCheck($dbTitleData['latest_chapter'], $titleData['latest_chapter'])) { |
|
396
|
|
|
$titleID = $dbTitleData['id']; |
|
397
|
|
View Code Duplication |
if($this->updateTitleById((int) $titleID, $titleData['latest_chapter'])) { |
|
398
|
|
|
//Make sure last_checked is always updated on successful run. |
|
399
|
|
|
//CHECK: Is there a reason we aren't just doing this in updateTitleById? |
|
400
|
|
|
$this->db->set('last_checked', 'CURRENT_TIMESTAMP', FALSE) |
|
401
|
|
|
->where('id', $titleID) |
|
402
|
|
|
->update('tracker_titles'); |
|
403
|
|
|
|
|
404
|
|
|
print " - ({$titleData['latest_chapter']})\n"; |
|
405
|
|
|
} else { |
|
406
|
|
|
print " - Title doesn't exist? ($titleID)\n"; |
|
407
|
|
|
} |
|
408
|
|
|
} else { |
|
409
|
|
|
print " - Failed Check.\n"; |
|
410
|
|
|
} |
|
411
|
|
|
} else { |
|
412
|
|
|
log_message('error', "{$titleData['title']} || Title does not exist in DB??"); |
|
413
|
|
|
print " - Possibly diff language than in DB? ($titleURL)\n"; |
|
414
|
|
|
} |
|
415
|
|
|
} else { |
|
416
|
|
|
log_message('error', "{$titleData['title']} failed to custom update successfully"); |
|
417
|
|
|
print " - FAILED TO PARSE\n"; |
|
418
|
|
|
} |
|
419
|
|
|
} |
|
420
|
|
|
} |
|
421
|
|
|
} |
|
422
|
|
|
} |
|
423
|
|
|
|
|
424
|
|
|
public function exportTrackerFromUserID(int $userID) { |
|
425
|
|
|
$query = $this->db |
|
426
|
|
|
->select('tracker_chapters.current_chapter, |
|
427
|
|
|
tracker_chapters.category, |
|
428
|
|
|
tracker_titles.title_url, |
|
429
|
|
|
tracker_sites.site') |
|
430
|
|
|
->from('tracker_chapters') |
|
431
|
|
|
->join('tracker_titles', 'tracker_chapters.title_id = tracker_titles.`id', 'left') |
|
432
|
|
|
->join('tracker_sites', 'tracker_sites.id = tracker_titles.site_id', 'left') |
|
433
|
|
|
->where('tracker_chapters.user_id', $userID) |
|
434
|
|
|
->where('tracker_chapters.active', 'Y') |
|
435
|
|
|
->get(); |
|
436
|
|
|
|
|
437
|
|
|
$arr = []; |
|
438
|
|
|
if($query->num_rows() > 0) { |
|
439
|
|
|
foreach ($query->result() as $row) { |
|
440
|
|
|
$arr[$row->category][] = [ |
|
441
|
|
|
'site' => $row->site, |
|
442
|
|
|
'title_url' => $row->title_url, |
|
443
|
|
|
'current_chapter' => $row->current_chapter |
|
444
|
|
|
]; |
|
445
|
|
|
} |
|
446
|
|
|
|
|
447
|
|
|
return $arr; |
|
448
|
|
|
} |
|
449
|
|
|
} |
|
450
|
|
|
|
|
451
|
|
|
public function importTrackerFromJSON(string $json_string) : array { |
|
452
|
|
|
//We already know the this is a valid JSON string as it was validated by form_validator. |
|
453
|
|
|
$json = json_decode($json_string, TRUE); |
|
454
|
|
|
|
|
455
|
|
|
/* |
|
456
|
|
|
* 0 = Success |
|
457
|
|
|
* 1 = Invalid keys. |
|
458
|
|
|
* 2 = Has failed rows |
|
459
|
|
|
*/ |
|
460
|
|
|
$status = ['code' => 0, 'failed_rows' => []]; |
|
461
|
|
|
|
|
462
|
|
|
$categories = array_keys($json); |
|
463
|
|
|
if(count($categories) === count(array_intersect(['reading', 'on-hold', 'plan-to-read', 'custom1', 'custom2', 'custom3'], $categories))) { |
|
464
|
|
|
$json_keys = array_keys(call_user_func_array('array_merge', call_user_func_array('array_merge', $json))); |
|
465
|
|
|
|
|
466
|
|
|
if(count($json_keys) === 3 && !array_diff(array('site', 'title_url', 'current_chapter'), $json_keys)) { |
|
467
|
|
|
foreach($categories as $category) { |
|
468
|
|
|
foreach($json[$category] as $row) { |
|
469
|
|
|
$success = $this->updateTracker($this->User->id, $row['site'], $row['title_url'], $row['current_chapter']); |
|
470
|
|
|
if(!$success) { |
|
471
|
|
|
$status['code'] = 2; |
|
472
|
|
|
$status['failed_rows'][] = $row; |
|
473
|
|
|
} |
|
474
|
|
|
} |
|
475
|
|
|
} |
|
476
|
|
|
} else { |
|
477
|
|
|
$status['code'] = 1; |
|
478
|
|
|
} |
|
479
|
|
|
} else { |
|
480
|
|
|
$status['code'] = 1; |
|
481
|
|
|
} |
|
482
|
|
|
return $status; |
|
483
|
|
|
} |
|
484
|
|
|
|
|
485
|
|
|
public function deleteTrackerByIDList(array $idList) : array { |
|
486
|
|
|
/* |
|
487
|
|
|
* 0 = Success |
|
488
|
|
|
* 1 = Invalid IDs |
|
489
|
|
|
*/ |
|
490
|
|
|
$status = ['code' => 0]; |
|
491
|
|
|
|
|
492
|
|
View Code Duplication |
foreach($idList as $id) { |
|
493
|
|
|
if(!(ctype_digit($id) && $this->deleteTrackerByID($this->User->id, (int) $id))) { |
|
494
|
|
|
$status['code'] = 1; |
|
495
|
|
|
} else { |
|
496
|
|
|
//Delete was successful, update history too. |
|
497
|
|
|
$this->History->userRemoveTitle((int) $id); |
|
498
|
|
|
} |
|
499
|
|
|
} |
|
500
|
|
|
|
|
501
|
|
|
return $status; |
|
502
|
|
|
} |
|
503
|
|
|
|
|
504
|
|
|
public function setCategoryByIDList(array $idList, string $category) : array { |
|
505
|
|
|
/* |
|
506
|
|
|
* 0 = Success |
|
507
|
|
|
* 1 = Invalid IDs |
|
508
|
|
|
* 2 = Invalid category |
|
509
|
|
|
*/ |
|
510
|
|
|
$status = ['code' => 0]; |
|
511
|
|
|
|
|
512
|
|
|
if(in_array($category, array_keys($this->enabledCategories))) { |
|
513
|
|
View Code Duplication |
foreach($idList as $id) { |
|
514
|
|
|
if(!(ctype_digit($id) && $this->setCategoryTrackerByID($this->User->id, (int) $id, $category))) { |
|
515
|
|
|
$status['code'] = 1; |
|
516
|
|
|
} else { |
|
517
|
|
|
//Category update was successful, update history too. |
|
518
|
|
|
$this->History->userUpdateCategory((int) $id, $category); |
|
519
|
|
|
} |
|
520
|
|
|
} |
|
521
|
|
|
} else { |
|
522
|
|
|
$status['code'] = 2; |
|
523
|
|
|
} |
|
524
|
|
|
|
|
525
|
|
|
return $status; |
|
526
|
|
|
} |
|
527
|
|
View Code Duplication |
public function setCategoryTrackerByID(int $userID, int $chapterID, string $category) : bool { |
|
528
|
|
|
$success = $this->db->set(['category' => $category, 'active' => 'Y', 'last_updated' => NULL]) |
|
529
|
|
|
->where('user_id', $userID) |
|
530
|
|
|
->where('id', $chapterID) |
|
531
|
|
|
->update('tracker_chapters'); |
|
532
|
|
|
|
|
533
|
|
|
return (bool) $success; |
|
534
|
|
|
} |
|
535
|
|
|
|
|
536
|
|
|
public function updateTagsByID(int $userID, int $chapterID, string $tag_string) : bool { |
|
537
|
|
|
$success = FALSE; |
|
538
|
|
|
if(preg_match("/^[a-z0-9\\-_,:]{0,255}$/", $tag_string)) { |
|
539
|
|
|
$success = (bool) $this->db->set(['tags' => $tag_string, 'active' => 'Y', 'last_updated' => NULL]) |
|
540
|
|
|
->where('user_id', $userID) |
|
541
|
|
|
->where('id', $chapterID) |
|
542
|
|
|
->update('tracker_chapters'); |
|
543
|
|
|
} |
|
544
|
|
|
|
|
545
|
|
|
if($success) { |
|
546
|
|
|
//Tag update was successful, update history |
|
547
|
|
|
$this->History->userUpdateTags($chapterID, $tag_string); |
|
548
|
|
|
} |
|
549
|
|
|
return $success; |
|
550
|
|
|
} |
|
551
|
|
|
|
|
552
|
|
|
public function favouriteChapter(int $userID, string $site, string $title, string $chapter) : array { |
|
553
|
|
|
$success = array( |
|
554
|
|
|
'status' => 'Something went wrong', |
|
555
|
|
|
'bool' => FALSE |
|
556
|
|
|
); |
|
557
|
|
|
if($siteData = $this->Tracker->getSiteDataFromURL($site)) { |
|
558
|
|
|
//Validate user input |
|
559
|
|
|
if(!$this->sites->{$siteData->site_class}->isValidTitleURL($title)) { |
|
560
|
|
|
//Error is already logged via isValidTitleURL |
|
561
|
|
|
$success['status'] = 'Title URL is not valid'; |
|
562
|
|
|
return $success; |
|
563
|
|
|
} |
|
564
|
|
|
if(!$this->sites->{$siteData->site_class}->isValidChapter($chapter)) { |
|
565
|
|
|
//Error is already logged via isValidChapter |
|
566
|
|
|
$success['status'] = 'Chapter URL is not valid'; |
|
567
|
|
|
return $success; |
|
568
|
|
|
} |
|
569
|
|
|
|
|
570
|
|
|
//NOTE: If the title doesn't exist it will be created. This maybe isn't perfect, but it works for now. |
|
571
|
|
|
$titleID = $this->Tracker->getTitleID($title, (int) $siteData->id); |
|
572
|
|
|
if($titleID === 0) { |
|
573
|
|
|
//Something went wrong. |
|
574
|
|
|
log_message('error', "TitleID = 0 for {$title} @ {$siteData->id}"); |
|
575
|
|
|
return $success; |
|
576
|
|
|
} |
|
577
|
|
|
|
|
578
|
|
|
//We need the series to be tracked |
|
579
|
|
|
$idCQuery = $this->db->select('id') |
|
580
|
|
|
->where('user_id', $userID) |
|
581
|
|
|
->where('title_id', $titleID) |
|
582
|
|
|
->get('tracker_chapters'); |
|
583
|
|
|
if($idCQuery->num_rows() > 0) { |
|
584
|
|
|
$idCQueryRow = $idCQuery->row(); |
|
585
|
|
|
|
|
586
|
|
|
//Check if it is already favourited |
|
587
|
|
|
$idFQuery = $this->db->select('id') |
|
588
|
|
|
->where('chapter_id', $idCQueryRow->id) |
|
589
|
|
|
->where('chapter', $chapter) |
|
590
|
|
|
->get('tracker_favourites'); |
|
591
|
|
|
if($idFQuery->num_rows() > 0) { |
|
592
|
|
|
//Chapter is already favourited, so remove it from DB |
|
593
|
|
|
$idFQueryRow = $idFQuery->row(); |
|
594
|
|
|
|
|
595
|
|
|
$isSuccess = (bool) $this->db->where('id', $idFQueryRow->id) |
|
596
|
|
|
->delete('tracker_favourites'); |
|
597
|
|
|
|
|
598
|
|
|
if($isSuccess) { |
|
599
|
|
|
$success = array( |
|
600
|
|
|
'status' => 'Unfavourited', |
|
601
|
|
|
'bool' => TRUE |
|
602
|
|
|
); |
|
603
|
|
|
$this->History->userRemoveFavourite((int) $idCQueryRow->id, $chapter); |
|
604
|
|
|
} |
|
605
|
|
|
} else { |
|
606
|
|
|
//Chapter is not favourited, so add to DB. |
|
607
|
|
|
$isSuccess = (bool) $this->db->insert('tracker_favourites', [ |
|
608
|
|
|
'chapter_id' => $idCQueryRow->id, |
|
609
|
|
|
'chapter' => $chapter, |
|
610
|
|
|
'updated_at' => date('Y-m-d H:i:s') |
|
611
|
|
|
]); |
|
612
|
|
|
|
|
613
|
|
|
if($isSuccess) { |
|
614
|
|
|
$success = array( |
|
615
|
|
|
'status' => 'Favourited', |
|
616
|
|
|
'bool' => TRUE |
|
617
|
|
|
); |
|
618
|
|
|
$this->History->userAddFavourite((int) $idCQueryRow->id, $chapter); |
|
619
|
|
|
} |
|
620
|
|
|
} |
|
621
|
|
|
} else { |
|
622
|
|
|
$success['status'] = 'Series needs to be tracked before we can favourite chapters'; |
|
623
|
|
|
} |
|
624
|
|
|
} |
|
625
|
|
|
return $success; |
|
626
|
|
|
} |
|
627
|
|
|
public function getFavourites(int $page) : array { |
|
628
|
|
|
$rowsPerPage = 50; |
|
629
|
|
|
$query = $this->db |
|
630
|
|
|
->select('SQL_CALC_FOUND_ROWS |
|
631
|
|
|
tt.title, tt.title_url, |
|
632
|
|
|
ts.site, ts.site_class, |
|
633
|
|
|
tf.chapter, tf.updated_at', FALSE) |
|
634
|
|
|
->from('tracker_favourites AS tf') |
|
635
|
|
|
->join('tracker_chapters AS tc', 'tf.chapter_id = tc.id', 'left') |
|
636
|
|
|
->join('tracker_titles AS tt', 'tc.title_id = tt.id', 'left') |
|
637
|
|
|
->join('tracker_sites AS ts', 'tt.site_id = ts.id', 'left') |
|
638
|
|
|
->where('tc.user_id', $this->User->id) //CHECK: Is this inefficient? Would it be better to have a user_id column in tracker_favourites? |
|
639
|
|
|
->order_by('tf.id DESC') |
|
640
|
|
|
->limit($rowsPerPage, ($rowsPerPage * ($page - 1))) |
|
641
|
|
|
->get(); |
|
642
|
|
|
|
|
643
|
|
|
$arr = ['rows' => [], 'totalPages' => 1]; |
|
644
|
|
|
if($query->num_rows() > 0) { |
|
645
|
|
|
foreach($query->result() as $row) { |
|
646
|
|
|
$arrRow = []; |
|
647
|
|
|
|
|
648
|
|
|
$arrRow['updated_at'] = $row->updated_at; |
|
649
|
|
|
$arrRow['title'] = $row->title; |
|
650
|
|
|
$arrRow['title_url'] = $this->Tracker->sites->{$row->site_class}->getFullTitleURL($row->title_url); |
|
651
|
|
|
|
|
652
|
|
|
$arrRow['site'] = $row->site; |
|
653
|
|
|
$arrRow['site_sprite'] = str_replace('.', '-', $row->site); |
|
654
|
|
|
|
|
655
|
|
|
$chapterData = $this->Tracker->sites->{$row->site_class}->getChapterData($row->title_url, $row->chapter); |
|
656
|
|
|
$arrRow['chapter'] = "<a href=\"{$chapterData['url']}\">{$chapterData['number']}</a>"; |
|
657
|
|
|
$arr['rows'][] = $arrRow; |
|
658
|
|
|
} |
|
659
|
|
|
$arr['totalPages'] = ceil($this->db->query('SELECT FOUND_ROWS() count;')->row()->count / $rowsPerPage); |
|
660
|
|
|
} |
|
661
|
|
|
return $arr; |
|
662
|
|
|
|
|
663
|
|
|
} |
|
664
|
|
|
|
|
665
|
|
|
public function getSites() : array { |
|
666
|
|
|
$query = $this->db->select('*') |
|
667
|
|
|
->from('tracker_sites') |
|
668
|
|
|
->where('status', 'enabled') |
|
669
|
|
|
->get(); |
|
670
|
|
|
|
|
671
|
|
|
return $query->result_array(); |
|
672
|
|
|
} |
|
673
|
|
|
|
|
674
|
|
|
public function getUsedCategories(int $userID) : array { |
|
675
|
|
|
$query = $this->db->distinct() |
|
676
|
|
|
->select('category') |
|
677
|
|
|
->from('tracker_chapters') |
|
678
|
|
|
->where('tracker_chapters.active', 'Y') |
|
679
|
|
|
->where('user_id', $userID) |
|
680
|
|
|
->get(); |
|
681
|
|
|
|
|
682
|
|
|
return array_column($query->result_array(), 'category'); |
|
683
|
|
|
} |
|
684
|
|
|
|
|
685
|
|
|
public function getStats() : array { |
|
686
|
|
|
if(!($stats = $this->cache->get('site_stats'))) { |
|
687
|
|
|
$stats = array(); |
|
688
|
|
|
|
|
689
|
|
|
//CHECK: Is it possible to merge some of these queries? |
|
690
|
|
|
$queryUsers = $this->db->select([ |
|
|
|
|
|
|
691
|
|
|
'COUNT(*) AS total_users', |
|
692
|
|
|
'SUM(CASE WHEN api_key IS NOT NULL THEN 1 ELSE 0 END) AS validated_users', |
|
693
|
|
|
'SUM(CASE WHEN (api_key IS NOT NULL AND from_unixtime(last_login) > DATE_SUB(NOW(), INTERVAL 7 DAY)) THEN 1 ELSE 0 END) AS active_users' |
|
694
|
|
|
], FALSE) |
|
695
|
|
|
->from('auth_users') |
|
696
|
|
|
->get(); |
|
697
|
|
|
$stats = array_merge($stats, $queryUsers->result_array()[0]); |
|
698
|
|
|
|
|
699
|
|
|
$queryCounts = $this->db->select([ |
|
|
|
|
|
|
700
|
|
|
'tracker_titles.title', |
|
701
|
|
|
'COUNT(tracker_chapters.title_id) AS count' |
|
702
|
|
|
], FALSE) |
|
703
|
|
|
->from('tracker_chapters') |
|
704
|
|
|
->join('tracker_titles', 'tracker_titles.id = tracker_chapters.title_id', 'left') |
|
705
|
|
|
->group_by('tracker_chapters.title_id') |
|
706
|
|
|
->having('count > 1') |
|
707
|
|
|
->order_by('count DESC') |
|
708
|
|
|
->get(); |
|
709
|
|
|
$stats['titles_tracked_more'] = count($queryCounts->result_array()); |
|
710
|
|
|
$stats['top_title_name'] = $queryCounts->result_array()[0]['title'] ?? 'N/A'; |
|
711
|
|
|
$stats['top_title_count'] = $queryCounts->result_array()[0]['count'] ?? 'N/A'; |
|
712
|
|
|
|
|
713
|
|
|
$queryTitles = $this->db->select([ |
|
|
|
|
|
|
714
|
|
|
'COUNT(DISTINCT tracker_titles.id) AS total_titles', |
|
715
|
|
|
'COUNT(DISTINCT tracker_titles.site_id) AS total_sites', |
|
716
|
|
|
'SUM(CASE WHEN from_unixtime(auth_users.last_login) > DATE_SUB(NOW(), INTERVAL 120 HOUR) IS NOT NULL THEN 0 ELSE 1 END) AS inactive_titles', |
|
717
|
|
|
'SUM(CASE WHEN (tracker_titles.last_updated > DATE_SUB(NOW(), INTERVAL 24 HOUR)) THEN 1 ELSE 0 END) AS updated_titles' |
|
718
|
|
|
], FALSE) |
|
719
|
|
|
->from('tracker_titles') |
|
720
|
|
|
->join('tracker_sites', 'tracker_sites.id = tracker_titles.site_id', 'left') |
|
721
|
|
|
->join('tracker_chapters', 'tracker_titles.id = tracker_chapters.title_id', 'left') |
|
722
|
|
|
->join('auth_users', 'tracker_chapters.user_id = auth_users.id', 'left') |
|
723
|
|
|
->get(); |
|
724
|
|
|
$stats = array_merge($stats, $queryTitles->result_array()[0]); |
|
725
|
|
|
|
|
726
|
|
|
$querySites = $this->db->select([ |
|
|
|
|
|
|
727
|
|
|
'tracker_sites.site', |
|
728
|
|
|
'COUNT(*) AS count' |
|
729
|
|
|
], FALSE) |
|
730
|
|
|
->from('tracker_titles') |
|
731
|
|
|
->join('tracker_sites', 'tracker_sites.id = tracker_titles.site_id', 'left') |
|
732
|
|
|
->group_by('tracker_titles.site_id') |
|
733
|
|
|
->order_by('count DESC') |
|
734
|
|
|
->limit(3) |
|
735
|
|
|
->get(); |
|
736
|
|
|
$querySitesResult = $querySites->result_array(); |
|
737
|
|
|
$stats['rank1_site'] = $querySitesResult[0]['site']; |
|
738
|
|
|
$stats['rank1_site_count'] = $querySitesResult[0]['count']; |
|
739
|
|
|
$stats['rank2_site'] = $querySitesResult[1]['site']; |
|
740
|
|
|
$stats['rank2_site_count'] = $querySitesResult[1]['count']; |
|
741
|
|
|
$stats['rank3_site'] = $querySitesResult[2]['site']; |
|
742
|
|
|
$stats['rank3_site_count'] = $querySitesResult[2]['count']; |
|
743
|
|
|
|
|
744
|
|
|
$queryTitlesU = $this->db->select([ |
|
|
|
|
|
|
745
|
|
|
'COUNT(*) AS title_updated_count' |
|
746
|
|
|
], FALSE) |
|
747
|
|
|
->from('tracker_titles_history') |
|
748
|
|
|
->get(); |
|
749
|
|
|
$stats = array_merge($stats, $queryTitlesU->result_array()[0]); |
|
750
|
|
|
|
|
751
|
|
|
$queryUsersU = $this->db->select([ |
|
|
|
|
|
|
752
|
|
|
'COUNT(*) AS user_updated_count' |
|
753
|
|
|
], FALSE) |
|
754
|
|
|
->from('tracker_user_history') |
|
755
|
|
|
->get(); |
|
756
|
|
|
$stats = array_merge($stats, $queryUsersU->result_array()[0]); |
|
757
|
|
|
|
|
758
|
|
|
$stats['live_time'] = timespan(/*2016-09-10T03:17:19*/ 1473477439, time(), 2); |
|
759
|
|
|
|
|
760
|
|
|
$this->cache->save('site_stats', $stats, 3600); //Cache for an hour |
|
761
|
|
|
} |
|
762
|
|
|
|
|
763
|
|
|
return $stats; |
|
764
|
|
|
} |
|
765
|
|
|
|
|
766
|
|
|
//FIXME: Should this be moved elsewhere?? |
|
767
|
|
|
public function getNextUpdateTime() : string { |
|
768
|
|
|
$temp_now = new DateTime(); |
|
769
|
|
|
$temp_now->setTimezone(new DateTimeZone('America/New_York')); |
|
770
|
|
|
$temp_now_formatted = $temp_now->format('Y-m-d H:i:s'); |
|
771
|
|
|
|
|
772
|
|
|
//NOTE: PHP Bug: DateTime:diff doesn't play nice with setTimezone, so we need to create another DT object |
|
773
|
|
|
$now = new DateTime($temp_now_formatted); |
|
774
|
|
|
$future_date = new DateTime($temp_now_formatted); |
|
775
|
|
|
$now_hour = (int) $now->format('H'); |
|
776
|
|
|
if($now_hour < 4) { |
|
777
|
|
|
//Time until 4am |
|
778
|
|
|
$future_date->setTime(4, 00); |
|
779
|
|
|
} elseif($now_hour < 8) { |
|
780
|
|
|
//Time until 8am |
|
781
|
|
|
$future_date->setTime(8, 00); |
|
782
|
|
|
} elseif($now_hour < 12) { |
|
783
|
|
|
//Time until 12pm |
|
784
|
|
|
$future_date->setTime(12, 00); |
|
785
|
|
|
} elseif($now_hour < 16) { |
|
786
|
|
|
//Time until 4pm |
|
787
|
|
|
$future_date->setTime(16, 00); |
|
788
|
|
|
} elseif($now_hour < 20) { |
|
789
|
|
|
//Time until 8pm |
|
790
|
|
|
$future_date->setTime(20, 00); |
|
791
|
|
|
} else { |
|
792
|
|
|
//Time until 12am |
|
793
|
|
|
$future_date->setTime(00, 00); |
|
794
|
|
|
$future_date->add(new DateInterval('P1D')); |
|
795
|
|
|
} |
|
796
|
|
|
|
|
797
|
|
|
$interval = $future_date->diff($now); |
|
798
|
|
|
return $interval->format("%H:%I:%S"); |
|
799
|
|
|
} |
|
800
|
|
|
|
|
801
|
|
|
public function reportBug(string $text, $userID = NULL, $url = NULL) : bool { |
|
802
|
|
|
$this->load->library('email'); |
|
803
|
|
|
|
|
804
|
|
|
//This is pretty barebones bug reporting, and honestly not a great way to do it, but it works for now (until the Github is public). |
|
805
|
|
|
$body = "". |
|
806
|
|
|
(!is_null($url) && !empty($url) ? "URL: ".htmlspecialchars(substr($url, 0, 255))."<br>\n" : ""). |
|
807
|
|
|
"Submitted by: ".$this->input->ip_address().(!is_null($userID) ? "| {$userID}" : "")."<br>\n". |
|
808
|
|
|
"<br>Bug report: ".htmlspecialchars(substr($text, 0, 1000)); |
|
809
|
|
|
|
|
810
|
|
|
$success = TRUE; |
|
811
|
|
|
$this->email->from('[email protected]', $this->config->item('site_title', 'ion_auth')); |
|
812
|
|
|
$this->email->to($this->config->item('admin_email', 'ion_auth')); |
|
813
|
|
|
$this->email->subject($this->config->item('site_title', 'ion_auth')." - Bug Report"); |
|
814
|
|
|
$this->email->message($body); |
|
815
|
|
|
if(!$this->email->send()) { |
|
|
|
|
|
|
816
|
|
|
$success = FALSE; |
|
817
|
|
|
} |
|
818
|
|
|
return $success; |
|
819
|
|
|
} |
|
820
|
|
|
|
|
821
|
|
|
/*************************************************/ |
|
822
|
|
|
public function sites() { |
|
823
|
|
|
return $this; |
|
824
|
|
|
} |
|
825
|
|
|
} |
|
826
|
|
|
|
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next
break.There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.