Skip to content

Commit 254e587

Browse files
committed
Merge branch 'lf-qa' into lf-live
* Fixes roles dropdown in user management view * Fixes project insights DTO (now won't crash on dangling owner ref)
2 parents 71a4795 + 2f94428 commit 254e587

File tree

6 files changed

+188
-15
lines changed

6 files changed

+188
-15
lines changed

scripts/tools/changeSiteName.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/php -q
2+
3+
<?php
4+
5+
require_once('../scriptsConfig.php');
6+
7+
use Api\Model\Shared\ProjectListModel;
8+
use Api\Model\Shared\ProjectModel;
9+
use Api\Model\Shared\UserListModel;
10+
use Api\Model\Shared\UserModel;
11+
12+
(php_sapi_name() == 'cli') or die('this script must be run on the command-line');
13+
14+
// When we change the site name, don't update the date modified timestamps
15+
define('MAPPERMODEL_NO_TIMESTAMP_UPDATE', true);
16+
17+
class ChangeSiteName
18+
{
19+
public static function getNewSiteName($target, $siteName) {
20+
if (strpos($siteName, "languageforge") !== false) {
21+
if ($target == "qa") {
22+
return "qa.languageforge.org";
23+
}
24+
return "languageforge.localhost";
25+
}
26+
if (strpos($siteName, "scriptureforge") !== false) {
27+
if ($target == "qa") {
28+
return "qa.scriptureforge.org";
29+
}
30+
return "scriptureforge.localhost";
31+
}
32+
return '';
33+
}
34+
35+
public static function run($mode, $target)
36+
{
37+
$testMode = ($mode != 'run');
38+
$siteNameCount = array();
39+
40+
// loop over every project
41+
$projectList = new ProjectListModel();
42+
$projectList->read();
43+
44+
print "Parsing " . $projectList->count . " projects.\n";
45+
foreach ($projectList->entries as $projectParams) { // foreach existing project
46+
$projectId = $projectParams['id'];
47+
$project = new ProjectModel($projectId);
48+
$siteName = $project->siteName;
49+
$newSiteName = self::getNewSiteName($target, $siteName);
50+
if ($newSiteName) {
51+
$project->siteName = $newSiteName;
52+
if (!$testMode) {
53+
$project->write();
54+
}
55+
if (array_key_exists($siteName, $siteNameCount)) {
56+
$siteNameCount[$siteName]++;
57+
} else {
58+
$siteNameCount[$siteName] = 1;
59+
}
60+
}
61+
}
62+
foreach(array_keys($siteNameCount) as $from) {
63+
$count = $siteNameCount[$from];
64+
print "$count $from projects changed site to " . self::getNewSiteName($target, $from) . "\n";
65+
}
66+
print "\n";
67+
68+
$siteNameCount = array();
69+
70+
// loop over every user
71+
$userList = new UserListModel();
72+
$userList->read();
73+
$userChangeCount = 0;
74+
print "Parsing " . $userList->count . " users.\n";
75+
foreach ($userList->entries as $userParams) {
76+
$siteNamesToRemove = array();
77+
$userId = $userParams['id'];
78+
$user = new UserModel($userId);
79+
foreach ($user->siteRole->getArrayCopy() as $siteName => $role) {
80+
$newSiteName = self::getNewSiteName($target, $siteName);
81+
if ($newSiteName) {
82+
$user->siteRole[$newSiteName] = $role;
83+
$siteNamesToRemove[] = $siteName;
84+
if (array_key_exists($siteName, $siteNameCount)) {
85+
$siteNameCount[$siteName]++;
86+
} else {
87+
$siteNameCount[$siteName] = 1;
88+
}
89+
$userChangeCount++;
90+
}
91+
}
92+
foreach ($siteNamesToRemove as $siteName) {
93+
unset($user->siteRole[$siteName]);
94+
}
95+
if (!$testMode) {
96+
$user->write();
97+
}
98+
}
99+
print "$userChangeCount users changed\n\n";
100+
foreach(array_keys($siteNameCount) as $from) {
101+
$count = $siteNameCount[$from];
102+
print "$count users of $from projects changed site to " . self::getNewSiteName($target, $from) . "\n";
103+
}
104+
print "\n";
105+
}
106+
}
107+
if (count($argv) != 3) {
108+
print "Usage:\n" . "php changeSiteName.php [run|test] [qa|local]\n\n" .
109+
"examples:\n\n" . "php changeSiteName.php test local\n - test changes but do not make actual changes. " .
110+
"Change site names to the localhost site available on developer machines\n\n" .
111+
"php changeSiteName.php run qa\n - change the database. change site names to the QA site\n";
112+
exit;
113+
}
114+
115+
$mode = $argv[1];
116+
if ($mode != 'test' && $mode != 'run') {
117+
print "Error: first argument must be either 'test' or 'run' which determines script run mode\n";
118+
exit;
119+
}
120+
121+
$target = $argv[2];
122+
if ($target != 'qa' && $target != 'local') {
123+
print "Error: second argument must be either 'qa' or 'local' which determines the target site\n";
124+
exit;
125+
}
126+
127+
ChangeSiteName::run($mode, $target);

scripts/tools/csvInsights.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/php -q
2+
3+
<?php
4+
5+
require_once('../scriptsConfig.php');
6+
7+
use Api\Model\Shared\Dto\ProjectInsightsDto;
8+
use Api\Library\Shared\Website;
9+
10+
(php_sapi_name() == 'cli') or die('this script must be run on the command-line');
11+
12+
ProjectInsightsDto::csvInsightsToFile(Website::get('languageforge.org'), 'languageforge.csv');
13+
ProjectInsightsDto::csvInsightsToFile(Website::get('scriptureforge.org'), 'scriptureforge.csv');

src/Api/Model/Shared/Dto/ProjectInsightsDto.php

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,17 @@ public static function singleProjectInsights($id, $website) {
3737
$projectData->url = "/app/{$project->appName}/$project->id/";
3838

3939
// owner data
40-
$owner = UserCommands::readUser($project->ownerRef->asString());
40+
try {
41+
$owner = UserCommands::readUser($project->ownerRef->asString());
42+
} catch (\Exception $e) {
43+
# there appears to be a dangling owner ref in our data
44+
$owner = [
45+
'username' => 'unknown',
46+
'email' => 'unknown',
47+
'name' => 'unknown',
48+
'role' => 'unknown',
49+
];
50+
}
4151
$projectData->ownerUserName = $owner['username'];
4252
$projectData->ownerEmail = $owner['email'];
4353
$projectData->ownerName = $owner['name'];
@@ -72,11 +82,13 @@ public static function singleProjectInsights($id, $website) {
7282
$recentUsers = [];
7383
$lastActivityDate = null;
7484
foreach ($projectActivity->entries as $event) {
75-
$userId = (string) $event['userRef'];
76-
$users[$userId] = array_key_exists($userId, $users) ? $users[$userId] + 1 : 1;
77-
if (date_create($event['date']) > date_create()->modify('-180 days')) {
78-
$recentUsers[$userId] = true;
79-
};
85+
if (array_key_exists('userRef', $event)) {
86+
$userId = (string) $event['userRef'];
87+
$users[$userId] = array_key_exists($userId, $users) ? $users[$userId] + 1 : 1;
88+
if (date_create($event['date']) > date_create()->modify('-180 days')) {
89+
$recentUsers[$userId] = true;
90+
};
91+
}
8092
$lastActivityDate = $lastActivityDate === null ? $event['date']->toDateTime() : max($event['date']->toDateTime(), $lastActivityDate);
8193
}
8294
$projectData->activeUsers = 0;
@@ -165,6 +177,22 @@ public static function allProjectInsights($website)
165177
}
166178

167179
public static function csvInsights($website) {
180+
$filePointer = fopen('php://memory', 'r+');
181+
self::writeInsightsToCsvFilePointer($website, $filePointer);
182+
rewind($filePointer);
183+
$csv = stream_get_contents($filePointer);
184+
fclose($filePointer);
185+
return $csv;
186+
}
187+
188+
public static function csvInsightsToFile($website, $filename) {
189+
$filePointer = fopen($filename, 'w');
190+
$count = self::writeInsightsToCsvFilePointer($website, $filePointer);
191+
fclose($filePointer);
192+
print "Wrote $count insights to CSV file $filename\n";
193+
}
194+
195+
private static function writeInsightsToCsvFilePointer($website, $filePointer) {
168196
$insights = ProjectInsightsDto::allProjectInsights($website);
169197

170198
// convert camelCase properties to sentence case for table headings
@@ -175,15 +203,11 @@ public static function csvInsights($website) {
175203
}
176204

177205
// in order to get automatic escaping of CSV we have to write to a "file"
178-
$filePointer = fopen('php://memory', 'r+');
179206
fputcsv($filePointer, $headings);
180207
foreach ($insights->projectList as $row) {
181208
fputcsv($filePointer, array_values((array) $row));
182209
}
183-
rewind($filePointer);
184-
$csv = stream_get_contents($filePointer);
185-
fclose($filePointer);
186-
return $csv;
210+
return count($insights->projectList);
187211
}
188212

189213
private static function appName($website) {

src/Api/Model/Shared/Mapper/MapperModel.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ public function write()
9191
{
9292
CodeGuard::checkTypeAndThrow($this->id, 'Api\Model\Shared\Mapper\Id');
9393
$now = UniversalTimestamp::now();
94-
$this->dateModified = $now;
94+
if (! defined('MAPPERMODEL_NO_TIMESTAMP_UPDATE')) {
95+
$this->dateModified = $now;
96+
}
9597
if (Id::isEmpty($this->id)) {
9698
$this->dateCreated = $now;
9799
}

src/angular-app/languageforge/lexicon/shared/share-with-others/role-dropdown.component.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,15 @@ export class RoleDropdownController implements angular.IController {
3232
if (changes.roles) this.buildRoleDetails();
3333

3434
if (changes.selectedRole) {
35-
if (!this.selectedRole) this.selectedRole = this.roles[this.roles.length - 1];
36-
this.selectedRoleDetail = this.roleDetails.find(p => p.role.key === this.selectedRole.key);
35+
const selectedRole = changes.selectedRole.currentValue || changes.selectedRole;
36+
const selectedRoleDetail = this.roleDetails.find(p => p.role.key === (selectedRole.key || selectedRole));
37+
if (selectedRoleDetail) {
38+
this.selectedRole = selectedRoleDetail.role;
39+
this.selectedRoleDetail = selectedRoleDetail;
40+
} else {
41+
this.selectedRole = this.roles[this.roles.length - 1];
42+
this.selectedRoleDetail = this.roleDetails.find(p => p.role.key === this.selectedRole.key);
43+
}
3744
}
3845
}
3946

src/angular-app/languageforge/lexicon/shared/share-with-others/user-management.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
<li class="list-group-item user-summary-item" data-ng-repeat="user in $ctrl.visibleMembers">
4141
<div>
42-
<img src="{{$ctrl.getAvatarUrl(user.avatar_ref)}}" class="rounded-circle" id="smallAvatarURL" />
42+
<img ng-src="{{$ctrl.getAvatarUrl(user.avatar_ref)}}" class="rounded-circle" id="smallAvatarURL" />
4343
</div>
4444
<div style="flex-grow: 1;" ng-class="{'text-muted': user.isInvitee}">
4545
<span ng-if="user.name">{{user.name}}<span ng-if="$ctrl.userIsCurrentUser(user)"> (you)</span><br></span>

0 commit comments

Comments
 (0)