diff --git a/.vscode/settings.json b/.vscode/settings.json index 14500d7f5706e26810d623cf2a6ba4c1ba59b88b..38a5306b5d41ad590e6f78981d6c59e71a6f8489 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -37,6 +37,7 @@ "grandlyon", "instagram", "linkedin", + "matomo", "metropole", "Metropole", "monday", diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 0000000000000000000000000000000000000000..3857c5e284e1195edea920277581ccec4647fa60 --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,14 @@ +version: '2' + +services: + web-app: + restart: unless-stopped + #build: . + image: registry.forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client:${TAG} + volumes: + - ./nginx/local.conf:/etc/nginx/conf.d/default.conf + - ./src/assets/config.json:/usr/share/nginx/html/assets/config.json + ports: + - 8030:8080 + extra_hosts: + - host.docker.internal:host-gateway diff --git a/docker-compose.yml b/docker-compose.yml index 51ec15731cc2d265cb31799b2825e83bae8208f3..12192986b3c846d84a4acd8abc377bcfe5d52aed 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,9 +3,9 @@ version: '2' services: web-app: restart: unless-stopped - build: . image: registry.forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client:${TAG} volumes: - ./dev.conf:/etc/nginx/conf.d/default.conf + - ./config.json:/usr/share/nginx/html/assets/config.json ports: - 8030:8080 diff --git a/nginx/dev.conf b/nginx/dev.conf index e1ea4905ddefb341b4252452cdc13f54cea5d1b3..4e4ae86ea78f66b656feb52d21c8c281a5a8edb6 100644 --- a/nginx/dev.conf +++ b/nginx/dev.conf @@ -1,7 +1,3 @@ -upstream api_node_js { - server service-ram:3000; -} - map $http_user_agent $outdated { default 0; "~MSIE [1-10]\." 1; @@ -22,25 +18,6 @@ server { listen 8080 default_server; root /usr/share/nginx/html/; - set $matomo_script - "<script type='text/javascript'> - var _paq = window._paq = window._paq || []; - _paq.push(['trackPageView']); - _paq.push(['enableLinkTracking']); - (function() { - var u='<URL_GDLYON>'; - _paq.push(['setTrackerUrl', u+'matomo.php']); - _paq.push(['setSiteId', '<SITE_ID>']); - var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); - })(); - </script>"; - - location ~ /index.html|.*\.json$ { - expires -1; - add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; - sub_filter '</head>' '$matomo_script</head>'; - } location / { # Redirect outdated nav diff --git a/nginx/local.conf b/nginx/local.conf new file mode 100644 index 0000000000000000000000000000000000000000..9ebd913798568e0f2dde87f5addea1370daf49cd --- /dev/null +++ b/nginx/local.conf @@ -0,0 +1,65 @@ +map $http_user_agent $outdated { + default 0; + "~MSIE [1-10]\." 1; + "~Trident/[5-7]\." 1; + "~Mozilla.*Firefox/[1-9]\." 1; + "~Mozilla.*Firefox/[0-2][0-9]\." 1; + "~Mozilla.*Firefox/3[0-1]\." 1; + "~Opera.*Version/[0-9]\." 1; + "~Opera.*Version/[0-1][0-9]\." 1; + "~Opera.*Version/2[0-1]\." 1; + "~AppleWebKit.*Version/[0-6]\..*Safari" 1; + "~Chrome/[0-9]\." 1; + "~Chrome/[0-2][0-9]\." 1; + "~Chrome/3[0-3]\." 1; +} + +server { + listen 8080 default_server; + + root /usr/share/nginx/html/; + + location / { + # Redirect outdated nav + if ($outdated = 1){ + rewrite ^ /outdated.html break; + } + # First attempt to serve request as file, then + # as directory, then fall back to displaying a 404. + # Angular routed apps must fall back to index.html ( https://angular.io/guide/deployment#server-configuration ) + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_pass http://host.docker.internal:3000; + } + + location /base-adresse/base-adresse-nationale/streets { + 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 /reverse { + proxy_pass https://api-adresse.data.gouv.fr/reverse; + } + + location /wfs/grandlyon { + proxy_pass https://download.data.grandlyon.com/wfs/grandlyon; + } + + location ~* (/ghost) { + expires epoch; + proxy_no_cache 1; + proxy_pass http://host.docker.internal:2368; + } + + # REALLY important for JavaScript modules (type="module") to work as expected!!! + location ~ \.js { + add_header Content-Type text/javascript; + } + +} + diff --git a/package-lock.json b/package-lock.json index e8f5ed0062bfad776229e9a395cd246634ae0792..bd8a334bb7cae87530d0932a6724de30de1411e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3063,6 +3063,22 @@ "integrity": "sha512-YtA8rWAglPuf4CSStrFAxaprTSYE+DREGrJFc3WvZLcF5XrwVK+H4CC4Pmz07iYsG1TXShR4bWp1fbGw1cmBKw==", "dev": true }, + "@ngx-matomo/router": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ngx-matomo/router/-/router-4.0.1.tgz", + "integrity": "sha512-o/kb1LdDtGZFWZav3HTGXPykMmCbrqC7n4PdQWZQNx8//JpDMBMNsk+FIh6vVTM4NOkURSBK73vIDMYJVHKj0g==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@ngx-matomo/tracker": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ngx-matomo/tracker/-/tracker-4.0.1.tgz", + "integrity": "sha512-JFdJOwpkGa8hdGy5MdUw2URI3Z9Ff3wjXrana3Ft8n2Pfr4y5lnKwrd70qcnE10rvRNm2pNR1ryZwsS4o+m4+g==", + "requires": { + "tslib": "^2.0.0" + } + }, "@ngx-translate/core": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", @@ -12573,6 +12589,14 @@ "queue-microtask": "^1.2.2" } }, + "runtime-config-loader": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/runtime-config-loader/-/runtime-config-loader-5.0.2.tgz", + "integrity": "sha512-6LnDfuV79wPuwykgxK0nDx/b28z6iXsKChlnc5OIr+iYPWNzgIe9MBaH7nNw9ACitWq4T1+Rkc+fvJeWNBBpug==", + "requires": { + "tslib": "^2.3.0" + } + }, "rxjs": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.6.0.tgz", @@ -14231,9 +14255,9 @@ "dev": true }, "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, "ua-parser-js": { diff --git a/package.json b/package.json index e566be841f2fc8f9d1af40d387cf76315fc06950..682c8ef5267ae6baeb8b3eeeff695c58c5c90e0e 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "@angular/router": "^15.1.3", "@angular/service-worker": "^15.1.3", "@asymmetrik/ngx-leaflet": "^8.1.0", + "@ngx-matomo/router": "^4.0.1", + "@ngx-matomo/tracker": "^4.0.1", "@ngx-translate/core": "^14.0.0", "ag-grid-angular": "^28.0.0", "ag-grid-community": "^28.0.0", @@ -38,6 +40,7 @@ "lodash": "^4.17.21", "luxon": "^1.25.0", "ngx-toastr": "^15.0.0", + "runtime-config-loader": "^5.0.2", "rxjs": "~7.6.0", "tslib": "^2.4.0", "zone.js": "~0.12.0" @@ -81,6 +84,6 @@ "standard-version": "^9.3.2", "ts-node": "~8.10.0", "tslint": "~6.1.0", - "typescript": "~4.8.3" + "typescript": "~4.9.4" } } diff --git a/src/app/admin/components/panel/panel.component.ts b/src/app/admin/components/panel/panel.component.ts index 9f0ce725b8ee376c2624142fb2b60295d64925fc..ff37d5f88a1f2c0c0410d8e83a3b9f72c14e33df 100644 --- a/src/app/admin/components/panel/panel.component.ts +++ b/src/app/admin/components/panel/panel.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { environment } from '../../../../environments/environment'; +import { RuntimeConfigLoaderService } from 'runtime-config-loader'; import { ButtonType } from '../../../shared/components/button/buttonType.enum'; import { AdminPanelEnum } from '../../../shared/enum/adminPanel.enum'; import { PanelRouteService } from '../../services/panel-route.service'; @@ -11,11 +11,14 @@ import { PanelRouteService } from '../../services/panel-route.service'; }) export class PanelComponent implements OnInit { public features = AdminPanelEnum; - public ghostLink = environment.ghostAdmin; + public ghostLink = this.runtimeConfigLoaderService.getConfigObjectKey('ghostAdmin'); public selectedFeature; public buttonTypeEnum = ButtonType; - constructor(private panelRouteService: PanelRouteService) { + constructor( + private panelRouteService: PanelRouteService, + private runtimeConfigLoaderService: RuntimeConfigLoaderService + ) { this.panelRouteService.destinationChanged$.subscribe((selected: AdminPanelEnum) => { this.selectedFeature = selected; }); diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 78557d27344396ab32fc081cfa8692a3ec680287..a5f733049866b9d636d4df1d10eeb315e66a0dbd 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -27,6 +27,14 @@ const footerOutletRoute: Route = { component: FooterComponent, }; +function buildTitle(pageTitle: string = '') { + let title: string = "Réseau des acteurs de l'inclusion numérique de la métropole de Lyon"; + if (pageTitle) { + title = pageTitle + ' | ' + title; + } + return title; +} + const routes: Routes = [ { path: 'print', @@ -45,6 +53,7 @@ const routes: Routes = [ }, { path: 'acteurs', + title: buildTitle('Cartographie'), children: [ { path: '', @@ -62,6 +71,7 @@ const routes: Routes = [ }, { path: 'login', + title: buildTitle('Connexion'), children: [ { path: '', @@ -82,6 +92,7 @@ const routes: Routes = [ }, { path: 'legal-notice', + title: buildTitle('Mentions légales'), children: [ { path: '', @@ -92,6 +103,7 @@ const routes: Routes = [ }, { path: 'page/:slugPage', + title: buildTitle(), children: [ { path: '', @@ -102,6 +114,7 @@ const routes: Routes = [ }, { path: 'contact', + title: buildTitle('Contact'), children: [ { path: '', @@ -132,6 +145,7 @@ const routes: Routes = [ }, { path: 'profile', + title: buildTitle('Profil'), children: [ { path: '', @@ -204,6 +218,7 @@ const routes: Routes = [ }, { path: 'newsletter', + title: buildTitle('Newsletter'), children: [ { path: '', @@ -224,6 +239,7 @@ const routes: Routes = [ }, { path: 'annuaire', + title: buildTitle('Annuaire'), children: [ { path: '', @@ -234,6 +250,7 @@ const routes: Routes = [ }, { path: 'news', + title: buildTitle('Actualités'), children: [ { path: '', @@ -244,6 +261,7 @@ const routes: Routes = [ }, { path: 'admin', + title: buildTitle('Admin'), children: [ { path: '', @@ -255,10 +273,12 @@ const routes: Routes = [ }, { path: 'form', + title: buildTitle(), loadChildren: () => import('./form/form-view/form-view.module').then((m) => m.FormViewModule), }, { path: 'orientation', + title: buildTitle('Orientation'), children: [ { path: '', diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 5d0893672b63680e6899448e0a712b30fffaca99..a0ba448a3a03c51f31ee89228b9fa603ae932e7c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -7,6 +7,8 @@ import { NavigationStart, Router, } from '@angular/router'; +import { MatomoInitializerService } from '@ngx-matomo/tracker'; +import { RuntimeConfigLoaderService } from 'runtime-config-loader'; import { ProfileService } from './profile/services/profile.service'; import { AuthService } from './services/auth.service'; import { RouterListenerService } from './services/routerListener.service'; @@ -28,7 +30,9 @@ export class AppComponent implements OnInit { private profilService: ProfileService, private routerListener: RouterListenerService, private updateService: UpdateService, - private router: Router + private router: Router, + private runtimeConfigLoaderService: RuntimeConfigLoaderService, + private matomoInitializer: MatomoInitializerService ) { if (this.authService.isLoggedIn()) { this.profilService.getProfile(); @@ -77,6 +81,15 @@ export class AppComponent implements OnInit { } document.getElementsByClassName('app-body')[0].scrollTo(0, 0); }); + + // Subscribe to the configSubject and access the configuration object that way (to be sure the loading is finished) + // (cf. https://github.com/pjlamb12/runtime-config-loader#overview ) + this.runtimeConfigLoaderService.configSubject.subscribe((config) => { + if (config.matomoTrackerUrl && config.matomoSiteId) { + this.matomoInitializer.initializeTracker({ trackerUrl: config.matomoTrackerUrl, siteId: config.matomoSiteId }); + } + }); + this.runtimeConfigLoaderService.loadConfig().subscribe(); } private setHeightApp(): void { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index e774a44e711049a0fc558aa27c2e33749f214041..36b35b928d3c68634135e95cfcc7e49e0afc5299 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -3,7 +3,10 @@ import { LOCALE_ID, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { ServiceWorkerModule } from '@angular/service-worker'; +import { NgxMatomoRouterModule } from '@ngx-matomo/router'; +import { MatomoInitializationMode, NgxMatomoTrackerModule } from '@ngx-matomo/tracker'; import { ToastrModule } from 'ngx-toastr'; +import { RuntimeConfigLoaderModule } from 'runtime-config-loader'; import { environment } from '../environments/environment'; import { AnnuaireComponent } from './annuaire/annuaire.component'; import { FilterModalComponent } from './annuaire/filter-modal/filter-modal.component'; @@ -78,6 +81,9 @@ import { StructureJoinComponent } from './structure/structure-join/structure-joi ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production, }), + RuntimeConfigLoaderModule, + NgxMatomoTrackerModule.forRoot({ mode: MatomoInitializationMode.AUTO_DEFERRED }), + NgxMatomoRouterModule, ], providers: [ { provide: LOCALE_ID, useValue: 'fr' }, diff --git a/src/assets/config.json b/src/assets/config.json new file mode 100644 index 0000000000000000000000000000000000000000..6b76e00ee16656f48018e4fc2f3e6b43a33bf8f2 --- /dev/null +++ b/src/assets/config.json @@ -0,0 +1,5 @@ +{ + "matomoTrackerUrl": "", + "matomoSiteId": "", + "ghostAdmin": "http://localhost:2368/ghost/" +} diff --git a/src/assets/config.template.json b/src/assets/config.template.json new file mode 100644 index 0000000000000000000000000000000000000000..94eb7dbf1d00d43f90242366235e1dc80003be0d --- /dev/null +++ b/src/assets/config.template.json @@ -0,0 +1,5 @@ +{ + "matomoTrackerUrl": "https://statweb.grandlyon.com/", + "matomoSiteId": "87", + "ghostAdmin": "http://localhost:2368/ghost/" +} diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 4e7f509afab7125a32416f80586ae5ed65d9c959..c9669790be176ac85a5d8c11278875c2f52dc507 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,4 +1,3 @@ export const environment = { production: true, - ghostAdmin: 'https://resin.grandlyon.com/blog/ghost', }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index d1ce31e014e04d40eb2033801227d6727018d530..31cb7855f14479143386a580d3e21e50a3735c22 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -4,8 +4,6 @@ export const environment = { production: false, - ghostAdmin: 'https://resin-dev.grandlyon.com/blog/ghost', - VERSION: require('../../package.json').version, }; /*