+function initProfileLists()
+{
+ printfnq("Ensuring all profile tags have a corresponding list...");
+
+ $ptag = new Profile_tag();
+ $ptag->selectAdd();
+ $ptag->selectAdd('tagger, tag, count(*) as tagged_count');
+ $ptag->whereAdd('NOT EXISTS (SELECT tagger, tagged from profile_list '.
+ 'where profile_tag.tagger = profile_list.tagger '.
+ 'and profile_tag.tag = profile_list.tag)');
+ $ptag->groupBy('tagger, tag');
+ $ptag->orderBy('tagger, tag');
+
+ if ($ptag->find()) {
+ while ($ptag->fetch()) {
+ $plist = new Profile_list();
+
+ $plist->tagger = $ptag->tagger;
+ $plist->tag = $ptag->tag;
+ $plist->private = 0;
+ $plist->created = common_sql_now();
+ $plist->modified = $plist->created;
+ $plist->mainpage = common_local_url('showprofiletag',
+ array('tagger' => $plist->getTagger()->nickname,
+ 'tag' => $plist->tag));;
+
+ $plist->tagged_count = $ptag->tagged_count;
+ $plist->subscriber_count = 0;
+
+ $plist->insert();
+
+ $orig = clone($plist);
+ // After insert since it uses auto-generated ID
+ $plist->uri = common_local_url('profiletagbyid',
+ array('id' => $plist->id, 'tagger_id' => $plist->tagger));
+
+ $plist->update($orig);
+ }
+ }
+
+ printfnq("DONE.\n");
+}
+
+/*
+ * Added as we now store interpretd width and height in File table.
+ */
+function fixupFileGeometry()
+{
+ printfnq("Ensuring width and height is set for supported local File objects...");
+
+ $file = new File();
+ $file->whereAdd('filename IS NOT NULL'); // local files
+ $file->whereAdd('width IS NULL OR width = 0');
+
+ if ($file->find()) {
+ while ($file->fetch()) {
+ // Set file geometrical properties if available
+ try {
+ $image = ImageFile::fromFileObject($file);
+ } catch (ServerException $e) {
+ // We couldn't make out an image from the file.
+ continue;
+ }
+ $orig = clone($file);
+ $file->width = $image->width;
+ $file->height = $image->height;
+ $file->update($orig);
+
+ // FIXME: Do this more automagically inside ImageFile or so.
+ if ($image->getPath() != $file->getPath()) {
+ $image->unlink();
+ }
+ unset($image);
+ }
+ }
+
+ printfnq("DONE.\n");
+}
+
+/*
+ * File_thumbnail objects for local Files store their own filenames in the database.
+ */
+function deleteLocalFileThumbnailsWithoutFilename()
+{
+ printfnq("Removing all local File_thumbnail entries without filename property...");
+
+ $file = new File();
+ $file->whereAdd('filename IS NOT NULL'); // local files
+
+ if ($file->find()) {
+ // Looping through local File entries
+ while ($file->fetch()) {
+ $thumbs = new File_thumbnail();
+ $thumbs->file_id = $file->id;
+ $thumbs->whereAdd('filename IS NULL');
+ // Checking if there were any File_thumbnail entries without filename
+ if (!$thumbs->find()) {
+ continue;
+ }
+ // deleting incomplete entry to allow regeneration
+ while ($thumbs->fetch()) {
+ $thumbs->delete();
+ }
+ }
+ }
+
+ printfnq("DONE.\n");
+}
+
+/*
+ * Delete File_thumbnail entries where the referenced file does not exist.
+ */
+function deleteMissingLocalFileThumbnails()
+{
+ printfnq("Removing all local File_thumbnail entries without existing files...");
+
+ $thumbs = new File_thumbnail();
+ $thumbs->whereAdd('filename IS NOT NULL'); // only fill in names where they're missing
+ // Checking if there were any File_thumbnail entries without filename
+ if ($thumbs->find()) {
+ while ($thumbs->fetch()) {
+ try {
+ $thumbs->getPath();
+ } catch (FileNotFoundException $e) {
+ $thumbs->delete();
+ }
+ }
+ }
+
+ printfnq("DONE.\n");
+}
+
+/*
+ * Files are now stored with their hash, so let's generate for previously uploaded files.
+ */
+function setFilehashOnLocalFiles()
+{
+ printfnq('Ensuring all local files have the filehash field set...');
+
+ $file = new File();
+ $file->whereAdd('filename IS NOT NULL'); // local files
+ $file->whereAdd('filehash IS NULL', 'AND'); // without filehash value
+
+ if ($file->find()) {
+ while ($file->fetch()) {
+ try {
+ $orig = clone($file);
+ $file->filehash = hash_file(File::FILEHASH_ALG, $file->getPath());
+ $file->update($orig);
+ } catch (FileNotFoundException $e) {
+ echo "\n WARNING: file ID {$file->id} does not exist on path '{$e->path}'. If there is no file system error, run: php scripts/clean_file_table.php";
+ }
+ }
+ }
+
+ printfnq("DONE.\n");
+}
+
+function fixupFileThumbnailUrlhash()
+{
+ printfnq("Setting urlhash for File_thumbnail entries: ");
+
+ $thumb = new File_thumbnail();
+ $thumb->query('UPDATE '.$thumb->escapedTableName().' SET urlhash=SHA2(url, 256) WHERE'.
+ ' url IS NOT NULL AND'. // find all entries with a url value
+ ' url != "" AND'. // precaution against non-null empty strings
+ ' urlhash IS NULL'); // but don't touch those we've already calculated
+
+ printfnq("DONE.\n");
+}
+
+function migrateProfilePrefs()
+{
+ printfnq("Finding and possibly migrating Profile_prefs entries: ");
+
+ $prefs = array(); // ['qvitter' => ['cover_photo'=>'profile_banner_url', ...], ...]
+ Event::handle('GetProfilePrefsMigrations', array(&$prefs));
+
+ foreach($prefs as $namespace=>$mods) {
+ echo "$namespace... ";
+ assert(is_array($mods));
+ $p = new Profile_prefs();
+ $p->namespace = $namespace;
+ // find all entries in all modified topics given in this namespace
+ $p->whereAddIn('topic', array_keys($mods), $p->columnType('topic'));
+ $p->find();
+ while ($p->fetch()) {
+ // for each entry, update 'topic' to the new key value
+ $orig = clone($p);
+ $p->topic = $mods[$p->topic];
+ $p->updateWithKeys($orig);
+ }
+ }
+
+ printfnq("DONE.\n");
+}
+