{"action":"created","comment":{"url":"https://api.github.com/repos/Wikia/app/pulls/comments/39014127","id":39014127,"diff_hunk":"@@ -0,0 +1,224 @@\n+<?php\n+\n+/**\n+ * Script migrates the user avatars from DFS to user avatars service\n+ *\n+ * @see PLATFORM-1419\n+ *\n+ * @author Macbre\n+ * @ingroup Maintenance\n+ */\n+\n+putenv( 'SERVER_ID=177' ); // run in the context of a community wiki\n+\n+require_once( __DIR__ . '/../../../../maintenance/Maintenance.php' );\n+\n+class AvatarsMigratorException extends Exception {}\n+\n+/**\n+ * Maintenance script class\n+ */\n+class AvatarsMigrator extends Maintenance {\n+\n+\tprivate $isDryRun = true;\n+\n+\t/**\n+\t * Set script options\n+\t */\n+\tpublic function __construct() {\n+\t\tparent::__construct();\n+\n+\t\t$this->addOption( 'dry-run', 'Don\\'t perform any operations [default]' );\n+\t\t$this->addOption( 'force', 'Perform the migration' );\n+\n+\t\t$this->mDescription = 'This script migrates the user avatars from DFS to user avatars service';\n+\t}\n+\n+\tpublic function execute() {\n+\t\t$this->output( date('r') . \"\\n\" );\n+\n+\t\t// read options\n+\t\t$this->isDryRun = $this->hasOption( 'dry-run' ) || !$this->hasOption( 'force' );\n+\n+\t\tif ( $this->isDryRun ) $this->output( \"Running in dry-run mode!\\n\\n\" );\n+\n+\t\t$this->output( \"Getting the list of all accounts...\\n\" );\n+\n+\t\t// get all accounts\n+\t\t$db = $this->getDB( DB_SLAVE );\n+\n+\t\t$res = $db->select(\n+\t\t\t'`user`',\n+\t\t\t'user_id AS id',\n+\t\t\t[],\n+\t\t\t__METHOD__\n+\t\t);\n+\n+\t\t$rows = $res->numRows();\n+\t\t$this->output( \"Processing {$rows} users...\\n\" );\n+\n+\t\t$this->output( \"Will start in 5 seconds...\\n\" );\n+\t\tsleep( 5 );\n+\n+\t\t// process users\n+\t\tforeach ( $res as $n => $row ) {\n+\t\t\ttry {\n+\t\t\t\t$user = User::newFromId( $row->id );\n+\t\t\t\t$this->output( sprintf( \"\\n%d (%.2f%%) [User #%d / %s]: \", ( $n + 1 ), ( ( $n + 1 ) / $rows * 100 ), $user->getId(), $user->getName() ) );\n+\t\t\t\t$this->processUser( $user );\n+\t\t\t}\n+\t\t\tcatch ( AvatarsMigratorException $e ) {\n+\t\t\t\t\\Wikia\\Logger\\WikiaLogger::instance()->error( __CLASS__, [\n+\t\t\t\t\t'exception' => $e,\n+\t\t\t\t\t'user_id'   => $user->getId(),\n+\t\t\t\t] );\n+\n+\t\t\t\t$this->output( sprintf( \"\\n\\t%s\", $e->getMessage() ) );\n+\t\t\t}\n+\t\t}\n+\n+\t\t$this->output( \"Dome!\\n\" );\n+\t\t$this->output( date('r') . \"\\n\" );\n+\t}\n+\n+\t/**\n+\t * Migrate the avatar of a given user\n+\t *\n+\t * @param User $user\n+\t * @throws AvatarsMigratorException\n+\t */\n+\tprivate function processUser( User $user ) {\n+\t\t$avatar = $user->getGlobalAttribute( AVATAR_USER_OPTION_NAME );\n+\n+\t\t// no avatar set, skip this account\n+\t\tif ( is_null( $avatar ) ) {\n+\t\t\t$this->output( 'no avatar set - skipping' );\n+\t\t\treturn;\n+\t\t}\n+\n+\t\t// no need to store default avatars in user properties - remove the entry\n+\t\telse if ( self::isDefaultAvatar( $avatar ) ) {\n+\t\t\t$this->output( 'default avatar set - removing an attribute' );\n+\n+\t\t\t$this->setAvatarUrl( $user, '' );\n+\t\t}\n+\t\t// predefined avatar (Avatar*.jpg)\n+\t\telse if ( self::isPredefinedAvatar( $avatar ) ) {\n+\t\t\t// store the full URL in user properties\n+\t\t\t$masthead = Masthead::newFromUser( $user );\n+\t\t\t$avatarUrl = $masthead->getPurgeUrl(); # e.g. http://images.wikia.com/messaging/images//1/19/Avatar.jpg\n+\n+\t\t\t$this->output( \"predefined avatar set <{$avatar}> - setting a full URL: <{$avatarUrl}>\" );\n+\n+\t\t\t$this->setAvatarUrl( $user, $avatarUrl );\n+\t\t}\n+\t\t// custom, old avatar - upload via avatars service\n+\t\telse if ( !self::isNewAvatar( $avatar ) ) {\n+\t\t\t$service = new UserAvatarsService( $user->getId() );\n+\n+\t\t\t// fetch the user-uploaded avatar\n+\t\t\t$masthead = Masthead::newFromUser( $user );\n+\t\t\t$avatarUrl = $masthead->getPurgeUrl();\n+\n+\t\t\t$this->output( sprintf( 'uploading <%s>', $avatarUrl ) );\n+\n+\t\t\tif ( $this->isDryRun ) return;\n+\n+\t\t\t$avatarContent = Http::get( $avatarUrl, 'default', [ 'noProxy' => true ] );\n+\t\t\tif ( empty( $avatarContent ) ) {\n+\t\t\t\tthrow new AvatarsMigratorException( 'Avatar fetch failed' );\n+\t\t\t}\n+\n+\t\t\t// store it in temporary file\n+\t\t\t$tmpFile = tempnam( wfTempDir(), 'avatar' );","path":"extensions/wikia/UserProfilePageV3/maintenance/migrateAvatarsViaService.php","position":133,"original_position":133,"commit_id":"e278fdebc6156a9045dce40682dd6c882103d536","original_commit_id":"e278fdebc6156a9045dce40682dd6c882103d536","user":{"login":"michalroszka","id":16726,"avatar_url":"https://avatars.githubusercontent.com/u/16726?v=3","gravatar_id":"","url":"https://api.github.com/users/michalroszka","html_url":"https://github.com/michalroszka","followers_url":"https://api.github.com/users/michalroszka/followers","following_url":"https://api.github.com/users/michalroszka/following{/other_user}","gists_url":"https://api.github.com/users/michalroszka/gists{/gist_id}","starred_url":"https://api.github.com/users/michalroszka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/michalroszka/subscriptions","organizations_url":"https://api.github.com/users/michalroszka/orgs","repos_url":"https://api.github.com/users/michalroszka/repos","events_url":"https://api.github.com/users/michalroszka/events{/privacy}","received_events_url":"https://api.github.com/users/michalroszka/received_events","type":"User","site_admin":false},"body":"Is it worth doing some randomization here to prevent race conditions (two migrations running at the same time or something)?","created_at":"2015-09-09T07:35:32Z","updated_at":"2015-09-09T07:35:32Z","html_url":"https://github.com/Wikia/app/pull/8181#discussion_r39014127","pull_request_url":"https://api.github.com/repos/Wikia/app/pulls/8181","_links":{"self":{"href":"https://api.github.com/repos/Wikia/app/pulls/comments/39014127"},"html":{"href":"https://github.com/Wikia/app/pull/8181#discussion_r39014127"},"pull_request":{"href":"https://api.github.com/repos/Wikia/app/pulls/8181"}}},"pull_request":{"url":"https://api.github.com/repos/Wikia/app/pulls/8181","id":43047859,"html_url":"https://github.com/Wikia/app/pull/8181","diff_url":"https://github.com/Wikia/app/pull/8181.diff","patch_url":"https://github.com/Wikia/app/pull/8181.patch","issue_url":"https://api.github.com/repos/Wikia/app/issues/8181","number":8181,"state":"open","locked":false,"title":"PLATFORM-1334: Masthead will now use the user avatar service","user":{"login":"macbre","id":1929317,"avatar_url":"https://avatars.githubusercontent.com/u/1929317?v=3","gravatar_id":"","url":"https://api.github.com/users/macbre","html_url":"https://github.com/macbre","followers_url":"https://api.github.com/users/macbre/followers","following_url":"https://api.github.com/users/macbre/following{/other_user}","gists_url":"https://api.github.com/users/macbre/gists{/gist_id}","starred_url":"https://api.github.com/users/macbre/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/macbre/subscriptions","organizations_url":"https://api.github.com/users/macbre/orgs","repos_url":"https://api.github.com/users/macbre/repos","events_url":"https://api.github.com/users/macbre/events{/privacy}","received_events_url":"https://api.github.com/users/macbre/received_events","type":"User","site_admin":false},"body":"* https://wikia-inc.atlassian.net/browse/PLATFORM-1334 (`Masthead` class to use the avatar service)\r\n* https://wikia-inc.atlassian.net/browse/PLATFORM-1419 (the avatars migration script)\r\n\r\nThe avatar functionality (which is a part of `Masthead` class) will now use a shiny new avatars service instead of direct uploads to DFS.\r\n\r\n* introduce `$wgAvatarsUseService` global that will turn on avatar uploads via service\r\n* clean-up `Masthead` class code and remove NFS support\r\n* introduce `UserAvatarsService` class generated by Swagger (used to communicate with a service)\r\n* `extensions/wikia/UserProfilePageV3/maintenance/migrateAvatarsViaService.php` maintenance script that will upload all existing avatars via avatars service (tested on devboxes)\r\n* extend the Vignette URL generator by introducing `StaticAssetsUrlGenerator` that will generate URLs to assets uploaded via Static Assets Service (used by avatars service)\r\n\r\n## The plan\r\n\r\n**Phase 1** set `$wgAvatarsUseService` to true and handle avatar uploads via service (make sure it works stable under production traffic)\r\n**Phase 2** run the migration script and upload all custom avatars to StaticAssetsService (via avatars service)\r\n\r\n@jcellary / @wladekb / @michalroszka ","created_at":"2015-08-21T15:08:24Z","updated_at":"2015-09-09T07:35:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"42b3061ce25893d6bc15d21234fd743fa2f31546","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Wikia/app/pulls/8181/commits","review_comments_url":"https://api.github.com/repos/Wikia/app/pulls/8181/comments","review_comment_url":"https://api.github.com/repos/Wikia/app/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Wikia/app/issues/8181/comments","statuses_url":"https://api.github.com/repos/Wikia/app/statuses/e278fdebc6156a9045dce40682dd6c882103d536","head":{"label":"Wikia:PLATFORM-1334-masthead-use-user-avatars-service","ref":"PLATFORM-1334-masthead-use-user-avatars-service","sha":"e278fdebc6156a9045dce40682dd6c882103d536","user":{"login":"Wikia","id":1171011,"avatar_url":"https://avatars.githubusercontent.com/u/1171011?v=3","gravatar_id":"","url":"https://api.github.com/users/Wikia","html_url":"https://github.com/Wikia","followers_url":"https://api.github.com/users/Wikia/followers","following_url":"https://api.github.com/users/Wikia/following{/other_user}","gists_url":"https://api.github.com/users/Wikia/gists{/gist_id}","starred_url":"https://api.github.com/users/Wikia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Wikia/subscriptions","organizations_url":"https://api.github.com/users/Wikia/orgs","repos_url":"https://api.github.com/users/Wikia/repos","events_url":"https://api.github.com/users/Wikia/events{/privacy}","received_events_url":"https://api.github.com/users/Wikia/received_events","type":"Organization","site_admin":false},"repo":{"id":5532313,"name":"app","full_name":"Wikia/app","owner":{"login":"Wikia","id":1171011,"avatar_url":"https://avatars.githubusercontent.com/u/1171011?v=3","gravatar_id":"","url":"https://api.github.com/users/Wikia","html_url":"https://github.com/Wikia","followers_url":"https://api.github.com/users/Wikia/followers","following_url":"https://api.github.com/users/Wikia/following{/other_user}","gists_url":"https://api.github.com/users/Wikia/gists{/gist_id}","starred_url":"https://api.github.com/users/Wikia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Wikia/subscriptions","organizations_url":"https://api.github.com/users/Wikia/orgs","repos_url":"https://api.github.com/users/Wikia/repos","events_url":"https://api.github.com/users/Wikia/events{/privacy}","received_events_url":"https://api.github.com/users/Wikia/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Wikia/app","description":"Wikia Application Code","fork":false,"url":"https://api.github.com/repos/Wikia/app","forks_url":"https://api.github.com/repos/Wikia/app/forks","keys_url":"https://api.github.com/repos/Wikia/app/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Wikia/app/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Wikia/app/teams","hooks_url":"https://api.github.com/repos/Wikia/app/hooks","issue_events_url":"https://api.github.com/repos/Wikia/app/issues/events{/number}","events_url":"https://api.github.com/repos/Wikia/app/events","assignees_url":"https://api.github.com/repos/Wikia/app/assignees{/user}","branches_url":"https://api.github.com/repos/Wikia/app/branches{/branch}","tags_url":"https://api.github.com/repos/Wikia/app/tags","blobs_url":"https://api.github.com/repos/Wikia/app/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Wikia/app/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Wikia/app/git/refs{/sha}","trees_url":"https://api.github.com/repos/Wikia/app/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Wikia/app/statuses/{sha}","languages_url":"https://api.github.com/repos/Wikia/app/languages","stargazers_url":"https://api.github.com/repos/Wikia/app/stargazers","contributors_url":"https://api.github.com/repos/Wikia/app/contributors","subscribers_url":"https://api.github.com/repos/Wikia/app/subscribers","subscription_url":"https://api.github.com/repos/Wikia/app/subscription","commits_url":"https://api.github.com/repos/Wikia/app/commits{/sha}","git_commits_url":"https://api.github.com/repos/Wikia/app/git/commits{/sha}","comments_url":"https://api.github.com/repos/Wikia/app/comments{/number}","issue_comment_url":"https://api.github.com/repos/Wikia/app/issues/comments{/number}","contents_url":"https://api.github.com/repos/Wikia/app/contents/{+path}","compare_url":"https://api.github.com/repos/Wikia/app/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Wikia/app/merges","archive_url":"https://api.github.com/repos/Wikia/app/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Wikia/app/downloads","issues_url":"https://api.github.com/repos/Wikia/app/issues{/number}","pulls_url":"https://api.github.com/repos/Wikia/app/pulls{/number}","milestones_url":"https://api.github.com/repos/Wikia/app/milestones{/number}","notifications_url":"https://api.github.com/repos/Wikia/app/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Wikia/app/labels{/name}","releases_url":"https://api.github.com/repos/Wikia/app/releases{/id}","created_at":"2012-08-23T20:55:58Z","updated_at":"2015-08-26T15:36:55Z","pushed_at":"2015-09-09T04:21:35Z","git_url":"git://github.com/Wikia/app.git","ssh_url":"git@github.com:Wikia/app.git","clone_url":"https://github.com/Wikia/app.git","svn_url":"https://github.com/Wikia/app","homepage":"http://dev.wikia.com","size":1480729,"stargazers_count":84,"watchers_count":84,"language":"PHP","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":66,"mirror_url":null,"open_issues_count":74,"forks":66,"open_issues":74,"watchers":84,"default_branch":"dev"}},"base":{"label":"Wikia:dev","ref":"dev","sha":"ada9117eaff7213cf0bb3b2de9d535b3965c972f","user":{"login":"Wikia","id":1171011,"avatar_url":"https://avatars.githubusercontent.com/u/1171011?v=3","gravatar_id":"","url":"https://api.github.com/users/Wikia","html_url":"https://github.com/Wikia","followers_url":"https://api.github.com/users/Wikia/followers","following_url":"https://api.github.com/users/Wikia/following{/other_user}","gists_url":"https://api.github.com/users/Wikia/gists{/gist_id}","starred_url":"https://api.github.com/users/Wikia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Wikia/subscriptions","organizations_url":"https://api.github.com/users/Wikia/orgs","repos_url":"https://api.github.com/users/Wikia/repos","events_url":"https://api.github.com/users/Wikia/events{/privacy}","received_events_url":"https://api.github.com/users/Wikia/received_events","type":"Organization","site_admin":false},"repo":{"id":5532313,"name":"app","full_name":"Wikia/app","owner":{"login":"Wikia","id":1171011,"avatar_url":"https://avatars.githubusercontent.com/u/1171011?v=3","gravatar_id":"","url":"https://api.github.com/users/Wikia","html_url":"https://github.com/Wikia","followers_url":"https://api.github.com/users/Wikia/followers","following_url":"https://api.github.com/users/Wikia/following{/other_user}","gists_url":"https://api.github.com/users/Wikia/gists{/gist_id}","starred_url":"https://api.github.com/users/Wikia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Wikia/subscriptions","organizations_url":"https://api.github.com/users/Wikia/orgs","repos_url":"https://api.github.com/users/Wikia/repos","events_url":"https://api.github.com/users/Wikia/events{/privacy}","received_events_url":"https://api.github.com/users/Wikia/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Wikia/app","description":"Wikia Application Code","fork":false,"url":"https://api.github.com/repos/Wikia/app","forks_url":"https://api.github.com/repos/Wikia/app/forks","keys_url":"https://api.github.com/repos/Wikia/app/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Wikia/app/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Wikia/app/teams","hooks_url":"https://api.github.com/repos/Wikia/app/hooks","issue_events_url":"https://api.github.com/repos/Wikia/app/issues/events{/number}","events_url":"https://api.github.com/repos/Wikia/app/events","assignees_url":"https://api.github.com/repos/Wikia/app/assignees{/user}","branches_url":"https://api.github.com/repos/Wikia/app/branches{/branch}","tags_url":"https://api.github.com/repos/Wikia/app/tags","blobs_url":"https://api.github.com/repos/Wikia/app/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Wikia/app/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Wikia/app/git/refs{/sha}","trees_url":"https://api.github.com/repos/Wikia/app/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Wikia/app/statuses/{sha}","languages_url":"https://api.github.com/repos/Wikia/app/languages","stargazers_url":"https://api.github.com/repos/Wikia/app/stargazers","contributors_url":"https://api.github.com/repos/Wikia/app/contributors","subscribers_url":"https://api.github.com/repos/Wikia/app/subscribers","subscription_url":"https://api.github.com/repos/Wikia/app/subscription","commits_url":"https://api.github.com/repos/Wikia/app/commits{/sha}","git_commits_url":"https://api.github.com/repos/Wikia/app/git/commits{/sha}","comments_url":"https://api.github.com/repos/Wikia/app/comments{/number}","issue_comment_url":"https://api.github.com/repos/Wikia/app/issues/comments{/number}","contents_url":"https://api.github.com/repos/Wikia/app/contents/{+path}","compare_url":"https://api.github.com/repos/Wikia/app/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Wikia/app/merges","archive_url":"https://api.github.com/repos/Wikia/app/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Wikia/app/downloads","issues_url":"https://api.github.com/repos/Wikia/app/issues{/number}","pulls_url":"https://api.github.com/repos/Wikia/app/pulls{/number}","milestones_url":"https://api.github.com/repos/Wikia/app/milestones{/number}","notifications_url":"https://api.github.com/repos/Wikia/app/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Wikia/app/labels{/name}","releases_url":"https://api.github.com/repos/Wikia/app/releases{/id}","created_at":"2012-08-23T20:55:58Z","updated_at":"2015-08-26T15:36:55Z","pushed_at":"2015-09-09T04:21:35Z","git_url":"git://github.com/Wikia/app.git","ssh_url":"git@github.com:Wikia/app.git","clone_url":"https://github.com/Wikia/app.git","svn_url":"https://github.com/Wikia/app","homepage":"http://dev.wikia.com","size":1480729,"stargazers_count":84,"watchers_count":84,"language":"PHP","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":66,"mirror_url":null,"open_issues_count":74,"forks":66,"open_issues":74,"watchers":84,"default_branch":"dev"}},"_links":{"self":{"href":"https://api.github.com/repos/Wikia/app/pulls/8181"},"html":{"href":"https://github.com/Wikia/app/pull/8181"},"issue":{"href":"https://api.github.com/repos/Wikia/app/issues/8181"},"comments":{"href":"https://api.github.com/repos/Wikia/app/issues/8181/comments"},"review_comments":{"href":"https://api.github.com/repos/Wikia/app/pulls/8181/comments"},"review_comment":{"href":"https://api.github.com/repos/Wikia/app/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Wikia/app/pulls/8181/commits"},"statuses":{"href":"https://api.github.com/repos/Wikia/app/statuses/e278fdebc6156a9045dce40682dd6c882103d536"}}}}