Commit 2dad46b7 authored by Hugo SUBTIL's avatar Hugo SUBTIL
Browse files

Merge branch 'dev' into 'recette'

release V1.10.0

See merge request !178
parents 827d13c4 b662ca0d
Pipeline #19270 passed with stage
in 3 minutes and 59 seconds
......@@ -49,3 +49,6 @@ Thumbs.db
.env
# apiMock
api/db.json
# Documentation generated with compodoc
documentation
image: docker:git
services:
- docker:dind
stages:
- sonar-analysis
- build
- deploy
build:
image: docker:18.09
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build
......@@ -22,7 +17,7 @@ build:
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
build_dev:
image: docker:18.09
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build
......@@ -34,7 +29,7 @@ build_dev:
- docker push "$CI_REGISTRY_IMAGE:dev"
build_mobile:
image: docker:18.09
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build
......@@ -46,7 +41,7 @@ build_mobile:
- docker push "$CI_REGISTRY_IMAGE:mobile"
build_json_server:
image: docker:18.09
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build
......@@ -97,29 +92,29 @@ deploy_rec:
- docker-compose up -d web-app-rec
- docker system prune -a -f
code_analysis:
image: skilldlabs/sonar-scanner:3.4.0
services:
- docker:18.09-dind
stage: sonar-analysis
only:
- dev
before_script:
- export NODE_PATH=$NODE_PATH:`npm root -g`
- npm install -g typescript
script:
- >
sonar-scanner
-Dsonar.projectName=${SONAR_PROJECT_KEY}
-Dsonar.projectVersion=1.0
-Dsonar.sourceEncoding=UTF-8
-Dsonar.projectBaseDir=.
-Dsonar.host.url=${SONAR_URL}
-Dsonar.projectKey=${SONAR_PROJECT_KEY}
-Dsonar.login=${SONAR_TOKEN}
# code_analysis:
# image: skilldlabs/sonar-scanner:3.4.0
# services:
# - docker:18.09-dind
# stage: sonar-analysis
# only:
# - dev
# before_script:
# - export NODE_PATH=$NODE_PATH:`npm root -g`
# - npm install -g typescript
# script:
# - >
# sonar-scanner
# -Dsonar.projectName=${SONAR_PROJECT_KEY}
# -Dsonar.projectVersion=1.0
# -Dsonar.sourceEncoding=UTF-8
# -Dsonar.projectBaseDir=.
# -Dsonar.host.url=${SONAR_URL}
# -Dsonar.projectKey=${SONAR_PROJECT_KEY}
# -Dsonar.login=${SONAR_TOKEN}
mr:
image: docker:18.09
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build
......
This diff is collapsed.
......@@ -35,6 +35,12 @@ Run `npm run e2e` to execute the end-to-end tests via [Protractor](http://www.pr
Use conventional commit format. For more info please read this article on [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/)
## Documentation
A documentation is generated with compodoc in addition of the existing documentation on the wiki.
```sh
npm run doc:serve
```
You can now visualize it at : `localhost:8080`
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
......@@ -36,9 +36,12 @@
"tsConfig": "tsconfig.app.json",
"localize": true,
"aot": true,
"allowedCommonJsDependencies": ["lodash", "leaflet.locatecontrol"],
"assets": [
"src/favicon.ico",
"src/assets",
"src/sitemap.xml",
"src/robots.txt",
{
"glob": "**/*",
"input": "./node_modules/leaflet/dist/images",
......
......@@ -30,7 +30,7 @@ module.exports = function (config) {
target: 'https://passerelle.formulaireextranet.grandlyon.com',
changeOrigin: true,
},
'/geocoding/photon/api': {
'/geocoding/photon-bal/api': {
target: 'https://download.data.grandlyon.com',
changeOrigin: true,
},
......
......@@ -52,8 +52,8 @@ server {
proxy_pass https://passerelle.formulaireextranet.grandlyon.com/base-adresse/base-adresse-nationale/streets;
}
location /geocoding/photon/api {
proxy_pass https://download.data.grandlyon.com/geocoding/photon/api;
location /geocoding/photon-bal/api {
proxy_pass https://download.data.grandlyon.com/geocoding/photon-bal/api;
}
location /reverse {
......
This diff is collapsed.
{
"name": "pamn",
"version": "1.6.0",
"version": "1.10.0",
"scripts": {
"ng": "ng",
"start": "ng serve --configuration=fr --proxy-config proxy.conf.json",
"build:prod": "ng build --prod --configuration=production,fr --output-path=dist",
"build:dev": "ng build --prod --configuration=fr --output-path=dist",
"build:prod": "ng build --prod --configuration=production,fr --output-path=dist --subresource-integrity",
"build:dev": "ng build --prod --configuration=fr --output-path=dist --subresource-integrity",
"doc": "npx @compodoc/compodoc -p tsconfig.doc.json",
"doc:serve": "npm run doc && npx compodoc -s",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
......@@ -15,16 +17,16 @@
},
"private": true,
"dependencies": {
"@angular/animations": "~10.1.3",
"@angular/animations": "~11.2.12",
"@angular/cdk": "^10.2.3",
"@angular/common": "~10.1.3",
"@angular/compiler": "~10.1.3",
"@angular/core": "~10.1.3",
"@angular/common": "~11.2.12",
"@angular/compiler": "~11.2.12",
"@angular/core": "~11.2.12",
"@angular/flex-layout": "^10.0.0-beta.32",
"@angular/forms": "~10.1.3",
"@angular/platform-browser": "~10.1.3",
"@angular/platform-browser-dynamic": "~10.1.3",
"@angular/router": "~10.1.3",
"@angular/forms": "~11.2.12",
"@angular/platform-browser": "~11.2.12",
"@angular/platform-browser-dynamic": "~11.2.12",
"@angular/router": "~11.2.12",
"@asymmetrik/ngx-leaflet": "^8.1.0",
"@ngx-translate/core": "^13.0.0",
"json-server": "^0.16.2",
......@@ -33,20 +35,22 @@
"leaflet.locatecontrol": "^0.72.0",
"lodash": "^4.17.20",
"luxon": "^1.25.0",
"npx": "^10.2.2",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"zone.js": "~0.10.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.1100.6",
"@angular/cli": "~10.1.3",
"@angular/compiler-cli": "~10.1.3",
"@angular/localize": "^10.1.3",
"@angular/cli": "^11.2.11",
"@angular/compiler-cli": "~11.2.12",
"@angular/localize": "^11.2.12",
"@compodoc/compodoc": "^1.1.11",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"@types/leaflet": "^1.5.17",
"@types/node": "^12.12.67",
"@types/leaflet.locatecontrol": "^0.60.7",
"@types/node": "^12.12.67",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
......
......@@ -26,7 +26,7 @@
"changeOrigin": true,
"logLevel": "info"
},
"/geocoding/photon/api": {
"/geocoding/photon-bal/api": {
"target": "https://download.data.grandlyon.com",
"secure": false,
"changeOrigin": true,
......
......@@ -19,9 +19,9 @@
services ont été identifiées :
</p>
<h2>Recenser et partager des ressources existantes (optimisation)</h2>
<img src="/assets/img/about_illustration_1.jpg" alt="illustration des besoins" />
<img src="/assets/img/about_illustration_1.jpg" width="640" height="114" alt="illustration des besoins" />
<h2>Co-construire de nouvelles ressources (développement)</h2>
<img src="/assets/img/about_illustration_2.jpg" alt="illustration des besoins" />
<img src="/assets/img/about_illustration_2.jpg" width="640" height="149" alt="illustration des besoins" />
<p>
Cet espace vise à centraliser et mettre en commun les ressources développées dans le cadre du réseau par ses
acteurs.
......@@ -29,8 +29,8 @@
<p>N'hésitez pas à contribuer à cet espace en partageant vos ressources</p>
</div>
<div fxLayout="column" fxLayoutAlign="center center" fxLayoutGap="20px">
<img src="/assets/logos/logo_europe.png" alt="logo de l'union européenne" />
<img src="/assets/logos/logo_region.png" alt="logo de la région Auverge-Rhône-Alpes" />
<img src="/assets/logos/logo_europe.png" width="220" height="168" alt="logo de l'union européenne" />
<img src="/assets/logos/logo_region.png" width="220" height="98" alt="logo de la région Auverge-Rhône-Alpes" />
</div>
</div>
</div>
......
@import '../../assets/scss/color';
.selector {
margin-bottom: 20px;
.option {
margin-right: 30px;
}
}
.results-tab {
margin-bottom: 20px;
}
.results-column {
width: 30%;
}
.incomplete {
color: $red;
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { PanelComponent } from './components/panel/panel.component';
const routes: Routes = [
{
path: '',
component: PanelComponent,
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class AdminRoutingModule {}
......@@ -2,10 +2,14 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { PanelComponent } from './components/panel/panel.component';
import { ClaimStructureComponent } from './components/claim-structure/claim-structure.component';
import { DeleteUserComponent } from './components/delete-user/delete-user.component';
import { SharedModule } from '../shared/shared.module';
import { NewsletterUsersComponent } from './components/newsletter-users/newsletter-users.component';
import { AdminStructuresListComponent } from './components/structures-list/admin-structures-list.component';
import { AdminRoutingModule } from './admin-routing.module';
@NgModule({
declarations: [PanelComponent, ClaimStructureComponent],
imports: [CommonModule, SharedModule],
declarations: [PanelComponent, ClaimStructureComponent, DeleteUserComponent, NewsletterUsersComponent, AdminStructuresListComponent],
imports: [CommonModule, AdminRoutingModule, SharedModule],
})
export class AdminModule {}
<div fxLayout="row" fxLayoutAlign="center center">
<table *ngIf="demandsAttachment" aria-describedby="demands attachment results">
<div fxLayout="column" fxLayoutAlign="center center">
<table *ngIf="isClaimedStructure" aria-describedby="demands attachment results" class="results-tab">
<thead>
<th scope="col">Utilisateur</th>
<th scope="col">Structure</th>
<th scope="col">Options</th>
</thead>
<tbody>
<tr *ngFor="let demand of demandsAttachment">
<td>{{ demand.userEmail }}</td>
<td>{{ demand.structureName }}</td>
<tr *ngFor="let structure of demandsAttachment">
<td>{{ structure.userEmail }}</td>
<td>{{ structure.structureName }}</td>
<td>
<button (click)="acceptDemand(demand)">Valider</button><button (click)="refuseDemand(demand)">Refuser</button>
<button (click)="acceptDemand(structure)">Valider</button
><button (click)="refuseDemand(structure)">Refuser</button>
</td>
</tr>
<tr *ngIf="!demandsAttachment.length">
<tr *ngIf="!demandsAttachment?.length">
<td colspan="3">Aucune demande en attente</td>
</tr>
</tbody>
......
import { Component, OnInit } from '@angular/core';
import { DemandAttachment } from '../../models/demandAttachment.model';
import { StructureAdminInfo } from '../../models/demandAttachment.model';
import { AdminService } from '../../services/admin.service';
@Component({
selector: 'app-admin-claim-structure',
templateUrl: './claim-structure.component.html',
styleUrls: ['../../admin-pannel.scss'],
})
export class ClaimStructureComponent implements OnInit {
public demandsAttachment: DemandAttachment[];
public demandsAttachment: StructureAdminInfo[];
public structuresUnclaimed: StructureAdminInfo[];
public isClaimedStructure: boolean = true;
public isUnclaimedStructure: boolean = false;
constructor(private adminService: AdminService) {}
ngOnInit(): void {
......@@ -16,7 +20,7 @@ export class ClaimStructureComponent implements OnInit {
});
}
public acceptDemand(demand: DemandAttachment): void {
public acceptDemand(demand: StructureAdminInfo): void {
this.adminService
.acceptStructureClaim(demand.userEmail, demand.structureId, demand.structureName)
.subscribe((data) => {
......@@ -24,11 +28,15 @@ export class ClaimStructureComponent implements OnInit {
});
}
public refuseDemand(demand: DemandAttachment): void {
public refuseDemand(demand: StructureAdminInfo): void {
this.adminService
.refuseStructureClaim(demand.userEmail, demand.structureId, demand.structureName)
.subscribe((data) => {
this.demandsAttachment = data;
});
}
public claimedStructure(event: boolean): void {
this.isClaimedStructure = !this.isClaimedStructure;
}
}
<div fxLayout="column" fxLayoutGap="5px" fxLayoutAlign="center center" class="userBlock">
<h4>Suppression d'utilisateurs</h4>
<div fxLayout="row">
<input #searchstring (keyup)="(0)" />
<button (click)="searchUsers(searchstring.value)">Rechercher</button>
</div>
<div class="userList">
<tr *ngFor="let user of users">
<td>{{ user.email }}</td>
<td>
<button (click)="toggleDeleteModal(user)">Supprimer</button>
</td>
</tr>
<app-modal-confirmation
*ngIf="userToDelete"
[openned]="deleteModalOpenned"
[content]="'Voulez-vous vraiment supprimer cet utilisateur&nbsp;? (' + userToDelete.email + ')'"
(closed)="deleteUser(userToDelete, $event)"
></app-modal-confirmation>
<div *ngIf="users && users.length == 0">Aucun résultat</div>
</div>
</div>
import { HttpClientModule } from '@angular/common/http';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { DeleteUserComponent } from './delete-user.component';
describe('DeleteUserComponent', () => {
let component: DeleteUserComponent;
let fixture: ComponentFixture<DeleteUserComponent>;
let USERS;
let service;
beforeEach(async () => {
USERS = [
{ email: 'paula@test.com', name: 'paula' },
{ email: 'jeanpaul@test.com', name: 'jeanpaul' },
{ email: 'admin@test.com', name: 'admin' },
];
await TestBed.configureTestingModule({
imports: [HttpClientModule],
declarations: [DeleteUserComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DeleteUserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
service = jasmine.createSpyObj(['searchUsers', 'deleteUser']);
component = new DeleteUserComponent(service);
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should searchUsers', () => {
let searchString = 'paula';
service.searchUsers.and.returnValue(of(USERS.filter((item) => item.email.indexOf(searchString) !== -1)));
component.users = USERS;
component.searchUsers(searchString);
expect(component.users.length).toBe(1);
});
it('should searchUsers all users', () => {
let searchString = '';
service.searchUsers.and.returnValue(of(USERS.filter((item) => item.email.indexOf(searchString) !== -1)));
component.users = USERS;
component.searchUsers(searchString);
expect(component.users.length).toBe(USERS.length);
});
it('should delete user', () => {
component.users = USERS;
service.deleteUser.and.returnValue(
of(
USERS.splice(
USERS.findIndex((e) => e.email === USERS[0].email),
1
)
)
);
component.deleteUser(component.users[0]);
expect(component.users.length).toBe(2);
});
});
import { Component } from '@angular/core';
import { User } from '../../../models/user.model';
import { ProfileService } from '../../../profile/services/profile.service';
import { AdminService } from '../../services/admin.service';
@Component({
selector: 'app-admin-delete-user',
templateUrl: './delete-user.component.html',
})
export class DeleteUserComponent {
public users: User[];
public deleteModalOpenned = false;
public userToDelete: User = null;
constructor(private adminService: AdminService, private profileService: ProfileService) {}
public deleteUser(user: User, shouldDelete: boolean): void {
this.toggleDeleteModal(user);
if (shouldDelete) {
this.adminService.deleteUser(user._id).subscribe((data) => {
this.users = this.users.filter((obj) => obj.email !== data.email);
});
}
}
public toggleDeleteModal(userToDelete: User): void {
this.userToDelete = userToDelete;
this.deleteModalOpenned = !this.deleteModalOpenned;
}
public searchUsers(searchString: string): void {
this.adminService.searchUsers(searchString).subscribe((users) => {
this.profileService.getProfile().then((profile) => {
this.users = users.filter((obj) => obj.email != profile.email);
});
});
}
}
<div fxLayout="column" fxLayoutGap="5px" fxLayoutAlign="center center" class="userBlock">
<h2>Gestion abonnement newsletter</h2>
<div fxLayout="row">
<button (click)="copySubscription()">Copier les adresses dans le presse papier</button>
</div>
<div fxLayout="row">Il y a actuellement {{ subscriptionsCount }} abonnés à la newsletter.</div>
<div fxLayout="row">
<input #searchstring (keyup)="(0)" />
<button (click)="searchSubscribedEmail(searchstring.value)">Rechercher</button>
</div>
<div class="userList">
<tr *ngFor="let subscription of subscriptions">
<td>{{ subscription.email }}</td>
<td>
<button (click)="toggleUnsubscribeModal(subscription.email)">Désabonner</button>
</td>
</tr>
<app-modal-confirmation
*ngIf="emailToUnsubscribe"
[openned]="deleteModalOpenned"
[content]="'Voulez-vous vraiment supprimer ' + emailToUnsubscribe + ' de la newsletter &nbsp;?'"
(closed)="unsubscribeEmail(emailToUnsubscribe, $event)"
></app-modal-confirmation>
<div *ngIf="subscriptions && subscriptions.length == 0">Aucun résultat</div>
</div>
</div>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment