]> git.mxchange.org Git - friendica.git/blob - src/Database/PostUpdate.php
Post update: Set "uri-id" in the contact tables
[friendica.git] / src / Database / PostUpdate.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2021, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Database;
23
24 use Friendica\Core\Logger;
25 use Friendica\Core\Protocol;
26 use Friendica\DI;
27 use Friendica\Model\Contact;
28 use Friendica\Model\GServer;
29 use Friendica\Model\Item;
30 use Friendica\Model\ItemURI;
31 use Friendica\Model\Photo;
32 use Friendica\Model\Post;
33 use Friendica\Model\Post\Category;
34 use Friendica\Model\Tag;
35 use Friendica\Model\Verb;
36 use Friendica\Util\Strings;
37
38 /**
39  * These database-intensive post update routines are meant to be executed in the background by the cronjob.
40  *
41  * If there is a need for a intensive migration after a database structure change, update this file
42  * by adding a new method at the end with the number of the new DB_UPDATE_VERSION.
43  */
44 class PostUpdate
45 {
46         // Needed for the helper function to read from the legacy term table
47         const OBJECT_TYPE_POST  = 1;
48         const VERSION = 1400;
49
50         /**
51          * Calls the post update functions
52          */
53         public static function update()
54         {
55                 if (!self::update1297()) {
56                         return false;
57                 }
58                 if (!self::update1322()) {
59                         return false;
60                 }
61                 if (!self::update1329()) {
62                         return false;
63                 }
64                 if (!self::update1341()) {
65                         return false;
66                 }
67                 if (!self::update1342()) {
68                         return false;
69                 }
70                 if (!self::update1345()) {
71                         return false;
72                 }
73                 if (!self::update1346()) {
74                         return false;
75                 }
76                 if (!self::update1347()) {
77                         return false;
78                 }
79                 if (!self::update1348()) {
80                         return false;
81                 }
82                 if (!self::update1349()) {
83                         return false;
84                 }
85                 if (!self::update1383()) {
86                         return false;
87                 }
88                 if (!self::update1384()) {
89                         return false;
90                 }
91                 if (!self::update1400()) {
92                         return false;
93                 }
94                 if (!self::update1424()) {
95                         return false;
96                 }
97                 if (!self::update1425()) {
98                         return false;
99                 }
100                 if (!self::update1426()) {
101                         return false;
102                 }
103                 return true;
104         }
105
106         /**
107          * Set the delivery queue count to a negative value for all items preceding the feature.
108          *
109          * @return bool "true" when the job is done
110          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
111          */
112         private static function update1297()
113         {
114                 // Was the script completed?
115                 if (DI::config()->get('system', 'post_update_version') >= 1297) {
116                         return true;
117                 }
118
119                 if (!DBStructure::existsTable('item-delivery-data')) {
120                         DI::config()->set('system', 'post_update_version', 1297);
121                         return true;
122                 }
123
124                 $max_item_delivery_data = DBA::selectFirst('item-delivery-data', ['iid'], ['queue_count > 0 OR queue_done > 0'], ['order' => ['iid']]);
125                 $max_iid = $max_item_delivery_data['iid'];
126
127                 Logger::info('Start update1297 with max iid: ' . $max_iid);
128
129                 $condition = ['`queue_count` = 0 AND `iid` < ?', $max_iid];
130
131                 DBA::update('item-delivery-data', ['queue_count' => -1], $condition);
132
133                 if (DBA::errorNo() != 0) {
134                         Logger::error('Database error ' . DBA::errorNo() . ':' . DBA::errorMessage());
135                         return false;
136                 }
137
138                 Logger::info('Processed rows: ' . DBA::affectedRows());
139
140                 DI::config()->set('system', 'post_update_version', 1297);
141
142                 Logger::info('Done');
143
144                 return true;
145         }
146         /**
147          * Remove contact duplicates
148          *
149          * @return bool "true" when the job is done
150          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
151          */
152         private static function update1322()
153         {
154                 // Was the script completed?
155                 if (DI::config()->get('system', 'post_update_version') >= 1322) {
156                         return true;
157                 }
158
159                 Logger::info('Start');
160
161                 $contacts = DBA::p("SELECT `nurl`, `uid` FROM `contact`
162                         WHERE EXISTS (SELECT `nurl` FROM `contact` AS `c2`
163                                 WHERE `c2`.`nurl` = `contact`.`nurl` AND `c2`.`id` != `contact`.`id` AND `c2`.`uid` = `contact`.`uid` AND `c2`.`network` IN (?, ?, ?) AND NOT `deleted`)
164                         AND (`network` IN (?, ?, ?) OR (`uid` = ?)) AND NOT `deleted` GROUP BY `nurl`, `uid`",
165                         Protocol::DIASPORA, Protocol::OSTATUS, Protocol::ACTIVITYPUB,
166                         Protocol::DIASPORA, Protocol::OSTATUS, Protocol::ACTIVITYPUB, 0);
167
168                 while ($contact = DBA::fetch($contacts)) {
169                         Logger::info('Remove duplicates', ['nurl' => $contact['nurl'], 'uid' => $contact['uid']]);
170                         Contact::removeDuplicates($contact['nurl'], $contact['uid']);
171                 }
172
173                 DBA::close($contact);
174                 DI::config()->set('system', 'post_update_version', 1322);
175
176                 Logger::info('Done');
177
178                 return true;
179         }
180
181         /**
182          * update user notification data
183          *
184          * @return bool "true" when the job is done
185          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
186          */
187         private static function update1329()
188         {
189                 // Was the script completed?
190                 if (DI::config()->get('system', 'post_update_version') >= 1329) {
191                         return true;
192                 }
193
194                 if (!DBStructure::existsTable('item')) {
195                         DI::config()->set('system', 'post_update_version', 1329);
196                         return true;
197                 }
198
199                 $id = DI::config()->get('system', 'post_update_version_1329_id', 0);
200
201                 Logger::info('Start', ['item' => $id]);
202
203                 $start_id = $id;
204                 $rows = 0;
205                 $condition = ["`id` > ?", $id];
206                 $params = ['order' => ['id'], 'limit' => 10000];
207                 $items = DBA::select('item', ['id', 'uri-id', 'uid'], $condition, $params);
208
209                 if (DBA::errorNo() != 0) {
210                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
211                         return false;
212                 }
213
214                 while ($item = DBA::fetch($items)) {
215                         $id = $item['id'];
216
217                         Post\UserNotification::setNotification($item['uri-id'], $item['uid']);
218
219                         ++$rows;
220                 }
221                 DBA::close($items);
222
223                 DI::config()->set('system', 'post_update_version_1329_id', $id);
224
225                 Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
226
227                 if ($start_id == $id) {
228                         DI::config()->set('system', 'post_update_version', 1329);
229                         Logger::info('Done');
230                         return true;
231                 }
232
233                 return false;
234         }
235
236         /**
237          * Fill the "tag" table with tags and mentions from the body
238          *
239          * @return bool "true" when the job is done
240          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
241          */
242         private static function update1341()
243         {
244                 // Was the script completed?
245                 if (DI::config()->get('system', 'post_update_version') >= 1341) {
246                         return true;
247                 }
248
249                 if (!DBStructure::existsTable('item-content')) {
250                         DI::config()->set('system', 'post_update_version', 1342);
251                         return true;
252                 }
253
254                 $id = DI::config()->get('system', 'post_update_version_1341_id', 0);
255
256                 Logger::info('Start', ['item' => $id]);
257
258                 $rows = 0;
259
260                 $items = DBA::p("SELECT `uri-id`,`body` FROM `item-content` WHERE
261                         (`body` LIKE ? OR `body` LIKE ? OR `body` LIKE ?) AND `uri-id` >= ?
262                         ORDER BY `uri-id` LIMIT 100000", '%#%', '%@%', '%!%', $id);
263
264                 if (DBA::errorNo() != 0) {
265                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
266                         return false;
267                 }
268
269                 while ($item = DBA::fetch($items)) {
270                         Tag::storeFromBody($item['uri-id'], $item['body'], '#!@', false);
271                         $id = $item['uri-id'];
272                         ++$rows;
273                         if ($rows % 1000 == 0) {
274                                 DI::config()->set('system', 'post_update_version_1341_id', $id);
275                         }
276                 }
277                 DBA::close($items);
278
279                 DI::config()->set('system', 'post_update_version_1341_id', $id);
280
281                 Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
282
283                 // When there are less than 1,000 items processed this means that we reached the end
284                 // The other entries will then be processed with the regular functionality
285                 if ($rows < 1000) {
286                         DI::config()->set('system', 'post_update_version', 1341);
287                         Logger::info('Done');
288                         return true;
289                 }
290
291                 return false;
292         }
293
294         /**
295          * Fill the "tag" table with tags and mentions from the "term" table
296          *
297          * @return bool "true" when the job is done
298          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
299          */
300         private static function update1342()
301         {
302                 // Was the script completed?
303                 if (DI::config()->get('system', 'post_update_version') >= 1342) {
304                         return true;
305                 }
306
307                 if (!DBStructure::existsTable('term') || !DBStructure::existsTable('item-content')) {
308                         DI::config()->set('system', 'post_update_version', 1342);
309                         return true;
310                 }
311
312                 $id = DI::config()->get('system', 'post_update_version_1342_id', 0);
313
314                 Logger::info('Start', ['item' => $id]);
315
316                 $rows = 0;
317
318                 $terms = DBA::p("SELECT `term`.`tid`, `item`.`uri-id`, `term`.`type`, `term`.`term`, `term`.`url`, `item-content`.`body`
319                         FROM `term`
320                         INNER JOIN `item` ON `item`.`id` = `term`.`oid`
321                         INNER JOIN `item-content` ON `item-content`.`uri-id` = `item`.`uri-id`
322                         WHERE term.type IN (?, ?, ?, ?) AND `tid` >= ? ORDER BY `tid` LIMIT 100000",
323                         Tag::HASHTAG, Tag::MENTION, Tag::EXCLUSIVE_MENTION, Tag::IMPLICIT_MENTION, $id);
324
325                 if (DBA::errorNo() != 0) {
326                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
327                         return false;
328                 }
329
330                 while ($term = DBA::fetch($terms)) {
331                         if (($term['type'] == Tag::MENTION) && !empty($term['url']) && !strstr($term['body'], $term['url'])) {
332                 $condition = ['nurl' => Strings::normaliseLink($term['url']), 'uid' => 0, 'deleted' => false];
333                 $contact = DBA::selectFirst('contact', ['url', 'alias'], $condition, ['order' => ['id']]);
334                 if (!DBA::isResult($contact)) {
335                         $ssl_url = str_replace('http://', 'https://', $term['url']);
336                         $condition = ['`alias` IN (?, ?, ?) AND `uid` = ? AND NOT `deleted`', $term['url'], Strings::normaliseLink($term['url']), $ssl_url, 0];
337                         $contact = DBA::selectFirst('contact', ['url', 'alias'], $condition, ['order' => ['id']]);
338                 }
339
340                 if (DBA::isResult($contact) && (!strstr($term['body'], $contact['url']) && (empty($contact['alias']) || !strstr($term['body'], $contact['alias'])))) {
341                         $term['type'] = Tag::IMPLICIT_MENTION;
342                 }
343                         }
344
345                         Tag::store($term['uri-id'], $term['type'], $term['term'], $term['url'], false);
346
347                         $id = $term['tid'];
348                         ++$rows;
349                         if ($rows % 1000 == 0) {
350                                 DI::config()->set('system', 'post_update_version_1342_id', $id);
351                         }
352                 }
353                 DBA::close($terms);
354
355                 DI::config()->set('system', 'post_update_version_1342_id', $id);
356
357                 Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
358
359                 // When there are less than 1,000 items processed this means that we reached the end
360                 // The other entries will then be processed with the regular functionality
361                 if ($rows < 1000) {
362                         DI::config()->set('system', 'post_update_version', 1342);
363                         Logger::info('Done');
364                         return true;
365                 }
366
367                 return false;
368         }
369
370         /**
371          * Fill the "post-delivery-data" table with data from the "item-delivery-data" table
372          *
373          * @return bool "true" when the job is done
374          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
375          */
376         private static function update1345()
377         {
378                 // Was the script completed?
379                 if (DI::config()->get('system', 'post_update_version') >= 1345) {
380                         return true;
381                 }
382
383                 if (!DBStructure::existsTable('item-delivery-data')) {
384                         DI::config()->set('system', 'post_update_version', 1345);
385                         return true;
386                 }
387
388                 $id = DI::config()->get('system', 'post_update_version_1345_id', 0);
389
390                 Logger::info('Start', ['item' => $id]);
391
392                 $rows = 0;
393
394                 $deliveries = DBA::p("SELECT `uri-id`, `iid`, `item-delivery-data`.`postopts`, `item-delivery-data`.`inform`,
395                         `queue_count`, `queue_done`, `activitypub`, `dfrn`, `diaspora`, `ostatus`, `legacy_dfrn`, `queue_failed`
396                         FROM `item-delivery-data`
397                         INNER JOIN `item` ON `item`.`id` = `item-delivery-data`.`iid`
398                         WHERE `iid` >= ? ORDER BY `iid` LIMIT 10000", $id);
399
400                 if (DBA::errorNo() != 0) {
401                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
402                         return false;
403                 }
404
405                 while ($delivery = DBA::fetch($deliveries)) {
406                         $id = $delivery['iid'];
407                         unset($delivery['iid']);
408                         DBA::insert('post-delivery-data', $delivery, Database::INSERT_UPDATE);
409                         ++$rows;
410                 }
411                 DBA::close($deliveries);
412
413                 DI::config()->set('system', 'post_update_version_1345_id', $id);
414
415                 Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
416
417                 // When there are less than 100 items processed this means that we reached the end
418                 // The other entries will then be processed with the regular functionality
419                 if ($rows < 100) {
420                         DI::config()->set('system', 'post_update_version', 1345);
421                         Logger::info('Done');
422                         return true;
423                 }
424
425                 return false;
426         }
427
428         /**
429          * Generates the legacy item.file field string from an item ID.
430          * Includes only file and category terms.
431          *
432          * @param int $item_id
433          * @return string
434          * @throws \Exception
435          */
436         private static function fileTextFromItemId($item_id)
437         {
438                 $file_text = '';
439
440                 $condition = ['otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'type' => [Category::FILE, Category::CATEGORY]];
441                 $tags = DBA::selectToArray('term', ['type', 'term', 'url'], $condition);
442                 foreach ($tags as $tag) {
443                         if ($tag['type'] == Category::CATEGORY) {
444                                 $file_text .= '<' . $tag['term'] . '>';
445                         } else {
446                                 $file_text .= '[' . $tag['term'] . ']';
447                         }
448                 }
449
450                 return $file_text;
451         }
452
453         /**
454          * Fill the "tag" table with tags and mentions from the "term" table
455          *
456          * @return bool "true" when the job is done
457          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
458          */
459         private static function update1346()
460         {
461                 // Was the script completed?
462                 if (DI::config()->get('system', 'post_update_version') >= 1346) {
463                         return true;
464                 }
465
466                 if (!DBStructure::existsTable('term')) {
467                         DI::config()->set('system', 'post_update_version', 1346);
468                         return true;
469                 }
470
471                 $id = DI::config()->get('system', 'post_update_version_1346_id', 0);
472
473                 Logger::info('Start', ['item' => $id]);
474
475                 $rows = 0;
476
477                 $terms = DBA::select('term', ['oid'],
478                         ["`type` IN (?, ?) AND `oid` >= ?", Category::CATEGORY, Category::FILE, $id],
479                         ['order' => ['oid'], 'limit' => 1000, 'group_by' => ['oid']]);
480
481                 if (DBA::errorNo() != 0) {
482                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
483                         return false;
484                 }
485
486                 while ($term = DBA::fetch($terms)) {
487                         $item = Post::selectFirst(['uri-id', 'uid'], ['id' => $term['oid']]);
488                         if (!DBA::isResult($item)) {
489                                 continue;
490                         }
491
492                         $file = self::fileTextFromItemId($term['oid']);
493                         if (!empty($file)) {
494                                 Category::storeTextByURIId($item['uri-id'], $item['uid'], $file);
495                         }
496
497                         $id = $term['oid'];
498                         ++$rows;
499                         if ($rows % 100 == 0) {
500                                 DI::config()->set('system', 'post_update_version_1346_id', $id);
501                         }
502                 }
503                 DBA::close($terms);
504
505                 DI::config()->set('system', 'post_update_version_1346_id', $id);
506
507                 Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
508
509                 // When there are less than 10 items processed this means that we reached the end
510                 // The other entries will then be processed with the regular functionality
511                 if ($rows < 10) {
512                         DI::config()->set('system', 'post_update_version', 1346);
513                         Logger::info('Done');
514                         return true;
515                 }
516
517                 return false;
518         }
519
520         /**
521          * update the "vid" (verb) field in the item table
522          *
523          * @return bool "true" when the job is done
524          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
525          * @throws \ImagickException
526          */
527         private static function update1347()
528         {
529                 // Was the script completed?
530                 if (DI::config()->get("system", "post_update_version") >= 1347) {
531                         return true;
532                 }
533
534                 if (!DBStructure::existsTable('item-activity') || !DBStructure::existsTable('item')) {
535                         DI::config()->set('system', 'post_update_version', 1347);
536                         return true;
537                 }
538
539                 $id = DI::config()->get("system", "post_update_version_1347_id", 0);
540
541                 Logger::info('Start', ['item' => $id]);
542
543                 $start_id = $id;
544                 $rows = 0;
545
546                 $items = DBA::p("SELECT `item`.`id`, `item`.`verb` AS `item-verb`, `item-content`.`verb`, `item-activity`.`activity`
547                         FROM `item` LEFT JOIN `item-content` ON `item-content`.`uri-id` = `item`.`uri-id`
548                         LEFT JOIN `item-activity` ON `item-activity`.`uri-id` = `item`.`uri-id` AND `item`.`gravity` = ?
549                         WHERE `item`.`id` >= ? AND `item`.`vid` IS NULL ORDER BY `item`.`id` LIMIT 10000", GRAVITY_ACTIVITY, $id);
550
551                 if (DBA::errorNo() != 0) {
552                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
553                         return false;
554                 }
555
556                 while ($item = DBA::fetch($items)) {
557                         $id = $item['id'];
558                         $verb = $item['item-verb'];
559                         if (empty($verb)) {
560                                 $verb = $item['verb'];
561                         }
562                         if (empty($verb) && is_int($item['activity'])) {
563                                 $verb = Item::ACTIVITIES[$item['activity']];
564                         }
565                         if (empty($verb)) {
566                                 continue;
567                         }
568
569                         DBA::update('item', ['vid' => Verb::getID($verb)], ['id' => $item['id']]);
570                         ++$rows;
571                 }
572                 DBA::close($items);
573
574                 DI::config()->set("system", "post_update_version_1347_id", $id);
575
576                 Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
577
578                 if ($start_id == $id) {
579                         DI::config()->set("system", "post_update_version", 1347);
580                         Logger::info('Done');
581                         return true;
582                 }
583
584                 return false;
585         }
586
587         /**
588          * update the "gsid" (global server id) field in the contact table
589          *
590          * @return bool "true" when the job is done
591          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
592          * @throws \ImagickException
593          */
594         private static function update1348()
595         {
596                 // Was the script completed?
597                 if (DI::config()->get("system", "post_update_version") >= 1348) {
598                         return true;
599                 }
600
601                 $id = DI::config()->get("system", "post_update_version_1348_id", 0);
602
603                 Logger::info('Start', ['contact' => $id]);
604
605                 $start_id = $id;
606                 $rows = 0;
607                 $condition = ["`id` > ? AND `gsid` IS NULL AND `baseurl` != '' AND NOT `baseurl` IS NULL", $id];
608                 $params = ['order' => ['id'], 'limit' => 10000];
609                 $contacts = DBA::select('contact', ['id', 'baseurl'], $condition, $params);
610
611                 if (DBA::errorNo() != 0) {
612                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
613                         return false;
614                 }
615
616                 while ($contact = DBA::fetch($contacts)) {
617                         $id = $contact['id'];
618
619                         DBA::update('contact',
620                                 ['gsid' => GServer::getID($contact['baseurl'], true), 'baseurl' => GServer::cleanURL($contact['baseurl'])],
621                                 ['id' => $contact['id']]);
622
623                         ++$rows;
624                 }
625                 DBA::close($contacts);
626
627                 DI::config()->set("system", "post_update_version_1348_id", $id);
628
629                 Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
630
631                 if ($start_id == $id) {
632                         DI::config()->set("system", "post_update_version", 1348);
633                         Logger::info('Done');
634                         return true;
635                 }
636
637                 return false;
638         }
639
640         /**
641          * update the "gsid" (global server id) field in the apcontact table
642          *
643          * @return bool "true" when the job is done
644          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
645          * @throws \ImagickException
646          */
647         private static function update1349()
648         {
649                 // Was the script completed?
650                 if (DI::config()->get("system", "post_update_version") >= 1349) {
651                         return true;
652                 }
653
654                 $id = DI::config()->get("system", "post_update_version_1349_id", '');
655
656                 Logger::info('Start', ['apcontact' => $id]);
657
658                 $start_id = $id;
659                 $rows = 0;
660                 $condition = ["`url` > ? AND `gsid` IS NULL AND `baseurl` != '' AND NOT `baseurl` IS NULL", $id];
661                 $params = ['order' => ['url'], 'limit' => 10000];
662                 $apcontacts = DBA::select('apcontact', ['url', 'baseurl'], $condition, $params);
663
664                 if (DBA::errorNo() != 0) {
665                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
666                         return false;
667                 }
668
669                 while ($apcontact = DBA::fetch($apcontacts)) {
670                         $id = $apcontact['url'];
671
672                         DBA::update('apcontact',
673                                 ['gsid' => GServer::getID($apcontact['baseurl'], true), 'baseurl' => GServer::cleanURL($apcontact['baseurl'])],
674                                 ['url' => $apcontact['url']]);
675
676                         ++$rows;
677                 }
678                 DBA::close($apcontacts);
679
680                 DI::config()->set("system", "post_update_version_1349_id", $id);
681
682                 Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
683
684                 if ($start_id == $id) {
685                         DI::config()->set("system", "post_update_version", 1349);
686                         Logger::info('Done');
687                         return true;
688                 }
689
690                 return false;
691         }
692
693         /**
694          * Remove orphaned photo entries
695          *
696          * @return bool "true" when the job is done
697          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
698          * @throws \ImagickException
699          */
700         private static function update1383()
701         {
702                 // Was the script completed?
703                 if (DI::config()->get("system", "post_update_version") >= 1383) {
704                         return true;
705                 }
706
707                 Logger::info('Start');
708
709                 $deleted = 0;
710                 $avatar = [4 => 'photo', 5 => 'thumb', 6 => 'micro'];
711
712                 $photos = DBA::select('photo', ['id', 'contact-id', 'resource-id', 'scale'], ["`contact-id` != ? AND `album` = ?", 0, Photo::CONTACT_PHOTOS]);
713                 while ($photo = DBA::fetch($photos)) {
714                         $delete = !in_array($photo['scale'], [4, 5, 6]);
715
716                         if (!$delete) {
717                                 // Check if there is a contact entry with that photo
718                                 $delete = !DBA::exists('contact', ["`id` = ? AND `" . $avatar[$photo['scale']] . "` LIKE ?",
719                                         $photo['contact-id'], '%' . $photo['resource-id'] . '%']);
720                         }
721
722                         if ($delete) {
723                                 Photo::delete(['id' => $photo['id']]);
724                                 $deleted++;
725                         }
726                 }
727                 DBA::close($photos);
728
729                 DI::config()->set("system", "post_update_version", 1383);
730                 Logger::info('Done', ['deleted' => $deleted]);
731                 return true;
732         }
733
734         /**
735          * update the "hash" field in the photo table
736          *
737          * @return bool "true" when the job is done
738          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
739          * @throws \ImagickException
740          */
741         private static function update1384()
742         {
743                 // Was the script completed?
744                 if (DI::config()->get("system", "post_update_version") >= 1384) {
745                         return true;
746                 }
747
748                 $condition = ["`hash` IS NULL"];
749                 Logger::info('Start', ['rest' => DBA::count('photo', $condition)]);
750
751                 $rows = 0;
752                 $photos = DBA::select('photo', [], $condition, ['limit' => 100]);
753
754                 if (DBA::errorNo() != 0) {
755                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
756                         return false;
757                 }
758
759                 while ($photo = DBA::fetch($photos)) {
760                         $img = Photo::getImageForPhoto($photo);
761                         if (!empty($img)) {
762                                 $md5 = md5($img->asString());
763                         } else {
764                                 $md5 = '';
765                         }
766                         DBA::update('photo', ['hash' => $md5], ['id' => $photo['id']]);
767                         ++$rows;
768                 }
769                 DBA::close($photos);
770
771                 Logger::info('Processed', ['rows' => $rows]);
772
773                 if ($rows <= 100) {
774                         DI::config()->set("system", "post_update_version", 1384);
775                         Logger::info('Done');
776                         return true;
777                 }
778
779                 return false;
780         }
781
782         /**
783          * update the "external-id" field in the post table
784          *
785          * @return bool "true" when the job is done
786          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
787          * @throws \ImagickException
788          */
789         private static function update1400()
790         {
791                 // Was the script completed?
792                 if (DI::config()->get("system", "post_update_version") >= 1400) {
793                         return true;
794                 }
795
796                 if (!DBStructure::existsTable('item')) {
797                         DI::config()->set("system", "post_update_version", 1400);
798                         return true;
799                 }
800
801                 $condition = ["`extid` != ? AND EXISTS(SELECT `id` FROM `post-user` WHERE `uri-id` = `item`.`uri-id` AND `uid` = `item`.`uid` AND `external-id` IS NULL)", ''];
802                 Logger::info('Start', ['rest' => DBA::count('item', $condition)]);
803
804                 $rows = 0;
805                 $items = DBA::select('item', ['uri-id', 'uid', 'extid'], $condition, ['order' => ['id'], 'limit' => 10000]);
806
807                 if (DBA::errorNo() != 0) {
808                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
809                         return false;
810                 }
811
812                 while ($item = DBA::fetch($items)) {
813                         Post::update(['external-id' => ItemURI::getIdByURI($item['extid'])], ['uri-id' => $item['uri-id'], 'uid' => $item['uid']]);
814                         ++$rows;
815                 }
816                 DBA::close($items);
817
818                 Logger::info('Processed', ['rows' => $rows]);
819
820                 if ($rows <= 100) {
821                         DI::config()->set("system", "post_update_version", 1400);
822                         Logger::info('Done');
823                         return true;
824                 }
825
826                 return false;
827         }
828
829         /**
830          * update the "uri-id" field in the contact table
831          *
832          * @return bool "true" when the job is done
833          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
834          * @throws \ImagickException
835          */
836         private static function update1424()
837         {
838                 // Was the script completed?
839                 if (DI::config()->get("system", "post_update_version") >= 1424) {
840                         return true;
841                 }
842
843                 $condition = ["`uri-id` IS NULL"];
844                 Logger::info('Start', ['rest' => DBA::count('contact', $condition)]);
845
846                 $rows = 0;
847                 $contacts = DBA::select('contact', ['id', 'url'], $condition, ['limit' => 1000]);
848
849                 if (DBA::errorNo() != 0) {
850                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
851                         return false;
852                 }
853
854                 while ($contact = DBA::fetch($contacts)) {
855                         DBA::update('contact', ['uri-id' => ItemURI::getIdByURI($contact['url'])], ['id' => $contact['id']]);
856                         ++$rows;
857                 }
858                 DBA::close($contacts);
859
860                 Logger::info('Processed', ['rows' => $rows]);
861
862                 if ($rows <= 100) {
863                         DI::config()->set("system", "post_update_version", 1424);
864                         Logger::info('Done');
865                         return true;
866                 }
867
868                 return false;
869         }
870
871         /**
872          * update the "uri-id" field in the fcontact table
873          *
874          * @return bool "true" when the job is done
875          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
876          * @throws \ImagickException
877          */
878         private static function update1425()
879         {
880                 // Was the script completed?
881                 if (DI::config()->get("system", "post_update_version") >= 1425) {
882                         return true;
883                 }
884
885                 $condition = ["`uri-id` IS NULL"];
886                 Logger::info('Start', ['rest' => DBA::count('fcontact', $condition)]);
887
888                 $rows = 0;
889                 $fcontacts = DBA::select('fcontact', ['id', 'url', 'guid'], $condition, ['limit' => 1000]);
890
891                 if (DBA::errorNo() != 0) {
892                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
893                         return false;
894                 }
895
896                 while ($fcontact = DBA::fetch($fcontacts)) {
897                         if (!empty($fcontact['guid'])) {
898                                 $uriid = ItemURI::insert(['uri' => $fcontact['url'], 'guid' => $fcontact['guid']]);
899                         } else {
900                                 $uriid = ItemURI::getIdByURI($fcontact['url']);
901                         }
902                         DBA::update('fcontact', ['uri-id' => $uriid], ['id' => $fcontact['id']]);
903                         ++$rows;
904                 }
905                 DBA::close($fcontacts);
906
907                 Logger::info('Processed', ['rows' => $rows]);
908
909                 if ($rows <= 100) {
910                         DI::config()->set("system", "post_update_version", 1425);
911                         Logger::info('Done');
912                         return true;
913                 }
914
915                 return false;
916         }
917
918         /**
919          * update the "uri-id" field in the apcontact table
920          *
921          * @return bool "true" when the job is done
922          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
923          * @throws \ImagickException
924          */
925         private static function update1426()
926         {
927                 // Was the script completed?
928                 if (DI::config()->get("system", "post_update_version") >= 1426) {
929                         return true;
930                 }
931
932                 $condition = ["`uri-id` IS NULL"];
933                 Logger::info('Start', ['rest' => DBA::count('apcontact', $condition)]);
934
935                 $rows = 0;
936                 $apcontacts = DBA::select('apcontact', ['url', 'uuid'], $condition, ['limit' => 1000]);
937
938                 if (DBA::errorNo() != 0) {
939                         Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
940                         return false;
941                 }
942
943                 while ($apcontact = DBA::fetch($apcontacts)) {
944                         if (!empty($apcontact['uuid'])) {
945                                 $uriid = ItemURI::insert(['uri' => $apcontact['url'], 'guid' => $apcontact['uuid']]);
946                         } else {
947                                 $uriid = ItemURI::getIdByURI($apcontact['url']);
948                         }
949                         DBA::update('apcontact', ['uri-id' => $uriid], ['url' => $apcontact['url']]);
950                         ++$rows;
951                 }
952                 DBA::close($apcontacts);
953
954                 Logger::info('Processed', ['rows' => $rows]);
955
956                 if ($rows <= 100) {
957                         DI::config()->set("system", "post_update_version", 1426);
958                         Logger::info('Done');
959                         return true;
960                 }
961
962                 return false;
963         }
964 }