From f1c5545a0ed88b98ea038fe1e0033867c044a1d9 Mon Sep 17 00:00:00 2001
From: milanmajchrak <90026355+milanmajchrak@users.noreply.github.com>
Date: Wed, 3 Jan 2024 09:47:21 +0100
Subject: [PATCH] customer/uk-it-7 (#436)
* ufal/fe-email-restricted-download (#430)
* ClarinAuthorization passed, but vanilla not because of vanilla check - I added dtoken into vanilla authorization url and because of that the vanilla authorization will be passed.
* Added message for the expiration token message - it was hardcoded.
* ufal/fe-not-show-shib-welcome-page
* Loaded property from the cfg and check if the page with idp attributes could be showed up. If not redirect the user to the home page. (#431)
* ufal/fe-s3-customization (#428)
* The admin could see in the bitstream admin UI if the bitstream is stored in both storages (S3, local).
* Fixed failing unit test - updated columnSizes object
* ufal/curate-translation-missing
Added curate collection edit translation and curation task name. (#434)
* ufal/upload-on-first-attempt-fix (#435)
* Moved file size limit into FileUploader options and handled Upload cancelation.
* Check that uploading is successful
* ufal/fe-show-checksum-result (#432)
* BitstreamChecksum values are fetched and parsed from the BE
* Checksum info is showed up.
* Added messages and translations.
* Added docs and refactored code
* Fixed failing tests
* Fixed wrong czech translations.
* ufal/shibboleth-redirect-from-login (#433)
* Send redirectUrl param to the IdP in the target url
* The code is updated to be more readable.
---------
Co-authored-by: Jozef Misutka <332350+vidiecan@users.noreply.github.com>
---
cypress/integration/submission.spec.ts | 2 +
src/aai/aai.js | 6 +-
...larin-bitstream-download-page.component.ts | 4 +-
...rin-bitstream-token-expired.component.html | 2 +-
.../core/bitstream-checksum-data.service.ts | 36 ++++++++++
src/app/core/core.module.ts | 6 +-
.../core/shared/bitstream-checksum.model.ts | 63 +++++++++++++++++
.../shared/bitstream-checksum.resource.ts | 9 +++
src/app/core/shared/bitstream.model.ts | 18 +++++
.../item-bitstreams.component.html | 1 +
.../item-bitstreams.component.ts | 6 +-
...-drag-and-drop-bitstream-list.component.ts | 3 +-
.../item-edit-bitstream.component.html | 60 +++++++++++++++++
.../item-edit-bitstream.component.spec.ts | 27 ++++++--
.../item-edit-bitstream.component.ts | 56 +++++++++++++++-
.../autoregistration.component.html | 2 +-
.../autoregistration.component.ts | 26 ++++++-
.../upload/uploader/uploader.component.ts | 67 ++++++++++++-------
src/app/thumbnail/thumbnail.component.spec.ts | 3 +-
src/assets/i18n/cs.json5 | 30 ++++++++-
src/assets/i18n/en.json5 | 17 ++++-
21 files changed, 398 insertions(+), 46 deletions(-)
create mode 100644 src/app/core/bitstream-checksum-data.service.ts
create mode 100644 src/app/core/shared/bitstream-checksum.model.ts
create mode 100644 src/app/core/shared/bitstream-checksum.resource.ts
diff --git a/cypress/integration/submission.spec.ts b/cypress/integration/submission.spec.ts
index b7eaf33b4a8..433e1b7e217 100644
--- a/cypress/integration/submission.spec.ts
+++ b/cypress/integration/submission.spec.ts
@@ -144,6 +144,8 @@ describe('New Submission page', () => {
// Wait for upload to complete before proceeding
cy.wait('@upload');
+ // Check the upload success notice
+ cy.get('ds-notification').contains('Upload successful');
// Close the upload success notice
cy.get('[data-dismiss="alert"]').click({multiple: true});
diff --git a/src/aai/aai.js b/src/aai/aai.js
index 23b60afd68e..455e7d1ad98 100644
--- a/src/aai/aai.js
+++ b/src/aai/aai.js
@@ -18,9 +18,11 @@
textHelpMore: "First check you are searching under the right country.\nIf your provider is not listed, please read these instructions to obtain an account."
};
this.setup = function(options) {
+ var targetUrl = '';
var opts = jQuery.extend({}, this.defaults, options),
defaultCallback = function(e) {
- window.location = opts.host + '/Shibboleth.sso/Login?SAMLDS=1&target=' + opts.target + '&entityID=' + window.encodeURIComponent(e.entityID);
+ targetUrl = opts.target + '?redirectUrl=' + window.location.href;
+ window.location = opts.host + '/Shibboleth.sso/Login?SAMLDS=1&target=' + targetUrl + '&entityID=' + window.encodeURIComponent(e.entityID);
};
//console.log(opts);
if(!opts.target){
@@ -33,7 +35,7 @@
opts.ourEntityID,
opts.responseUrl,
[ ],
- opts.host + '/Shibboleth.sso/Login?SAMLDS=1&target='+opts.target+'&entityID=');
+ opts.host + '/Shibboleth.sso/Login?SAMLDS=1&target=' + targetUrl + '&entityID=');
djc.discoPath = window.location.origin + (namespace === '' ? namespace : '/' + namespace) + "/assets/";
djc.metadata = [opts.metadataFeed];
djc.subtitle = "Login via Your home institution (e.g. university)";
diff --git a/src/app/bitstream-page/clarin-bitstream-download-page/clarin-bitstream-download-page.component.ts b/src/app/bitstream-page/clarin-bitstream-download-page/clarin-bitstream-download-page.component.ts
index b9e5c356b35..04d2fe87bb9 100644
--- a/src/app/bitstream-page/clarin-bitstream-download-page/clarin-bitstream-download-page.component.ts
+++ b/src/app/bitstream-page/clarin-bitstream-download-page/clarin-bitstream-download-page.component.ts
@@ -85,7 +85,9 @@ export class ClarinBitstreamDownloadPageComponent implements OnInit {
this.requestService.send(headRequest);
const clarinIsAuthorized$ = this.rdbService.buildFromRequestUUID(requestId);
- const isAuthorized$ = this.authorizationService.isAuthorized(FeatureID.CanDownload, isNotEmpty(bitstream) ? bitstream.self : undefined);
+ // Clarin authorization will check dtoken parameter from the request
+ const dtoken = isNotEmpty(this.dtoken) ? '?dtoken=' + this.dtoken : '';
+ const isAuthorized$ = this.authorizationService.isAuthorized(FeatureID.CanDownload, isNotEmpty(bitstream) ? bitstream.self + dtoken : undefined);
const isLoggedIn$ = this.auth.isAuthenticated();
return observableCombineLatest([clarinIsAuthorized$, isAuthorized$, isLoggedIn$, observableOf(bitstream)]);
}),
diff --git a/src/app/bitstream-page/clarin-bitstream-token-expired/clarin-bitstream-token-expired.component.html b/src/app/bitstream-page/clarin-bitstream-token-expired/clarin-bitstream-token-expired.component.html
index 835832bb45a..ec0a094f6f2 100644
--- a/src/app/bitstream-page/clarin-bitstream-token-expired/clarin-bitstream-token-expired.component.html
+++ b/src/app/bitstream-page/clarin-bitstream-token-expired/clarin-bitstream-token-expired.component.html
@@ -1,5 +1,5 @@
-
The download token is expired, you will be redirected to the download page.
+ {{'clarin.bitstream.expired.dtoken.message' | translate}}
diff --git a/src/app/core/bitstream-checksum-data.service.ts b/src/app/core/bitstream-checksum-data.service.ts
new file mode 100644
index 00000000000..94dfef62de0
--- /dev/null
+++ b/src/app/core/bitstream-checksum-data.service.ts
@@ -0,0 +1,36 @@
+import { Injectable } from '@angular/core';
+import { dataService } from './data/base/data-service.decorator';
+import { BaseDataService } from './data/base/base-data.service';
+import { RequestService } from './data/request.service';
+import { RemoteDataBuildService } from './cache/builders/remote-data-build.service';
+import { Store } from '@ngrx/store';
+import { CoreState } from './core-state.model';
+import { HALEndpointService } from './shared/hal-endpoint.service';
+import { ObjectCacheService } from './cache/object-cache.service';
+import { DefaultChangeAnalyzer } from './data/default-change-analyzer.service';
+import { HttpClient } from '@angular/common/http';
+import { NotificationsService } from '../shared/notifications/notifications.service';
+import { linkName } from './data/clarin/clrua-data.service';
+import { BitstreamChecksum } from './shared/bitstream-checksum.model';
+
+/**
+ * A service responsible for fetching BitstreamChecksum objects from the REST API
+ */
+@Injectable()
+@dataService(BitstreamChecksum.type)
+export class BitstreamChecksumDataService extends BaseDataService {
+ protected linkPath = 'checksum';
+
+ constructor(
+ protected requestService: RequestService,
+ protected rdbService: RemoteDataBuildService,
+ protected store: Store,
+ protected halService: HALEndpointService,
+ protected objectCache: ObjectCacheService,
+ protected comparator: DefaultChangeAnalyzer,
+ protected http: HttpClient,
+ protected notificationsService: NotificationsService,
+ ) {
+ super(linkName, requestService, rdbService, objectCache, halService, undefined);
+ }
+}
diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts
index 306b950f8f4..20a32beef40 100644
--- a/src/app/core/core.module.ts
+++ b/src/app/core/core.module.ts
@@ -189,6 +189,8 @@ import { ClarinUserMetadataDataService } from './data/clarin/clarin-user-metadat
import { ClarinLicenseResourceMappingService } from './data/clarin/clarin-license-resource-mapping-data.service';
import { ClarinVerificationTokenDataService } from './data/clarin/clarin-verification-token-data.service';
import { ClruaDataService } from './data/clarin/clrua-data.service';
+import { BitstreamChecksum } from './shared/bitstream-checksum.model';
+import { BitstreamChecksumDataService } from './bitstream-checksum-data.service';
/**
* When not in production, endpoint responses can be mocked for testing purposes
@@ -322,7 +324,8 @@ const PROVIDERS = [
OrcidQueueDataService,
OrcidHistoryDataService,
SupervisionOrderDataService,
- HandleDataService
+ HandleDataService,
+ BitstreamChecksumDataService
];
/**
@@ -335,6 +338,7 @@ export const models =
Bundle,
Bitstream,
BitstreamFormat,
+ BitstreamChecksum,
Item,
Site,
Collection,
diff --git a/src/app/core/shared/bitstream-checksum.model.ts b/src/app/core/shared/bitstream-checksum.model.ts
new file mode 100644
index 00000000000..c6c282d0428
--- /dev/null
+++ b/src/app/core/shared/bitstream-checksum.model.ts
@@ -0,0 +1,63 @@
+import { BITSTREAM_CHECKSUM } from './bitstream-checksum.resource';
+import { excludeFromEquals } from '../utilities/equals.decorators';
+import { autoserialize, deserialize } from 'cerialize';
+import { ResourceType } from './resource-type';
+import { HALLink } from './hal-link.model';
+import { typedObject } from '../cache/builders/build-decorators';
+import { TypedObject } from '../cache/typed-object.model';
+
+
+/**
+ * Model class containing the checksums of a bitstream (local, S3, DB)
+ */
+@typedObject
+export class BitstreamChecksum extends TypedObject {
+ /**
+ * The `bitstreamchecksum` object type.
+ */
+ static type = BITSTREAM_CHECKSUM;
+
+ /**
+ * The object type
+ */
+ @excludeFromEquals
+ @autoserialize
+ type: ResourceType;
+
+ /**
+ * The identifier of this BitstreamChecksum object
+ */
+ @autoserialize
+ id: string;
+
+ /**
+ * The checksum of the active store (local/S3)
+ */
+ @autoserialize
+ activeStore: CheckSum;
+
+ /**
+ * The checksum from the database
+ */
+ @autoserialize
+ databaseChecksum: CheckSum;
+
+ /**
+ * The checksum of the synchronized store (S3, local)
+ */
+ @autoserialize
+ synchronizedStore: CheckSum;
+
+ @deserialize
+ _links: {
+ self: HALLink
+ };
+}
+
+/**
+ * Model class containing a checksum value and algorithm
+ */
+export interface CheckSum {
+ checkSumAlgorithm: string;
+ value: string;
+}
diff --git a/src/app/core/shared/bitstream-checksum.resource.ts b/src/app/core/shared/bitstream-checksum.resource.ts
new file mode 100644
index 00000000000..8404c0e7ca6
--- /dev/null
+++ b/src/app/core/shared/bitstream-checksum.resource.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for BitstreamChecksum
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const BITSTREAM_CHECKSUM = new ResourceType('bitstreamchecksum');
diff --git a/src/app/core/shared/bitstream.model.ts b/src/app/core/shared/bitstream.model.ts
index c855325d2d6..fe5aed6dab0 100644
--- a/src/app/core/shared/bitstream.model.ts
+++ b/src/app/core/shared/bitstream.model.ts
@@ -10,6 +10,11 @@ import { HALLink } from './hal-link.model';
import {BUNDLE} from './bundle.resource-type';
import {Bundle} from './bundle.model';
import { ChildHALResource } from './child-hal-resource.model';
+import { BITSTREAM_CHECKSUM } from './bitstream-checksum.resource';
+import { BitstreamChecksum } from './bitstream-checksum.model';
+
+// Store number if the bitstream is stored in the both stores (S3 and local)
+export const SYNCHRONIZED_STORES_NUMBER = 77;
@typedObject
@inheritSerialization(DSpaceObject)
@@ -34,6 +39,12 @@ export class Bitstream extends DSpaceObject implements ChildHALResource {
@autoserialize
bundleName: string;
+ /**
+ * The number of the store where the bitstream is store, it could be S3, local or both.
+ */
+ @autoserialize
+ storeNumber: number;
+
/**
* The {@link HALLink}s for this Bitstream
*/
@@ -44,6 +55,7 @@ export class Bitstream extends DSpaceObject implements ChildHALResource {
format: HALLink;
content: HALLink;
thumbnail: HALLink;
+ checksum: HALLink;
};
/**
@@ -67,6 +79,12 @@ export class Bitstream extends DSpaceObject implements ChildHALResource {
@link(BUNDLE)
bundle?: Observable>;
+ /**
+ * The checksum values fetched from the DB, local and S3 store.
+ */
+ @link(BITSTREAM_CHECKSUM)
+ checksum?: Observable>;
+
getParentLinkKey(): keyof this['_links'] {
return 'format';
}
diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html
index 4cb9577fcb5..b5c84ab8760 100644
--- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html
+++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html
@@ -32,6 +32,7 @@
{{'item.edit.bitstreams.headers.description' | translate}}
{{'item.edit.bitstreams.headers.format' | translate}}
{{'item.edit.bitstreams.headers.actions' | translate}}
+ {{'item.edit.bitstreams.headers.synchronized' | translate}}
this.bundleService.getBitstreams(
this.bundle.id,
paginatedOptions,
- followLink('format')
+ followLink('format'),
+ followLink('checksum')
))
);
})
diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html
index a3e29ac10c2..dfd1c49fadf 100644
--- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html
+++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html
@@ -48,4 +48,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{'item.edit.bitstreams.checksum.database' | translate}}
+
+
+ {{'item.edit.bitstreams.checksum.algorithm' | translate}} {{bitstreamChecksum.databaseChecksum.checkSumAlgorithm}}
+
+
+ {{'item.edit.bitstreams.checksum.value' | translate}} {{ bitstreamChecksum.databaseChecksum.value }}
+
+
+
+
+ {{'item.edit.bitstreams.checksum.active-store' | translate}}
+
+
+ {{'item.edit.bitstreams.checksum.algorithm' | translate}} {{bitstreamChecksum.activeStore.checkSumAlgorithm}}
+
+
+ {{'item.edit.bitstreams.checksum.value' | translate}} {{ bitstreamChecksum.activeStore.value }}
+
+
+
+
+ {{'item.edit.bitstreams.checksum.sync-store' | translate}}
+
+
+ {{'item.edit.bitstreams.checksum.algorithm' | translate}} {{bitstreamChecksum.synchronizedStore.checkSumAlgorithm}}
+
+
+ {{'item.edit.bitstreams.checksum.value' | translate}} {{ bitstreamChecksum.synchronizedStore.value }}
+
+
+
diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.spec.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.spec.ts
index 306c0d41e39..fec8a62448a 100644
--- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.spec.ts
+++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.spec.ts
@@ -14,6 +14,7 @@ import { getBitstreamDownloadRoute } from '../../../../app-routing-paths';
import { By } from '@angular/platform-browser';
import { BrowserOnlyMockPipe } from '../../../../shared/testing/browser-only-mock.pipe';
import { RouterLinkDirectiveStub } from '../../../../shared/testing/router-link-directive.stub';
+import { BitstreamChecksum } from '../../../../core/shared/bitstream-checksum.model';
let comp: ItemEditBitstreamComponent;
let fixture: ComponentFixture;
@@ -21,13 +22,30 @@ let fixture: ComponentFixture;
const columnSizes = new ResponsiveTableSizes([
new ResponsiveColumnSizes(2, 2, 3, 4, 4),
new ResponsiveColumnSizes(2, 3, 3, 3, 3),
- new ResponsiveColumnSizes(2, 2, 2, 2, 2),
- new ResponsiveColumnSizes(6, 5, 4, 3, 3)
+ new ResponsiveColumnSizes(1, 1, 1, 1, 1),
+ new ResponsiveColumnSizes(5, 4, 3, 2, 2),
+ new ResponsiveColumnSizes(2, 2, 2, 2, 2)
]);
const format = Object.assign(new BitstreamFormat(), {
shortDescription: 'PDF'
});
+
+const checksum = Object.assign(new BitstreamChecksum(), {
+ activeStore: {
+ checkSumAlgorithm: 'MD5',
+ value: '123'
+ },
+ synchronizedStore: {
+ checkSumAlgorithm: 'MD5',
+ value: '456'
+ },
+ databaseChecksum: {
+ checkSumAlgorithm: 'MD5',
+ value: '789'
+ }
+});
+
const bitstream = Object.assign(new Bitstream(), {
uuid: 'bitstreamUUID',
name: 'Fake Bitstream',
@@ -37,7 +55,8 @@ const bitstream = Object.assign(new Bitstream(), {
content: { href: 'content-link' }
},
- format: createSuccessfulRemoteDataObject$(format)
+ format: createSuccessfulRemoteDataObject$(format),
+ checksum: createSuccessfulRemoteDataObject$(checksum)
});
const fieldUpdate = {
field: bitstream,
@@ -81,7 +100,7 @@ describe('ItemEditBitstreamComponent', () => {
RouterLinkDirectiveStub
],
providers: [
- { provide: ObjectUpdatesService, useValue: objectUpdatesService }
+ { provide: ObjectUpdatesService, useValue: objectUpdatesService },
], schemas: [
NO_ERRORS_SCHEMA
]
diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts
index fcb5c706ac7..a4c81901304 100644
--- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts
+++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts
@@ -1,15 +1,20 @@
import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core';
-import { Bitstream } from '../../../../core/shared/bitstream.model';
+import { Bitstream, SYNCHRONIZED_STORES_NUMBER } from '../../../../core/shared/bitstream.model';
import cloneDeep from 'lodash/cloneDeep';
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
import { Observable } from 'rxjs';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
-import { getRemoteDataPayload, getFirstSucceededRemoteData } from '../../../../core/shared/operators';
+import {
+ getRemoteDataPayload,
+ getFirstSucceededRemoteData,
+ getFirstCompletedRemoteData
+} from '../../../../core/shared/operators';
import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { FieldUpdate } from '../../../../core/data/object-updates/field-update.model';
import { FieldChangeType } from '../../../../core/data/object-updates/field-change-type.model';
import { getBitstreamDownloadRoute } from '../../../../app-routing-paths';
+import { BitstreamChecksum, CheckSum } from '../../../../core/shared/bitstream-checksum.model';
@Component({
selector: 'ds-item-edit-bitstream',
@@ -63,6 +68,16 @@ export class ItemEditBitstreamComponent implements OnChanges, OnInit {
*/
format$: Observable;
+ /**
+ * True on mouseover, false otherwise
+ */
+ showChecksumValues = false;
+
+ /**
+ * Object containing all checksums
+ */
+ checkSum$: Observable;
+
constructor(private objectUpdatesService: ObjectUpdatesService,
private dsoNameService: DSONameService,
private viewContainerRef: ViewContainerRef) {
@@ -84,6 +99,10 @@ export class ItemEditBitstreamComponent implements OnChanges, OnInit {
getFirstSucceededRemoteData(),
getRemoteDataPayload()
);
+ this.checkSum$ = this.bitstream.checksum.pipe(
+ getFirstCompletedRemoteData(),
+ getRemoteDataPayload()
+ );
}
/**
@@ -114,4 +133,37 @@ export class ItemEditBitstreamComponent implements OnChanges, OnInit {
return this.fieldUpdate.changeType >= 0;
}
+ /**
+ * Compare if two checksums are equal
+ *
+ * @param checksum1 e.g. DB checksum
+ * @param checksum2 e.g. Active store checksum (local or S3)
+ */
+ compareChecksums(checksum1: CheckSum, checksum2: CheckSum): boolean {
+ return checksum1.value === checksum2.value && checksum1.checkSumAlgorithm === checksum2.checkSumAlgorithm;
+ }
+
+ /**
+ * Compare if all checksums are equal (DB, Active store, Synchronized store)
+ *
+ * @param bitstreamChecksum which contains all checksums
+ */
+ checksumsAreEqual(bitstreamChecksum: BitstreamChecksum): boolean {
+ if (this.isBitstreamSynchronized()) {
+ // Compare DB and Active store checksums
+ // Compare DB and Synchronized and Active store checksums
+ return this.compareChecksums(bitstreamChecksum.databaseChecksum, bitstreamChecksum.activeStore) &&
+ this.compareChecksums(bitstreamChecksum.synchronizedStore, bitstreamChecksum.activeStore);
+ }
+ // Compare DB and Active store checksums
+ return this.compareChecksums(bitstreamChecksum.databaseChecksum, bitstreamChecksum.activeStore);
+ }
+
+ /**
+ * Check if the bitstream is stored in both stores (S3 and local)
+ */
+ isBitstreamSynchronized() {
+ return this.bitstream?.storeNumber === SYNCHRONIZED_STORES_NUMBER;
+ }
+
}
diff --git a/src/app/login-page/autoregistration/autoregistration.component.html b/src/app/login-page/autoregistration/autoregistration.component.html
index 8b9ac388f4e..8c2343ab387 100644
--- a/src/app/login-page/autoregistration/autoregistration.component.html
+++ b/src/app/login-page/autoregistration/autoregistration.component.html
@@ -1,4 +1,4 @@
-
+
{{'clarin.autoregistration.welcome.message' | translate}} {{dspaceName$ | async}}
diff --git a/src/app/login-page/autoregistration/autoregistration.component.ts b/src/app/login-page/autoregistration/autoregistration.component.ts
index 9ae0681ff18..bfd67f62e85 100644
--- a/src/app/login-page/autoregistration/autoregistration.component.ts
+++ b/src/app/login-page/autoregistration/autoregistration.component.ts
@@ -23,6 +23,7 @@ import { hasSucceeded } from 'src/app/core/data/request-entry-state.model';
import { FindListOptions } from '../../core/data/find-list-options.model';
import { getBaseUrl } from '../../shared/clarin-shared-util';
import { ConfigurationProperty } from '../../core/shared/configuration-property.model';
+import { RemoteData } from '../../core/data/remote-data';
/**
* This component is showed up when the user has clicked on the `verification token`.
@@ -62,6 +63,12 @@ export class AutoregistrationComponent implements OnInit {
*/
baseUrl = '';
+ /**
+ * Show attributes passed from the IdP or not.
+ * It could be disabled by the cfg property `authentication-shibboleth.show.idp-attributes`
+ */
+ showAttributes: BehaviorSubject
= new BehaviorSubject(false);
+
constructor(protected router: Router,
public route: ActivatedRoute,
private requestService: RequestService,
@@ -82,6 +89,14 @@ export class AutoregistrationComponent implements OnInit {
// Load the `ClarinVerificationToken` based on the `verificationToken` value
this.loadVerificationToken();
await this.assignBaseUrl();
+ await this.loadShowAttributes().then((value: RemoteData) => {
+ const stringBoolean = value?.payload?.values?.[0];
+ this.showAttributes.next(stringBoolean === 'true');
+ });
+
+ if (this.showAttributes.value === false) {
+ this.sendAutoLoginRequest();
+ }
}
/**
@@ -241,8 +256,17 @@ export class AutoregistrationComponent implements OnInit {
return baseUrlResponse?.values?.[0];
});
}
-}
+ /**
+ * Load the `authentication-shibboleth.show.idp-attributes` property from the cfg
+ */
+ async loadShowAttributes(): Promise {
+ return await this.configurationService.findByPropertyName('authentication-shibboleth.show.idp-attributes')
+ .pipe(
+ getFirstCompletedRemoteData()
+ ).toPromise();
+ }
+}
/**
* ShibHeaders string value from the verificationToken$ parsed to the objects.
*/
diff --git a/src/app/shared/upload/uploader/uploader.component.ts b/src/app/shared/upload/uploader/uploader.component.ts
index c8963847e92..6bcedd0260e 100644
--- a/src/app/shared/upload/uploader/uploader.component.ts
+++ b/src/app/shared/upload/uploader/uploader.component.ts
@@ -1,7 +1,18 @@
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostListener, Input, Output, ViewEncapsulation, } from '@angular/core';
+import {
+ AfterViewInit,
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ EventEmitter,
+ HostListener,
+ Input,
+ OnInit,
+ Output,
+ ViewEncapsulation,
+} from '@angular/core';
import { firstValueFrom, Observable, of as observableOf } from 'rxjs';
-import { FileItem, FileUploader } from 'ng2-file-upload';
+import { FileUploader, FileUploaderOptions} from 'ng2-file-upload';
import uniqueId from 'lodash/uniqueId';
import { ScrollToService } from '@nicky-lenaers/ngx-scroll-to';
@@ -18,6 +29,7 @@ import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { RemoteData } from '../../../core/data/remote-data';
import { ConfigurationProperty } from '../../../core/shared/configuration-property.model';
import { TranslateService } from '@ngx-translate/core';
+import { FileLikeObject } from 'ng2-file-upload/file-upload/file-like-object.class';
export const MAX_UPLOAD_FILE_SIZE_CFG_PROPERTY = 'spring.servlet.multipart.max-file-size';
@Component({
@@ -28,7 +40,7 @@ export const MAX_UPLOAD_FILE_SIZE_CFG_PROPERTY = 'spring.servlet.multipart.max-f
encapsulation: ViewEncapsulation.Emulated
})
-export class UploaderComponent {
+export class UploaderComponent implements OnInit, AfterViewInit {
/**
* The message to show when drag files on the drop zone
@@ -120,6 +132,12 @@ export class UploaderComponent {
queueLimit: this.uploadFilesOptions.maxFileNumber,
});
+ // Update the max file size in the uploader options. Fetch the max file size from the BE configuration.
+ void this.getMaxFileSizeInBytes().then((maxFileSize) => {
+ this.uploader.options.maxFileSize = maxFileSize === -1 ? undefined : maxFileSize;
+ this.uploader.setOptions(this.uploader.options);
+ });
+
if (isUndefined(this.enableDragOverDocument)) {
this.enableDragOverDocument = false;
}
@@ -139,19 +157,6 @@ export class UploaderComponent {
this.onBeforeUpload = () => {return;};
}
this.uploader.onBeforeUploadItem = async (item) => {
- // Check if the file size is within the maximum upload size
- const canUpload = await this.checkFileSizeLimit(item);
- // If the file size is too large, emit an error and cancel all uploads
- if (!canUpload) {
- this.onUploadError.emit({
- item: item,
- response: this.translate.instant('submission.sections.upload.upload-failed.size-limit-exceeded'),
- status: 400,
- headers: {}
- });
- this.uploader.cancelAll();
- return;
- }
if (item.url !== this.uploader.options.url) {
item.url = this.uploader.options.url;
}
@@ -193,6 +198,16 @@ export class UploaderComponent {
this.onUploadError.emit({ item: item, response: response, status: status, headers: headers });
this.uploader.cancelAll();
};
+ this.uploader.onWhenAddingFileFailed = (item: any, filter: any, options: any) => {
+ if (this.itemFileSizeExceeded(item, options)) {
+ this.onUploadError.emit({
+ item: item,
+ response: this.translate.instant('submission.sections.upload.upload-failed.size-limit-exceeded'),
+ status: 400,
+ headers: {}
+ });
+ }
+ };
this.uploader.onProgressAll = () => this.onProgress();
this.uploader.onProgressItem = () => this.onProgress();
}
@@ -247,20 +262,20 @@ export class UploaderComponent {
this.cookieService.set(XSRF_COOKIE, token);
}
- // Check if the file size is within the maximum upload size
- private async checkFileSizeLimit(item: FileItem): Promise {
+ private async getMaxFileSizeInBytes() {
const maxFileUploadSize = await firstValueFrom(this.getMaxFileUploadSizeFromCfg());
if (maxFileUploadSize) {
const maxSizeInGigabytes = parseInt(maxFileUploadSize?.[0], 10);
- const maxSizeInBytes = this.gigabytesToBytes(maxSizeInGigabytes);
- // If maxSizeInBytes is -1, it means the value in the config is invalid. The file won't be uploaded and the user
- // will see error messages in the UI.
- if (maxSizeInBytes === -1) {
- return false;
- }
- return item?.file?.size <= maxSizeInBytes;
+ return this.gigabytesToBytes(maxSizeInGigabytes);
}
- return false;
+ // If maxSizeInBytes is -1, it means the value in the config is invalid. The file won't be uploaded and the user
+ // will see error messages in the UI.
+ return -1;
+ }
+ // Check if the file size is exceeded the maximum upload size
+ private itemFileSizeExceeded(item: FileLikeObject, options: FileUploaderOptions): boolean {
+ const maxSizeInBytes = options.maxFileSize;
+ return item?.size > maxSizeInBytes;
}
// Convert gigabytes to bytes
diff --git a/src/app/thumbnail/thumbnail.component.spec.ts b/src/app/thumbnail/thumbnail.component.spec.ts
index 29aebe03fc2..1f9fa6caed4 100644
--- a/src/app/thumbnail/thumbnail.component.spec.ts
+++ b/src/app/thumbnail/thumbnail.component.spec.ts
@@ -290,7 +290,8 @@ describe('ThumbnailComponent', () => {
bundle: { href: 'bundle.url' },
format: { href: 'format.url' },
content: { href: CONTENT },
- thumbnail: undefined
+ thumbnail: undefined,
+ checksum: undefined
};
});
diff --git a/src/assets/i18n/cs.json5 b/src/assets/i18n/cs.json5
index bbd929911e2..b965e838893 100644
--- a/src/assets/i18n/cs.json5
+++ b/src/assets/i18n/cs.json5
@@ -1039,6 +1039,10 @@
// "clarin.license.agreement.notification.cannot.send.email": "Error: cannot send the email.",
"clarin.license.agreement.notification.cannot.send.email": "Error: cannot send the email.",
+
+ // "clarin.bitstream.expired.dtoken.message": "The download token is expired, you will be redirected to the download page.",
+ "clarin.bitstream.expired.dtoken.message": "Platnost tokenu pro stahování vypršel, budete přesměrováni na stránku stahování.",
+
// "bitstream.download.page.back": "Back" ,
"bitstream.download.page.back" : "Zpět",
@@ -1513,7 +1517,7 @@
// "collection.edit.tabs.curate.head": "Curate",
- "collection.edit.tabs.curate.head" : "",
+ "collection.edit.tabs.curate.head" : "Kurátor",
// "collection.edit.tabs.curate.title": "Collection Edit - Curate",
"collection.edit.tabs.curate.title" : "Úprava kolekce - kurátor",
@@ -2164,7 +2168,7 @@
"curation-task.task.vscan.label" : "Virová kontrola",
// "curation-task.task.register-doi.label": "Register DOI",
- "curation-task.task.register-doi.label" : "Registrovat DOI",
+ "curation-task.task.registerdoi.label" : "Registrovat DOI",
@@ -3208,6 +3212,9 @@
// "item.edit.bitstreams.empty": "This item doesn't contain any bitstreams. Click the upload button to create one.",
"item.edit.bitstreams.empty" : "Tato položka neobsahuje žádné bitstreamy. Klikněte na tlačítko pro nahrání a jeden vytvořte.",
+ // "item.edit.bitstreams.headers.synchronized": "Synchronized",
+ "item.edit.bitstreams.headers.synchronized": "Synchronizováno",
+
// "item.edit.bitstreams.headers.actions": "Actions",
"item.edit.bitstreams.headers.actions" : "Akce",
@@ -3263,6 +3270,22 @@
"item.edit.bitstreams.upload-button" : "Nahrát",
+// "item.edit.bitstreams.checksum.algorithm": "Algorithm: ",
+ "item.edit.bitstreams.checksum.algorithm": "Algoritmus: ",
+
+// "item.edit.bitstreams.checksum.value": "Value: ",
+ "item.edit.bitstreams.checksum.value": "Hodnota: ",
+
+// "item.edit.bitstreams.checksum.database": "DB",
+ "item.edit.bitstreams.checksum.database": "DB",
+
+// "item.edit.bitstreams.checksum.active-store": "Active store",
+ "item.edit.bitstreams.checksum.active-store": "Aktivní úložiště",
+
+// "item.edit.bitstreams.checksum.sync-store": "Sync store",
+ "item.edit.bitstreams.checksum.sync-store": "Sync úložiště",
+
+
// "item.edit.delete.cancel": "Cancel",
"item.edit.delete.cancel" : "Zrušit",
@@ -7500,6 +7523,9 @@
// "submission.sections.upload.upload-successful": "Upload successful",
"submission.sections.upload.upload-successful" : "Úspěšné nahrání",
+ // "submission.sections.upload.upload-failed.size-limit-exceeded": "File size exceeds the maximum upload size",
+ "submission.sections.upload.upload-failed.size-limit-exceeded": "Soubor přesahuje maximální povolenou velikost",
+
// "submission.sections.accesses.form.discoverable-description": "When checked, this item will be discoverable in search/browse. When unchecked, the item will only be available via a direct link and will never appear in search/browse.",
"submission.sections.accesses.form.discoverable-description" : "Pokud je tato položka zaškrtnuta, bude ji možné hledat ve vyhledávání/prohlížení. Pokud není zaškrtnuta, bude položka dostupná pouze prostřednictvím přímého odkazu a nikdy se nezobrazí ve vyhledávání/prohlížení.",
diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5
index 0ec92262265..41456da3d75 100644
--- a/src/assets/i18n/en.json5
+++ b/src/assets/i18n/en.json5
@@ -699,6 +699,9 @@
"clarin.license.agreement.notification.check.email": "You will receive email with download link.",
"clarin.license.agreement.notification.cannot.send.email": "Error: cannot send the email.",
+
+ "clarin.bitstream.expired.dtoken.message": "The download token is expired, you will be redirected to the download page.",
+
"bitstream.download.page.back": "Back" ,
@@ -1462,7 +1465,7 @@
"curation-task.task.vscan.label": "Virus Scan",
- "curation-task.task.register-doi.label": "Register DOI",
+ "curation-task.task.registerdoi.label": "Register DOI",
@@ -2175,6 +2178,8 @@
"item.edit.bitstreams.empty": "This item doesn't contain any bitstreams. Click the upload button to create one.",
+ "item.edit.bitstreams.headers.synchronized": "Sync | Checksum",
+
"item.edit.bitstreams.headers.actions": "Actions",
"item.edit.bitstreams.headers.bundle": "Bundle",
@@ -2211,6 +2216,16 @@
"item.edit.bitstreams.upload-button": "Upload",
+ "item.edit.bitstreams.checksum.algorithm": "Algorithm: ",
+
+ "item.edit.bitstreams.checksum.value": "Value: ",
+
+ "item.edit.bitstreams.checksum.database": "DB",
+
+ "item.edit.bitstreams.checksum.active-store": "Active store",
+
+ "item.edit.bitstreams.checksum.sync-store": "Sync store",
+
"item.edit.delete.cancel": "Cancel",