2018-02-09 04:49:49 +01:00
< ? php
/**
* @ file src / Database / PostUpdate . php
*/
namespace Friendica\Database ;
use Friendica\Core\Config ;
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-07-28 22:04:56 +02:00
use Friendica\Database\DBA ;
2018-02-09 04:49:49 +01:00
require_once 'include/dba.php' ;
/**
* 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 :: update1198 ()) {
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
}
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
*/
private static function update1194 ()
{
// Was the script completed?
if ( Config :: get ( " system " , " post_update_version " ) >= 1194 ) {
return true ;
}
logger ( " Start " , LOGGER_DEBUG );
$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 " );
}
}
logger ( " End ID: " . $end_id , LOGGER_DEBUG );
$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-07-21 15:10:13 +02:00
DBA :: escape ( NETWORK_DFRN ), DBA :: escape ( NETWORK_DIASPORA ), DBA :: escape ( NETWORK_OSTATUS ));
2018-05-03 22:49:32 +02:00
if ( ! $r ) {
Config :: set ( " system " , " post_update_version " , 1194 );
logger ( " Update is done " , LOGGER_DEBUG );
return true ;
} else {
Config :: set ( " system " , " post_update_1194_start " , $r [ 0 ][ " id " ]);
$start_id = Config :: get ( " system " , " post_update_1194_start " );
}
logger ( " Start ID: " . $start_id , LOGGER_DEBUG );
$r = q ( $query1 . $query2 . $query3 . " ORDER BY `item`.`id` LIMIT 1000,1 " ,
intval ( $start_id ), intval ( $end_id ),
2018-07-21 15:10:13 +02:00
DBA :: escape ( NETWORK_DFRN ), DBA :: escape ( NETWORK_DIASPORA ), DBA :: escape ( NETWORK_OSTATUS ));
2018-05-03 22:49:32 +02:00
if ( $r ) {
$pos_id = $r [ 0 ][ " id " ];
} else {
$pos_id = $end_id ;
}
logger ( " Progress: Start: " . $start_id . " position: " . $pos_id . " end: " . $end_id , LOGGER_DEBUG );
q ( " UPDATE `item` " . $query2 . " SET `item`.`global` = 1 " . $query3 ,
intval ( $start_id ), intval ( $pos_id ),
2018-07-21 15:10:13 +02:00
DBA :: escape ( NETWORK_DFRN ), DBA :: escape ( NETWORK_DIASPORA ), DBA :: escape ( NETWORK_OSTATUS ));
2018-05-03 22:49:32 +02:00
logger ( " Done " , LOGGER_DEBUG );
}
/**
* @ brief set the author - id and owner - id in all item entries
*
* This job has to be started multiple times until all entries are set .
* It isn ' t started in the update function since it would consume too much time and can be done in the background .
*
* @ return bool " true " when the job is done
*/
private static function update1198 ()
{
// Was the script completed?
if ( Config :: get ( " system " , " post_update_version " ) >= 1198 ) {
return true ;
}
logger ( " Start " , LOGGER_DEBUG );
// Check if the first step is done (Setting "author-id" and "owner-id" in the item table)
2018-05-11 11:20:59 +02:00
$fields = [ 'author-link' , 'author-name' , 'author-avatar' , 'owner-link' , 'owner-name' , 'owner-avatar' , 'network' , 'uid' ];
2018-07-20 14:19:26 +02:00
$r = DBA :: select ( 'item' , $fields , [ 'author-id' => 0 , 'owner-id' => 0 ], [ 'limit' => 1000 ]);
2018-05-03 22:49:32 +02:00
if ( ! $r ) {
// Are there unfinished entries in the thread table?
$r = q ( " SELECT COUNT(*) AS `total` FROM `thread`
INNER JOIN `item` ON `item` . `id` = `thread` . `iid`
WHERE `thread` . `author-id` = 0 AND `thread` . `owner-id` = 0 AND
( `thread` . `uid` IN ( SELECT `uid` from `user` ) OR `thread` . `uid` = 0 ) " );
if ( $r && ( $r [ 0 ][ " total " ] == 0 )) {
Config :: set ( " system " , " post_update_version " , 1198 );
logger ( " Done " , LOGGER_DEBUG );
return true ;
}
// Update the thread table from the item table
$r = q ( " UPDATE `thread` INNER JOIN `item` ON `item`.`id`=`thread`.`iid`
SET `thread` . `author-id` = `item` . `author-id` ,
`thread` . `owner-id` = `item` . `owner-id`
WHERE `thread` . `author-id` = 0 AND `thread` . `owner-id` = 0 AND
( `thread` . `uid` IN ( SELECT `uid` from `user` ) OR `thread` . `uid` = 0 ) " );
logger ( " Updated threads " , LOGGER_DEBUG );
2018-07-21 14:46:04 +02:00
if ( DBA :: isResult ( $r )) {
2018-05-03 22:49:32 +02:00
Config :: set ( " system " , " post_update_version " , 1198 );
logger ( " Done " , LOGGER_DEBUG );
return true ;
}
return false ;
}
logger ( " Query done " , LOGGER_DEBUG );
$item_arr = [];
foreach ( $r as $item ) {
$index = $item [ " author-link " ] . " - " . $item [ " owner-link " ] . " - " . $item [ " uid " ];
$item_arr [ $index ] = [ " author-link " => $item [ " author-link " ],
" owner-link " => $item [ " owner-link " ],
" uid " => $item [ " uid " ]];
}
// Set the "author-id" and "owner-id" in the item table and add a new public contact entry if needed
foreach ( $item_arr as $item ) {
2018-05-11 11:20:59 +02:00
$default = [ 'url' => $item [ 'author-link' ], 'name' => $item [ 'author-name' ],
'photo' => $item [ 'author-avatar' ], 'network' => $item [ 'network' ]];
$author_id = Contact :: getIdForURL ( $item [ " author-link " ], 0 , false , $default );
$default = [ 'url' => $item [ 'owner-link' ], 'name' => $item [ 'owner-name' ],
'photo' => $item [ 'owner-avatar' ], 'network' => $item [ 'network' ]];
$owner_id = Contact :: getIdForURL ( $item [ " owner-link " ], 0 , false , $default );
2018-05-03 22:49:32 +02:00
if ( $author_id == 0 ) {
$author_id = - 1 ;
}
if ( $owner_id == 0 ) {
$owner_id = - 1 ;
}
2018-07-20 14:19:26 +02:00
DBA :: update ( 'item' , [ 'author-id' => $author_id , 'owner-id' => $owner_id ], [ 'uid' => $item [ 'uid' ], 'author-link' => $item [ 'author-link' ], 'owner-link' => $item [ 'owner-link' ], 'author-id' => 0 , 'owner-id' => 0 ]);
2018-05-03 22:49:32 +02:00
}
logger ( " Updated items " , LOGGER_DEBUG );
return false ;
}
/**
* @ 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
*/
private static function update1206 ()
{
// Was the script completed?
if ( Config :: get ( " system " , " post_update_version " ) >= 1206 ) {
return true ;
}
logger ( " Start " , LOGGER_DEBUG );
$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 );
logger ( " Done " , LOGGER_DEBUG );
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
*/
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-07-15 20:36:20 +02:00
logger ( " 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-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-07-15 20:36:20 +02:00
logger ( " 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 => '' ];
logger ( " Setting ' " . $field . " ' to null if empty. " , LOGGER_DEBUG );
// 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-07-06 07:17:44 +02:00
logger ( " Done " , LOGGER_DEBUG );
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
*/
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 );
logger ( " Start from item " . $id , LOGGER_DEBUG );
$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 );
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 );
logger ( " Processed rows: " . $rows . " - last processed item: " . $id , LOGGER_DEBUG );
if ( $start_id == $id ) {
logger ( " Updating item-uri in item-activity " , LOGGER_DEBUG );
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 " );
logger ( " Updating item-uri in item-content " , LOGGER_DEBUG );
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 );
logger ( " Done " , LOGGER_DEBUG );
return true ;
}
return false ;
}
2018-02-09 04:49:49 +01:00
}