Skip to content

Commit

Permalink
Merged from dtq-dev and fixed conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
milanmajchrak committed Dec 6, 2023
2 parents c4b7c2e + c4e8387 commit 35bd16b
Show file tree
Hide file tree
Showing 42 changed files with 8,001 additions and 5,572 deletions.
4 changes: 2 additions & 2 deletions .github/actions/import-db/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ runs:
with:
repository: dataquest-dev/dspace-python-api
path: dspace-python-api
ref: 'refactor_jm'
ref: 'main'


- name: stop and remove containers
Expand All @@ -44,7 +44,7 @@ runs:
# create otherwise it will be created with root owner
cid=$(docker run -d --rm --name $DB5NAME -v $(pwd):/dq/scripts -v $DATADIR/dump:/dq/dump -p 127.0.0.1:$DB5PORT:5432 -e POSTGRES_DB=empty -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=dspace postgres /bin/bash -c "cd /dq/scripts && ./init.dspacedb5.sh")
echo "cid=$cid" >> $GITHUB_OUTPUT
sleep 10
sleep 60
echo "====="
docker logs $DB5NAME || true
echo "====="
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { of as observableOf} from 'rxjs';
import { ActivatedRoute } from '@angular/router';
import { ConfigurationDataService } from '../../core/data/configuration-data.service';
import {createSuccessfulRemoteDataObject$} from '../../shared/remote-data.utils';
import { ConfigurationProperty } from '../../core/shared/configuration-property.model';
import { HELP_DESK_PROPERTY } from '../../item-page/tombstone/tombstone.component';
import { TranslateModule } from '@ngx-translate/core';
import { AuthFailedPageComponent } from './auth-failed-page.component';
import { RequestService } from '../../core/data/request.service';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import { getMockRemoteDataBuildService } from '../../shared/mocks/remote-data-build.service.mock';
import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { NotificationsService } from '../../shared/notifications/notifications.service';

describe('DuplicateUserErrorComponent', () => {
let component: AuthFailedPageComponent;
let fixture: ComponentFixture<AuthFailedPageComponent>;
let mockConfigurationDataService: ConfigurationDataService;
let requestService: RequestService;
let activatedRoute: any;
let halService: HALEndpointService;
let rdbService: RemoteDataBuildService;
let notificationService: NotificationsServiceStub;

const rootUrl = 'root url';
const queryParams = 'netid[idp]';
const encodedQueryParams = 'netid%5Bidp%5D&email=';

activatedRoute = {
params: observableOf({}),
snapshot: {
queryParams: {
netid: queryParams
}
}
};

mockConfigurationDataService = jasmine.createSpyObj('configurationDataService', {
findByPropertyName: createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), {
name: HELP_DESK_PROPERTY,
values: [
'email'
]
}))
});

requestService = jasmine.createSpyObj('requestService', {
send: observableOf('response'),
generateRequestId: observableOf('123456'),
});

halService = jasmine.createSpyObj('authService', {
getRootHref: rootUrl,
});

