Commit 58f0230d authored by Jean-François LOTHEAL's avatar Jean-François LOTHEAL
Browse files

Merge branch 'D81919' into 'master'

D81919

See merge request !115
parents adb619af 356b7acf
Pipeline #10112 passed with stage
in 8 minutes and 39 seconds
{
"name": "webapp",
"version": "2.6.6",
"version": "2.6.11",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......
{
"name": "webapp",
"version": "2.6.15",
"version": "2.6.16",
"license": "GNU Affero General Public License v3.0",
"scripts": {
"ng": "ng",
......
......@@ -7,6 +7,7 @@ import { MatomoService } from './matomo.service';
import { NavigationHistoryService } from './navigation-history.service';
import { NotificationService } from './notification.service';
import { StorageService } from './storage.service';
import { ToolsService } from './tools.service';
// tslint:disable-next-line: max-line-length
export { ErrorService, NotificationService, MatomoService, NavigationHistoryService, EmailService, FileService, AppConfigService, AppStateService, };
......@@ -22,4 +23,5 @@ export const CoreServices = [
FileService,
AppConfigService,
AppStateService,
ToolsService,
];
import { Injectable } from '@angular/core';
@Injectable()
export class ToolsService {
constructor(
) { }
/**
* Détermine si une url est externe
* @param url
* @return boolean
*/
isExternalURL(url:string) {
return new URL(url).host !== (location.host);
}
/**
* Ajoute de nouveaux attributs html aux urls externes
* @param html
*/
decorateRichText(html) {
const domParser = new DOMParser()
const document = domParser.parseFromString(html, `text/html`)
const serializer = new XMLSerializer()
// Handles external links
const links = document.querySelectorAll(`a`);
links.forEach((link) => {
if (link.href) {
if (this.isExternalURL(link.href)) {
link.target = `_blank`
link.rel = `noopener noreferrer`
}
}
})
return serializer.serializeToString(document)
}
}
\ No newline at end of file
......@@ -226,11 +226,11 @@ export class DatasetDetailComponent implements OnInit, OnDestroy {
this._router.navigate([
`/${AppRoutes.datasets.uri}/${this._datasetDetailService.dataset.slug}/${AppRoutes.data.uri}`,
// tslint:disable-next-line: align
], { queryParamsHandling: 'preserve' });
], { queryParamsHandling: 'preserve', replaceUrl: true });
} else {
this._router.navigate([
`/${AppRoutes.datasets.uri}/${this._datasetDetailService.dataset.slug}/${AppRoutes.info.uri}`,
]);
], {replaceUrl: true});
}
} else {
// Making that the url contains the slug and not the uuid of the dataset
......@@ -239,7 +239,7 @@ export class DatasetDetailComponent implements OnInit, OnDestroy {
`/${AppRoutes.datasets.uri}/${this._datasetDetailService.dataset.slug}/${this._route.snapshot.firstChild.url[0]}`,
],
// tslint:disable-next-line: align
{ queryParamsHandling: 'preserve' });
{ queryParamsHandling: 'preserve', replaceUrl: true });
}
// Emit event to indicate to child component that the dataset has changed
......
......@@ -2,6 +2,7 @@ import { Location } from '@angular/common';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { geosource } from '../../../../i18n/traductions';
import { NavigationHistoryService } from '../../../core/services';
import { Aggregation, Filter, IActiveFiltersTemplate } from '../../../elasticsearch/models';
import { AppRoutes } from '../../../routes';
import { scopesResearch } from '../../../shared/variables';
......@@ -24,9 +25,11 @@ export class FilterListComponent implements OnInit, OnDestroy {
constructor(
private _datasetResearchService: DatasetResearchService,
private _location: Location,
private _navigationHistoryService: NavigationHistoryService,
) { }
ngOnInit() {
const filters = this._datasetResearchService.filters;
if (filters) {
this.initFilters();
......@@ -103,6 +106,7 @@ export class FilterListComponent implements OnInit, OnDestroy {
this._datasetResearchService.resetActiveAggregations();
this._datasetResearchService.triggerSearchChange();
this._location.go(AppRoutes.research.uri, '');
this._navigationHistoryService.add(this._location.path());
}
ngOnDestroy() {
......
......@@ -87,11 +87,14 @@ export class ResultsComponent implements OnInit, OnDestroy {
// If there are parameters, we extract them to set the ESoptions for a news search.
private manageUrlParameters(params) {
this._datasetResearchService.resetActiveAggregations();
if (params && Object.keys(params).length > 0) {
this.hasParams = true;
// We need to make an initial request to get the aggregations and subaggregations
this._datasetResearchService.getResults().subscribe(() => {
// Create the ESOptions
const options = this._researchUrlService.getOptionsFromParameters(params);
this._datasetResearchService.elasticSearchOptions.setElasticsearchOptions(options);
// Force to recalculate the aggregate counts
......@@ -112,7 +115,6 @@ export class ResultsComponent implements OnInit, OnDestroy {
let parentAgg = '';
filters.forEach((filter) => {
if (filter.field === aggField) {
// No need this rule. In this case we control the parameters, and we want a loose
// comparison to handle the filter with a 'Date' type (where the key aggregation is a number).
......@@ -139,13 +141,17 @@ export class ResultsComponent implements OnInit, OnDestroy {
});
}
});
this._datasetResearchService.updateAggregation(newAggField, aggKey, true, parentAgg, false);
});
});
this._datasetResearchService.triggerSearchChange();
});
}
else {
//reset filters recorded when there are not get parameters
this._datasetResearchService.triggerSearchChange();
this._researchUrlService.reset();
}
}
ngOnDestroy() {
......@@ -260,6 +266,6 @@ export class ResultsComponent implements OnInit, OnDestroy {
}
get toResultNumber() {
return Math.min(((this.paginator.pageIndex - 1) * this.paginator.pageSize) + 10, this.paginator.length);
return Math.min((this.paginator.pageIndex * this.paginator.pageSize), this.paginator.length);
}
}
......@@ -37,7 +37,7 @@ export class DatasetResearchService {
this._searchChangeSubject = new Subject<any>();
this._datasetsReloadedSubject = new Subject<any>();
this._scopeChangedSubject = new Subject<any>();
this._elasticsearchOptions = new ElasticsearchOptions({ pageSize: 10 });
this._elasticsearchOptions = new ElasticsearchOptions({ pageSize: 5 });
this._resultsCount = [];
}
......
import { Location } from '@angular/common';
import { Injectable } from '@angular/core';
import { NavigationHistoryService } from '../../core/services';
import { Aggregation, IElasticsearchOptions, ISortOption } from '../../elasticsearch/models';
import { AppRoutes } from '../../routes';
import { scopesResearch } from '../../shared/variables';
......@@ -12,6 +13,7 @@ export class ResearchUrlService {
constructor(
private _location: Location,
private _navigationHistoryService: NavigationHistoryService
) { }
// Get the ES options from parameters
......@@ -78,6 +80,7 @@ export class ResearchUrlService {
this._parameters[key] = searchValue;
const params = this.generateUrlParams();
this._location.go(AppRoutes.research.uri, params);
this._navigationHistoryService.add(this._location.path());
}
// Set an aggregation parameter in the _aggParameters variable, and change the url
......@@ -132,6 +135,7 @@ export class ResearchUrlService {
}
const params = this.generateUrlParams();
this._location.go(AppRoutes.research.uri, params);
this._navigationHistoryService.add(this._location.path());
}
private addAggregation(fieldKey: string, aggregationKey: string) {
......@@ -168,6 +172,7 @@ export class ResearchUrlService {
this._parameters['sort'] = value;
const params = this.generateUrlParams();
this._location.go(AppRoutes.research.uri, params);
this._navigationHistoryService.add(this._location.path());
}
// Generate the parameters to set into the url from the _parameters and _aggParametersa arrays
......
......@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
import { DomSanitizer, Meta, SafeHtml } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import { environment } from '../../../../environments/environment';
import { ToolsService } from '../../../core/services/tools.service';
import { AppRoutes } from '../../../routes';
import { IPageHeaderInfo } from '../../../shared/models';
import { CMSContent } from '../../models';
......@@ -23,6 +24,7 @@ export class CMSPageComponent implements OnInit {
private _route: ActivatedRoute,
private _editorialisationService: EditorialisationService,
private sanitizer: DomSanitizer,
private _toolsService: ToolsService,
private _router: Router,
private _meta: Meta,
) {
......@@ -46,7 +48,7 @@ export class CMSPageComponent implements OnInit {
if (!(this.page instanceof CMSContent)) {
this._router.navigate(['/', AppRoutes.page404.uri]);
} else {
this.safePageContent = this.sanitizer.bypassSecurityTrustHtml(this.page.content.html);
this.safePageContent = this.sanitizer.bypassSecurityTrustHtml(this._toolsService.decorateRichText(this.page.content.html));
this.pageHeaderInfo.title = this.page.content.title;
}
});
......
......@@ -2,7 +2,8 @@ import { DatePipe } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { DomSanitizer, Meta, SafeHtml } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import { notificationMessages } from '../../../../i18n/traductions';
import { datasetStatistics, notificationMessages } from '../../../../i18n/traductions';
import { ToolsService } from '../../../core/services/tools.service';
import { ElasticsearchService } from '../../../elasticsearch/services/elasticsearch.service';
import { AppRoutes } from '../../../routes';
import { IPageHeaderInfo, Metadata, typesMetadata } from '../../../shared/models';
......@@ -35,6 +36,7 @@ export class CMSPostDetailComponent implements OnInit {
private _datePipe: DatePipe,
private _sanitizer: DomSanitizer,
private _elasticSearchService: ElasticsearchService,
private _toolsService: ToolsService,
private _meta: Meta,
) {
}
......@@ -47,7 +49,7 @@ export class CMSPostDetailComponent implements OnInit {
// Set the title and description for a CMS post
this._meta.updateTag({ name: 'description', content: this.post.content.excerpt });
this.safePostContent = this._sanitizer.bypassSecurityTrustHtml(this.post.content.html);
this.safePostContent = this._sanitizer.bypassSecurityTrustHtml(this._toolsService.decorateRichText(this.post.content.html));
// Construct header informations: (Date + tags) and title
this.pageHeaderInfo.title = this.post.content.title;
......@@ -78,6 +80,8 @@ export class CMSPostDetailComponent implements OnInit {
}
}
setBackupImage(metadata: Metadata) {
// Init the image property to make sure that 'url' is accessible in the following lines
metadata.image = {
......
import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
import { map, mergeMap, tap } from 'rxjs/operators';
import { notificationMessages, pageTitles } from '../../../../i18n/traductions';
......@@ -30,6 +31,7 @@ export class OrganizationsComponent implements OnInit {
private _datasetResearchService: DatasetResearchService,
private _notificationService: NotificationService,
private _router: Router,
private _location: Location
) { }
ngOnInit() {
......@@ -79,7 +81,7 @@ export class OrganizationsComponent implements OnInit {
this._datasetResearchService.getResults().subscribe(() => {
this._datasetResearchService.updateAggregation('metadata-fr.responsibleParty.organisationName', name, true);
this._datasetResearchService.scopeReasearch = scopesResearch.datasets;
this._router.navigate(['/', AppRoutes.research.uri]);
this._router.navigateByUrl(this._location.path());
});
}
......@@ -89,7 +91,7 @@ export class OrganizationsComponent implements OnInit {
this._datasetResearchService.getResults().subscribe(() => {
this._datasetResearchService.updateAggregation('metadata-fr.responsibleParty.organisationName', name, true);
this._datasetResearchService.scopeReasearch = scopesResearch.services;
this._router.navigate(['/', AppRoutes.research.uri]);
this._router.navigateByUrl(this._location.path());
});
}
......
......@@ -6,6 +6,7 @@ import { UserService } from '../../../services';
import { AppRoutes } from '../../../../routes';
import { IPageHeaderInfo } from '../../../../shared/models';
import { pageTitles } from '../../../../../i18n/traductions';
import { NavigationHistoryService } from '../../../../core/services';
@Component({
selector: 'app-login',
......@@ -22,6 +23,7 @@ export class LoginComponent implements OnInit {
};
showPassword: boolean;
returnUrl: string;
// Account validation
token: string; // uuid4 allowing to identify the account that needs to be validated
......@@ -33,12 +35,18 @@ export class LoginComponent implements OnInit {
private _userService: UserService,
private _router: Router,
private _activatedRoute: ActivatedRoute,
private _navigationHistoryService: NavigationHistoryService,
) {
this.form = this._fb.group({
username: ['', [Validators.required, Validators.email]],
password: ['', Validators.required],
});
this.returnUrl = this._navigationHistoryService.getFromLast(0);
if(null == this.returnUrl || this._router.url == this.returnUrl){
this.returnUrl = '/' + AppRoutes.home.uri;
}
}
ngOnInit() {
......@@ -73,7 +81,7 @@ export class LoginComponent implements OnInit {
(res) => {
this.form.enable();
this.errorStatus = null;
this._router.navigate(['/', AppRoutes.home.uri]);
this._router.navigate([this.returnUrl]);
},
(err) => {
if (err instanceof HttpErrorResponse) {
......
......@@ -796,8 +796,8 @@ Here is the list of the last evolutions of the portal. If you wish to contribute
<target>Your credentials are not correct.</target>
</trans-unit>
<trans-unit id="login.internalError" datatype="html">
<source>Something went wrong, please try again later.</source>
<target>Something went wrong, please try again later.</target>
<source>Please enter a valid email and password.</source>
<target>Please enter a valid email and password.</target>
</trans-unit>
<trans-unit id="login.emailRequired" datatype="html">
<source>Email is required.</source>
......
......@@ -805,8 +805,8 @@ Voici la liste des dernières évolutions du portail. Si vous souhaitez contribu
<target>Vos identifiants ne sont pas corrects.</target>
</trans-unit>
<trans-unit id="login.internalError" datatype="html">
<source>Something went wrong, please try again later.</source>
<target>Une erreur est survenue, veuillez réessayer ultérieurement.</target>
<source>Please enter a valid email and password.</source>
<target>Merci de saisir un email et un mot de passe valides.</target>
</trans-unit>
<trans-unit id="login.emailRequired" datatype="html">
<source>Email is required.</source>
......
Supports Markdown
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