From 3c86542a403ed9f1242487ccc6d230fc7d3547c8 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Fri, 4 Sep 2015 22:25:11 +0200 Subject: [PATCH] Move notice location data to Notice_location Will probably take a _long_ time to do scripts/upgrade.php but don't worry, it can be aborted and resumed. --- classes/Notice.php | 123 ++++++++++++++++++--------- lib/apiaction.php | 26 ++++-- lib/noticelistitem.php | 15 ++-- lib/rss10action.php | 20 +++-- plugins/Mapstraction/actions/map.php | 8 +- 5 files changed, 126 insertions(+), 66 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index 050eeaf90d..0d0933115e 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -65,10 +65,6 @@ class Notice extends Managed_DataObject public $is_local; // int(4) public $source; // varchar(32) public $conversation; // int(4) - public $lat; // decimal(10,7) - public $lon; // decimal(10,7) - public $location_id; // int(4) - public $location_ns; // int(4) public $repeat_of; // int(4) public $verb; // varchar(191) not 255 because utf8mb4 takes more space public $object_type; // varchar(191) not 255 because utf8mb4 takes more space @@ -93,10 +89,6 @@ class Notice extends Managed_DataObject 'is_local' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'notice was generated by a user'), 'source' => array('type' => 'varchar', 'length' => 32, 'description' => 'source of comment, like "web", "im", or "clientname"'), 'conversation' => array('type' => 'int', 'description' => 'id of root notice in this conversation'), - 'lat' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'), - 'lon' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'), - 'location_id' => array('type' => 'int', 'description' => 'location id if possible'), - 'location_ns' => array('type' => 'int', 'description' => 'namespace for location'), 'repeat_of' => array('type' => 'int', 'description' => 'notice this is a repeat of'), 'object_type' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI representing activity streams object type', 'default' => 'http://activitystrea.ms/schema/1.0/note'), 'verb' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI representing activity streams verb', 'default' => 'http://activitystrea.ms/schema/1.0/post'), @@ -196,6 +188,7 @@ class Notice extends Managed_DataObject // Clear related records $this->clearReplies(); + $this->clearLocation(); $this->clearRepeats(); $this->clearTags(); $this->clearGroupInboxes(); @@ -621,14 +614,15 @@ class Notice extends Managed_DataObject } } + $notloc = new Notice_location(); if (!empty($lat) && !empty($lon)) { - $notice->lat = $lat; - $notice->lon = $lon; + $notloc->lat = $lat; + $notloc->lon = $lon; } if (!empty($location_ns) && !empty($location_id)) { - $notice->location_id = $location_id; - $notice->location_ns = $location_ns; + $notloc->location_id = $location_id; + $notloc->location_ns = $location_ns; } if (!empty($rendered)) { @@ -667,7 +661,13 @@ class Notice extends Managed_DataObject // XXX: some of these functions write to the DB try { - $notice->insert(); // throws exception on failure + $notice->insert(); // throws exception on failure, if successful we have an ->id + + if (($notloc->lat && $notloc->lon) || ($notloc->location_id && $notloc->location_ns)) { + $notloc->notice_id = $notice->getID(); + $notloc->insert(); // store the notice location if it had any information + } + // If it's not part of a conversation, it's // the beginning of a new conversation. if (empty($notice->conversation)) { @@ -868,15 +868,10 @@ class Notice extends Managed_DataObject } } + $notloc = null; if ($act->context instanceof ActivityContext) { - $location = $act->context->location; - if ($location) { - $stored->lat = $location->lat; - $stored->lon = $location->lon; - if ($location->location_id) { - $stored->location_ns = $location->location_ns; - $stored->location_id = $location->location_id; - } + if ($act->context->location instanceof Location) { + $notloc = Notice_location::fromLocation($act->context->location); } } else { $act->context = new ActivityContext(); @@ -903,6 +898,12 @@ class Notice extends Managed_DataObject try { $stored->insert(); // throws exception on error + + if ($notloc instanceof Notice_location) { + $notloc->notice_id = $stored->getID(); + $notloc->insert(); + } + $orig = clone($stored); // for updating later in this try clause $object = null; @@ -1844,7 +1845,11 @@ class Notice extends Managed_DataObject // This is not a reply to something } - $ctx->location = $this->getLocation(); + try { + $ctx->location = Notice_location::locFromStored($this); + } catch (ServerException $e) { + $ctx->location = null; + } $conv = null; @@ -2090,23 +2095,6 @@ class Notice extends Managed_DataObject return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit)); } - function getLocation() - { - $location = null; - - if (!empty($this->location_id) && !empty($this->location_ns)) { - $location = Location::fromId($this->location_id, $this->location_ns); - } - - if (is_null($location)) { // no ID, or Location::fromId() failed - if (!empty($this->lat) && !empty($this->lon)) { - $location = Location::fromLatLon($this->lat, $this->lon); - } - } - - return $location; - } - /** * Convenience function for posting a repeat of an existing message. * @@ -2277,6 +2265,16 @@ class Notice extends Managed_DataObject $reply->free(); } + function clearLocation() + { + $loc = new Notice_location(); + $loc->notice_id = $this->id; + + if ($loc->find()) { + $loc->delete(); + } + } + function clearFiles() { $f2p = new File_to_post(); @@ -2885,4 +2883,51 @@ class Notice extends Managed_DataObject $notice->_setReplies($ids); } } + + static public function beforeSchemaUpdate() + { + $table = strtolower(get_called_class()); + $schema = Schema::get(); + $schemadef = $schema->getTableDef($table); + + // 2015-09-04 We move Notice location data to Notice_location + // First we see if we have to do this at all + if (!isset($schemadef['fields']['lat']) + && !isset($schemadef['fields']['lon']) + && !isset($schemadef['fields']['location_id']) + && !isset($schemadef['fields']['location_ns'])) { + // We have already removed the location fields, so no need to migrate. + return; + } + // Then we make sure the Notice_location table is created! + $schema->ensureTable('notice_location', Notice_location::schemaDef()); + + // Then we continue on our road to migration! + echo "\nFound old $table table, moving location data to 'notice_location' table... (this will probably take a LONG time, but can be aborted and continued)"; + + $notice = new Notice(); + $notice->query(sprintf('SELECT id, lat, lon, location_id, location_ns FROM %1$s ' . + 'WHERE lat IS NOT NULL ' . + 'OR lon IS NOT NULL ' . + 'OR location_id IS NOT NULL ' . + 'OR location_ns IS NOT NULL', + $schema->quoteIdentifier($table))); + print "\nFound {$notice->N} notices with location data, inserting"; + while ($notice->fetch()) { + $notloc = Notice_location::getKV('notice_id', $notice->id); + if ($notloc instanceof Notice_location) { + print "-"; + continue; + } + $notloc = new Notice_location(); + $notloc->notice_id = $notice->id; + $notloc->lat= $notice->lat; + $notloc->lon= $notice->lon; + $notloc->location_id= $notice->location_id; + $notloc->location_ns= $notice->location_ns; + $notloc->insert(); + print "."; + } + print "\n"; + } } diff --git a/lib/apiaction.php b/lib/apiaction.php index cd2207b378..fae8f33d0e 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -366,12 +366,13 @@ class ApiAction extends Action $twitter_status['in_reply_to_screen_name'] = ($replier_profile) ? $replier_profile->nickname : null; - if (isset($notice->lat) && isset($notice->lon)) { + try { + $notloc = Notice_location::locFromStored($notice); // This is the format that GeoJSON expects stuff to be in $twitter_status['geo'] = array('type' => 'Point', - 'coordinates' => array((float) $notice->lat, - (float) $notice->lon)); - } else { + 'coordinates' => array((float) $notloc->lat, + (float) $notloc->lon)); + } catch (ServerException $e) { $twitter_status['geo'] = null; } @@ -547,13 +548,14 @@ class ApiAction extends Action $entry['pubDate'] = common_date_rfc2822($notice->created); $entry['guid'] = $entry['link']; - if (isset($notice->lat) && isset($notice->lon)) { + try { + $notloc = Notice_location::locFromStored($notice); // This is the format that GeoJSON expects stuff to be in. // showGeoRSS() below uses it for XML output, so we reuse it $entry['geo'] = array('type' => 'Point', - 'coordinates' => array((float) $notice->lat, - (float) $notice->lon)); - } else { + 'coordinates' => array((float) $notloc->lat, + (float) $notloc->lon)); + } catch (ServerException $e) { $entry['geo'] = null; } @@ -997,7 +999,13 @@ class ApiAction extends Action $statuses = array(); if (is_array($notice)) { - $notice = new ArrayWrapper($notice); + //FIXME: make everything calling showJsonTimeline use only Notice objects + common_debug('ArrayWrapper avoidance in progress! Beep boop, make showJsonTimeline only receive Notice objects!'); + $ids = array(); + foreach ($notice as $n) { + $ids[] = $n->getID(); + } + $notice = Notice::multiGet('id', $ids); } while ($notice->fetch()) { diff --git a/lib/noticelistitem.php b/lib/noticelistitem.php index f25613b9a9..dc171409f4 100644 --- a/lib/noticelistitem.php +++ b/lib/noticelistitem.php @@ -368,18 +368,19 @@ class NoticeListItem extends Widget */ function showNoticeLocation() { - $id = $this->notice->id; - - $location = $this->notice->getLocation(); - - if (empty($location)) { + return; + try { + $location = Notice_location::locFromStored($this->notice); + } catch (NoResultException $e) { + return; + } catch (ServerException $e) { return; } $name = $location->getName(); - $lat = $this->notice->lat; - $lon = $this->notice->lon; + $lat = $location->lat; + $lon = $location->lon; $latlon = (!empty($lat) && !empty($lon)) ? $lat.';'.$lon : ''; if (empty($name)) { diff --git a/lib/rss10action.php b/lib/rss10action.php index 744d1e4b7a..137015530b 100644 --- a/lib/rss10action.php +++ b/lib/rss10action.php @@ -216,15 +216,19 @@ class Rss10Action extends ManagedAction $this->element('dc:creator', null, ($profile->fullname) ? $profile->fullname : $profile->nickname); $this->element('foaf:maker', array('rdf:resource' => $creator_uri)); $this->element('sioc:has_creator', array('rdf:resource' => $creator_uri.'#acct')); - $location = $notice->getLocation(); - if ($location && isset($location->lat) && isset($location->lon)) { - $location_uri = $location->getRdfURL(); - $attrs = array('geo:lat' => $location->lat, - 'geo:long' => $location->lon); - if (strlen($location_uri)) { - $attrs['rdf:resource'] = $location_uri; + try { + $location = Notice_location::locFromStored($notice); + if (isset($location->lat) && isset($location->lon)) { + $location_uri = $location->getRdfURL(); + $attrs = array('geo:lat' => $location->lat, + 'geo:long' => $location->lon); + if (strlen($location_uri)) { + $attrs['rdf:resource'] = $location_uri; + } + $this->element('statusnet:origin', $attrs); } - $this->element('statusnet:origin', $attrs); + } catch (ServerException $e) { + // No result, so no location data } $this->element('statusnet:postIcon', array('rdf:resource' => $profile->avatarUrl())); $this->element('cc:licence', array('rdf:resource' => common_config('license', 'url'))); diff --git a/plugins/Mapstraction/actions/map.php b/plugins/Mapstraction/actions/map.php index be59f5ba0b..48861af994 100644 --- a/plugins/Mapstraction/actions/map.php +++ b/plugins/Mapstraction/actions/map.php @@ -120,9 +120,11 @@ class MapAction extends Action $jsonArray = array(); while ($this->notice->fetch()) { - if (!empty($this->notice->lat) && !empty($this->notice->lon)) { - $jsonNotice = $this->noticeAsJson($this->notice); - $jsonArray[] = $jsonNotice; + try { + $notloc = Notice_location::locFromStored($this->notice); + $jsonArray[] = $this->noticeAsJson($this->notice); + } catch (ServerException $e) { + // no location data } }