rdbService = getMockRemoteDataBuildService();
notificationService = new NotificationsServiceStub();

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [ AuthFailedPageComponent ],
providers: [
{ provide: ActivatedRoute, useValue: activatedRoute },
{ provide: ConfigurationDataService, useValue: mockConfigurationDataService },
{ provide: RequestService, useValue: requestService },
{ provide: HALEndpointService, useValue: halService },
{ provide: RemoteDataBuildService, useValue: rdbService },
{ provide: NotificationsService, useValue: notificationService },
]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(AuthFailedPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should send request with encoded netId and email param', () => {
component.ngOnInit();
component.sendEmail();
expect(requestService.send).toHaveBeenCalledWith(jasmine.objectContaining({
href: rootUrl + '/autoregistration?netid=' + encodedQueryParams,
}));
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { RemoteData } from '../../core/data/remote-data';
import { ConfigurationProperty } from '../../core/shared/configuration-property.model';
Expand Down Expand Up @@ -42,7 +42,6 @@ export class AuthFailedPageComponent implements OnInit {

constructor(
protected configurationDataService: ConfigurationDataService,
protected router: Router,
public route: ActivatedRoute,
private requestService: RequestService,
protected halService: HALEndpointService,
Expand All @@ -61,7 +60,8 @@ export class AuthFailedPageComponent implements OnInit {
public sendEmail() {
const requestId = this.requestService.generateRequestId();

const url = this.halService.getRootHref() + '/autoregistration?netid=' + this.netid + '&email=' + this.email;
const url = this.halService.getRootHref() + '/autoregistration?netid=' + encodeURIComponent(this.netid) +
'&email=' + encodeURIComponent(this.email);
const postRequest = new PostRequest(requestId, url);
// Send POST request
this.requestService.send(postRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ResetAuthenticationMessagesAction
} from '../../../../core/auth/auth.actions';

import { getAuthenticationError, getAuthenticationInfo, } from '../../../../core/auth/selectors';
import { getAuthenticationError, getAuthenticationInfo } from '../../../../core/auth/selectors';
import { isEmpty, isNotEmpty } from '../../../empty.util';
import { fadeOut } from '../../../animations/fade';
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
Expand Down Expand Up @@ -145,10 +145,13 @@ export class LogInPasswordComponent implements OnInit {
* Set up redirect URL. It could be loaded from the `authorizationService.getRedirectUrl()` or from the url.
*/
public async setUpRedirectUrl() {
// Get redirect URL from the authService `redirectUrl` property.
const fetchedRedirectUrl = await firstValueFrom(this.authService.getRedirectUrl());
if (isNotEmpty(fetchedRedirectUrl)) {
this.redirectUrl = fetchedRedirectUrl;
// Bring over the item ID as a query parameter
const queryParams = { redirectUrl: fetchedRedirectUrl };
// Redirect to login with `redirectUrl` param because the redirectionUrl is lost from the store after click on
// `local` login.
void this.router.navigate(['login'], { queryParams: queryParams });
}

// Store the `redirectUrl` value from the url and then remove that value from url.
Expand Down
4 changes: 3 additions & 1 deletion src/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ import { EpersonGroupListComponent } from './eperson-group-list/eperson-group-li
import { EpersonSearchBoxComponent } from './eperson-group-list/eperson-search-box/eperson-search-box.component';
import { GroupSearchBoxComponent } from './eperson-group-list/group-search-box/group-search-box.component';
import { HtmlContentService } from './html-content.service';
import { ClarinSafeHtmlPipe } from './utils/clarin-safehtml.pipe';

const MODULES = [
CommonModule,
Expand Down Expand Up @@ -319,7 +320,8 @@ const PIPES = [
ClarinLicenseCheckedPipe,
ClarinLicenseLabelRadioValuePipe,
ClarinLicenseRequiredInfoPipe,
CharToEndPipe
CharToEndPipe,
ClarinSafeHtmlPipe
];

const COMPONENTS = [
Expand Down
15 changes: 15 additions & 0 deletions src/app/shared/utils/clarin-safehtml.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

/**
* Pipe to keep html tags e.g., `id` in the `innerHTML` attribute.
*/
@Pipe({
name: 'dsSafeHtml'
})
export class ClarinSafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {}
transform(htmlString: string): SafeHtml {
return this.sanitized.bypassSecurityTrustHtml(htmlString);
}
}
2 changes: 1 addition & 1 deletion src/app/static-page/static-page.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div class="container" >
<div [innerHTML]="(htmlContent | async)"></div>
<div [innerHTML]="(htmlContent | async) | dsSafeHtml" (click)="processLinks($event)"></div>
</div>
19 changes: 15 additions & 4 deletions src/app/static-page/static-page.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,42 @@ import { RouterMock } from '../shared/mocks/router.mock';
import { LocaleService } from '../core/locale/locale.service';
import { TranslateModule } from '@ngx-translate/core';
import { of } from 'rxjs';
import { APP_CONFIG } from '../../config/app-config.interface';
import { environment } from '../../environments/environment';
import { ClarinSafeHtmlPipe } from '../shared/utils/clarin-safehtml.pipe';

describe('StaticPageComponent', () => {
let component: StaticPageComponent;
let fixture: ComponentFixture<StaticPageComponent>;

let htmlContentService: HtmlContentService;
let localeService: any;
let appConfig: any;

beforeEach(async () => {
htmlContentService = jasmine.createSpyObj('htmlContentService', {
fetchHtmlContent: of('<div>TEST MESSAGE</div>')
fetchHtmlContent: of('<div id="idShouldNotBeRemoved">TEST MESSAGE</div>')
});
localeService = jasmine.createSpyObj('LocaleService', {
getCurrentLanguageCode: jasmine.createSpy('getCurrentLanguageCode'),
});

appConfig = Object.assign(environment, {
ui: {
namespace: 'testNamespace'
}
});

TestBed.configureTestingModule({
declarations: [ StaticPageComponent ],
declarations: [ StaticPageComponent, ClarinSafeHtmlPipe ],
imports: [
TranslateModule.forRoot()
],
providers: [
{ provide: HtmlContentService, useValue: htmlContentService },
{ provide: Router, useValue: new RouterMock() },
{ provide: LocaleService, useValue: localeService }
{ provide: LocaleService, useValue: localeService },
{ provide: APP_CONFIG, useValue: appConfig }
]
});

Expand All @@ -51,6 +62,6 @@ describe('StaticPageComponent', () => {
// Load `TEST MESSAGE`
it('should load html file content', async () => {
await component.ngOnInit();
expect(component.htmlContent.value).toBe('<div>TEST MESSAGE</div>');
expect(component.htmlContent.value).toBe('<div id="idShouldNotBeRemoved">TEST MESSAGE</div>');
});
});
36 changes: 30 additions & 6 deletions src/app/static-page/static-page.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { HtmlContentService } from '../shared/html-content.service';
import { BehaviorSubject, firstValueFrom } from 'rxjs';
import { Router } from '@angular/router';
import { isEmpty, isNotEmpty } from '../shared/empty.util';
import { LocaleService } from '../core/locale/locale.service';
import { STATIC_FILES_DEFAULT_ERROR_PAGE_PATH, STATIC_FILES_PROJECT_PATH } from './static-page-routing-paths';
import { APP_CONFIG, AppConfig } from '../../config/app-config.interface';

/**
* Component which load and show static files from the `static-files` folder.
Expand All @@ -17,15 +18,17 @@ import { STATIC_FILES_DEFAULT_ERROR_PAGE_PATH, STATIC_FILES_PROJECT_PATH } from
})
export class StaticPageComponent implements OnInit {
htmlContent: BehaviorSubject<string> = new BehaviorSubject<string>('');
htmlFileName: string;

constructor(private htmlContentService: HtmlContentService,
private router: Router,
private localeService: LocaleService) { }
private localeService: LocaleService,
@Inject(APP_CONFIG) protected appConfig?: AppConfig) { }

async ngOnInit(): Promise<void> {
let url = '';
// Fetch html file name from the url path. `static/some_file.html`
let htmlFileName = this.getHtmlFileName();
this.htmlFileName = this.getHtmlFileName();

// Get current language
let language = this.localeService.getCurrentLanguageCode();
Expand All @@ -35,15 +38,15 @@ export class StaticPageComponent implements OnInit {
// Try to find the html file in the translated package. `static-files/language_code/some_file.html`
// Compose url
url = STATIC_FILES_PROJECT_PATH;
url += isEmpty(language) ? '/' + htmlFileName : '/' + language + '/' + htmlFileName;
url += isEmpty(language) ? '/' + this.htmlFileName : '/' + language + '/' + this.htmlFileName;
let potentialContent = await firstValueFrom(this.htmlContentService.fetchHtmlContent(url));
if (isNotEmpty(potentialContent)) {
this.htmlContent.next(potentialContent);
return;
}

// If the file wasn't find, get the non-translated file from the default package.
url = STATIC_FILES_PROJECT_PATH + '/' + htmlFileName;
url = STATIC_FILES_PROJECT_PATH + '/' + this.htmlFileName;
potentialContent = await firstValueFrom(this.htmlContentService.fetchHtmlContent(url));
if (isNotEmpty(potentialContent)) {
this.htmlContent.next(potentialContent);
Expand All @@ -54,6 +57,27 @@ export class StaticPageComponent implements OnInit {
await this.loadErrorPage();
}

processLinks(e) {
const element: HTMLElement = e.target;
if (element.nodeName === 'A') {
e.preventDefault();
const href = element.getAttribute('href')?.replace('/', '');
let redirectUrl = window.location.origin + this.appConfig.ui.nameSpace + '/static/';
// Start with `#` - redirect to the fragment
if (href.startsWith('#')) {
redirectUrl += this.htmlFileName + href;
} else if (href.startsWith('.')) {
// Redirect using namespace e.g. `./test.html` -> `<UI_PATH>/namespace/static/test.html`
redirectUrl += href.replace('.', '') + '.html';
} else {
// Redirect without using namespace e.g. `/test.html` -> `<UI_PATH>/test.html`
redirectUrl = redirectUrl.replace(this.appConfig.ui.nameSpace, '') + href;
}
// Call redirect
window.location.href = redirectUrl;
}
}

/**
* Load file name from the URL - `static/FILE_NAME.html`
* @private
Expand All @@ -69,7 +93,7 @@ export class StaticPageComponent implements OnInit {
}

// If the url is too long take just the first string after `/static` prefix.
return urlInList[1];
return urlInList[1]?.split('#')?.[0];
}

/**
Expand Down
10 changes: 6 additions & 4 deletions src/app/static-page/static-page.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import { CommonModule } from '@angular/common';

import { StaticPageRoutingModule } from './static-page-routing.module';
import { StaticPageComponent } from './static-page.component';
import { SharedModule } from '../shared/shared.module';


@NgModule({
declarations: [
StaticPageComponent
],
imports: [
CommonModule,
StaticPageRoutingModule,
]
imports: [
CommonModule,
StaticPageRoutingModule,
SharedModule,
]
})
export class StaticPageModule { }
Loading

0 comments on commit 35bd16b

Please sign in to comment.