diff --git a/scripts/tools/changeSiteName.php b/scripts/tools/changeSiteName.php new file mode 100644 index 0000000000..c6ebfe7875 --- /dev/null +++ b/scripts/tools/changeSiteName.php @@ -0,0 +1,127 @@ +#!/usr/bin/php -q + +read(); + + print "Parsing " . $projectList->count . " projects.\n"; + foreach ($projectList->entries as $projectParams) { // foreach existing project + $projectId = $projectParams['id']; + $project = new ProjectModel($projectId); + $siteName = $project->siteName; + $newSiteName = self::getNewSiteName($target, $siteName); + if ($newSiteName) { + $project->siteName = $newSiteName; + if (!$testMode) { + $project->write(); + } + if (array_key_exists($siteName, $siteNameCount)) { + $siteNameCount[$siteName]++; + } else { + $siteNameCount[$siteName] = 1; + } + } + } + foreach(array_keys($siteNameCount) as $from) { + $count = $siteNameCount[$from]; + print "$count $from projects changed site to " . self::getNewSiteName($target, $from) . "\n"; + } + print "\n"; + + $siteNameCount = array(); + + // loop over every user + $userList = new UserListModel(); + $userList->read(); + $userChangeCount = 0; + print "Parsing " . $userList->count . " users.\n"; + foreach ($userList->entries as $userParams) { + $siteNamesToRemove = array(); + $userId = $userParams['id']; + $user = new UserModel($userId); + foreach ($user->siteRole->getArrayCopy() as $siteName => $role) { + $newSiteName = self::getNewSiteName($target, $siteName); + if ($newSiteName) { + $user->siteRole[$newSiteName] = $role; + $siteNamesToRemove[] = $siteName; + if (array_key_exists($siteName, $siteNameCount)) { + $siteNameCount[$siteName]++; + } else { + $siteNameCount[$siteName] = 1; + } + $userChangeCount++; + } + } + foreach ($siteNamesToRemove as $siteName) { + unset($user->siteRole[$siteName]); + } + if (!$testMode) { + $user->write(); + } + } + print "$userChangeCount users changed\n\n"; + foreach(array_keys($siteNameCount) as $from) { + $count = $siteNameCount[$from]; + print "$count users of $from projects changed site to " . self::getNewSiteName($target, $from) . "\n"; + } + print "\n"; + } +} +if (count($argv) != 3) { + print "Usage:\n" . "php changeSiteName.php [run|test] [qa|local]\n\n" . + "examples:\n\n" . "php changeSiteName.php test local\n - test changes but do not make actual changes. " . + "Change site names to the localhost site available on developer machines\n\n" . + "php changeSiteName.php run qa\n - change the database. change site names to the QA site\n"; + exit; +} + +$mode = $argv[1]; +if ($mode != 'test' && $mode != 'run') { + print "Error: first argument must be either 'test' or 'run' which determines script run mode\n"; + exit; +} + +$target = $argv[2]; +if ($target != 'qa' && $target != 'local') { + print "Error: second argument must be either 'qa' or 'local' which determines the target site\n"; + exit; +} + +ChangeSiteName::run($mode, $target); diff --git a/scripts/tools/csvInsights.php b/scripts/tools/csvInsights.php new file mode 100644 index 0000000000..6d6731d02b --- /dev/null +++ b/scripts/tools/csvInsights.php @@ -0,0 +1,13 @@ +#!/usr/bin/php -q + +url = "/app/{$project->appName}/$project->id/"; // owner data - $owner = UserCommands::readUser($project->ownerRef->asString()); + try { + $owner = UserCommands::readUser($project->ownerRef->asString()); + } catch (\Exception $e) { + # there appears to be a dangling owner ref in our data + $owner = [ + 'username' => 'unknown', + 'email' => 'unknown', + 'name' => 'unknown', + 'role' => 'unknown', + ]; + } $projectData->ownerUserName = $owner['username']; $projectData->ownerEmail = $owner['email']; $projectData->ownerName = $owner['name']; @@ -72,11 +82,13 @@ public static function singleProjectInsights($id, $website) { $recentUsers = []; $lastActivityDate = null; foreach ($projectActivity->entries as $event) { - $userId = (string) $event['userRef']; - $users[$userId] = array_key_exists($userId, $users) ? $users[$userId] + 1 : 1; - if (date_create($event['date']) > date_create()->modify('-180 days')) { - $recentUsers[$userId] = true; - }; + if (array_key_exists('userRef', $event)) { + $userId = (string) $event['userRef']; + $users[$userId] = array_key_exists($userId, $users) ? $users[$userId] + 1 : 1; + if (date_create($event['date']) > date_create()->modify('-180 days')) { + $recentUsers[$userId] = true; + }; + } $lastActivityDate = $lastActivityDate === null ? $event['date']->toDateTime() : max($event['date']->toDateTime(), $lastActivityDate); } $projectData->activeUsers = 0; @@ -165,6 +177,22 @@ public static function allProjectInsights($website) } public static function csvInsights($website) { + $filePointer = fopen('php://memory', 'r+'); + self::writeInsightsToCsvFilePointer($website, $filePointer); + rewind($filePointer); + $csv = stream_get_contents($filePointer); + fclose($filePointer); + return $csv; + } + + public static function csvInsightsToFile($website, $filename) { + $filePointer = fopen($filename, 'w'); + $count = self::writeInsightsToCsvFilePointer($website, $filePointer); + fclose($filePointer); + print "Wrote $count insights to CSV file $filename\n"; + } + + private static function writeInsightsToCsvFilePointer($website, $filePointer) { $insights = ProjectInsightsDto::allProjectInsights($website); // convert camelCase properties to sentence case for table headings @@ -175,15 +203,11 @@ public static function csvInsights($website) { } // in order to get automatic escaping of CSV we have to write to a "file" - $filePointer = fopen('php://memory', 'r+'); fputcsv($filePointer, $headings); foreach ($insights->projectList as $row) { fputcsv($filePointer, array_values((array) $row)); } - rewind($filePointer); - $csv = stream_get_contents($filePointer); - fclose($filePointer); - return $csv; + return count($insights->projectList); } private static function appName($website) { diff --git a/src/Api/Model/Shared/Mapper/MapperModel.php b/src/Api/Model/Shared/Mapper/MapperModel.php index b2ff87838f..2cf100efce 100644 --- a/src/Api/Model/Shared/Mapper/MapperModel.php +++ b/src/Api/Model/Shared/Mapper/MapperModel.php @@ -91,7 +91,9 @@ public function write() { CodeGuard::checkTypeAndThrow($this->id, 'Api\Model\Shared\Mapper\Id'); $now = UniversalTimestamp::now(); - $this->dateModified = $now; + if (! defined('MAPPERMODEL_NO_TIMESTAMP_UPDATE')) { + $this->dateModified = $now; + } if (Id::isEmpty($this->id)) { $this->dateCreated = $now; } diff --git a/src/angular-app/languageforge/lexicon/shared/share-with-others/role-dropdown.component.ts b/src/angular-app/languageforge/lexicon/shared/share-with-others/role-dropdown.component.ts index d49a4ced10..497fc9faef 100644 --- a/src/angular-app/languageforge/lexicon/shared/share-with-others/role-dropdown.component.ts +++ b/src/angular-app/languageforge/lexicon/shared/share-with-others/role-dropdown.component.ts @@ -32,8 +32,15 @@ export class RoleDropdownController implements angular.IController { if (changes.roles) this.buildRoleDetails(); if (changes.selectedRole) { - if (!this.selectedRole) this.selectedRole = this.roles[this.roles.length - 1]; - this.selectedRoleDetail = this.roleDetails.find(p => p.role.key === this.selectedRole.key); + const selectedRole = changes.selectedRole.currentValue || changes.selectedRole; + const selectedRoleDetail = this.roleDetails.find(p => p.role.key === (selectedRole.key || selectedRole)); + if (selectedRoleDetail) { + this.selectedRole = selectedRoleDetail.role; + this.selectedRoleDetail = selectedRoleDetail; + } else { + this.selectedRole = this.roles[this.roles.length - 1]; + this.selectedRoleDetail = this.roleDetails.find(p => p.role.key === this.selectedRole.key); + } } } diff --git a/src/angular-app/languageforge/lexicon/shared/share-with-others/user-management.component.html b/src/angular-app/languageforge/lexicon/shared/share-with-others/user-management.component.html index 2f87d43d95..ae171353fe 100644 --- a/src/angular-app/languageforge/lexicon/shared/share-with-others/user-management.component.html +++ b/src/angular-app/languageforge/lexicon/shared/share-with-others/user-management.component.html @@ -39,7 +39,7 @@
  • - +
    {{user.name}} (you)