From 9c010ab29646bcf9140032464aa54e582e2f2e71 Mon Sep 17 00:00:00 2001
From: Damien <damien.burel@maarch.org>
Date: Tue, 26 Jun 2018 12:33:13 +0200
Subject: [PATCH] FEAT #7990 Display baskets in group administration

---
 .../Views/group-administration.component.html | 119 ++++++++++--------
 .../group-administration.component.ts         |  39 +++---
 .../js/angular/lang/lang-en.ts                |   1 +
 .../js/angular/lang/lang-fr.ts                |   1 +
 .../models/GroupBasketModelAbstract.php       |  24 +++-
 src/app/group/controllers/GroupController.php |  11 +-
 test/GroupControllerTest.php                  |  12 ++
 test/ResControllerTest.php                    |   3 +-
 8 files changed, 139 insertions(+), 71 deletions(-)

diff --git a/apps/maarch_entreprise/Views/group-administration.component.html b/apps/maarch_entreprise/Views/group-administration.component.html
index a8db256420f..62846508f41 100644
--- a/apps/maarch_entreprise/Views/group-administration.component.html
+++ b/apps/maarch_entreprise/Views/group-administration.component.html
@@ -91,56 +91,77 @@
                         </mat-tab-group>
                     </mat-tab>
                     <mat-tab label="{{lang.relatedUsers}}" *ngIf="!creationMode">
-                            <div class="row" style="margin:0px;">
-                                <div class="col-md-12" *ngIf="group.canAdminUsers" style="padding:5px;">
-                                    <mat-form-field>
-                                        <span matPrefix><mat-icon class="fa fa-user-plus" color="primary"></mat-icon>&nbsp;&nbsp;</span>
-                                        <input class="autocompleteSearch" #autocompleteFilter placeholder="{{lang.linkUser}}" type="text" matInput [matAutocomplete]="auto"
-                                            [formControl]="userCtrl">
-                                        <mat-autocomplete #auto="matAutocomplete">
-                                            <mat-option *ngFor="let user of filteredUsers | async" [value]="user.idToDisplay" (click)="linkUser(user)">
-                                                <p mat-line style="margin:0;">
-                                                    <span class="col-xm-1" style="padding-right:5px;">
-                                                        <mat-icon color="primary" [class]="user.type == 'entity' ? 'fa fa-sitemap fa-2x' : 'fa fa-user fa-2x'" style="margin-right:0px;"></mat-icon>
-                                                    </span>
-                                                    <span class="col-xm-11">
-                                                        {{ user.idToDisplay }}
-                                                        <small>{{ user.otherInfo }}</small>
-                                                    </span>
-                                                </p>
-                                            </mat-option>
-                                        </mat-autocomplete>
-                                    </mat-form-field>
-                                    <hr/>
-                                </div>
-                                <div class="col-md-6 col-xs-6">
-                                    <mat-form-field>
-                                        <input matInput (keyup)="applyFilter($event.target.value)" placeholder="{{lang.filterBy}}">
-                                    </mat-form-field>
-                                </div>
-                                <div class="col-md-6 col-xs-6">
-                                    <mat-paginator #paginator [length]="100" [pageSize]="10">
-                                    </mat-paginator>
-                                </div>
+                        <div class="row" style="margin:0px;">
+                            <div class="col-md-12" *ngIf="group.canAdminUsers" style="padding:5px;">
+                                <mat-form-field>
+                                    <span matPrefix><mat-icon class="fa fa-user-plus" color="primary"></mat-icon>&nbsp;&nbsp;</span>
+                                    <input class="autocompleteSearch" #autocompleteFilter placeholder="{{lang.linkUser}}" type="text" matInput [matAutocomplete]="auto"
+                                        [formControl]="userCtrl">
+                                    <mat-autocomplete #auto="matAutocomplete">
+                                        <mat-option *ngFor="let user of filteredUsers | async" [value]="user.idToDisplay" (click)="linkUser(user)">
+                                            <p mat-line style="margin:0;">
+                                                <span class="col-xm-1" style="padding-right:5px;">
+                                                    <mat-icon color="primary" [class]="user.type == 'entity' ? 'fa fa-sitemap fa-2x' : 'fa fa-user fa-2x'" style="margin-right:0px;"></mat-icon>
+                                                </span>
+                                                <span class="col-xm-11">
+                                                    {{ user.idToDisplay }}
+                                                    <small>{{ user.otherInfo }}</small>
+                                                </span>
+                                            </p>
+                                        </mat-option>
+                                    </mat-autocomplete>
+                                </mat-form-field>
+                                <hr/>
+                            </div>
+                            <div class="col-md-6 col-xs-6">
+                                <mat-form-field>
+                                    <input matInput (keyup)="applyFilter($event.target.value)" placeholder="{{lang.filterBy}}">
+                                </mat-form-field>
+                            </div>
+                            <div class="col-md-6 col-xs-6">
+                                <mat-paginator #paginator [length]="100" [pageSize]="10">
+                                </mat-paginator>
                             </div>
