1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Saito - The Threaded Web Forum |
7
|
|
|
* |
8
|
|
|
* @copyright Copyright (c) the Saito Project Developers |
9
|
|
|
* @link https://github.com/Schlaefer/Saito |
10
|
|
|
* @license http://opensource.org/licenses/MIT |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace App\Model\Table; |
14
|
|
|
|
15
|
|
|
use Cake\ORM\Query; |
16
|
|
|
use Cake\ORM\Table; |
17
|
|
|
use Cake\Validation\Validator; |
18
|
|
|
use Stopwatch\Lib\Stopwatch; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Stores which users are online |
22
|
|
|
* |
23
|
|
|
* Storage can be nopersistent as it is constantly rebuild with live-data. |
24
|
|
|
* |
25
|
|
|
* Field notes: |
26
|
|
|
* - `time` - Timestamp as int unix-epoch instead regular DATETIME. Makes it |
27
|
|
|
* cheap to clear out-timed users by comparing int values. |
28
|
|
|
*/ |
29
|
|
|
class UserOnlineTable extends Table |
30
|
|
|
{ |
31
|
|
|
/** |
32
|
|
|
* Time in seconds until a user is considered offline |
33
|
|
|
* |
34
|
|
|
* @var int |
35
|
|
|
*/ |
36
|
|
|
public $timeUntilOffline = 1200; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* {@inheritDoc} |
40
|
|
|
*/ |
41
|
|
|
public function initialize(array $config) |
42
|
|
|
{ |
43
|
|
|
$this->setTable('useronline'); |
44
|
|
|
|
45
|
|
|
$this->addBehavior('Timestamp'); |
46
|
|
|
|
47
|
|
|
$this->addBehavior( |
48
|
|
|
'Cron.Cron', |
49
|
|
|
[ |
50
|
|
|
'gc' => [ |
51
|
|
|
'id' => 'UserOnline.deleteGone', |
52
|
|
|
'due' => '+1 minutes', |
53
|
|
|
], |
54
|
|
|
] |
55
|
|
|
); |
56
|
|
|
|
57
|
|
|
$this->belongsTo( |
58
|
|
|
'Users', |
59
|
|
|
[ |
60
|
|
|
'foreignKey' => 'user_id' |
61
|
|
|
] |
62
|
|
|
); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* {@inheritDoc} |
67
|
|
|
*/ |
68
|
|
|
public function validationDefault(Validator $validator) |
69
|
|
|
{ |
70
|
|
|
$validator |
|
|
|
|
71
|
|
|
//= uuid |
72
|
|
|
->notEmpty('uuid') |
73
|
|
|
->requirePresence('uuid') |
74
|
|
|
->add( |
75
|
|
|
'uuid', |
76
|
|
|
[ |
77
|
|
|
'isUnique' => [ |
78
|
|
|
'rule' => 'validateUnique', |
79
|
|
|
'provider' => 'table' |
80
|
|
|
], |
81
|
|
|
] |
82
|
|
|
); |
83
|
|
|
|
84
|
|
|
return $validator; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Sets user with `$id` online |
89
|
|
|
* |
90
|
|
|
* @param int|string $id user-ID |
91
|
|
|
* @param bool $loggedIn user is logged-in |
92
|
|
|
* @return void |
93
|
|
|
* @throws \InvalidArgumentException |
94
|
|
|
*/ |
95
|
|
|
public function setOnline($id, bool $loggedIn): void |
96
|
|
|
{ |
97
|
|
|
if (empty($id)) { |
98
|
|
|
throw new \InvalidArgumentException( |
99
|
|
|
sprintf('Invalid Argument $id in setOnline(): %s', $id) |
100
|
|
|
); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
$now = time(); |
104
|
|
|
$id = $this->getShortendedId((string)$id); |
105
|
|
|
$data = [ |
106
|
|
|
'uuid' => $id, |
107
|
|
|
'logged_in' => $loggedIn, |
108
|
|
|
'time' => $now |
109
|
|
|
]; |
110
|
|
|
|
111
|
|
|
if ($loggedIn) { |
112
|
|
|
$data['user_id'] = $id; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
$user = $this->find() |
116
|
|
|
->where(['uuid' => $id]) |
117
|
|
|
->first(); |
118
|
|
|
|
119
|
|
|
if ($user) { |
120
|
|
|
// only hit database if timestamp is outdated |
121
|
|
|
if ($user->get('time') < ($now - $this->timeUntilOffline)) { |
122
|
|
|
$user->set('time', $now); |
123
|
|
|
$this->save($user); |
|
|
|
|
124
|
|
|
} |
125
|
|
|
} else { |
126
|
|
|
$user = $this->newEntity($data); |
127
|
|
|
$this->save($user); |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Removes user with uuid `$id` from UserOnline |
133
|
|
|
* |
134
|
|
|
* @param int|string $id id |
135
|
|
|
* @return void |
136
|
|
|
*/ |
137
|
|
|
public function setOffline($id): void |
138
|
|
|
{ |
139
|
|
|
$id = $this->getShortendedId((string)$id); |
140
|
|
|
$this->deleteAll(['UserOnline.uuid' => $id]); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Get all logged-in users |
145
|
|
|
* |
146
|
|
|
* Don't use directly but use \Saito\App\Stats |
147
|
|
|
* |
148
|
|
|
* @td @sm make finder |
149
|
|
|
* |
150
|
|
|
* @return Query |
151
|
|
|
*/ |
152
|
|
|
public function getLoggedIn(): Query |
153
|
|
|
{ |
154
|
|
|
Stopwatch::start('UserOnline->getLoggedIn()'); |
155
|
|
|
$loggedInUsers = $this->find( |
156
|
|
|
'all', |
157
|
|
|
[ |
158
|
|
|
'contain' => [ |
159
|
|
|
'Users' => [ |
160
|
|
|
'fields' => ['id', 'user_type', 'username'] |
161
|
|
|
] |
162
|
|
|
], |
163
|
|
|
'conditions' => ['UserOnline.logged_in' => true], |
164
|
|
|
'fields' => ['id'], |
165
|
|
|
'order' => ['LOWER(Users.username)' => 'ASC'] |
166
|
|
|
] |
167
|
|
|
); |
168
|
|
|
Stopwatch::stop('UserOnline->getLoggedIn()'); |
169
|
|
|
|
170
|
|
|
return $loggedInUsers; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Removes users which weren't online $timeDiff seconds |
175
|
|
|
* |
176
|
|
|
* @return void |
177
|
|
|
*/ |
178
|
|
|
public function gc(): void |
179
|
|
|
{ |
180
|
|
|
$this->deleteAll(['time <' => time() - ($this->timeUntilOffline)]); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* shorten string |
185
|
|
|
* |
186
|
|
|
* @param string $id string |
187
|
|
|
* @return string |
188
|
|
|
*/ |
189
|
|
|
protected function getShortendedId(string $id) |
190
|
|
|
{ |
191
|
|
|
return substr($id, 0, 32); |
192
|
|
|
} |
193
|
|
|
} |
194
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.