diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 45e5fd67fe1055a03f7f5daeca663cdbf47ddf96..80e43de02e6b333441c54db6298fa4dd3888e8ed 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,8 +21,8 @@ before_script: - sed 's!<server>.*</server>!<server>postgres</server>!;s!<password>.*</password>!<password>maarch</password>!;s!<name>.*</name>!<name>MaarchParapheur</name>!;s!<user>.*</user>!<user>maarch</user>!;s!<enable>.*</enable>!<enable>true</enable>!' config/config.xml.default > config/config.xml - sed -i 's/rights="none" pattern="PDF"/rights="read | write" pattern="PDF"/' /etc/ImageMagick-6/policy.xml -job_php-7.4: - image: php:7.4-apache +job_php-8.1: + image: php:8.1-apache stage: test services: - name: postgres:10.1 @@ -30,18 +30,22 @@ job_php-7.4: script: - curl --location -s --output /usr/local/bin/phpunit https://phar.phpunit.de/phpunit-9.phar - chmod +x /usr/local/bin/phpunit - - phpunit --coverage-text --colors=never -c phpunit.xml - only: - - develop - except: - - schedules + - phpunit --coverage-text --colors=never + # only: + # - develop + # except: + # - schedules + rules: + - if: '$CI_COMMIT_BRANCH =~ /(feat|fix)\/[0-9]{4,5}\/develop/' + artifacts: paths: - test/unitTests/build/ expire_in: 2h + # coverage: '^\s*Lines:\s*\d+.\d+\%' -job_php-7.3: - image: php:7.3-apache +job_php-8.0: + image: php:8.0-apache stage: test services: - name: postgres:10.1 @@ -50,90 +54,118 @@ job_php-7.3: - curl --location -s --output /usr/local/bin/phpunit https://phar.phpunit.de/phpunit-9.phar - chmod +x /usr/local/bin/phpunit - phpunit --coverage-text --colors=never + # only: + # - develop + # except: + # - schedules + rules: + - if: '$CI_COMMIT_BRANCH =~ /(feat|fix)\/[0-9]{4,5}\/develop/' + artifacts: + paths: + - test/unitTests/build/ + expire_in: 2h + # coverage: '^\s*Lines:\s*\d+.\d+\%' + +job_php-7.4: + image: php:7.4-apache + stage: test + services: + - name: postgres:10.1 + command: [ "-c", "datestyle=iso,dmy" ] + script: + - curl --location -s --output /usr/local/bin/phpunit https://phar.phpunit.de/phpunit-9.phar + - chmod +x /usr/local/bin/phpunit + - phpunit --coverage-text --colors=never -c phpunit.xml + # only: + # - develop + # except: + # - schedules + rules: + - if: '$CI_COMMIT_BRANCH =~ /(feat|fix)\/[0-9]{4,5}\/develop/' + artifacts: + paths: + - test/unitTests/build/ + expire_in: 2h + # coverage: '^\s*Lines:\s*\d+.\d+\%' + +commits: + image: debian:10-slim + stage: synchronization only: - develop + - "21.03" except: + - tags - schedules - - -commits: - image: debian:10-slim - stage: synchronization - only: - - develop - - "21.03" - except: - - tags - - schedules - before_script: - # Skip the synchronisation if it is not enabled - - if [ $SYNC_ENABLED = "true" ]; then echo "Sync enabled"; else echo "Sync disabled, stopping the job" && exit 0; fi - # Configure ssh, with the private key to push to the private repository - - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - ssh-keyscan "$GITLAB_URL" >> ~/.ssh/known_hosts - - chmod 644 ~/.ssh/known_hosts - - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config' - # Install git command - - apt install -y git - script: - - chmod +x ./ci/commit_synchronization.sh - - ./ci/commit_synchronization.sh + before_script: + # Skip the synchronisation if it is not enabled + - if [ $SYNC_ENABLED = "true" ]; then echo "Sync enabled"; else echo "Sync disabled, stopping the job" && exit 0; fi + # Configure ssh, with the private key to push to the private repository + - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' + - eval $(ssh-agent -s) + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - ssh-keyscan "$GITLAB_URL" >> ~/.ssh/known_hosts + - chmod 644 ~/.ssh/known_hosts + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config' + # Install git command + - apt install -y git + script: + - chmod +x ./ci/commit_synchronization.sh + - ./ci/commit_synchronization.sh tags: - image: debian:10-slim - stage: synchronization - only: - - tags - except: - - schedules - before_script: - # Skip the synchronisation if it is not enabled - - if [ $SYNC_ENABLED = "true" ]; then echo "Sync enabled"; else echo "Sync disabled, stopping the job" && exit 0; fi - # Configure ssh, with the private key to push to the private repository - - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - ssh-keyscan "$GITLAB_URL" >> ~/.ssh/known_hosts - - chmod 644 ~/.ssh/known_hosts - - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config' - # Install git and curl command - - apt install -y git - - apt install -y curl - # Install npm - - curl -sL https://deb.nodesource.com/setup_14.x | bash - - - apt install -y nodejs - script: - - git config --global user.email "$CI_EMAIL" && git config --global user.name "$CI_USER" - # We will work in another directory, to avoid git conflicts - - mkdir tmp - - cd tmp - # Find the branch name from tag name - - VERSION1=$(echo $CI_COMMIT_TAG| cut -d'.' -f 1) - - VERSION2=$(echo $CI_COMMIT_TAG| cut -d'.' -f 2) - - VERSION="${VERSION1}.${VERSION2}" - # Pull the private repository - - git init && git remote add origin $PRIVATE_REPOSITORY_URL_SSH - - git pull origin $VERSION - # Update and push build prod - - npm install - - npm run build-prod - - git status - - git add -f dist/ - - git status - - git commit -m "Build prod for tag ${CI_COMMIT_TAG}" - - git show-ref - - git push origin HEAD:$VERSION - - git status - # Do the tag on the private repo - - git tag $CI_COMMIT_TAG - - git status - - git push origin --tags + image: debian:10-slim + stage: synchronization + only: + - tags + except: + - schedules + before_script: + # Skip the synchronisation if it is not enabled + - if [ $SYNC_ENABLED = "true" ]; then echo "Sync enabled"; else echo "Sync disabled, stopping the job" && exit 0; fi + # Configure ssh, with the private key to push to the private repository + - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' + - eval $(ssh-agent -s) + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - ssh-keyscan "$GITLAB_URL" >> ~/.ssh/known_hosts + - chmod 644 ~/.ssh/known_hosts + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config' + # Install git and curl command + - apt install -y git + - apt install -y curl + # Install npm + - curl -sL https://deb.nodesource.com/setup_14.x | bash - + - apt install -y nodejs + script: + - git config --global user.email "$CI_EMAIL" && git config --global user.name "$CI_USER" + # We will work in another directory, to avoid git conflicts + - mkdir tmp + - cd tmp + # Find the branch name from tag name + - VERSION1=$(echo $CI_COMMIT_TAG| cut -d'.' -f 1) + - VERSION2=$(echo $CI_COMMIT_TAG| cut -d'.' -f 2) + - VERSION="${VERSION1}.${VERSION2}" + # Pull the private repository + - git init && git remote add origin $PRIVATE_REPOSITORY_URL_SSH + - git pull origin $VERSION + # Update and push build prod + - npm install + - npm run build-prod + - git status + - git add -f dist/ + - git status + - git commit -m "Build prod for tag ${CI_COMMIT_TAG}" + - git show-ref + - git push origin HEAD:$VERSION + - git status + # Do the tag on the private repo + - git tag $CI_COMMIT_TAG + - git status + - git push origin --tags logs: @@ -177,39 +209,39 @@ logs: - curl -v -H 'Content-Type:application/json' -H "X-Redmine-API-Key:$REDMINE_API_KEY" -d "$BODY" -X PUT https://forge.maarch.org/issues/$ISSUE_ID.json new_branch: - image: debian:10-slim - stage: new_branch - only: - - branches - before_script: - # Install git and curl command - - apt-get update -yqq > /dev/null - - apt install -y curl - - apt install -y jq - script: - - chmod +x ./ci/create_mr.sh - - ./ci/create_mr.sh + image: debian:10-slim + stage: new_branch + only: + - branches + before_script: + # Install git and curl command + - apt-get update -yqq > /dev/null + - apt install -y curl + - apt install -y jq + script: + - chmod +x ./ci/create_mr.sh + - ./ci/create_mr.sh new_tag: - image: debian:10-slim - stage: new_tag - only: - - tags - before_script: - # Install git and curl command - - apt-get update -yqq > /dev/null - - 'which ssh-agent || ( apt-get install openssh-client -y )' - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY_2" | tr -d '\r' | ssh-add - - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - ssh-keyscan "$GITLAB_URL" >> ~/.ssh/known_hosts - - chmod 644 ~/.ssh/known_hosts - - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config' - - apt install -y git - - apt install -y curl - - apt install -y jq - script: - - chmod +x ./ci/new_tag.sh - - ./ci/new_tag.sh + image: debian:10-slim + stage: new_tag + only: + - tags + before_script: + # Install git and curl command + - apt-get update -yqq > /dev/null + - 'which ssh-agent || ( apt-get install openssh-client -y )' + - eval $(ssh-agent -s) + - echo "$SSH_PRIVATE_KEY_2" | tr -d '\r' | ssh-add - + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - ssh-keyscan "$GITLAB_URL" >> ~/.ssh/known_hosts + - chmod 644 ~/.ssh/known_hosts + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config' + - apt install -y git + - apt install -y curl + - apt install -y jq + script: + - chmod +x ./ci/new_tag.sh + - ./ci/new_tag.sh diff --git a/lang/en.json b/lang/en.json index 9d210c5bedf32b4c874c19d207e97898c06b0aee..194886f70f7c4b212e3a8926ff6e5f9eedaf8111 100755 --- a/lang/en.json +++ b/lang/en.json @@ -650,6 +650,8 @@ "groupsToManage": "Choose the authorized assignment groups", "unlinkGroup": "Unlink group", "emptyGroups": "No groups available to associate", - "errorConvertingDocument": "Error converting document" + "errorConvertingDocument": "Error converting document", + "emptyGroupUsers": "No users associated with this group", + "emptyUsers": "No users available to associate" } } \ No newline at end of file diff --git a/lang/fr.json b/lang/fr.json index ec399440da4daac570badc2325e790235d096a31..c645ffa04533f504883585f3ec56ba737846946c 100755 --- a/lang/fr.json +++ b/lang/fr.json @@ -649,6 +649,8 @@ "groupsToManage": "Choisir les groupes d'affectations autorisés", "unlinkGroup": "Dissocier le groupe", "emptyGroups": "Aucun groupe disponible à associer", - "errorConvertingDocument": "Erreur lors de la conversion du document" + "errorConvertingDocument": "Erreur lors de la conversion du document", + "emptyGroupUsers": "Aucun utilisateur associé à ce groupe", + "emptyUsers": "Aucun utilisateur disponible à associer" } } diff --git a/phpunit.xml b/phpunit.xml index f062ec810c67a21709f308afaeb05b6273df07de..8648b358c763e5e56ae2432487ee1c87ec7cd8c4 100755 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" bootstrap="test/unitTests/define.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"> + <php> + <server name='HTTP_HOST' value='http://localhost/MaarchParapheur' /> + <server name='SERVER_PORT' value='80' /> + </php> <coverage> <include> <directory suffix="Test.php">test</directory> diff --git a/src/app/email/controllers/EmailController.php b/src/app/email/controllers/EmailController.php index 8601bbad15c93bf1ec57b8472437354d4dcca8dc..b4cc19f7e9b6cac8f25bc82c286efd26fa290a7d 100644 --- a/src/app/email/controllers/EmailController.php +++ b/src/app/email/controllers/EmailController.php @@ -132,10 +132,10 @@ class EmailController $email['cci'] = json_decode($email['cci']); $configuration = ConfigurationModel::getByIdentifier(['identifier' => 'emailServer', 'select' => ['value']]); - $configuration = json_decode($configuration[0]['value'], true); if (empty($configuration)) { return ['errors' => 'Configuration is missing']; } + $configuration = json_decode($configuration[0]['value'], true); $phpmailer = new PHPMailer(); $phpmailer->setFrom($configuration['from']); diff --git a/src/app/user/controllers/UserController.php b/src/app/user/controllers/UserController.php index 3cae1c2259c90d7f90d9a0711ab19bd98b226956..ed9398ada46fd0c28a6943bd3b2d84a1aa0aa170 100755 --- a/src/app/user/controllers/UserController.php +++ b/src/app/user/controllers/UserController.php @@ -179,7 +179,11 @@ class UserController return $response->withStatus(400)->withJson(['errors' => 'Login already exists', 'lang' => 'userLoginAlreadyExists']); } - $body['x509_fingerprint'] = $body['x509Fingerprint']; + $body['x509_fingerprint'] = !empty($body['x509Fingerprint']) ? $body['x509Fingerprint'] : null; + + if (empty($body['phone'])) { + $body['phone'] = null; + } if (!empty($body['isRest'])) { $body['"isRest"'] = true; @@ -254,7 +258,6 @@ class UserController 'firstname' => $body['firstname'], 'lastname' => $body['lastname'], 'email' => $body['email'], - 'phone' => $body['phone'], 'signature_modes' => [] ]; diff --git a/src/app/user/models/UserModel.php b/src/app/user/models/UserModel.php index cf400b123e8cc27ea472e0b568ce2f1d7b817481..8cef89e10253b8a781bf7a5f12f832544eb70b92 100755 --- a/src/app/user/models/UserModel.php +++ b/src/app/user/models/UserModel.php @@ -103,7 +103,7 @@ class UserModel 'picture' => $args['picture'], 'password_modification_date' => 'CURRENT_TIMESTAMP', 'signature_modes' => $args['signatureModes'], - 'x509_fingerprint' => $args['x509_fingerprint'], + 'x509_fingerprint' => $args['x509_fingerprint'] ] ]); diff --git a/src/core/controllers/AuthenticationController.php b/src/core/controllers/AuthenticationController.php index 32dde88a04da6ff6514252c465a40d18c0c5adbe..fed906f671102396ab98c4c002c01778e69e7980 100755 --- a/src/core/controllers/AuthenticationController.php +++ b/src/core/controllers/AuthenticationController.php @@ -105,7 +105,7 @@ class AuthenticationController $connection = ConfigurationModel::getConnection(); if (in_array($connection, ['default', 'ldap'])) { - if (!Validator::stringType()->notEmpty()->validate($body['login']) || !Validator::stringType()->notEmpty()->validate($body['password'])) { + if (!array_key_exists('login', $body) || !array_key_exists('password', $body) || !Validator::stringType()->notEmpty()->validate($body['login']) || !Validator::stringType()->notEmpty()->validate($body['password'])) { return $response->withStatus(400)->withJson(['errors' => 'Bad Request']); } } diff --git a/src/core/models/DatabasePDO.php b/src/core/models/DatabasePDO.php index ba426ebf7c06933a36d764b6ca5872e84a616bd4..e47f6c31a80b3ac35ea81f79bf5eeff31f055ebe 100755 --- a/src/core/models/DatabasePDO.php +++ b/src/core/models/DatabasePDO.php @@ -69,7 +69,7 @@ class DatabasePDO \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_CASE => \PDO::CASE_LOWER ]; - + try { self::$pdo = new \PDO($dsn, $user, $password, $options); break; @@ -79,7 +79,7 @@ class DatabasePDO self::$pdo = new \PDO($dsn, $user, $password, $options); break; } catch (\PDOException $PDOException) { - if (!empty($loadedXml->database[$key + 1])) { + if (!empty($loadedXml->{$key.'1'})) { continue; } else { throw new \Exception($PDOException->getMessage()); diff --git a/src/core/models/PasswordModel.php b/src/core/models/PasswordModel.php index 2ddb2fae0a3e11f0a603c5555daccf3515514158..c2e2ee351e48d5d24c250afba3b5f97385256557 100755 --- a/src/core/models/PasswordModel.php +++ b/src/core/models/PasswordModel.php @@ -23,8 +23,8 @@ class PasswordModel $aRules = DatabaseModel::select([ 'select' => empty($aArgs['select']) ? ['*'] : $aArgs['select'], 'table' => ['password_rules'], - 'where' => $aArgs['where'], - 'data' => $aArgs['data'], + 'where' => $aArgs['where'] ?? [], + 'data' => $aArgs['data'] ?? [], ]); return $aRules; diff --git a/src/frontend/app/administration/group/group.component.html b/src/frontend/app/administration/group/group.component.html index 4643365fa63bd6b55163dd8d7d3bc9abb3b39f23..2d2fd6526dd72e574b4a8e27bc1ff80d2aa3e024 100644 --- a/src/frontend/app/administration/group/group.component.html +++ b/src/frontend/app/administration/group/group.component.html @@ -29,52 +29,61 @@ </ion-button> </ion-item> </div> - <ion-item lines="none" *ngIf="!creationMode"> - <ion-label color="secondary">{{'lang.linkedUsers' | translate}} :</ion-label> - </ion-item> - <ion-searchbar [placeholder]="'lang.filter' | translate" style="margin-left: 4x; display: flex; width: 50%;" - (ionChange)="applyFilter($event.detail.value)"> - </ion-searchbar> - <ion-card *ngIf="!creationMode" style="height: 400px; overflow-y: auto;"> - <ion-list> - <ion-item style="position: sticky;top:0px;z-index:1;"> - <ng-container style="display: flex;align-items: center;justify-content: center;width: 100%;background: white;"> - <ion-label color="primary" matSort [matSortActive]="displayedColumns[1]" matSortDirection='asc' - style="display: flex;font-size: 12px;align-items: center;" (matSortChange)="sortData($event)"> - <ng-container *ngFor="let col of displayedColumns"> - <div [mat-sort-header]="col" disableClear style="flex: 1" *ngIf="col!=='actions'"> - {{'lang.' + col | translate}} - </div> - </ng-container> - <div style="flex: 1;text-align: right;" *ngIf="displayedColumns.indexOf('actions') > -1"> - <ion-button slot="end" color="primary" fille="outline" shape="round" - (click)="openUserList()"> - {{'lang.add' | translate}} - </ion-button> - </div> - </ion-label> - </ng-container> - <ion-button slot="end" fill="clear" shape="round" disabled> - <ion-icon></ion-icon> - </ion-button> - </ion-item> - <ion-virtual-scroll [items]="sortedData" approxItemHeight="50px"> - <ion-item *virtualItem="let element" style="display: flex;"> - <ion-label style="display: flex;cursor: pointer;" - routerLink="/administration/users/{{element.id}}"> - <div style="flex: 1" *ngFor="let col of displayedColumns"> - {{element[col]}} + <ng-container *ngIf="!creationMode"> + <ion-item lines="none"> + <ion-label color="secondary">{{'lang.linkedUsers' | translate}} :</ion-label> + </ion-item> + <ion-searchbar [placeholder]="'lang.filter' | translate" style="margin-left: 4x; display: flex; width: 50%;" + (ionChange)="applyFilter($event.detail.value)"> + </ion-searchbar> + <ion-content style="height: 400px; overflow-y: auto;"> + <ion-list> + <ion-item style="position: sticky;top:0px;z-index:1;"> + <ng-container style="display: flex;align-items: center;justify-content: center;width: 100%;background: white;"> + <ion-label color="primary" matSort [matSortActive]="displayedColumns[1]" matSortDirection='asc' + style="display: flex;font-size: 12px;align-items: center;" (matSortChange)="sortData($event)"> + <ng-container *ngFor="let col of displayedColumns"> + <div [mat-sort-header]="col" disableClear style="flex: 1" *ngIf="col!=='actions'"> + {{'lang.' + col | translate}} + </div> + </ng-container> + <div style="flex: 1;text-align: right;" *ngIf="displayedColumns.indexOf('actions') > -1"> + <ion-button slot="end" color="primary" fille="outline" shape="round" + (click)="openUserList()"> + {{'lang.add' | translate}} + </ion-button> </div> </ion-label> - <ion-button slot="end" fill="clear" shape="round" - (click)="$event.stopPropagation();unlinkUser(element)" - title="{{'lang.unlinkUser' | translate}}"> - <ion-icon color="danger" slot="icon-only" name="close-outline"></ion-icon> + </ng-container> + <ion-button slot="end" fill="clear" shape="round" disabled> + <ion-icon></ion-icon> </ion-button> </ion-item> - </ion-virtual-scroll> - </ion-list> - </ion-card> + <ion-virtual-scroll [items]="sortedData" approxItemHeight="50px"> + <ion-item *virtualItem="let element" style="display: flex;"> + <ion-label style="display: flex;cursor: pointer;" + routerLink="/administration/users/{{element.id}}"> + <div style="flex: 1" *ngFor="let col of displayedColumns"> + {{element[col]}} + </div> + </ion-label> + <ion-button slot="end" fill="clear" shape="round" + (click)="$event.stopPropagation();unlinkUser(element)" + title="{{'lang.unlinkUser' | translate}}"> + <ion-icon color="danger" slot="icon-only" name="close-outline"></ion-icon> + </ion-button> + </ion-item> + </ion-virtual-scroll> + <ion-infinite-scroll threshold="100px" (ionInfinite)="loadData($event)" *ngIf="group.users.length > 7"> + <ion-infinite-scroll-content loadingSpinner="bubbles" [loadingText]="'lang.loadingMoreData' | translate"> + </ion-infinite-scroll-content> + </ion-infinite-scroll> + </ion-list> + <ion-item lines="none" *ngIf="group.users.length === 0" style="text-align: center; font-size: 20px; color: gray; margin-top: 5px;"> + <ion-label>{{ 'lang.emptyGroupUsers' | translate }}</ion-label> + </ion-item> + </ion-content> + </ng-container> <ion-item text-center lines="none" style="position: sticky;bottom:0px;z-index:1;"> <div style="display: flex;align-items: center;justify-content: center;width: 100%;background: white;"> <ion-button type="submit" shape="round" size="large" fill="outline" color="primary" diff --git a/src/frontend/app/administration/group/group.component.ts b/src/frontend/app/administration/group/group.component.ts index d17dee44095f02f094368a2768cf93b649fd7ea6..4f7916496dfd136f71a46c28a9f61d1ab93850de 100644 --- a/src/frontend/app/administration/group/group.component.ts +++ b/src/frontend/app/administration/group/group.component.ts @@ -84,7 +84,7 @@ export class GroupComponent implements OnInit { this.creationMode = false; this.usersList = []; - this.http.get('../rest/groups/' + params['id']) + this.http.get(`../rest/groups/${params['id']}`) .pipe( map((data: any) => data.group), finalize(() => { @@ -462,6 +462,11 @@ export class GroupComponent implements OnInit { canManage(privilege: any) { return privilege.id === 'manage_users' && privilege.checked; } + + loadData(event: any) { + event.target.complete(); + event.target.disabled = true; + } } diff --git a/src/frontend/app/administration/group/list/users.component.html b/src/frontend/app/administration/group/list/users.component.html index 2af53a9763a8c074cdb47950f5e74a4dbad21a1d..7d5ba32e6c5388a536e983d87cc83ac976aaf380 100644 --- a/src/frontend/app/administration/group/list/users.component.html +++ b/src/frontend/app/administration/group/list/users.component.html @@ -4,7 +4,7 @@ </ion-toolbar> </ion-header> <ion-content> - <ion-list> + <ion-list *ngIf="usersList.length > 0"> <ion-virtual-scroll [items]="usersList" approxItemHeight="50px" style="height: 450px;"> <ion-item button *virtualItem="let element" (click)="selectUser(element)"> <ion-label> @@ -13,4 +13,7 @@ </ion-item> </ion-virtual-scroll> </ion-list> + <ion-item lines="none" *ngIf="usersList.length === 0" style="text-align: center; font-size: 20px; color: gray; margin-top: 35%;"> + <ion-label>{{'lang.emptyUsers' | translate}}</ion-label> + </ion-item> </ion-content> \ No newline at end of file diff --git a/test/unitTests/app/user/UserControllerTest.php b/test/unitTests/app/user/UserControllerTest.php index 1d573d5b63e680f81feace4edfd08aab1600e66d..6bd12b4a1bc05f96d3f7cab7e3df7a7f7ed8dde3 100755 --- a/test/unitTests/app/user/UserControllerTest.php +++ b/test/unitTests/app/user/UserControllerTest.php @@ -13,6 +13,7 @@ class UserControllerTest extends TestCase { private static $signatureId = null; private static $userId = null; + private static $userIdToDelete = null; public function testCreateUser() { @@ -22,10 +23,11 @@ class UserControllerTest extends TestCase $request = \Slim\Http\Request::createFromEnvironment($environment); $aArgs = [ - 'login' => 'emailLogin', - 'firstname' => 'Prénom', - 'lastname' => 'Nom', - 'email' => 'email@test.fr' + 'login' => 'emailLoginFingerprint', + 'firstname' => 'Prénom', + 'lastname' => 'Nom', + 'email' => 'email@test.fr', + 'phone' => '0701020304' ]; $fullRequest = \httpRequestCustom::addContentInBody($aArgs, $request); @@ -35,6 +37,23 @@ class UserControllerTest extends TestCase $this->assertIsInt($responseBody->id); self::$userId = $responseBody->id; + //with x509Fingerprint + $aArgs = [ + 'login' => 'emailLogin', + 'firstname' => 'Prénom', + 'lastname' => 'Nom', + 'email' => 'email@test.fr', + 'x509Fingerprint' => 'fingerprint', + 'isRest' => true + ]; + + $fullRequest = \httpRequestCustom::addContentInBody($aArgs, $request); + $response = $userController->create($fullRequest, new \Slim\Http\Response()); + $responseBody = json_decode((string)$response->getBody()); + + $this->assertIsInt($responseBody->id); + self::$userIdToDelete = $responseBody->id; + //Mail missing $aArgs = [ 'login' => 'failLogin', @@ -162,11 +181,27 @@ class UserControllerTest extends TestCase $this->assertSame('email@test.fr', $responseBody->user->email); $this->assertSame('Prénom', $responseBody->user->firstname); $this->assertSame('Nom', $responseBody->user->lastname); + $this->assertSame('0701020304', $responseBody->user->phone); $response = $userController->getById($request, new \Slim\Http\Response(), ['id' => -1]); + $this->assertSame(400, $response->getStatusCode()); $responseBody = json_decode((string)$response->getBody()); + $this->assertSame('User does not exist', $responseBody->errors); + } - $this->assertEmpty($responseBody->users); + public function testGetFingerprintById() + { + $previousUserId = $GLOBALS['id']; + $GLOBALS['id'] = self::$userIdToDelete; + $userController = new \User\controllers\UserController(); + + //find "userIdToDelete" fingerprint before user gets deleted + $response = $userController->getUserInformationsById(['id' => self::$userIdToDelete]); + + $this->assertNotEmpty($response); + $this->assertNotEmpty($response['x509Fingerprint']); + $this->assertSame('fingerprint', $response['x509Fingerprint']); + $GLOBALS['id'] = $previousUserId; } public function testUpdate() @@ -181,13 +216,14 @@ class UserControllerTest extends TestCase $request = \Slim\Http\Request::createFromEnvironment($environment); $aArgs = [ - 'writingMode' => 'stylus', - 'writingSize' => 2, - 'writingColor' => '#F1F1F1', - 'lang' => 'fr', - 'notifications' => [ - 'instant' => true, - 'summaries' => [], + 'writingMode' => 'stylus', + 'writingSize' => 2, + 'writingColor' => '#F1F1F1', + 'lang' => 'fr', + 'signatureScaling' => false, + 'notifications' => [ + 'instant' => true, + 'summaries' => [], ], ]; @@ -203,7 +239,8 @@ class UserControllerTest extends TestCase $aArgs = [ 'firstname' => 'Jolly', 'lastname' => 'Jumper', - 'email' => 'email@test.fr' + 'email' => 'email@test.fr', + 'phone' => '0701020304' ]; $fullRequest = \httpRequestCustom::addContentInBody($aArgs, $request); @@ -241,7 +278,7 @@ class UserControllerTest extends TestCase $aArgs = [ 'encodedSignature' => base64_encode(file_get_contents('test/unitTests/samples/signature.jpg')), 'format' => 'jpg' - ]; + ]; $fullRequest = \httpRequestCustom::addContentInBody($aArgs, $request); $response = $signatureController->create($fullRequest, new \Slim\Http\Response(), ['id' => self::$userId]); @@ -290,4 +327,30 @@ class UserControllerTest extends TestCase ]); $GLOBALS['id'] = $previousUserId; } + + public function testDelete() + { + $userController = new \User\controllers\UserController(); + + $environment = \Slim\Http\Environment::mock(['REQUEST_METHOD' => 'DELETE']); + $request = \Slim\Http\Request::createFromEnvironment($environment); + + $response = $userController->delete($request, new \Slim\Http\Response(), ['id' => self::$userIdToDelete]); + $this->assertSame(204, $response->getStatusCode()); + + $response = $userController->delete($request, new \Slim\Http\Response(), ['id' => self::$userIdToDelete]); + $responseBody = json_decode((string)$response->getBody()); + $this->assertSame(400, $response->getStatusCode()); + $this->assertSame('User does not exist', $responseBody->errors); + + $response = $userController->delete($request, new \Slim\Http\Response(), ['id' => '1']); + $responseBody = json_decode((string)$response->getBody()); + $this->assertSame(403, $response->getStatusCode()); + $this->assertSame('Privilege forbidden', $responseBody->errors); + + $response = $userController->delete($request, new \Slim\Http\Response(), ['id' => 1.1]); + $responseBody = json_decode((string)$response->getBody()); + $this->assertSame(400, $response->getStatusCode()); + $this->assertSame('Route id is not an integer', $responseBody->errors); + } }