-                            <mat-table #table [dataSource]="dataSource" matSort matSortActive="lastname" matSortDirection="asc">
-                                <ng-container matColumnDef="user_id">
-                                    <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.id}}</mat-header-cell>
-                                    <mat-cell *matCellDef="let element"> {{element.user_id}} </mat-cell>
-                                </ng-container>
-                                <ng-container matColumnDef="firstname">
-                                    <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.firstname}}</mat-header-cell>
-                                    <mat-cell *matCellDef="let element"> {{element.firstname}} </mat-cell>
-                                </ng-container>
-                                <ng-container matColumnDef="lastname">
-                                    <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.lastname}}</mat-header-cell>
-                                    <mat-cell *matCellDef="let element"> {{element.lastname}} </mat-cell>
-                                </ng-container>
-                                <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
-                                <mat-row *matRowDef="let row; columns: displayedColumns;" routerLink="/administration/users/{{row.id}}" matTooltip="{{lang.view}}"
-                                    style="cursor:pointer;"></mat-row>
-                            </mat-table>
-                        </mat-tab>
+                        </div>
+                        <mat-table #table [dataSource]="usersDataSource" matSort matSortActive="lastname" matSortDirection="asc">
+                            <ng-container matColumnDef="firstname">
+                                <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.firstname}}</mat-header-cell>
+                                <mat-cell *matCellDef="let element"> {{element.firstname}} </mat-cell>
+                            </ng-container>
+                            <ng-container matColumnDef="lastname">
+                                <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.lastname}}</mat-header-cell>
+                                <mat-cell *matCellDef="let element"> {{element.lastname}} </mat-cell>
+                            </ng-container>
+                            <mat-header-row *matHeaderRowDef="usersDisplayedColumns"></mat-header-row>
+                            <mat-row *matRowDef="let row; columns: usersDisplayedColumns;" routerLink="/administration/users/{{row.id}}" matTooltip="{{lang.view}}"
+                                style="cursor:pointer;"></mat-row>
+                        </mat-table>
+                    </mat-tab>
+                    <mat-tab label="{{lang.relatedBaskets}}" *ngIf="!creationMode">
+                        <div class="row" style="margin:0px;">
+                            <div class="col-md-6 col-xs-6">
+                                <mat-form-field>
+                                    <input matInput (keyup)="applyBasketsFilter($event.target.value)" placeholder="{{lang.filterBy}}">
+                                </mat-form-field>
+                            </div>
+                            <div class="col-md-6 col-xs-6">
+                                <mat-paginator #paginatorBaskets [length]="100" [pageSize]="10">
+                                </mat-paginator>
+                            </div>
+                        </div>
+                        <mat-table #table [dataSource]="basketsDataSource" matSort matSortActive="basket_name" matSortDirection="asc">
+                            <ng-container matColumnDef="basket_name">
+                                <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.label}}</mat-header-cell>
+                                <mat-cell *matCellDef="let element"> {{element.basket_name}} </mat-cell>
+                            </ng-container>
+                            <ng-container matColumnDef="basket_desc">
+                                <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.description}}</mat-header-cell>
+                                <mat-cell *matCellDef="let element"> {{element.basket_desc}} </mat-cell>
+                            </ng-container>
+                            <mat-header-row *matHeaderRowDef="basketsDisplayedColumns"></mat-header-row>
+                            <mat-row *matRowDef="let row; columns: basketsDisplayedColumns;" routerLink="/administration/baskets/{{row.basket_id}}" matTooltip="{{lang.view}}" style="cursor:pointer;"></mat-row>
+                        </mat-table>
+                    </mat-tab>
                 </mat-tab-group>
             </mat-card>
         </mat-sidenav-content>
