2018-02-09 04:49:49 +01:00
< ? php
/**
* @ file src / Database / PostUpdate . php
*/
namespace Friendica\Database ;
use Friendica\Core\Config ;
2018-10-29 22:20:46 +01:00
use Friendica\Core\Logger ;
2018-08-11 22:40:44 +02:00
use Friendica\Core\Protocol ;
2018-02-09 04:49:49 +01:00
use Friendica\Model\Contact ;
2018-07-01 21:02:29 +02:00
use Friendica\Model\Item ;
2018-08-06 18:40:41 +02:00
use Friendica\Model\ItemURI ;
2018-07-19 15:52:05 +02:00
use Friendica\Model\PermissionSet ;
2018-02-09 04:49:49 +01:00
/**
* Post update functions
*/
class PostUpdate
{
2018-05-03 22:49:32 +02:00
/**
* @ brief Calls the post update functions
*/
public static function update ()
{
if ( ! self :: update1194 ()) {
2018-08-10 23:20:25 +02:00
return false ;
2018-05-03 22:49:32 +02:00
}
if ( ! self :: update1206 ()) {
2018-08-10 23:20:25 +02:00
return false ;
2018-05-03 22:49:32 +02:00
}
2018-07-19 23:56:52 +02:00
if ( ! self :: update1279 ()) {
2018-08-10 23:20:25 +02:00
return false ;
2018-07-06 07:17:44 +02:00
}
2018-08-06 18:40:41 +02:00
if ( ! self :: update1281 ()) {
2018-08-10 23:20:25 +02:00
return false ;
2018-08-06 18:40:41 +02:00
}
2019-01-23 06:02:00 +01:00
if ( ! self :: update1297 ()) {
return false ;
}
2019-08-29 06:06:41 +02:00
if ( ! self :: update1322 ()) {
return false ;
}
2018-08-10 23:20:25 +02:00
return true ;
2018-05-03 22:49:32 +02:00
}
/**
* @ brief Updates the " global " field in the item table
*
* @ return bool " true " when the job is done
2019-01-06 22:06:53 +01:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2018-05-03 22:49:32 +02:00
*/
private static function update1194 ()
{
// Was the script completed?
if ( Config :: get ( " system " , " post_update_version " ) >= 1194 ) {
return true ;
}
2018-10-30 14:58:45 +01:00
Logger :: log ( " Start " , Logger :: DEBUG );
2018-05-03 22:49:32 +02:00
$end_id = Config :: get ( " system " , " post_update_1194_end " );
if ( ! $end_id ) {
$r = q ( " SELECT `id` FROM `item` WHERE `uid` != 0 ORDER BY `id` DESC LIMIT 1 " );
if ( $r ) {
Config :: set ( " system " , " post_update_1194_end " , $r [ 0 ][ " id " ]);
$end_id = Config :: get ( " system " , " post_update_1194_end " );
}
}
2018-10-30 14:58:45 +01:00
Logger :: log ( " End ID: " . $end_id , Logger :: DEBUG );
2018-05-03 22:49:32 +02:00
$start_id = Config :: get ( " system " , " post_update_1194_start " );
$query1 = " SELECT `item`.`id` FROM `item` " ;
$query2 = " INNER JOIN `item` AS `shadow` ON `item`.`uri` = `shadow`.`uri` AND `shadow`.`uid` = 0 " ;
$query3 = " WHERE `item`.`uid` != 0 AND `item`.`id` >= %d AND `item`.`id` <= %d
AND `item` . `visible` AND NOT `item` . `private`
AND NOT `item` . `deleted` AND NOT `item` . `moderated`
AND `item` . `network` IN ( '%s' , '%s' , '%s' , '' )
AND NOT `item` . `global` " ;
$r = q ( $query1 . $query2 . $query3 . " ORDER BY `item`.`id` LIMIT 1 " ,
intval ( $start_id ), intval ( $end_id ),
2018-08-11 22:40:44 +02:00
DBA :: escape ( Protocol :: DFRN ), DBA :: escape ( Protocol :: DIASPORA ), DBA :: escape ( Protocol :: OSTATUS ));
2018-05-03 22:49:32 +02:00
if ( ! $r ) {
Config :: set ( " system " , " post_update_version " , 1194 );
2018-10-30 14:58:45 +01:00
Logger :: log ( " Update is done " , Logger :: DEBUG );
2018-05-03 22:49:32 +02:00
return true ;
} else {
Config :: set ( " system " , " post_update_1194_start " , $r [ 0 ][ " id " ]);
$start_id = Config :: get ( " system " , " post_update_1194_start " );
}
2018-10-30 14:58:45 +01:00
Logger :: log ( " Start ID: " . $start_id , Logger :: DEBUG );
2018-05-03 22:49:32 +02:00
$r = q ( $query1 . $query2 . $query3 . " ORDER BY `item`.`id` LIMIT 1000,1 " ,
intval ( $start_id ), intval ( $end_id ),
2018-08-11 22:40:44 +02:00
DBA :: escape ( Protocol :: DFRN ), DBA :: escape ( Protocol :: DIASPORA ), DBA :: escape ( Protocol :: OSTATUS ));
2018-05-03 22:49:32 +02:00
if ( $r ) {
$pos_id = $r [ 0 ][ " id " ];
} else {
$pos_id = $end_id ;
}
2018-10-30 14:58:45 +01:00
Logger :: log ( " Progress: Start: " . $start_id . " position: " . $pos_id . " end: " . $end_id , Logger :: DEBUG );
2018-05-03 22:49:32 +02:00
q ( " UPDATE `item` " . $query2 . " SET `item`.`global` = 1 " . $query3 ,
intval ( $start_id ), intval ( $pos_id ),
2018-08-11 22:40:44 +02:00
DBA :: escape ( Protocol :: DFRN ), DBA :: escape ( Protocol :: DIASPORA ), DBA :: escape ( Protocol :: OSTATUS ));
2018-05-03 22:49:32 +02:00
2018-10-30 14:58:45 +01:00
Logger :: log ( " Done " , Logger :: DEBUG );
2018-05-03 22:49:32 +02:00
}
/**
* @ brief update the " last-item " field in the " self " contact
*
* This field avoids cost intensive calls in the admin panel and in " nodeinfo "
*
* @ return bool " true " when the job is done
2019-01-06 22:06:53 +01:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2018-05-03 22:49:32 +02:00
*/
private static function update1206 ()
{
// Was the script completed?
if ( Config :: get ( " system " , " post_update_version " ) >= 1206 ) {
return true ;
}
2018-10-30 14:58:45 +01:00
Logger :: log ( " Start " , Logger :: DEBUG );
2018-05-03 22:49:32 +02:00
$r = q ( " SELECT `contact`.`id`, `contact`.`last-item`,
( SELECT MAX ( `changed` ) FROM `item` USE INDEX ( `uid_wall_changed` ) WHERE `wall` AND `uid` = `user` . `uid` ) AS `lastitem_date`
FROM `user`
INNER JOIN `contact` ON `contact` . `uid` = `user` . `uid` AND `contact` . `self` " );
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $r )) {
2018-05-03 22:49:32 +02:00
return false ;
}
foreach ( $r as $user ) {
if ( ! empty ( $user [ " lastitem_date " ]) && ( $user [ " lastitem_date " ] > $user [ " last-item " ])) {
2018-07-20 14:19:26 +02:00
DBA :: update ( 'contact' , [ 'last-item' => $user [ 'lastitem_date' ]], [ 'id' => $user [ 'id' ]]);
2018-05-03 22:49:32 +02:00
}
}
Config :: set ( " system " , " post_update_version " , 1206 );
2018-10-30 14:58:45 +01:00
Logger :: log ( " Done " , Logger :: DEBUG );
2018-05-03 22:49:32 +02:00
return true ;
}
2018-07-01 21:02:29 +02:00
/**
2018-07-15 20:36:20 +02:00
* @ brief update the item related tables
2018-07-01 21:02:29 +02:00
*
* @ return bool " true " when the job is done
2019-01-06 22:06:53 +01:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
* @ throws \ImagickException
2018-07-01 21:02:29 +02:00
*/
2018-07-19 23:56:52 +02:00
private static function update1279 ()
2018-07-01 21:02:29 +02:00
{
// Was the script completed?
2018-07-19 23:56:52 +02:00
if ( Config :: get ( " system " , " post_update_version " ) >= 1279 ) {
2018-07-01 21:02:29 +02:00
return true ;
}
2018-07-19 23:56:52 +02:00
$id = Config :: get ( " system " , " post_update_version_1279_id " , 0 );
2018-07-01 21:02:29 +02:00
2018-10-30 14:58:45 +01:00
Logger :: log ( " Start from item " . $id , Logger :: DEBUG );
2018-07-01 21:02:29 +02:00
2018-07-15 20:36:20 +02:00
$fields = array_merge ( Item :: MIXED_CONTENT_FIELDLIST , [ 'network' , 'author-id' , 'owner-id' , 'tag' , 'file' ,
2018-07-19 15:52:05 +02:00
'author-name' , 'author-avatar' , 'author-link' , 'owner-name' , 'owner-avatar' , 'owner-link' , 'id' ,
2018-07-19 23:56:52 +02:00
'uid' , 'allow_cid' , 'allow_gid' , 'deny_cid' , 'deny_gid' , 'psid' , 'post-type' , 'bookmark' , 'type' ,
2018-07-28 01:24:26 +02:00
'inform' , 'postopts' , 'icid' ]);
2018-07-01 21:02:29 +02:00
2018-07-15 20:36:20 +02:00
$start_id = $id ;
2018-07-01 21:02:29 +02:00
$rows = 0 ;
2018-07-15 20:36:20 +02:00
$condition = [ " `id` > ? " , $id ];
$params = [ 'order' => [ 'id' ], 'limit' => 10000 ];
$items = Item :: select ( $fields , $condition , $params );
2018-08-28 13:56:25 +02:00
if ( DBA :: errorNo () != 0 ) {
2018-10-29 22:20:46 +01:00
Logger :: log ( 'Database error ' . DBA :: errorNo () . ':' . DBA :: errorMessage ());
2018-08-28 13:56:25 +02:00
return false ;
}
2018-07-01 21:02:29 +02:00
while ( $item = Item :: fetch ( $items )) {
2018-07-15 20:36:20 +02:00
$id = $item [ 'id' ];
if ( empty ( $item [ 'author-id' ])) {
$default = [ 'url' => $item [ 'author-link' ], 'name' => $item [ 'author-name' ],
'photo' => $item [ 'author-avatar' ], 'network' => $item [ 'network' ]];
$item [ 'author-id' ] = Contact :: getIdForURL ( $item [ " author-link " ], 0 , false , $default );
2018-07-01 21:33:42 +02:00
}
2018-07-15 20:36:20 +02:00
if ( empty ( $item [ 'owner-id' ])) {
$default = [ 'url' => $item [ 'owner-link' ], 'name' => $item [ 'owner-name' ],
'photo' => $item [ 'owner-avatar' ], 'network' => $item [ 'network' ]];
$item [ 'owner-id' ] = Contact :: getIdForURL ( $item [ " owner-link " ], 0 , false , $default );
2018-07-01 21:33:42 +02:00
}
2018-07-28 19:11:46 +02:00
if ( empty ( $item [ 'psid' ])) {
2018-07-19 15:52:05 +02:00
$item [ 'psid' ] = PermissionSet :: fetchIDForPost ( $item );
2018-07-28 01:24:26 +02:00
} else {
$item [ 'allow_cid' ] = null ;
$item [ 'allow_gid' ] = null ;
$item [ 'deny_cid' ] = null ;
$item [ 'deny_gid' ] = null ;
2018-07-19 15:52:05 +02:00
}
if ( $item [ 'post-type' ] == 0 ) {
if ( ! empty ( $item [ 'type' ]) && ( $item [ 'type' ] == 'note' )) {
$item [ 'post-type' ] = Item :: PT_PERSONAL_NOTE ;
} elseif ( ! empty ( $item [ 'type' ]) && ( $item [ 'type' ] == 'photo' )) {
$item [ 'post-type' ] = Item :: PT_IMAGE ;
} elseif ( ! empty ( $item [ 'bookmark' ]) && $item [ 'bookmark' ]) {
$item [ 'post-type' ] = Item :: PT_PAGE ;
}
}
2018-07-28 01:24:26 +02:00
self :: createLanguage ( $item );
if ( ! empty ( $item [ 'icid' ]) && ! empty ( $item [ 'language' ])) {
DBA :: update ( 'item-content' , [ 'language' => $item [ 'language' ]], [ 'id' => $item [ 'icid' ]]);
}
unset ( $item [ 'language' ]);
2018-07-15 20:36:20 +02:00
Item :: update ( $item , [ 'id' => $id ]);
2018-07-01 21:02:29 +02:00
++ $rows ;
}
2018-07-20 14:19:26 +02:00
DBA :: close ( $items );
2018-07-01 21:02:29 +02:00
2018-07-19 23:56:52 +02:00
Config :: set ( " system " , " post_update_version_1279_id " , $id );
2018-07-06 07:17:44 +02:00
2018-10-30 14:58:45 +01:00
Logger :: log ( " Processed rows: " . $rows . " - last processed item: " . $id , Logger :: DEBUG );
2018-07-06 07:17:44 +02:00
2018-07-15 20:36:20 +02:00
if ( $start_id == $id ) {
2018-07-28 01:24:26 +02:00
// Set all deprecated fields to "null" if they contain an empty string
$nullfields = [ 'allow_cid' , 'allow_gid' , 'deny_cid' , 'deny_gid' , 'postopts' , 'inform' , 'type' ,
'bookmark' , 'file' , 'location' , 'coord' , 'tag' , 'plink' , 'title' , 'content-warning' ,
'body' , 'app' , 'verb' , 'object-type' , 'object' , 'target-type' , 'target' ,
'author-name' , 'author-link' , 'author-avatar' , 'owner-name' , 'owner-link' , 'owner-avatar' ,
'rendered-hash' , 'rendered-html' ];
foreach ( $nullfields as $field ) {
$fields = [ $field => null ];
$condition = [ $field => '' ];
2018-10-30 14:58:45 +01:00
Logger :: log ( " Setting ' " . $field . " ' to null if empty. " , Logger :: DEBUG );
2018-07-28 01:24:26 +02:00
// Important: This has to be a "DBA::update", not a "Item::update"
DBA :: update ( 'item' , $fields , $condition );
}
2018-07-19 23:56:52 +02:00
Config :: set ( " system " , " post_update_version " , 1279 );
2018-10-30 14:58:45 +01:00
Logger :: log ( " Done " , Logger :: DEBUG );
2018-07-06 07:17:44 +02:00
return true ;
}
2018-07-15 20:36:20 +02:00
return false ;
2018-07-01 21:02:29 +02:00
}
2018-07-28 01:24:26 +02:00
private static function createLanguage ( & $item )
{
if ( empty ( $item [ 'postopts' ])) {
return ;
}
$opts = explode ( ',' , $item [ 'postopts' ]);
$postopts = [];
foreach ( $opts as $opt ) {
if ( strstr ( $opt , 'lang=' )) {
$language = substr ( $opt , 5 );
} else {
$postopts [] = $opt ;
}
}
if ( empty ( $language )) {
return ;
}
if ( ! empty ( $postopts )) {
$item [ 'postopts' ] = implode ( ',' , $postopts );
} else {
$item [ 'postopts' ] = null ;
}
$lang_pairs = explode ( ':' , $language );
$lang_arr = [];
foreach ( $lang_pairs as $pair ) {
$lang_pair_arr = explode ( ';' , $pair );
if ( count ( $lang_pair_arr ) == 2 ) {
$lang_arr [ $lang_pair_arr [ 0 ]] = $lang_pair_arr [ 1 ];
}
}
$item [ 'language' ] = json_encode ( $lang_arr );
}
2018-08-06 18:40:41 +02:00
/**
* @ brief update item - uri data . Prerequisite for the next item structure update .
*
* @ return bool " true " when the job is done
2019-01-06 22:06:53 +01:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2018-08-06 18:40:41 +02:00
*/
private static function update1281 ()
{
// Was the script completed?
if ( Config :: get ( " system " , " post_update_version " ) >= 1281 ) {
return true ;
}
$id = Config :: get ( " system " , " post_update_version_1281_id " , 0 );
2018-10-30 14:58:45 +01:00
Logger :: log ( " Start from item " . $id , Logger :: DEBUG );
2018-08-06 18:40:41 +02:00
$fields = [ 'id' , 'guid' , 'uri' , 'uri-id' , 'parent-uri' , 'parent-uri-id' , 'thr-parent' , 'thr-parent-id' ];
$start_id = $id ;
$rows = 0 ;
$condition = [ " `id` > ? " , $id ];
$params = [ 'order' => [ 'id' ], 'limit' => 10000 ];
$items = DBA :: select ( 'item' , $fields , $condition , $params );
2018-08-28 13:56:25 +02:00
if ( DBA :: errorNo () != 0 ) {
2018-10-29 22:20:46 +01:00
Logger :: log ( 'Database error ' . DBA :: errorNo () . ':' . DBA :: errorMessage ());
2018-08-28 13:56:25 +02:00
return false ;
}
2018-08-06 18:40:41 +02:00
while ( $item = DBA :: fetch ( $items )) {
$id = $item [ 'id' ];
if ( empty ( $item [ 'uri' ])) {
// Should not happen
continue ;
} elseif ( empty ( $item [ 'uri-id' ])) {
$item [ 'uri-id' ] = ItemURI :: insert ([ 'uri' => $item [ 'uri' ], 'guid' => $item [ 'guid' ]]);
}
if ( empty ( $item [ 'parent-uri' ])) {
$item [ 'parent-uri-id' ] = $item [ 'uri-id' ];
} elseif ( empty ( $item [ 'parent-uri-id' ])) {
$item [ 'parent-uri-id' ] = ItemURI :: getIdByURI ( $item [ 'parent-uri' ]);
}
// Very old items don't have this field
if ( empty ( $item [ 'thr-parent' ])) {
$item [ 'thr-parent-id' ] = $item [ 'parent-uri-id' ];
} elseif ( empty ( $item [ 'thr-parent-id' ])) {
$item [ 'thr-parent-id' ] = ItemURI :: getIdByURI ( $item [ 'thr-parent' ]);
}
unset ( $item [ 'id' ]);
unset ( $item [ 'guid' ]);
unset ( $item [ 'uri' ]);
unset ( $item [ 'parent-uri' ]);
unset ( $item [ 'thr-parent' ]);
DBA :: update ( 'item' , $item , [ 'id' => $id ]);
++ $rows ;
}
DBA :: close ( $items );
Config :: set ( " system " , " post_update_version_1281_id " , $id );
2018-10-30 14:58:45 +01:00
Logger :: log ( " Processed rows: " . $rows . " - last processed item: " . $id , Logger :: DEBUG );
2018-08-06 18:40:41 +02:00
if ( $start_id == $id ) {
2018-10-30 14:58:45 +01:00
Logger :: log ( " Updating item-uri in item-activity " , Logger :: DEBUG );
2018-08-06 18:40:41 +02:00
DBA :: e ( " UPDATE `item-activity` INNER JOIN `item-uri` ON `item-uri`.`uri` = `item-activity`.`uri` SET `item-activity`.`uri-id` = `item-uri`.`id` WHERE `item-activity`.`uri-id` IS NULL " );
2018-10-30 14:58:45 +01:00
Logger :: log ( " Updating item-uri in item-content " , Logger :: DEBUG );
2018-08-06 18:40:41 +02:00
DBA :: e ( " UPDATE `item-content` INNER JOIN `item-uri` ON `item-uri`.`uri` = `item-content`.`uri` SET `item-content`.`uri-id` = `item-uri`.`id` WHERE `item-content`.`uri-id` IS NULL " );
Config :: set ( " system " , " post_update_version " , 1281 );
2018-10-30 14:58:45 +01:00
Logger :: log ( " Done " , Logger :: DEBUG );
2018-08-06 18:40:41 +02:00
return true ;
}
return false ;
}
2019-01-23 06:02:00 +01:00
/**
* Set the delivery queue count to a negative value for all items preceding the feature .
*
* @ return bool " true " when the job is done
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function update1297 ()
{
// Was the script completed?
if ( Config :: get ( 'system' , 'post_update_version' ) >= 1297 ) {
return true ;
}
$max_item_delivery_data = DBA :: selectFirst ( 'item-delivery-data' , [ 'iid' ], [ 'queue_count > 0 OR queue_done > 0' ], [ 'order' => [ 'iid' ]]);
$max_iid = $max_item_delivery_data [ 'iid' ];
Logger :: info ( 'Start update1297 with max iid: ' . $max_iid );
$condition = [ '`queue_count` = 0 AND `iid` < ?' , $max_iid ];
DBA :: update ( 'item-delivery-data' , [ 'queue_count' => - 1 ], $condition );
if ( DBA :: errorNo () != 0 ) {
Logger :: error ( 'Database error ' . DBA :: errorNo () . ':' . DBA :: errorMessage ());
return false ;
}
Logger :: info ( 'Processed rows: ' . DBA :: affectedRows ());
Config :: set ( 'system' , 'post_update_version' , 1297 );
Logger :: info ( 'Done' );
2019-08-29 06:06:41 +02:00
return true ;
}
/**
2019-08-30 07:38:42 +02:00
* Remove contact duplicates
2019-08-29 06:06:41 +02:00
*
* @ return bool " true " when the job is done
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function update1322 ()
{
// Was the script completed?
if ( Config :: get ( 'system' , 'post_update_version' ) >= 1322 ) {
return true ;
}
Logger :: info ( 'Start' );
2019-08-29 06:55:36 +02:00
$contacts = DBA :: p ( " SELECT ANY_VALUE(`id`) AS `id`, ANY_VALUE(`nurl`) AS `nurl` FROM `contact`
2019-08-29 06:06:41 +02:00
WHERE EXISTS ( SELECT `nurl` FROM `contact` AS `c2`
2019-08-29 07:22:29 +02:00
WHERE `c2` . `nurl` = `contact` . `nurl` AND `c2` . `id` != `contact` . `id` AND `c2` . `uid` = `contact` . `uid` AND `c2` . `network` IN ( ? , ? , ? ) AND NOT `deleted` )
AND ( `network` IN ( ? , ? , ? ) OR ( `uid` = ? )) AND NOT `deleted` GROUP BY `nurl` , `uid` " ,
2019-08-29 06:55:36 +02:00
Protocol :: DIASPORA , Protocol :: OSTATUS , Protocol :: ACTIVITYPUB ,
Protocol :: DIASPORA , Protocol :: OSTATUS , Protocol :: ACTIVITYPUB , 0 );
2019-08-29 06:06:41 +02:00
while ( $contact = DBA :: fetch ( $contacts )) {
Logger :: info ( 'Remove duplicates' , [ 'id' => $contact [ 'id' ]]);
Contact :: handleDuplicateByID ( $contact [ 'id' ]);
}
DBA :: close ( $contact );
Config :: set ( 'system' , 'post_update_version' , 1322 );
Logger :: info ( 'Done' );
2019-01-23 06:02:00 +01:00
return true ;
}
2018-02-09 04:49:49 +01:00
}