Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.83% covered (success)
95.83%
184 / 192
77.78% covered (warning)
77.78%
14 / 18
CRAP
0.00% covered (danger)
0.00%
0 / 1
SuperAdminDAO
95.83% covered (success)
95.83%
184 / 192
77.78% covered (warning)
77.78%
14 / 18
43
0.00% covered (danger)
0.00%
0 / 1
 getWorkspaces
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getUsers
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 getUserByName
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
2.01
 getWorkspacesByUser
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
2
 getMapWorkspaceToRoleByUser
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 setWorkspaceRightsByUser
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 setPassword
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
 checkPassword
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 createUser
95.45% covered (success)
95.45%
21 / 22
0.00% covered (danger)
0.00%
0 / 1
5
 deleteUsers
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 getOrCreateWorkspace
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 createWorkspace
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
2
 setWorkspaceName
94.74% covered (success)
94.74%
18 / 19
0.00% covered (danger)
0.00%
0 / 1
3.00
 deleteWorkspaces
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 getUsersByWorkspace
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 getMapUserToRoleByWorkspace
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 setUserRightsForWorkspace
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
 setSuperAdminStatus
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/** @noinspection PhpUnhandledExceptionInspection */
3declare(strict_types=1);
4
5class SuperAdminDAO extends DAO {
6  public function getWorkspaces(): array {
7    return $this->_(
8      'select workspaces.id, workspaces.name, MAX(files.modification_ts) AS latest_modification_ts
9      FROM workspaces
10      LEFT JOIN files ON workspaces.id = files.workspace_id
11      GROUP BY workspaces.id, workspaces.name
12      ORDER BY workspaces.name',
13      [],
14      true
15    );
16  }
17
18  public function getUsers(): array {
19    return array_map(
20      function($user) {
21        $user['isSuperadmin'] = (bool) $user['isSuperadmin'];
22        return $user;
23      },
24      $this->_(
25        'select users.name, users.id, users.email, users.is_superadmin as "isSuperadmin" from users order by users.name',
26        [],
27        true
28      ));
29  }
30
31  public function getUserByName(string $userName): array { // TODO isSuperadmin should be boolean
32    $user = $this->_(
33      'select 
34                    users.name, 
35                    users.id, 
36                    users.email, 
37                    users.is_superadmin as "isSuperadmin" 
38                from users 
39                where users.name=:user_name',
40      [':user_name' => $userName]
41    );
42    if ($user == null) {
43      throw new Exception("User `$userName` does not exist");
44    }
45    return $user;
46  }
47
48  // id, name, selected, role
49  public function getWorkspacesByUser(int $userId): array {
50    $userRolesByWorkspace = $this->getMapWorkspaceToRoleByUser($userId);
51
52    $allWorkspaces = $this->_(
53      'select workspaces.id, workspaces.name from workspaces order by workspaces.name',
54      [],
55      true
56    );
57
58    $allWorkspacesWithUsersRole = [];
59    foreach ($allWorkspaces as $workspace) {
60      $allWorkspacesWithUsersRole[] = [
61        'id' => $workspace['id'],
62        'name' => $workspace['name'],
63        'selected' => isset($userRolesByWorkspace[$workspace['id']]),
64        'role' => $userRolesByWorkspace[$workspace['id']] ?? ''
65      ];
66    }
67
68    return $allWorkspacesWithUsersRole;
69  }
70
71  public function getMapWorkspaceToRoleByUser(int $userId): array {
72    $userWorkspaces = $this->_(
73      'select 
74                workspace_users.workspace_id as id, 
75                workspace_users.role as role  
76            from workspace_users
77                inner join users on users.id = workspace_users.user_id
78            where 
79                users.id = :user_id',
80      [':user_id' => $userId],
81      true
82    );
83
84    $mapWorkspaceToRole = [];
85    foreach ($userWorkspaces as $userWorkspace) {
86      $mapWorkspaceToRole[$userWorkspace['id']] = $userWorkspace['role'];
87    }
88    return $mapWorkspaceToRole;
89  }
90
91  public function setWorkspaceRightsByUser(int $userId, array $listOfWorkspaceIdsAndRoles) {
92    $this->_('delete from workspace_users where workspace_users.user_id=:user_id', [':user_id' => $userId]);
93
94    foreach ($listOfWorkspaceIdsAndRoles as $workspaceIdAndRole) {
95      if (strlen($workspaceIdAndRole->role) > 0) {
96        $this->_(
97          'insert into workspace_users (workspace_id, user_id, role) values (:workspaceId, :userId, :role)',
98          [
99            ':workspaceId' => $workspaceIdAndRole->id,
100            ':role' => $workspaceIdAndRole->role,
101            ':userId' => $userId
102          ]
103        );
104      }
105    }
106  }
107
108  public function setPassword(int $userId, string $password, ?AuthToken $authToken = null): void {
109    Password::validate($password);
110
111    $this->_(
112      'update users set password = :password, pw_set_by_admin = :pw_set_by_admin where id = :user_id',
113      [
114        ':user_id' => $userId,
115        ':pw_set_by_admin' => (!is_null($authToken) && $authToken->getmode() === 'super-admin') ? 1 : 0,
116        ':password' => Password::encrypt($password, $this->passwordSalt, $this->insecurePasswords)
117      ]
118    );
119  }
120
121  public function checkPassword(int $userId, string $password): bool {
122    $usersOfThisName = $this->_(
123      'select * from users where users.id = :id',
124      [':id' => $userId],
125      true
126    );
127
128    // we always check at least one user to not leak the existence of username to time-attacks
129    $usersOfThisName = (!count($usersOfThisName)) ? ['password' => 'dummy'] : $usersOfThisName;
130
131    foreach ($usersOfThisName as $user) {
132      if (Password::verify($password, $user['password'], $this->passwordSalt)) {
133        return true;
134      }
135    }
136
137    return false;
138  }
139
140  public function createUser(string $userName, string $password, bool $isSuperadmin = false, bool $pwSetByAdmin = false): array {
141    Password::validate($password);
142
143    $user = $this->_(
144      'select users.name from users where users.name=:user_name',
145      [':user_name' => $userName]
146    );
147
148    if ($user) {
149      throw new HttpError("User with name `$userName` already exists!", 400);
150    }
151
152    $this->_(
153      'insert into users (name, password, is_superadmin, pw_set_by_admin) values (:user_name, :user_password, :is_superadmin, :pw_set_by_admin)',
154      [
155        ':user_name' => $userName,
156        ':user_password' => Password::encrypt($password, $this->passwordSalt, $this->insecurePasswords),
157        ':is_superadmin' => $isSuperadmin ? 1 : 0,
158        ':pw_set_by_admin' => $pwSetByAdmin ? 1 : 0
159      ]
160    );
161
162    return [
163      'id' => $this->pdoDBhandle->lastInsertId(),
164      'name' => $userName,
165      'email' => null,
166      'isSuperadmin' => $isSuperadmin ? 1 : 0
167    ];
168  }
169
170  public function deleteUsers(array $userIds): void { // TODO add unit test
171
172    foreach ($userIds as $userId) {
173      $this->_(
174        'delete from users where users.id = :user_id',
175        [':user_id' => $userId]
176      );
177    }
178  }
179
180  public function getOrCreateWorkspace(string $name): array {
181    $workspace = $this->_(
182      "select workspaces.id, workspaces.name from workspaces where `name` = :ws_name",
183      [':ws_name' => $name]
184    );
185
186    if ($workspace != null) {
187      return $workspace;
188    }
189
190    return $this->createWorkspace($name);
191  }
192
193  public function createWorkspace($name): array {
194    $workspace = $this->_(
195      'select workspaces.id from workspaces where workspaces.name=:ws_name',
196      [':ws_name' => $name]
197    );
198
199    if ($workspace) {
200      throw new HttpError("Workspace with name `$name` already exists!", 400);
201    }
202
203    $this->_(
204      'insert into workspaces (name) values (:ws_name)',
205      [':ws_name' => $name]
206    );
207
208    return [
209      'id' => $this->pdoDBhandle->lastInsertId(),
210      'name' => $name
211    ];
212  }
213
214  public function setWorkspaceName($wsId, $newName) {
215    $workspace = $this->_(
216      'select workspaces.id from workspaces where workspaces.id=:ws_id',
217      [':ws_id' => $wsId]
218    );
219
220    if (!$workspace) {
221      throw new HttpError("Workspace with id `$wsId` does not exist!", 400);
222    }
223
224    $workspace = $this->_(
225      "select workspaces.id, workspaces.name from workspaces where `name` = :ws_name",
226      [':ws_name' => $newName]
227    );
228
229    if ($workspace) {
230      throw new HttpError("Workspace with name `$newName` already exists!", 400);
231    }
232
233    $this->_(
234      'update workspaces set name = :name where id = :id',
235      [
236        ':name' => $newName,
237        ':id' => $wsId
238      ]
239    );
240  }
241
242  public function deleteWorkspaces(array $wsIds): void {
243    foreach ($wsIds as $wsId) {
244      $this->_(
245        'delete from workspaces
246                where workspaces.id = :ws_id',
247        [':ws_id' => $wsId]
248      );
249    }
250    // TODO ROLLBACK if one fails!
251  }
252
253  public function getUsersByWorkspace(int $workspaceId): array {
254    $workspaceRolesPerUser = $this->getMapUserToRoleByWorkspace($workspaceId);
255
256    $allUsers = $this->_('select users.id, users.name from users order by users.name', [], true);
257
258    $allUsersWithTheirRolesOnWorkspace = [];
259    foreach ($allUsers as $user) {
260      $allUsersWithTheirRolesOnWorkspace[] = [
261        'id' => $user['id'],
262        'name' => $user['name'],
263        'selected' => isset($workspaceRolesPerUser[$user['id']]),
264        'role' => $workspaceRolesPerUser[$user['id']] ?? '',
265      ];
266    }
267    return $allUsersWithTheirRolesOnWorkspace;
268  }
269
270  public function getMapUserToRoleByWorkspace(int $workspaceId): array {
271    $workspaceUsers = $this->_(
272      'select 
273                workspace_users.user_id as id, 
274                workspace_users.role as role 
275            from workspace_users
276            where workspace_users.workspace_id=:ws_id',
277      [':ws_id' => $workspaceId],
278      true
279    );
280    $workspaceRolesPerUser = [];
281    foreach ($workspaceUsers as $workspaceUser) {
282      $workspaceRolesPerUser[$workspaceUser['id']] = $workspaceUser['role'];
283    }
284    return $workspaceRolesPerUser;
285  }
286
287  public function setUserRightsForWorkspace(int $wsId, array $listOfUserIdsAndRoles): void {
288    $this->_('delete from workspace_users where workspace_users.workspace_id=:ws_id', [':ws_id' => $wsId]);
289
290    foreach ($listOfUserIdsAndRoles as $userIdAndRole) {
291      if (strlen($userIdAndRole->role) > 0) {
292        $this->_(
293          'insert into workspace_users (workspace_id, user_id, role) 
294                    values(:workspaceId, :userId, :role)',
295          [
296            ':workspaceId' => $wsId,
297            ':role' => $userIdAndRole->role,
298            ':userId' => $userIdAndRole->id
299          ]
300        );
301      }
302    }
303  }
304
305  public function setSuperAdminStatus(int $userId, bool $isSuperAdmin): void {
306    $this->_(
307      'update users set is_superadmin = :is_superadmin where id = :user_id',
308      [
309        ':user_id' => $userId,
310        ':is_superadmin' => $isSuperAdmin ? 1 : 0
311      ]
312    );
313  }
314}