diff --git a/apps/maarch_entreprise/js/angular/app/administration/group-administration.component.ts b/apps/maarch_entreprise/js/angular/app/administration/group-administration.component.ts
index 686644a14c1..98329eaca6d 100644
--- a/apps/maarch_entreprise/js/angular/app/administration/group-administration.component.ts
+++ b/apps/maarch_entreprise/js/angular/app/administration/group-administration.component.ts
@@ -30,16 +30,25 @@ export class GroupAdministrationComponent  extends AutoCompletePlugin implements
     };
     creationMode                    : boolean;
 
-    displayedColumns    = ['firstname', 'lastname'];
-    dataSource          : any;
+    usersDisplayedColumns           = ['firstname', 'lastname'];
+    basketsDisplayedColumns         = ['basket_name', 'basket_desc'];
+    usersDataSource                 : any;
+    basketsDataSource               : any;
 
 
+    @ViewChild('paginatorBaskets') paginatorBaskets: MatPaginator;
     @ViewChild(MatPaginator) paginator: MatPaginator;
     @ViewChild(MatSort) sort: MatSort;
+
     applyFilter(filterValue: string) {
         filterValue = filterValue.trim();
         filterValue = filterValue.toLowerCase();
-        this.dataSource.filter = filterValue;
+        this.usersDataSource.filter = filterValue;
+    }
+    applyBasketsFilter(filterValue: string) {
+        filterValue = filterValue.trim();
+        filterValue = filterValue.toLowerCase();
+        this.basketsDataSource.filter = filterValue;
     }
 
     constructor(changeDetectorRef: ChangeDetectorRef, media: MediaMatcher,public http: HttpClient, private route: ActivatedRoute, private router: Router, private notify: NotificationService) {
@@ -69,9 +78,12 @@ export class GroupAdministrationComponent  extends AutoCompletePlugin implements
                         this.group = data['group'];
                         this.loading = false;
                         setTimeout(() => {
-                            this.dataSource = new MatTableDataSource(this.group.users);
-                            this.dataSource.paginator = this.paginator;
-                            this.dataSource.sort = this.sort;
+                            this.usersDataSource = new MatTableDataSource(this.group.users);
+                            this.usersDataSource.paginator = this.paginator;
+                            this.usersDataSource.sort = this.sort;
+                            this.basketsDataSource = new MatTableDataSource(this.group.baskets);
+                            this.basketsDataSource.paginator = this.paginatorBaskets;
+                            this.basketsDataSource.sort = this.sort;
                         }, 0);
 
                     }, () => {
@@ -98,7 +110,6 @@ export class GroupAdministrationComponent  extends AutoCompletePlugin implements
                     this.notify.error(err.error.errors);
                 });
         }
