Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
100.00% |
1 / 1 |
|
100.00% |
9 / 9 |
CRAP | |
100.00% |
42 / 42 |
GSActor | |
100.00% |
1 / 1 |
|
100.00% |
9 / 9 |
40 | |
100.00% |
42 / 42 |
setId | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getId | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setNickname | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getNickname | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setNormalizedNickname | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getNormalizedNickname | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setFullname | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getFullname | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setRoles | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getRoles | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setHomepage | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getHomepage | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setBio | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getBio | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setLocation | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getLocation | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setLat | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getLat | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setLon | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getLon | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setLocationId | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getLocationId | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setLocationService | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getLocationService | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setCreated | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getCreated | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
setModified | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getModified | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
getAvatarUrl | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
getFromId | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
getFromNickname | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
getNicknameFromId | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
getSelfTags | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
setSelfTags | |
100.00% |
1 / 1 |
3 | |
100.00% |
11 / 11 |
|||
getFollowersCount | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
getFollowedCount | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
schemaDef | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
1 | <?php |
2 | |
3 | // {{{ License |
4 | |
5 | // This file is part of GNU social - https://www.gnu.org/software/social |
6 | // |
7 | // GNU social is free software: you can redistribute it and/or modify |
8 | // it under the terms of the GNU Affero General Public License as published by |
9 | // the Free Software Foundation, either version 3 of the License, or |
10 | // (at your option) any later version. |
11 | // |
12 | // GNU social is distributed in the hope that it will be useful, |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | // GNU Affero General Public License for more details. |
16 | // |
17 | // You should have received a copy of the GNU Affero General Public License |
18 | // along with GNU social. If not, see <http://www.gnu.org/licenses/>. |
19 | |
20 | // }}} |
21 | |
22 | namespace App\Entity; |
23 | |
24 | use App\Core\Cache; |
25 | use App\Core\DB\DB; |
26 | use App\Core\Entity; |
27 | use App\Core\Event; |
28 | use App\Core\UserRoles; |
29 | use DateTimeInterface; |
30 | use Functional as F; |
31 | |
32 | /** |
33 | * Entity for actors |
34 | * |
35 | * @category DB |
36 | * @package GNUsocial |
37 | * |
38 | * @author Zach Copley <zach@status.net> |
39 | * @copyright 2010 StatusNet Inc. |
40 | * @author Mikael Nordfeldth <mmn@hethane.se> |
41 | * @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org |
42 | * @author Hugo Sales <hugo@hsal.es> |
43 | * @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org |
44 | * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later |
45 | */ |
46 | class GSActor extends Entity |
47 | { |
48 | // {{{ Autocode |
49 | // @codeCoverageIgnoreStart |
50 | private int $id; |
51 | private string $nickname; |
52 | private string $normalized_nickname; |
53 | private ?string $fullname; |
54 | private int $roles = 4; |
55 | private ?string $homepage; |
56 | private ?string $bio; |
57 | private ?string $location; |
58 | private ?float $lat; |
59 | private ?float $lon; |
60 | private ?int $location_id; |
61 | private ?int $location_service; |
62 | private \DateTimeInterface $created; |
63 | private \DateTimeInterface $modified; |
64 | |
65 | public function setId(int $id): self |
66 | { |
67 | $this->id = $id; |
68 | return $this; |
69 | } |
70 | |
71 | public function getId(): int |
72 | { |
73 | return $this->id; |
74 | } |
75 | |
76 | public function setNickname(string $nickname): self |
77 | { |
78 | $this->nickname = $nickname; |
79 | return $this; |
80 | } |
81 | |
82 | public function getNickname(): string |
83 | { |
84 | return $this->nickname; |
85 | } |
86 | |
87 | public function setNormalizedNickname(string $normalized_nickname): self |
88 | { |
89 | $this->normalized_nickname = $normalized_nickname; |
90 | return $this; |
91 | } |
92 | |
93 | public function getNormalizedNickname(): string |
94 | { |
95 | return $this->normalized_nickname; |
96 | } |
97 | |
98 | public function setFullname(?string $fullname): self |
99 | { |
100 | $this->fullname = $fullname; |
101 | return $this; |
102 | } |
103 | |
104 | public function getFullname(): ?string |
105 | { |
106 | return $this->fullname; |
107 | } |
108 | |
109 | public function setRoles(int $roles): self |
110 | { |
111 | $this->roles = $roles; |
112 | return $this; |
113 | } |
114 | |
115 | public function getRoles(): int |
116 | { |
117 | return $this->roles; |
118 | } |
119 | |
120 | public function setHomepage(?string $homepage): self |
121 | { |
122 | $this->homepage = $homepage; |
123 | return $this; |
124 | } |
125 | |
126 | public function getHomepage(): ?string |
127 | { |
128 | return $this->homepage; |
129 | } |
130 | |
131 | public function setBio(?string $bio): self |
132 | { |
133 | $this->bio = $bio; |
134 | return $this; |
135 | } |
136 | |
137 | public function getBio(): ?string |
138 | { |
139 | return $this->bio; |
140 | } |
141 | |
142 | public function setLocation(?string $location): self |
143 | { |
144 | $this->location = $location; |
145 | return $this; |
146 | } |
147 | |
148 | public function getLocation(): ?string |
149 | { |
150 | return $this->location; |
151 | } |
152 | |
153 | public function setLat(?float $lat): self |
154 | { |
155 | $this->lat = $lat; |
156 | return $this; |
157 | } |
158 | |
159 | public function getLat(): ?float |
160 | { |
161 | return $this->lat; |
162 | } |
163 | |
164 | public function setLon(?float $lon): self |
165 | { |
166 | $this->lon = $lon; |
167 | return $this; |
168 | } |
169 | |
170 | public function getLon(): ?float |
171 | { |
172 | return $this->lon; |
173 | } |
174 | |
175 | public function setLocationId(?int $location_id): self |
176 | { |
177 | $this->location_id = $location_id; |
178 | return $this; |
179 | } |
180 | |
181 | public function getLocationId(): ?int |
182 | { |
183 | return $this->location_id; |
184 | } |
185 | |
186 | public function setLocationService(?int $location_service): self |
187 | { |
188 | $this->location_service = $location_service; |
189 | return $this; |
190 | } |
191 | |
192 | public function getLocationService(): ?int |
193 | { |
194 | return $this->location_service; |
195 | } |
196 | |
197 | public function setCreated(DateTimeInterface $created): self |
198 | { |
199 | $this->created = $created; |
200 | return $this; |
201 | } |
202 | |
203 | public function getCreated(): DateTimeInterface |
204 | { |
205 | return $this->created; |
206 | } |
207 | |
208 | public function setModified(DateTimeInterface $modified): self |
209 | { |
210 | $this->modified = $modified; |
211 | return $this; |
212 | } |
213 | |
214 | public function getModified(): DateTimeInterface |
215 | { |
216 | return $this->modified; |
217 | } |
218 | |
219 | // @codeCoverageIgnoreEnd |
220 | // }}} Autocode |
221 | |
222 | public function getAvatarUrl() |
223 | { |
224 | $url = null; |
225 | Event::handle('GetAvatarUrl', [$this->getId(), &$url]); |
226 | return $url; |
227 | } |
228 | |
229 | public static function getFromId(int $id): ?self |
230 | { |
231 | return Cache::get('gsactor-id-' . $id, function () use ($id) { |
232 | return DB::find('gsactor', ['id' => $id]); |
233 | }); |
234 | } |
235 | |
236 | public static function getFromNickname(string $nickname): ?self |
237 | { |
238 | return Cache::get('gsactor-nick-' . $nickname, function () use ($nickname) { |
239 | return DB::findOneBy('gsactor', ['nickname' => $nickname]); |
240 | }); |
241 | } |
242 | |
243 | public static function getNicknameFromId(int $id): string |
244 | { |
245 | return Cache::get('gsactor-nick-id-' . $id, function () use ($id) { |
246 | return self::getFromId($id)->getNickname(); |
247 | }); |
248 | } |
249 | |
250 | public function getSelfTags(bool $_test_force_recompute = false): array |
251 | { |
252 | return Cache::get('selftags-' . $this->id, |
253 | function () { |
254 | return DB::findBy('gsactor_tag', ['tagger' => $this->id, 'tagged' => $this->id]); |
255 | }, beta: $_test_force_recompute ? INF : 1.0); |
256 | } |
257 | |
258 | public function setSelfTags(array $tags, array $existing): void |
259 | { |
260 | $tag_existing = F\map($existing, function ($pt) { return $pt->getTag(); }); |
261 | $tag_to_add = array_diff($tags, $tag_existing); |
262 | $tag_to_remove = array_diff($tag_existing, $tags); |
263 | $pt_to_remove = F\filter($existing, function ($pt) use ($tag_to_remove) { return in_array($pt->getTag(), $tag_to_remove); }); |
264 | foreach ($tag_to_add as $tag) { |
265 | $pt = GSActorTag::create(['tagger' => $this->id, 'tagged' => $this->id, 'tag' => $tag]); |
266 | DB::persist($pt); |
267 | } |
268 | foreach ($pt_to_remove as $pt) { |
269 | DB::remove($pt); |
270 | } |
271 | Cache::delete('selftags-' . $this->id); |
272 | } |
273 | |
274 | public function getFollowersCount() |
275 | { |
276 | return Cache::get('followers-' . $this->id, |
277 | function () { |
278 | return DB::dql('select count(f) from App\Entity\Follow f where f.followed = :followed', |
279 | ['followed' => $this->id])[0][1] - 1; // Remove self follow |
280 | }); |
281 | } |
282 | |
283 | public function getFollowedCount() |
284 | { |
285 | return Cache::get('followed-' . $this->id, |
286 | function () { |
287 | return DB::dql('select count(f) from App\Entity\Follow f where f.follower = :follower', |
288 | ['follower' => $this->id])[0][1] - 1; // Remove self follow |
289 | }); |
290 | } |
291 | |
292 | public static function schemaDef(): array |
293 | { |
294 | $def = [ |
295 | 'name' => 'gsactor', |
296 | 'description' => 'local and remote users, groups and bots are gsactors, for instance', |
297 | 'fields' => [ |
298 | 'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'], |
299 | 'nickname' => ['type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'nickname or username'], |
300 | 'fullname' => ['type' => 'text', 'description' => 'display name'], |
301 | 'roles' => ['type' => 'int', 'not null' => true, 'default' => UserRoles::USER, 'description' => 'Bitmap of permissions this gsactor has'], |
302 | 'homepage' => ['type' => 'text', 'description' => 'identifying URL'], |
303 | 'bio' => ['type' => 'text', 'description' => 'descriptive biography'], |
304 | 'location' => ['type' => 'text', 'description' => 'physical location'], |
305 | 'lat' => ['type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'], |
306 | 'lon' => ['type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'], |
307 | 'location_id' => ['type' => 'int', 'description' => 'location id if possible'], |
308 | 'location_service' => ['type' => 'int', 'description' => 'service used to obtain location id'], |
309 | 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], |
310 | 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], |
311 | ], |
312 | 'primary key' => ['id'], |
313 | 'indexes' => [ |
314 | 'gsactor_nickname_idx' => ['nickname'], |
315 | ], |
316 | 'fulltext indexes' => [ |
317 | 'gsactor_fulltext_idx' => ['nickname', 'fullname', 'location', 'bio', 'homepage'], |
318 | ], |
319 | ]; |
320 | |
321 | return $def; |
322 | } |
323 | } |