-
     }
 
     updateService(service: any) {
@@ -115,22 +126,22 @@ export class GroupAdministrationComponent  extends AutoCompletePlugin implements
         this.userCtrl.setValue('');
         $j('.autocompleteSearch').blur();
         var groupReq = {
-            "groupId": this.group.group_id,
-            "role": this.group.role
+            "groupId"   : this.group.group_id,
+            "role"      : this.group.role
         };
         this.http.post(this.coreUrl + "rest/users/" + newUser.id + "/groups", groupReq)
-            .subscribe((data: any) => {
+            .subscribe(() => {
                 var displayName = newUser.idToDisplay.split(" ");
                 var user = {
                     id : newUser.id,
                     user_id : newUser.otherInfo,
                     firstname : displayName[0],
                     lastname : displayName[1]
-                }
+                };
                 this.group.users.push(user);
-                this.dataSource = new MatTableDataSource(this.group.users);
-                this.dataSource.paginator = this.paginator;
-                this.dataSource.sort = this.sort;
+                this.usersDataSource = new MatTableDataSource(this.group.users);
+                this.usersDataSource.paginator = this.paginator;
+                this.usersDataSource.sort = this.sort;
                 this.notify.success(this.lang.userAdded);
             }, (err) => {
                 this.notify.error(err.error.errors);
diff --git a/apps/maarch_entreprise/js/angular/lang/lang-en.ts b/apps/maarch_entreprise/js/angular/lang/lang-en.ts
index 7e244ae2e40..eee9d2b0ea1 100755
--- a/apps/maarch_entreprise/js/angular/lang/lang-en.ts
+++ b/apps/maarch_entreprise/js/angular/lang/lang-en.ts
@@ -319,6 +319,7 @@ export const LANG_EN = {
     "redirects"                         : "Redirections",
     "reinitPassword"                    : "Reset password",
     "relatedUsers"                      : "Related users",
+    "relatedBaskets"                    : "Related basket(s)",
     "removeUserRedirect"                : "Remove user (diffusion list + diffusion model entity)",
     "renewPsw"                          : "Enter the password again",
     "reports"                           : "Reports",
diff --git a/apps/maarch_entreprise/js/angular/lang/lang-fr.ts b/apps/maarch_entreprise/js/angular/lang/lang-fr.ts
index d4e99e41137..de4abfa135d 100755
--- a/apps/maarch_entreprise/js/angular/lang/lang-fr.ts
+++ b/apps/maarch_entreprise/js/angular/lang/lang-fr.ts
@@ -401,6 +401,7 @@ export const LANG_FR = {
     "redirectWhenAbscence"              : "Rediriger la bannette à une personne",
     "reinitPassword"                    : "Réinitialiser le mot de passe",
     "relatedUsers"                      : "Utilisateur(s) associé(s)",
+    "relatedBaskets"                    : "Bannette(s) associée(s)",
     "removeUserRedirect"                : "Supprimer la personne (liste de diffusion + modèle de l'entité)",
     "renewPsw"                          : "Retaper le mot de passe",
     "reports"                           : "Statistiques",
diff --git a/src/app/basket/models/GroupBasketModelAbstract.php b/src/app/basket/models/GroupBasketModelAbstract.php
index 4d5e2e0e0a8..75e62fd0be3 100644
--- a/src/app/basket/models/GroupBasketModelAbstract.php
+++ b/src/app/basket/models/GroupBasketModelAbstract.php
@@ -23,13 +23,15 @@ abstract class GroupBasketModelAbstract
     public static function get(array $aArgs)
     {
         ValidatorModel::arrayType($aArgs, ['select', 'where', 'data', 'orderBy']);
+        ValidatorModel::intType($aArgs, ['limit']);
 
         $aGroupsBaskets = DatabaseModel::select([
             'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
             'table'     => ['groupbasket'],
-            'where'     => $aArgs['where'],
-            'data'      => $aArgs['data'],
-            'order_by'  => $aArgs['orderBy']
+            'where'     => empty($aArgs['where']) ? [] : $aArgs['where'],
+            'data'      => empty($aArgs['data']) ? [] : $aArgs['data'],
+            'order_by'  => empty($aArgs['orderBy']) ? [] : $aArgs['orderBy'],
+            'limit'     => empty($aArgs['limit']) ? 0 : $aArgs['limit']
         ]);
 
         return $aGroupsBaskets;
@@ -91,4 +93,20 @@ abstract class GroupBasketModelAbstract
 
         return true;
     }
+
+    public static function getBasketsByGroupId(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['groupId']);
+        ValidatorModel::stringType($aArgs, ['groupId']);
+        ValidatorModel::arrayType($aArgs, ['select']);
+
+        $aGroupsBaskets = DatabaseModel::select([
+            'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
+            'table'     => ['groupbasket, baskets'],
+            'where'     => ['groupbasket.group_id = ?', 'groupbasket.basket_id = baskets.basket_id'],
+            'data'      => [$aArgs['groupId']]
+        ]);
+
+        return $aGroupsBaskets;
+    }
 }
diff --git a/src/app/group/controllers/GroupController.php b/src/app/group/controllers/GroupController.php
index 7ff0cb92480..a4699f7add7 100644
--- a/src/app/group/controllers/GroupController.php
+++ b/src/app/group/controllers/GroupController.php
@@ -2,6 +2,7 @@
 
 namespace Group\controllers;
 
+use Basket\models\GroupBasketModel;
 use Group\models\ServiceModel;
 use Group\models\GroupModel;
 use Respect\Validation\Validator;
@@ -134,10 +135,12 @@ class GroupController
             return $response->withStatus(400)->withJson(['errors' => 'Group not found']);
         }
 
-        $group['users']         = GroupModel::getUsersByGroupId(['groupId' => $group['group_id'], 'select' => ['users.id', 'users.user_id', 'users.firstname', 'users.lastname']]);
-        $group['security']      = GroupModel::getSecurityByGroupId(['groupId' => $group['group_id']]);
-        $group['services']      = GroupModel::getAllServicesByGroupId(['groupId' => $group['group_id']]);
-        $group['canAdminUsers'] = ServiceModel::hasService(['id' => 'admin_users', 'userId' => $GLOBALS['userId'], 'location' => 'apps', 'type' => 'admin']);
+        $group['security']          = GroupModel::getSecurityByGroupId(['groupId' => $group['group_id']]);
+        $group['services']          = GroupModel::getAllServicesByGroupId(['groupId' => $group['group_id']]);
+        $group['users']             = GroupModel::getUsersByGroupId(['groupId' => $group['group_id'], 'select' => ['users.id', 'users.user_id', 'users.firstname', 'users.lastname']]);
+        $group['baskets']           = GroupBasketModel::getBasketsByGroupId(['select' => ['baskets.basket_id', 'baskets.basket_name', 'baskets.basket_desc'], 'groupId' => $group['group_id']]);
+        $group['canAdminUsers']     = ServiceModel::hasService(['id' => 'admin_users', 'userId' => $GLOBALS['userId'], 'location' => 'apps', 'type' => 'admin']);
+        $group['canAdminBaskets']   = ServiceModel::hasService(['id' => 'admin_baskets', 'userId' => $GLOBALS['userId'], 'location' => 'basket', 'type' => 'admin']);
 
         return $response->withJson(['group' => $group]);
     }
diff --git a/test/GroupControllerTest.php b/test/GroupControllerTest.php
index fc323c47a34..a80eb0f910e 100644
--- a/test/GroupControllerTest.php
+++ b/test/GroupControllerTest.php
@@ -51,6 +51,12 @@ class GroupControllerTest extends TestCase
         $this->assertSame('Y', $responseBody->group->enabled);
         $this->assertSame('1=2', $responseBody->group->security->where_clause);
         $this->assertSame('commentateur du dimanche', $responseBody->group->security->maarch_comment);
+        $this->assertInternalType('array', $responseBody->group->users);
+        $this->assertInternalType('array', $responseBody->group->baskets);
+        $this->assertEmpty($responseBody->group->users);
+        $this->assertEmpty($responseBody->group->baskets);
+        $this->assertSame(true, $responseBody->group->canAdminUsers);
+        $this->assertSame(true, $responseBody->group->canAdminBaskets);
     }
 
     public function testUpdate()
@@ -86,6 +92,12 @@ class GroupControllerTest extends TestCase
         $this->assertSame('Y', $responseBody->group->enabled);
         $this->assertSame('1=3', $responseBody->group->security->where_clause);
         $this->assertSame('commentateur du dimanche #2', $responseBody->group->security->maarch_comment);
+        $this->assertInternalType('array', $responseBody->group->users);
+        $this->assertInternalType('array', $responseBody->group->baskets);
+        $this->assertEmpty($responseBody->group->users);
+        $this->assertEmpty($responseBody->group->baskets);
+        $this->assertSame(true, $responseBody->group->canAdminUsers);
+        $this->assertSame(true, $responseBody->group->canAdminBaskets);
     }
 
     public function testDelete()
diff --git a/test/ResControllerTest.php b/test/ResControllerTest.php
index b8482059e27..22043b79c95 100644
--- a/test/ResControllerTest.php
+++ b/test/ResControllerTest.php
@@ -369,6 +369,7 @@ class ResControllerTest extends TestCase
 
         //  READ
         $res = \Resource\models\ResModel::getById(['resId' => self::$id]);
-        $this->assertSame(null, $res);
+        $this->assertInternalType('array', $res);
+        $this->assertEmpty($res);
     }
 }
-- 
GitLab