From 5431f8855d91bacd2181a91f095b821d8fc65d0c Mon Sep 17 00:00:00 2001 From: William Welling Date: Tue, 16 Jan 2024 14:10:33 -0600 Subject: [PATCH 01/19] TAMU theme proxy license step --- src/app/core/shared/collection.model.ts | 9 + src/app/core/shared/license.model.ts | 7 + .../workspaceitem-section-license.model.ts | 5 + .../themed-section-licence.component.ts | 25 ++ src/assets/i18n/en.json5 | 22 +- .../license/section-license.component.html | 40 +++ .../license/section-license.component.ts | 298 ++++++++++++++++++ .../sections/license/section-license.model.ts | 16 + src/themes/tamu/assets/i18n/en.json5 | 22 ++ src/themes/tamu/eager-theme.module.ts | 7 +- src/themes/tamu/styles/_global-styles.scss | 32 +- 11 files changed, 480 insertions(+), 3 deletions(-) create mode 100644 src/app/submission/sections/license/themed-section-licence.component.ts create mode 100644 src/themes/tamu/app/submission/sections/license/section-license.component.html create mode 100644 src/themes/tamu/app/submission/sections/license/section-license.component.ts create mode 100644 src/themes/tamu/app/submission/sections/license/section-license.model.ts diff --git a/src/app/core/shared/collection.model.ts b/src/app/core/shared/collection.model.ts index c97c61eceb6..fd90db9c25c 100644 --- a/src/app/core/shared/collection.model.ts +++ b/src/app/core/shared/collection.model.ts @@ -33,6 +33,8 @@ export class Collection extends DSpaceObject implements ChildHALResource, Handle @deserialize _links: { license: HALLink; + // TAMU Customization - available licenses HALLink for this collection + licenses: HALLink; harvester: HALLink; mappedItems: HALLink; itemtemplate: HALLink; @@ -54,6 +56,13 @@ export class Collection extends DSpaceObject implements ChildHALResource, Handle @link(LICENSE) license?: Observable>; + /** + * TAMU Customization - The available licenses for this Collection + * Will be undefined unless the licenses {@link HALLink} has been resolved. + */ + @link(LICENSE) + licenses?: Observable>>; + /** * The logo for this Collection * Will be undefined unless the logo {@link HALLink} has been resolved. diff --git a/src/app/core/shared/license.model.ts b/src/app/core/shared/license.model.ts index 2b2477c1f8f..1cbd9102ef0 100644 --- a/src/app/core/shared/license.model.ts +++ b/src/app/core/shared/license.model.ts @@ -19,4 +19,11 @@ export class License extends DSpaceObject { */ @autoserialize text: string; + + /** + * TAMU Customization - The radio label for the license + */ + @autoserialize + label?: string; + } diff --git a/src/app/core/submission/models/workspaceitem-section-license.model.ts b/src/app/core/submission/models/workspaceitem-section-license.model.ts index 26f625871e7..6fc4788b718 100644 --- a/src/app/core/submission/models/workspaceitem-section-license.model.ts +++ b/src/app/core/submission/models/workspaceitem-section-license.model.ts @@ -17,4 +17,9 @@ export interface WorkspaceitemSectionLicenseObject { * A boolean representing if license has been granted */ granted: boolean; + + /** + * TAMU Customization - A string representing which license has been selected + */ + selected?: string; } diff --git a/src/app/submission/sections/license/themed-section-licence.component.ts b/src/app/submission/sections/license/themed-section-licence.component.ts new file mode 100644 index 00000000000..3e5e4b1c50c --- /dev/null +++ b/src/app/submission/sections/license/themed-section-licence.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; +import { ThemedComponent } from '../../../shared/theme-support/themed.component'; +import { SubmissionSectionLicenseComponent } from './section-license.component'; + +/** + * Themed wrapper for SubmissionSectionLicenseComponent + */ +@Component({ + selector: 'ds-themed-section-license', + styleUrls: [], + templateUrl: './../../../shared/theme-support/themed.component.html' +}) +export class ThemedSubmissionSectionLicenseComponent extends ThemedComponent { + protected getComponentName(): string { + return 'SubmissionSectionLicenseComponent'; + } + + protected importThemedComponent(themeName: string): Promise { + return import(`../../../themes/${themeName}/app/submission/sections/section-license.component`); + } + + protected importUnthemedComponent(): Promise { + return import(`./section-license.component`); + } +} diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index e08750fc464..3fa1a2dd236 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -4524,7 +4524,7 @@ "submission.sections.accesses.form.until-placeholder": "Until", - "submission.sections.license.granted-label": "I confirm the license above", + "submission.sections.license.granted-label": "I accept the terms of this license.", "submission.sections.license.required": "You must accept the license", @@ -5253,4 +5253,24 @@ "communityList.expandAll": "Expand All", "communityList.collapseAll": "Collapse All", + + "submission.sections.proxy-license.header": "Granting a License", + + "submission.sections.proxy-license.last-step-label": "There is one last step:", + + "submission.sections.proxy-license.last-step": "In order for OAKTrust to reproduce, translate and distribute your submission worldwide, you must agree to the following terms.", + + "submission.sections.proxy-license.instructions": "Please select the license that best matches your situation, grant the license by selecting 'I accept the terms of this license.'; and then click '+Deposit'.", + + "submission.sections.proxy-license.label": "Distribution license: ", + + "submission.sections.proxy-license.permission-upload-label": "Proxy Submission License: ", + + "submission.sections.proxy-license.permission-upload-instructions": "If you have a separate permission document from the copyright owner authorizing the release of this item, please attach it here.", + + "submission.sections.proxy-license.permission-upload-successful": "Proxy license permission upload successful", + + "submission.sections.proxy-license.permission-upload-failed": "Proxy license permission upload failed", + + "submission.sections.proxy-license.permission-upload-drop-message": "Drop permission document to attach to the item", } diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.html b/src/themes/tamu/app/submission/sections/license/section-license.component.html new file mode 100644 index 00000000000..dfa26a5796d --- /dev/null +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.html @@ -0,0 +1,40 @@ +
+
{{"submission.sections.proxy-license.header" | translate}}
+

+ {{"submission.sections.proxy-license.last-step-label" | translate}} + {{"submission.sections.proxy-license.last-step" | translate}} +

+

{{"submission.sections.proxy-license.instructions" | translate}}

+
+ +
+ +
+ +
+

+
+ +
+ + + {{"submission.sections.proxy-license.permission-upload-instructions" | translate}} +
+ +
+ + +
diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts new file mode 100644 index 00000000000..54a96bd6beb --- /dev/null +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -0,0 +1,298 @@ +import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@angular/core'; +import { DynamicCheckboxModel, DynamicFormLayout, DynamicRadioGroupModel, MATCH_DISABLED } from '@ng-dynamic-forms/core'; +import { TranslateService } from '@ngx-translate/core'; +import { BehaviorSubject, Observable, of } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; + +import { AuthService } from '../../../../../../app/core/auth/auth.service'; +import { CollectionDataService } from '../../../../../../app/core/data/collection-data.service'; +import { PaginatedList } from '../../../../../../app/core/data/paginated-list.model'; +import { RemoteData } from '../../../../../../app/core/data/remote-data'; +import { JsonPatchOperationsBuilder } from '../../../../../../app/core/json-patch/builder/json-patch-operations-builder'; +import { Collection } from '../../../../../../app/core/shared/collection.model'; +import { HALEndpointService } from '../../../../../../app/core/shared/hal-endpoint.service'; +import { License } from '../../../../../../app/core/shared/license.model'; +import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; +import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; +import { normalizeSectionData } from '../../../../../../app/core/submission/submission-response-parsing.service'; +import { isEmpty, isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; +import { FormBuilderService } from '../../../../../../app/shared/form/builder/form-builder.service'; +import { FormService } from '../../../../../../app/shared/form/form.service'; +import { NotificationsService } from '../../../../../../app/shared/notifications/notifications.service'; +import { UploaderOptions } from '../../../../../../app/shared/upload/uploader/uploader-options.model'; +import { followLink } from '../../../../../../app/shared/utils/follow-link-config.model'; +import { SectionFormOperationsService } from '../../../../../../app/submission/sections/form/section-form-operations.service'; +import { SubmissionSectionLicenseComponent as BaseComponent } from '../../../../../../app/submission/sections/license/section-license.component'; +import { SectionDataObject } from '../../../../../../app/submission/sections/models/section-data.model'; +import { renderSectionFor } from '../../../../../../app/submission/sections/sections-decorator'; +import { SectionsType } from '../../../../../../app/submission/sections/sections-type'; +import { SectionsService } from '../../../../../../app/submission/sections/sections.service'; +import { SubmissionService } from '../../../../../../app/submission/submission.service'; +import parseSectionErrors from '../../../../../../app/submission/utils/parseSectionErrors'; +import { SECTION_LICENSE_FORM_LAYOUT } from './section-license.model'; + +/** + * This component represents a section that contains the submission license form. + */ +@Component({ + selector: 'ds-submission-section-license', + // styleUrls: ['./section-license.component.scss'], + templateUrl: './section-license.component.html', + // templateUrl: '../../../../../../app/submission/sections/license/section-license.component.html', +}) +@renderSectionFor(SectionsType.License) +export class SubmissionSectionLicenseComponent extends BaseComponent { + + /** + * The [[DynamicFormLayout]] object + * @type {DynamicFormLayout} + */ + public formLayout: DynamicFormLayout = SECTION_LICENSE_FORM_LAYOUT; + + /** + * The uploader configuration options + * @type {UploaderOptions} + */ + public uploadFilesOptions: UploaderOptions = new UploaderOptions(); + + /** + * A boolean representing if is possible to active drop zone over the document page + * @type {boolean} + */ + public enableDragOverDocument = true; + + /** + * i18n message label + * @type {string} + */ + public dropMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; + + /** + * i18n message label + * @type {string} + */ + public dropOverDocumentMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; + + /** + * The license label wrapper element reference + */ + @ViewChild('labelWrapper') private labelWrapper: ElementRef; + + /** + * The license text wrapper element reference + */ + @ViewChild('licenseWrapper') private licenseWrapper: ElementRef; + + /** + * The proxy permission license uploader wrapper element reference + */ + @ViewChild('uploaderWrapper') private uploaderWrapper: ElementRef; + + /** + * The license step form wrapper element reference + */ + @ViewChild('formWrapper') private formWrapper: ElementRef; + + private _license: BehaviorSubject; + + public get license(): Observable { + return this._license.asObservable(); + } + + private _proxy: BehaviorSubject; + + public get proxy(): Observable { + return this._proxy.asObservable(); + } + + constructor( + private authService: AuthService, + private halEndpointService: HALEndpointService, + private notificationsService: NotificationsService, + protected changeDetectorRef: ChangeDetectorRef, + protected collectionDataService: CollectionDataService, + protected formBuilderService: FormBuilderService, + protected formOperationsService: SectionFormOperationsService, + protected formService: FormService, + protected operationsBuilder: JsonPatchOperationsBuilder, + protected sectionService: SectionsService, + protected submissionService: SubmissionService, + protected translateService: TranslateService, + @Inject('collectionIdProvider') public injectedCollectionId: string, + @Inject('sectionDataProvider') public injectedSectionData: SectionDataObject, + @Inject('submissionIdProvider') public injectedSubmissionId: string + ) { + super( + changeDetectorRef, + collectionDataService, + formBuilderService, + formOperationsService, + formService, + operationsBuilder, + sectionService, + submissionService, + translateService, + injectedCollectionId, + injectedSectionData, + injectedSubmissionId + ); + this._license = new BehaviorSubject(undefined); + this._proxy = new BehaviorSubject(false); + } + + ngOnInit(): void { + this.subs.push( + this.halEndpointService.getEndpoint(this.submissionService.getSubmissionObjectLinkName()).pipe( + filter((href: string) => isNotEmpty(href)), + distinctUntilChanged()) + .subscribe((endpointURL) => { + this.uploadFilesOptions.authToken = this.authService.buildAuthHeader(); + this.uploadFilesOptions.url = endpointURL.concat(`/${this.submissionId}`); + this.changeDetectorRef.detectChanges(); + }) + ); + + + // get the license by following collection link + this.collectionDataService.findById(this.collectionId, true, true, followLink('licenses')).pipe( + filter((collectionData: RemoteData) => isNotUndefined((collectionData.payload))), + take(1), + switchMap((collectionData: RemoteData) => (collectionData.payload as any).licenses), + filter((licenseData: RemoteData>) => licenseData.hasSucceeded), + map((licenseData: RemoteData>) => licenseData.payload.page), + filter((licences: License[]) => !!licences && Array.isArray(licences) && licences.length > 0), + take(1) + ).subscribe((licences: License[]) => { + + // initialize the base component + this.onSectionInit(); + + // create a license form model with license options + const licenseFormModel = this.formBuilderService.fromJSON([ + { + id: 'selected', + options: licences.map((license: License) => { + return { + label: license.label, + value: license.name + }; + }), + type: 'RADIO_GROUP', + } + ]); + + const getLicense = (name: string) => licences.find((license: License) => license.name === name); + + // get the license granted form control model + const grantedFormControlModel = this.formBuilderService.findById('granted', this.formModel); + + // get the license selected form control model + const selectionFormControlModel = this.formBuilderService.findById('selected', licenseFormModel); + + this.subs.push( + // listen license selected/change and show license + (selectionFormControlModel as DynamicRadioGroupModel).valueChanges.pipe( + filter((name: string) => !!name) + ).subscribe((name: string) => { + + if (name !== (this.sectionData.data as WorkspaceitemSectionLicenseObject).selected) { + (grantedFormControlModel as DynamicCheckboxModel).value = false; + } + + const isProxy = name === 'proxy'; + + // temporary workaround to figuring out theming custom dynamic form model component + setTimeout(() => { + let children = this.formWrapper.nativeElement.children; + while (!!children && children.length > 0 && !children[0].classList.contains('tamu-control')) { + children = children[0].children; + } + let control = children[children.length - 1]; + while (control.classList.contains('tamu-control-license')) { + control.remove(); + control = children[children.length - 1]; + } + + control.parentNode.insertBefore(this.labelWrapper.nativeElement, control.nextSibling); + + if (isProxy) { + control.parentNode.insertBefore(this.uploaderWrapper.nativeElement, control.nextSibling); + } + + control.parentNode.insertBefore(this.licenseWrapper.nativeElement, control.nextSibling); + + const license = getLicense(name); + + this._proxy.next(isProxy); + this._license.next(license.text.replace(/\n/g, '
')); + }); + }) + ); + + (selectionFormControlModel as DynamicRadioGroupModel).value = (this.sectionData.data as WorkspaceitemSectionLicenseObject).selected; + + grantedFormControlModel.relations.push({ + match: MATCH_DISABLED, + when: [{ id: 'selected', value: null }], + }); + + // add the license form control model to the base component form model + this.formModel.unshift(selectionFormControlModel); + + this.updateSectionStatus(); + }); + } + + /** + * Save submission before to upload a file + */ + public onBeforeUpload = () => { + return of(); + }; + + /** + * Parse the submission object retrieved from REST after upload + * + * @param workspaceitem + * The submission object retrieved from REST + */ + public onCompleteItem(workspaceitem: WorkspaceItem) { + const { sections } = workspaceitem; + const { errors } = workspaceitem; + console.log(sections); + console.log(errors); + const errorsList = parseSectionErrors(errors); + console.log(errorsList); + if (sections && isNotEmpty(sections)) { + Object.keys(sections) + .forEach((sectionId) => { + const sectionData = normalizeSectionData(sections[sectionId]); + console.log(sectionData); + const sectionErrors = errorsList[sectionId]; + console.log(sectionErrors); + this.sectionService.isSectionType(this.submissionId, sectionId, SectionsType.License) + .pipe(take(1)) + .subscribe((isUpload) => { + if (isUpload) { + // Look for errors on upload + if ((isEmpty(sectionErrors))) { + this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); + } else { + console.log('these', sectionErrors); + this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.permission-upload-failed')); + } + } + }); + this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData, sectionErrors, sectionErrors); + }); + } + } + + /** + * Show error notification on upload fails + */ + public onUploadError() { + this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.permission-upload-failed')); + } + +} diff --git a/src/themes/tamu/app/submission/sections/license/section-license.model.ts b/src/themes/tamu/app/submission/sections/license/section-license.model.ts new file mode 100644 index 00000000000..662f55089d1 --- /dev/null +++ b/src/themes/tamu/app/submission/sections/license/section-license.model.ts @@ -0,0 +1,16 @@ +export const SECTION_LICENSE_FORM_LAYOUT = { + selected: { + element: { + container: 'tamu-control tamu-radio pl-1', + control: 'tamu-control-input', + label: 'tamu-control-label pt-1' + } + }, + granted: { + element: { + container: 'custom-control custom-checkbox pl-1', + control: 'custom-control-input', + label: 'custom-control-label pt-1' + } + } +}; diff --git a/src/themes/tamu/assets/i18n/en.json5 b/src/themes/tamu/assets/i18n/en.json5 index 11e2a9f6d6f..aca6e21f32c 100644 --- a/src/themes/tamu/assets/i18n/en.json5 +++ b/src/themes/tamu/assets/i18n/en.json5 @@ -19,4 +19,26 @@ "communityList.collapseAll": "Collapse All", + "submission.sections.license.granted-label": "I accept the terms of this license.", + + "submission.sections.proxy-license.label": "Distribution license: ", + + "submission.sections.proxy-license.header": "Granting a License", + + "submission.sections.proxy-license.last-step-label": "There is one last step:", + + "submission.sections.proxy-license.last-step": "In order for OAKTrust to reproduce, translate and distribute your submission worldwide, you must agree to the following terms.", + + "submission.sections.proxy-license.instructions": "Please select the license that best matches your situation, grant the license by selecting 'I accept the terms of this license.'; and then click '+Deposit'.", + + "submission.sections.proxy-license.permission-upload-label": "Proxy Submission License: ", + + "submission.sections.proxy-license.permission-upload-drop-message": "Drop permission document to attach to the item", + + "submission.sections.proxy-license.permission-upload-instructions": "If you have a separate permission document from the copyright owner authorizing the release of this item, please attach it here.", + + "submission.sections.proxy-license.permission-upload-successful": "Proxy license permission upload successful", + + "submission.sections.proxy-license.permission-upload-failed": "Proxy license permission upload failed", + } diff --git a/src/themes/tamu/eager-theme.module.ts b/src/themes/tamu/eager-theme.module.ts index fea4fecd485..459ad0199f9 100644 --- a/src/themes/tamu/eager-theme.module.ts +++ b/src/themes/tamu/eager-theme.module.ts @@ -8,6 +8,7 @@ import { RootModule } from '../../app/root.module'; import { SharedBrowseByModule } from '../../app/shared/browse-by/shared-browse-by.module'; import { ComcolModule } from '../../app/shared/comcol/comcol.module'; import { DsoPageModule } from '../../app/shared/dso-page/dso-page.module'; +import { FormModule } from '../../app/shared/form/form.module'; import { ResultsBackButtonModule } from '../../app/shared/results-back-button/results-back-button.module'; import { SharedModule } from '../../app/shared/shared.module'; import { StatisticsModule } from '../../app/statistics/statistics.module'; @@ -17,13 +18,15 @@ import { HeaderNavbarWrapperComponent } from './app/header-nav-wrapper/header-na import { HeaderComponent } from './app/header/header.component'; import { HomeNewsComponent } from './app/home-page/home-news/home-news.component'; import { NavbarComponent } from './app/navbar/navbar.component'; +import { SubmissionSectionLicenseComponent } from './app/submission/sections/license/section-license.component'; /** * Add components that use a custom decorator to ENTRY_COMPONENTS as well as DECLARATIONS. * This will ensure that decorator gets picked up when the app loads */ const ENTRY_COMPONENTS = [ - CommunityPageComponent + CommunityPageComponent, + SubmissionSectionLicenseComponent ]; const DECLARATIONS = [ @@ -38,6 +41,7 @@ const DECLARATIONS = [ @NgModule({ imports: [ CommonModule, + FormModule, SharedModule, SharedBrowseByModule, ResultsBackButtonModule, @@ -46,6 +50,7 @@ const DECLARATIONS = [ ComcolModule, DsoPageModule, StatisticsModule, + // SubmissionModule, CommunityPageModule, CdkTreeModule, ], diff --git a/src/themes/tamu/styles/_global-styles.scss b/src/themes/tamu/styles/_global-styles.scss index 5bd4c19bc04..6757c6956e5 100644 --- a/src/themes/tamu/styles/_global-styles.scss +++ b/src/themes/tamu/styles/_global-styles.scss @@ -3,7 +3,8 @@ // imports the base global style @import '../../../styles/_global-styles.scss'; -.facet-filter, .setting-option { +.facet-filter, +.setting-option { background-color: var(--bs-light); border-radius: var(--bs-border-radius); @@ -21,3 +22,32 @@ font-size: 1.1rem } } + +.tamu-control-input { + display: flex; + flex-direction: column; + + label { + text-align: left; + padding-left: 0px; + box-shadow: none !important; + + input[type=radio] { + position: relative !important; + } + + span { + margin-left: 10px !important; + } + } +} + +.tamu-control-label { + font-weight: bold; + margin: 15px 0px 0px 0px; +} + + +.tamu-control-license { + margin: 0px 0px 10px 0px; +} From d5ed1f6359d213bfd47ffdd01f96bdbd4e36dad7 Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 01:42:54 -0600 Subject: [PATCH 02/19] Get submission workspace item bitstreams --- .../license/section-license.component.ts | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 54a96bd6beb..730c42147e8 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -5,6 +5,7 @@ import { BehaviorSubject, Observable, of } from 'rxjs'; import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; import { AuthService } from '../../../../../../app/core/auth/auth.service'; +import { BitstreamDataService } from '../../../../../../app/core/data/bitstream-data.service'; import { CollectionDataService } from '../../../../../../app/core/data/collection-data.service'; import { PaginatedList } from '../../../../../../app/core/data/paginated-list.model'; import { RemoteData } from '../../../../../../app/core/data/remote-data'; @@ -15,7 +16,7 @@ import { License } from '../../../../../../app/core/shared/license.model'; import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; import { normalizeSectionData } from '../../../../../../app/core/submission/submission-response-parsing.service'; -import { isEmpty, isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; +import { isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; import { FormBuilderService } from '../../../../../../app/shared/form/builder/form-builder.service'; import { FormService } from '../../../../../../app/shared/form/form.service'; import { NotificationsService } from '../../../../../../app/shared/notifications/notifications.service'; @@ -28,8 +29,9 @@ import { renderSectionFor } from '../../../../../../app/submission/sections/sect import { SectionsType } from '../../../../../../app/submission/sections/sections-type'; import { SectionsService } from '../../../../../../app/submission/sections/sections.service'; import { SubmissionService } from '../../../../../../app/submission/submission.service'; -import parseSectionErrors from '../../../../../../app/submission/utils/parseSectionErrors'; import { SECTION_LICENSE_FORM_LAYOUT } from './section-license.model'; +import { SubmissionObject } from 'src/app/core/submission/models/submission-object.model'; +import { Bitstream } from 'src/app/core/shared/bitstream.model'; /** * This component represents a section that contains the submission license form. @@ -43,6 +45,8 @@ import { SECTION_LICENSE_FORM_LAYOUT } from './section-license.model'; @renderSectionFor(SectionsType.License) export class SubmissionSectionLicenseComponent extends BaseComponent { + public licenseBitstreams: Observable>; + /** * The [[DynamicFormLayout]] object * @type {DynamicFormLayout} @@ -107,6 +111,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { constructor( private authService: AuthService, + private bitstreamService: BitstreamDataService, private halEndpointService: HALEndpointService, private notificationsService: NotificationsService, protected changeDetectorRef: ChangeDetectorRef, @@ -152,8 +157,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { }) ); - - // get the license by following collection link + // get the license by following collection licenses link this.collectionDataService.findById(this.collectionId, true, true, followLink('licenses')).pipe( filter((collectionData: RemoteData) => isNotUndefined((collectionData.payload))), take(1), @@ -201,7 +205,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { const isProxy = name === 'proxy'; - // temporary workaround to figuring out theming custom dynamic form model component + // simple workaround opposed to shimming themed custom dynamic form model component setTimeout(() => { let children = this.formWrapper.nativeElement.children; while (!!children && children.length > 0 && !children[0].classList.contains('tamu-control')) { @@ -217,6 +221,18 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { if (isProxy) { control.parentNode.insertBefore(this.uploaderWrapper.nativeElement, control.nextSibling); + + this.licenseBitstreams = this.submissionService.retrieveSubmission(this.submissionId).pipe( + filter((data: RemoteData) => !!data && data.isSuccess), + map((data: RemoteData) => data.payload), + switchMap((submission: SubmissionObject) => { + return this.bitstreamService.findAllByItemAndBundleName(submission.item, 'LICENSE', {}, true, true).pipe( + filter((data: RemoteData>) => !!data && data.isSuccess), + map((data: RemoteData>) => data.payload), + ) + })); + + this.licenseBitstreams.subscribe(console.log); } control.parentNode.insertBefore(this.licenseWrapper.nativeElement, control.nextSibling); @@ -243,53 +259,32 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { }); } - /** - * Save submission before to upload a file - */ - public onBeforeUpload = () => { + /** + * Nothing to do here + * + * @returns empty observable + */ + public onBeforeUpload = () => { return of(); - }; + }; /** - * Parse the submission object retrieved from REST after upload - * - * @param workspaceitem - * The submission object retrieved from REST + * Show success notification on upload successful */ public onCompleteItem(workspaceitem: WorkspaceItem) { const { sections } = workspaceitem; - const { errors } = workspaceitem; - console.log(sections); - console.log(errors); - const errorsList = parseSectionErrors(errors); - console.log(errorsList); if (sections && isNotEmpty(sections)) { Object.keys(sections) .forEach((sectionId) => { const sectionData = normalizeSectionData(sections[sectionId]); - console.log(sectionData); - const sectionErrors = errorsList[sectionId]; - console.log(sectionErrors); - this.sectionService.isSectionType(this.submissionId, sectionId, SectionsType.License) - .pipe(take(1)) - .subscribe((isUpload) => { - if (isUpload) { - // Look for errors on upload - if ((isEmpty(sectionErrors))) { - this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); - } else { - console.log('these', sectionErrors); - this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.permission-upload-failed')); - } - } - }); - this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData, sectionErrors, sectionErrors); + this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); + this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData); }); } } /** - * Show error notification on upload fails + * Show error notification on upload failed */ public onUploadError() { this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.permission-upload-failed')); From 8f35bc0fc483c4eac2f37b682c8885cbd9a511ae Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 11:41:01 -0600 Subject: [PATCH 03/19] Only notify success once and display upload proxy license filename --- .../license/section-license.component.html | 3 ++ .../license/section-license.component.ts | 51 ++++++++++++------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.html b/src/themes/tamu/app/submission/sections/license/section-license.component.html index dfa26a5796d..2301a553cc6 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.html +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.html @@ -25,6 +25,9 @@ [uploadFilesOptions]="uploadFilesOptions" (onCompleteItem)="onCompleteItem($event)" (onUploadError)="onUploadError()"> +
+ {{proxy.metadata['dc.source'][0].value}} +
{{"submission.sections.proxy-license.permission-upload-instructions" | translate}} diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 730c42147e8..c0700d42b90 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -10,11 +10,14 @@ import { CollectionDataService } from '../../../../../../app/core/data/collectio import { PaginatedList } from '../../../../../../app/core/data/paginated-list.model'; import { RemoteData } from '../../../../../../app/core/data/remote-data'; import { JsonPatchOperationsBuilder } from '../../../../../../app/core/json-patch/builder/json-patch-operations-builder'; +import { Bitstream } from '../../../../../../app/core/shared/bitstream.model'; import { Collection } from '../../../../../../app/core/shared/collection.model'; import { HALEndpointService } from '../../../../../../app/core/shared/hal-endpoint.service'; import { License } from '../../../../../../app/core/shared/license.model'; +import { SubmissionObject } from '../../../../../../app/core/submission/models/submission-object.model'; import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; +import { SubmissionJsonPatchOperationsService } from '../../../../../../app/core/submission/submission-json-patch-operations.service'; import { normalizeSectionData } from '../../../../../../app/core/submission/submission-response-parsing.service'; import { isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; import { FormBuilderService } from '../../../../../../app/shared/form/builder/form-builder.service'; @@ -30,8 +33,6 @@ import { SectionsType } from '../../../../../../app/submission/sections/sections import { SectionsService } from '../../../../../../app/submission/sections/sections.service'; import { SubmissionService } from '../../../../../../app/submission/submission.service'; import { SECTION_LICENSE_FORM_LAYOUT } from './section-license.model'; -import { SubmissionObject } from 'src/app/core/submission/models/submission-object.model'; -import { Bitstream } from 'src/app/core/shared/bitstream.model'; /** * This component represents a section that contains the submission license form. @@ -45,8 +46,6 @@ import { Bitstream } from 'src/app/core/shared/bitstream.model'; @renderSectionFor(SectionsType.License) export class SubmissionSectionLicenseComponent extends BaseComponent { - public licenseBitstreams: Observable>; - /** * The [[DynamicFormLayout]] object * @type {DynamicFormLayout} @@ -77,6 +76,16 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { */ public dropOverDocumentMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; + public proxyLicense: Observable; + + public get license(): Observable { + return this._license.asObservable() + } + + public get proxy(): Observable { + return this._proxy.asObservable(); + } + /** * The license label wrapper element reference */ @@ -99,21 +108,14 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { private _license: BehaviorSubject; - public get license(): Observable { - return this._license.asObservable(); - } - private _proxy: BehaviorSubject; - public get proxy(): Observable { - return this._proxy.asObservable(); - } - constructor( private authService: AuthService, private bitstreamService: BitstreamDataService, private halEndpointService: HALEndpointService, private notificationsService: NotificationsService, + private operationsService: SubmissionJsonPatchOperationsService, protected changeDetectorRef: ChangeDetectorRef, protected collectionDataService: CollectionDataService, protected formBuilderService: FormBuilderService, @@ -222,17 +224,21 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { if (isProxy) { control.parentNode.insertBefore(this.uploaderWrapper.nativeElement, control.nextSibling); - this.licenseBitstreams = this.submissionService.retrieveSubmission(this.submissionId).pipe( + this.proxyLicense = this.submissionService.retrieveSubmission(this.submissionId).pipe( filter((data: RemoteData) => !!data && data.isSuccess), map((data: RemoteData) => data.payload), + take(1), switchMap((submission: SubmissionObject) => { return this.bitstreamService.findAllByItemAndBundleName(submission.item, 'LICENSE', {}, true, true).pipe( filter((data: RemoteData>) => !!data && data.isSuccess), map((data: RemoteData>) => data.payload), + map((page: PaginatedList) => page.page), + map((bitstreams: Array) => bitstreams + .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION'))), ) })); - this.licenseBitstreams.subscribe(console.log); + this.proxyLicense.subscribe(console.log); } control.parentNode.insertBefore(this.licenseWrapper.nativeElement, control.nextSibling); @@ -265,6 +271,13 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * @returns empty observable */ public onBeforeUpload = () => { + // const sub: Subscription = this.operationsService.jsonPatchByResourceType( + // this.submissionService.getSubmissionObjectLinkName(), + // this.submissionId, + // 'sections') + // .subscribe(); + // this.subs.push(sub); + // return sub; return of(); }; @@ -276,10 +289,14 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { if (sections && isNotEmpty(sections)) { Object.keys(sections) .forEach((sectionId) => { - const sectionData = normalizeSectionData(sections[sectionId]); - this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); - this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData); + this.sectionService.isSectionType(this.submissionId, sectionId, SectionsType.License) + .pipe(take(1)) + .subscribe(() => { + const sectionData = normalizeSectionData(sections[sectionId]); + this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData); + }); }); + this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); } } From e0c048987b31a31348023a93baecd55632ba1145 Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 12:13:05 -0600 Subject: [PATCH 04/19] Some hacks until learning how dspace uses NGRX store --- .../license/section-license.component.html | 4 +- .../license/section-license.component.ts | 86 +++++++++++-------- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.html b/src/themes/tamu/app/submission/sections/license/section-license.component.html index 2301a553cc6..1b9713901b4 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.html +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.html @@ -15,7 +15,7 @@

-
+
-
+
{{proxy.metadata['dc.source'][0].value}}
{{"submission.sections.proxy-license.permission-upload-instructions" | translate}} diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index c0700d42b90..5c402a1b87c 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -1,8 +1,8 @@ import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@angular/core'; import { DynamicCheckboxModel, DynamicFormLayout, DynamicRadioGroupModel, MATCH_DISABLED } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, Observable, of } from 'rxjs'; -import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; +import { BehaviorSubject, Observable, Subscription, of } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; import { AuthService } from '../../../../../../app/core/auth/auth.service'; import { BitstreamDataService } from '../../../../../../app/core/data/bitstream-data.service'; @@ -76,14 +76,16 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { */ public dropOverDocumentMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; - public proxyLicense: Observable; + public get proxy(): Observable { + return this._proxy.asObservable() + } public get license(): Observable { return this._license.asObservable() } - public get proxy(): Observable { - return this._proxy.asObservable(); + public get selected(): Observable { + return this._selected.asObservable(); } /** @@ -106,16 +108,17 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { */ @ViewChild('formWrapper') private formWrapper: ElementRef; + private _proxy: BehaviorSubject; + private _license: BehaviorSubject; - private _proxy: BehaviorSubject; + private _selected: BehaviorSubject; constructor( private authService: AuthService, private bitstreamService: BitstreamDataService, private halEndpointService: HALEndpointService, private notificationsService: NotificationsService, - private operationsService: SubmissionJsonPatchOperationsService, protected changeDetectorRef: ChangeDetectorRef, protected collectionDataService: CollectionDataService, protected formBuilderService: FormBuilderService, @@ -143,8 +146,9 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { injectedSectionData, injectedSubmissionId ); + this._proxy = new BehaviorSubject(undefined); this._license = new BehaviorSubject(undefined); - this._proxy = new BehaviorSubject(false); + this._selected = new BehaviorSubject(undefined); } ngOnInit(): void { @@ -205,8 +209,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { (grantedFormControlModel as DynamicCheckboxModel).value = false; } - const isProxy = name === 'proxy'; - // simple workaround opposed to shimming themed custom dynamic form model component setTimeout(() => { let children = this.formWrapper.nativeElement.children; @@ -221,32 +223,27 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { control.parentNode.insertBefore(this.labelWrapper.nativeElement, control.nextSibling); - if (isProxy) { + if (name === 'proxy') { control.parentNode.insertBefore(this.uploaderWrapper.nativeElement, control.nextSibling); - this.proxyLicense = this.submissionService.retrieveSubmission(this.submissionId).pipe( - filter((data: RemoteData) => !!data && data.isSuccess), - map((data: RemoteData) => data.payload), - take(1), - switchMap((submission: SubmissionObject) => { - return this.bitstreamService.findAllByItemAndBundleName(submission.item, 'LICENSE', {}, true, true).pipe( - filter((data: RemoteData>) => !!data && data.isSuccess), - map((data: RemoteData>) => data.payload), - map((page: PaginatedList) => page.page), - map((bitstreams: Array) => bitstreams - .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION'))), - ) - })); - - this.proxyLicense.subscribe(console.log); + // another workaround, this time to not using the store + setTimeout(() => { + // should be one subscritpion with multiple action dispatched + this.fetchProxyLicenseBitstream().pipe(take(1)).subscribe((bitstream: Bitstream) => { + this._proxy.next(bitstream); + }); + }); + + } else { + this._proxy.next(undefined); } control.parentNode.insertBefore(this.licenseWrapper.nativeElement, control.nextSibling); const license = getLicense(name); - - this._proxy.next(isProxy); this._license.next(license.text.replace(/\n/g, '
')); + + this._selected.next(name); }); }) ); @@ -271,13 +268,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * @returns empty observable */ public onBeforeUpload = () => { - // const sub: Subscription = this.operationsService.jsonPatchByResourceType( - // this.submissionService.getSubmissionObjectLinkName(), - // this.submissionId, - // 'sections') - // .subscribe(); - // this.subs.push(sub); - // return sub; return of(); }; @@ -296,7 +286,11 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData); }); }); - this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); + // preferably dispatch action here to update observable to the store + this.fetchProxyLicenseBitstream().pipe(take(1)).subscribe((bitstream: Bitstream) => { + this._proxy.next(bitstream); + }); + this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); } } @@ -307,4 +301,24 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.permission-upload-failed')); } + /** + * Convenience method opposed to dispatching action and subscribing to the store. + * + * @returns Proxy license bitstream if attached + */ + private fetchProxyLicenseBitstream(): Observable { + return this.submissionService.retrieveSubmission(this.submissionId).pipe( + filter((data: RemoteData) => !!data && data.isSuccess), + map((data: RemoteData) => data.payload), + switchMap((submission: SubmissionObject) => { + return this.bitstreamService.findAllByItemAndBundleName(submission.item, 'LICENSE', {}, true, true).pipe( + filter((data: RemoteData>) => !!data && data.isSuccess), + map((data: RemoteData>) => data.payload), + map((page: PaginatedList) => page.page), + map((bitstreams: Array) => bitstreams + .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION'))), + ) + })); + } + } From 8cdd08dad6298efdca03470b16f4a2941b8bf15f Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 12:15:53 -0600 Subject: [PATCH 05/19] Add missing semicolons --- .../submission/sections/license/section-license.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 5c402a1b87c..42929b0c919 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -77,11 +77,11 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { public dropOverDocumentMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; public get proxy(): Observable { - return this._proxy.asObservable() + return this._proxy.asObservable(); } public get license(): Observable { - return this._license.asObservable() + return this._license.asObservable(); } public get selected(): Observable { From a2de62e4f7fd559f0fad008d46449d1798ebee4c Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 15:07:54 -0600 Subject: [PATCH 06/19] Some commenting out until resolving step concurrency issue --- .../license/section-license.component.html | 2 +- .../license/section-license.component.ts | 89 +++++++++---------- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.html b/src/themes/tamu/app/submission/sections/license/section-license.component.html index 1b9713901b4..d0709e082e0 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.html +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.html @@ -25,7 +25,7 @@ [uploadFilesOptions]="uploadFilesOptions" (onCompleteItem)="onCompleteItem($event)" (onUploadError)="onUploadError()"> -
+
{{proxy.metadata['dc.source'][0].value}}
{{"submission.sections.proxy-license.permission-upload-instructions" | translate}} diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 42929b0c919..da0a3e44fa2 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -1,11 +1,10 @@ import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@angular/core'; import { DynamicCheckboxModel, DynamicFormLayout, DynamicRadioGroupModel, MATCH_DISABLED } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, Observable, Subscription, of } from 'rxjs'; -import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; +import { BehaviorSubject, Observable, of } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; import { AuthService } from '../../../../../../app/core/auth/auth.service'; -import { BitstreamDataService } from '../../../../../../app/core/data/bitstream-data.service'; import { CollectionDataService } from '../../../../../../app/core/data/collection-data.service'; import { PaginatedList } from '../../../../../../app/core/data/paginated-list.model'; import { RemoteData } from '../../../../../../app/core/data/remote-data'; @@ -14,10 +13,8 @@ import { Bitstream } from '../../../../../../app/core/shared/bitstream.model'; import { Collection } from '../../../../../../app/core/shared/collection.model'; import { HALEndpointService } from '../../../../../../app/core/shared/hal-endpoint.service'; import { License } from '../../../../../../app/core/shared/license.model'; -import { SubmissionObject } from '../../../../../../app/core/submission/models/submission-object.model'; import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; -import { SubmissionJsonPatchOperationsService } from '../../../../../../app/core/submission/submission-json-patch-operations.service'; import { normalizeSectionData } from '../../../../../../app/core/submission/submission-response-parsing.service'; import { isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; import { FormBuilderService } from '../../../../../../app/shared/form/builder/form-builder.service'; @@ -76,9 +73,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { */ public dropOverDocumentMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; - public get proxy(): Observable { - return this._proxy.asObservable(); - } + public proxyLicense: Observable; public get license(): Observable { return this._license.asObservable(); @@ -108,15 +103,14 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { */ @ViewChild('formWrapper') private formWrapper: ElementRef; - private _proxy: BehaviorSubject; - private _license: BehaviorSubject; private _selected: BehaviorSubject; constructor( + // private activatedRoute: ActivatedRoute, private authService: AuthService, - private bitstreamService: BitstreamDataService, + // private bitstreamService: BitstreamDataService, private halEndpointService: HALEndpointService, private notificationsService: NotificationsService, protected changeDetectorRef: ChangeDetectorRef, @@ -146,7 +140,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { injectedSectionData, injectedSubmissionId ); - this._proxy = new BehaviorSubject(undefined); this._license = new BehaviorSubject(undefined); this._selected = new BehaviorSubject(undefined); } @@ -163,6 +156,40 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { }) ); + // observe the proxy bitstream! + // this.activatedRoute.data.pipe( + // map((data: any) => data.wsi), + // map((wsi: RemoteData) => wsi.payload), + // switchMap((data: any) => data.item.pipe( + // map((item: RemoteData) => item.payload), + // switchMap((item: any) => { + // console.log(item); + // return this.bitstreamService + // .findAllByItemAndBundleName(item, 'LICENSE', {}, true, true).pipe( + // map((data: RemoteData>) => data.payload), + // map((page: PaginatedList) => page.page), + // map((bitstreams: Array) => bitstreams + // .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION')))); + // }))) + // ).subscribe((bitstream: any) => { + // console.log('observing the proxy bitstream', bitstream); + // }); + + // this.submissionService.retrieveSubmission(this.submissionId).pipe( + // filter((data: RemoteData) => !!data && data.isSuccess), + // map((data: RemoteData) => data.payload), + // switchMap((submission: SubmissionObject) => this.bitstreamService + // .findAllByItemAndBundleName(submission.item, 'LICENSE', {}, true, true).pipe( + // filter((data: RemoteData>) => !!data && data.isSuccess), + // map((data: RemoteData>) => data.payload), + // map((page: PaginatedList) => page.page), + // map((bitstreams: Array) => bitstreams + // .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION')))))) + // .subscribe((bitstream: any) => { + // console.log('retrieve the proxy bitstream', bitstream); + // });; + + // get the license by following collection licenses link this.collectionDataService.findById(this.collectionId, true, true, followLink('licenses')).pipe( filter((collectionData: RemoteData) => isNotUndefined((collectionData.payload))), @@ -205,6 +232,8 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { filter((name: string) => !!name) ).subscribe((name: string) => { + console.log('select changed', name); + if (name !== (this.sectionData.data as WorkspaceitemSectionLicenseObject).selected) { (grantedFormControlModel as DynamicCheckboxModel).value = false; } @@ -226,16 +255,9 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { if (name === 'proxy') { control.parentNode.insertBefore(this.uploaderWrapper.nativeElement, control.nextSibling); - // another workaround, this time to not using the store - setTimeout(() => { - // should be one subscritpion with multiple action dispatched - this.fetchProxyLicenseBitstream().pipe(take(1)).subscribe((bitstream: Bitstream) => { - this._proxy.next(bitstream); - }); - }); + // this.proxyLicense = this.fetchProxyLicenseBitstream(); - } else { - this._proxy.next(undefined); + // this.proxyLicense.subscribe(console.log); } control.parentNode.insertBefore(this.licenseWrapper.nativeElement, control.nextSibling); @@ -268,6 +290,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * @returns empty observable */ public onBeforeUpload = () => { + this.submissionService.dispatchSave(this.submissionId, true); return of(); }; @@ -286,10 +309,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData); }); }); - // preferably dispatch action here to update observable to the store - this.fetchProxyLicenseBitstream().pipe(take(1)).subscribe((bitstream: Bitstream) => { - this._proxy.next(bitstream); - }); this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); } } @@ -301,24 +320,4 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.permission-upload-failed')); } - /** - * Convenience method opposed to dispatching action and subscribing to the store. - * - * @returns Proxy license bitstream if attached - */ - private fetchProxyLicenseBitstream(): Observable { - return this.submissionService.retrieveSubmission(this.submissionId).pipe( - filter((data: RemoteData) => !!data && data.isSuccess), - map((data: RemoteData) => data.payload), - switchMap((submission: SubmissionObject) => { - return this.bitstreamService.findAllByItemAndBundleName(submission.item, 'LICENSE', {}, true, true).pipe( - filter((data: RemoteData>) => !!data && data.isSuccess), - map((data: RemoteData>) => data.payload), - map((page: PaginatedList) => page.page), - map((bitstreams: Array) => bitstreams - .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION'))), - ) - })); - } - } From 938052740d5f08a1c07f73e0b09f48b2b4792153 Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 15:11:54 -0600 Subject: [PATCH 07/19] Not save submission before uploading proxy license --- .../submission/sections/license/section-license.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index da0a3e44fa2..9ab731f5df1 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -290,7 +290,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * @returns empty observable */ public onBeforeUpload = () => { - this.submissionService.dispatchSave(this.submissionId, true); + // this.submissionService.dispatchSave(this.submissionId, true); return of(); }; From e908183a68cb96ffc9195d703acabbe5be2f9a27 Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 15:44:05 -0600 Subject: [PATCH 08/19] Observe proxy license bitstream --- .../license/section-license.component.ts | 80 +++++++------------ 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 9ab731f5df1..bd2c0e17f39 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -2,9 +2,11 @@ import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@an import { DynamicCheckboxModel, DynamicFormLayout, DynamicRadioGroupModel, MATCH_DISABLED } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; +import { ActivatedRoute, Data } from '@angular/router'; import { AuthService } from '../../../../../../app/core/auth/auth.service'; +import { BitstreamDataService } from '../../../../../../app/core/data/bitstream-data.service'; import { CollectionDataService } from '../../../../../../app/core/data/collection-data.service'; import { PaginatedList } from '../../../../../../app/core/data/paginated-list.model'; import { RemoteData } from '../../../../../../app/core/data/remote-data'; @@ -30,6 +32,7 @@ import { SectionsType } from '../../../../../../app/submission/sections/sections import { SectionsService } from '../../../../../../app/submission/sections/sections.service'; import { SubmissionService } from '../../../../../../app/submission/submission.service'; import { SECTION_LICENSE_FORM_LAYOUT } from './section-license.model'; +import { Item } from 'src/app/core/shared/item.model'; /** * This component represents a section that contains the submission license form. @@ -73,7 +76,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { */ public dropOverDocumentMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; - public proxyLicense: Observable; + public proxyLicense: Observable; public get license(): Observable { return this._license.asObservable(); @@ -108,9 +111,9 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { private _selected: BehaviorSubject; constructor( - // private activatedRoute: ActivatedRoute, + private activatedRoute: ActivatedRoute, private authService: AuthService, - // private bitstreamService: BitstreamDataService, + private bitstreamService: BitstreamDataService, private halEndpointService: HALEndpointService, private notificationsService: NotificationsService, protected changeDetectorRef: ChangeDetectorRef, @@ -157,38 +160,30 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { ); // observe the proxy bitstream! - // this.activatedRoute.data.pipe( - // map((data: any) => data.wsi), - // map((wsi: RemoteData) => wsi.payload), - // switchMap((data: any) => data.item.pipe( - // map((item: RemoteData) => item.payload), - // switchMap((item: any) => { - // console.log(item); - // return this.bitstreamService - // .findAllByItemAndBundleName(item, 'LICENSE', {}, true, true).pipe( - // map((data: RemoteData>) => data.payload), - // map((page: PaginatedList) => page.page), - // map((bitstreams: Array) => bitstreams - // .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION')))); - // }))) - // ).subscribe((bitstream: any) => { - // console.log('observing the proxy bitstream', bitstream); - // }); - - // this.submissionService.retrieveSubmission(this.submissionId).pipe( - // filter((data: RemoteData) => !!data && data.isSuccess), - // map((data: RemoteData) => data.payload), - // switchMap((submission: SubmissionObject) => this.bitstreamService - // .findAllByItemAndBundleName(submission.item, 'LICENSE', {}, true, true).pipe( - // filter((data: RemoteData>) => !!data && data.isSuccess), - // map((data: RemoteData>) => data.payload), - // map((page: PaginatedList) => page.page), - // map((bitstreams: Array) => bitstreams - // .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION')))))) - // .subscribe((bitstream: any) => { - // console.log('retrieve the proxy bitstream', bitstream); - // });; + this.proxyLicense = this.activatedRoute.data.pipe( + tap(console.log), + map((data: Data) => data.wsi), + tap(console.log), + filter((wsird: RemoteData) => !!wsird && wsird.isSuccess), + map((wsird: RemoteData) => wsird.payload), + tap(console.log), + switchMap((wi: WorkspaceItem) => wi.item.pipe( + tap(console.log), + filter((ird: RemoteData) => !!ird && ird.isSuccess), + map((ird: RemoteData) => ird.payload), + tap(console.log), + switchMap((item: Item) => this.bitstreamService + .findAllByItemAndBundleName(item, 'LICENSE', {}, true, true).pipe( + filter((bplrd: RemoteData>) => !!bplrd && bplrd.isSuccess), + map((bplrd: RemoteData>) => bplrd.payload), + map((bpl: PaginatedList) => bpl.page), + map((bitstreams: Array) => bitstreams + .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION'))))))) + ); + this.proxyLicense.subscribe((bitstream: any) => { + console.log('observing the proxy bitstream', bitstream); + }); // get the license by following collection licenses link this.collectionDataService.findById(this.collectionId, true, true, followLink('licenses')).pipe( @@ -254,10 +249,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { if (name === 'proxy') { control.parentNode.insertBefore(this.uploaderWrapper.nativeElement, control.nextSibling); - - // this.proxyLicense = this.fetchProxyLicenseBitstream(); - - // this.proxyLicense.subscribe(console.log); } control.parentNode.insertBefore(this.licenseWrapper.nativeElement, control.nextSibling); @@ -290,7 +281,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * @returns empty observable */ public onBeforeUpload = () => { - // this.submissionService.dispatchSave(this.submissionId, true); return of(); }; @@ -300,15 +290,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { public onCompleteItem(workspaceitem: WorkspaceItem) { const { sections } = workspaceitem; if (sections && isNotEmpty(sections)) { - Object.keys(sections) - .forEach((sectionId) => { - this.sectionService.isSectionType(this.submissionId, sectionId, SectionsType.License) - .pipe(take(1)) - .subscribe(() => { - const sectionData = normalizeSectionData(sections[sectionId]); - this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData); - }); - }); + this.submissionService.dispatchSave(this.submissionId, true); this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); } } From 7b1d5e9f3d0f32be3f92ff99181bb145df71078a Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 15:44:23 -0600 Subject: [PATCH 09/19] Cleanup imports and remove console logs --- .../sections/license/section-license.component.ts | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index bd2c0e17f39..3907531fe56 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -5,6 +5,7 @@ import { BehaviorSubject, Observable, of } from 'rxjs'; import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; import { ActivatedRoute, Data } from '@angular/router'; +import { Item } from 'src/app/core/shared/item.model'; import { AuthService } from '../../../../../../app/core/auth/auth.service'; import { BitstreamDataService } from '../../../../../../app/core/data/bitstream-data.service'; import { CollectionDataService } from '../../../../../../app/core/data/collection-data.service'; @@ -17,7 +18,6 @@ import { HALEndpointService } from '../../../../../../app/core/shared/hal-endpoi import { License } from '../../../../../../app/core/shared/license.model'; import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; -import { normalizeSectionData } from '../../../../../../app/core/submission/submission-response-parsing.service'; import { isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; import { FormBuilderService } from '../../../../../../app/shared/form/builder/form-builder.service'; import { FormService } from '../../../../../../app/shared/form/form.service'; @@ -32,7 +32,6 @@ import { SectionsType } from '../../../../../../app/submission/sections/sections import { SectionsService } from '../../../../../../app/submission/sections/sections.service'; import { SubmissionService } from '../../../../../../app/submission/submission.service'; import { SECTION_LICENSE_FORM_LAYOUT } from './section-license.model'; -import { Item } from 'src/app/core/shared/item.model'; /** * This component represents a section that contains the submission license form. @@ -161,17 +160,12 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { // observe the proxy bitstream! this.proxyLicense = this.activatedRoute.data.pipe( - tap(console.log), map((data: Data) => data.wsi), - tap(console.log), filter((wsird: RemoteData) => !!wsird && wsird.isSuccess), map((wsird: RemoteData) => wsird.payload), - tap(console.log), switchMap((wi: WorkspaceItem) => wi.item.pipe( - tap(console.log), filter((ird: RemoteData) => !!ird && ird.isSuccess), map((ird: RemoteData) => ird.payload), - tap(console.log), switchMap((item: Item) => this.bitstreamService .findAllByItemAndBundleName(item, 'LICENSE', {}, true, true).pipe( filter((bplrd: RemoteData>) => !!bplrd && bplrd.isSuccess), @@ -181,10 +175,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION'))))))) ); - this.proxyLicense.subscribe((bitstream: any) => { - console.log('observing the proxy bitstream', bitstream); - }); - // get the license by following collection licenses link this.collectionDataService.findById(this.collectionId, true, true, followLink('licenses')).pipe( filter((collectionData: RemoteData) => isNotUndefined((collectionData.payload))), @@ -227,8 +217,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { filter((name: string) => !!name) ).subscribe((name: string) => { - console.log('select changed', name); - if (name !== (this.sectionData.data as WorkspaceitemSectionLicenseObject).selected) { (grantedFormControlModel as DynamicCheckboxModel).value = false; } @@ -290,6 +278,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { public onCompleteItem(workspaceitem: WorkspaceItem) { const { sections } = workspaceitem; if (sections && isNotEmpty(sections)) { + // save the selected license upon successful proxy license upload this.submissionService.dispatchSave(this.submissionId, true); this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); } From 6ffac150527cae0a0bc65b2517213ea23eac5b12 Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 18:52:36 -0600 Subject: [PATCH 10/19] Send section id as additional parameters of multipart form --- src/app/shared/upload/uploader/uploader-options.model.ts | 7 +++++++ src/app/shared/upload/uploader/uploader.component.ts | 1 + .../sections/license/section-license.component.ts | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/app/shared/upload/uploader/uploader-options.model.ts b/src/app/shared/upload/uploader/uploader-options.model.ts index 559fb0485b0..f30efb35546 100644 --- a/src/app/shared/upload/uploader/uploader-options.model.ts +++ b/src/app/shared/upload/uploader/uploader-options.model.ts @@ -22,6 +22,13 @@ export class UploaderOptions { */ maxFileNumber: number; + /** + * Additional parameters to inform which step made upload request + */ + additionalParameter?: { + [key: string]: any; + }; + /** * The request method to use for the file upload request */ diff --git a/src/app/shared/upload/uploader/uploader.component.ts b/src/app/shared/upload/uploader/uploader.component.ts index ef4ce4ee451..bc7ecc51928 100644 --- a/src/app/shared/upload/uploader/uploader.component.ts +++ b/src/app/shared/upload/uploader/uploader.component.ts @@ -109,6 +109,7 @@ export class UploaderComponent { autoUpload: this.uploadFilesOptions.autoUpload, method: this.uploadFilesOptions.method, queueLimit: this.uploadFilesOptions.maxFileNumber, + additionalParameter: this.uploadFilesOptions.additionalParameter, }); if (isUndefined(this.enableDragOverDocument)) { diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 3907531fe56..cee1ca5ae96 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@an import { DynamicCheckboxModel, DynamicFormLayout, DynamicRadioGroupModel, MATCH_DISABLED } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; import { ActivatedRoute, Data } from '@angular/router'; import { Item } from 'src/app/core/shared/item.model'; @@ -152,6 +152,9 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { filter((href: string) => isNotEmpty(href)), distinctUntilChanged()) .subscribe((endpointURL) => { + this.uploadFilesOptions.additionalParameter = { + sectionId: this.sectionData.id + }; this.uploadFilesOptions.authToken = this.authService.buildAuthHeader(); this.uploadFilesOptions.url = endpointURL.concat(`/${this.submissionId}`); this.changeDetectorRef.detectChanges(); From 8742072d07090296e6ead7b66346bfeace0401bd Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 18 Jan 2024 18:56:33 -0600 Subject: [PATCH 11/19] Add TAMU customization comments --- src/app/shared/upload/uploader/uploader-options.model.ts | 2 +- src/app/shared/upload/uploader/uploader.component.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/shared/upload/uploader/uploader-options.model.ts b/src/app/shared/upload/uploader/uploader-options.model.ts index f30efb35546..1735575dadd 100644 --- a/src/app/shared/upload/uploader/uploader-options.model.ts +++ b/src/app/shared/upload/uploader/uploader-options.model.ts @@ -23,7 +23,7 @@ export class UploaderOptions { maxFileNumber: number; /** - * Additional parameters to inform which step made upload request + * TAMU Customization - Additional parameters to inform which step made upload request */ additionalParameter?: { [key: string]: any; diff --git a/src/app/shared/upload/uploader/uploader.component.ts b/src/app/shared/upload/uploader/uploader.component.ts index bc7ecc51928..9cb4994c7c7 100644 --- a/src/app/shared/upload/uploader/uploader.component.ts +++ b/src/app/shared/upload/uploader/uploader.component.ts @@ -109,6 +109,7 @@ export class UploaderComponent { autoUpload: this.uploadFilesOptions.autoUpload, method: this.uploadFilesOptions.method, queueLimit: this.uploadFilesOptions.maxFileNumber, + // TAMU Customization - include additional parameter map to provide section id additionalParameter: this.uploadFilesOptions.additionalParameter, }); From e3def6fa2a764ca9ef6d0c478930332ef51a22da Mon Sep 17 00:00:00 2001 From: William Welling Date: Fri, 19 Jan 2024 09:44:38 -0600 Subject: [PATCH 12/19] Styling with download and remove proxy license bitstream --- .../license/section-license.component.html | 46 ++++++++++++++-- .../license/section-license.component.ts | 54 ++++++++++++++++--- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.html b/src/themes/tamu/app/submission/sections/license/section-license.component.html index d0709e082e0..30527ca7c5c 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.html +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.html @@ -25,9 +25,31 @@ [uploadFilesOptions]="uploadFilesOptions" (onCompleteItem)="onCompleteItem($event)" (onUploadError)="onUploadError()"> -
- {{proxy.metadata['dc.source'][0].value}} -
+ +
+
+
+ {{proxy.metadata['dc.source'][0].value}} ({{proxy.sizeBytes | dsFileSize}}) +
+
+ + + + + + +
+
+
+
{{"submission.sections.proxy-license.permission-upload-instructions" | translate}}
@@ -41,3 +63,21 @@ (dfChange)="onChange($event)">
+ + + + + + diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index cee1ca5ae96..fb1e279c44b 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -1,11 +1,11 @@ import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@angular/core'; +import { ActivatedRoute, Data } from '@angular/router'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { DynamicCheckboxModel, DynamicFormLayout, DynamicRadioGroupModel, MATCH_DISABLED } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; -import { ActivatedRoute, Data } from '@angular/router'; -import { Item } from 'src/app/core/shared/item.model'; import { AuthService } from '../../../../../../app/core/auth/auth.service'; import { BitstreamDataService } from '../../../../../../app/core/data/bitstream-data.service'; import { CollectionDataService } from '../../../../../../app/core/data/collection-data.service'; @@ -15,6 +15,7 @@ import { JsonPatchOperationsBuilder } from '../../../../../../app/core/json-patc import { Bitstream } from '../../../../../../app/core/shared/bitstream.model'; import { Collection } from '../../../../../../app/core/shared/collection.model'; import { HALEndpointService } from '../../../../../../app/core/shared/hal-endpoint.service'; +import { Item } from '../../../../../../app/core/shared/item.model'; import { License } from '../../../../../../app/core/shared/license.model'; import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; @@ -85,6 +86,10 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { return this._selected.asObservable(); } + public get removingProxy(): Observable { + return this._removing_proxy.asObservable(); + } + /** * The license label wrapper element reference */ @@ -109,11 +114,14 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { private _selected: BehaviorSubject; + private _removing_proxy: BehaviorSubject; + constructor( private activatedRoute: ActivatedRoute, private authService: AuthService, private bitstreamService: BitstreamDataService, private halEndpointService: HALEndpointService, + private modalService: NgbModal, private notificationsService: NotificationsService, protected changeDetectorRef: ChangeDetectorRef, protected collectionDataService: CollectionDataService, @@ -144,6 +152,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { ); this._license = new BehaviorSubject(undefined); this._selected = new BehaviorSubject(undefined); + this._removing_proxy = new BehaviorSubject(false); } ngOnInit(): void { @@ -161,23 +170,37 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { }) ); - // observe the proxy bitstream! + // observe the proxy bitstream this.proxyLicense = this.activatedRoute.data.pipe( map((data: Data) => data.wsi), + tap((d) => console.log('1', d)), filter((wsird: RemoteData) => !!wsird && wsird.isSuccess), + tap((d) => console.log('2', d)), map((wsird: RemoteData) => wsird.payload), + tap((d) => console.log('3', d)), switchMap((wi: WorkspaceItem) => wi.item.pipe( + tap((d) => console.log('4', d)), filter((ird: RemoteData) => !!ird && ird.isSuccess), + tap((d) => console.log('5', d)), map((ird: RemoteData) => ird.payload), + tap((d) => console.log('6', d)), switchMap((item: Item) => this.bitstreamService .findAllByItemAndBundleName(item, 'LICENSE', {}, true, true).pipe( + tap((d) => console.log('7', d)), filter((bplrd: RemoteData>) => !!bplrd && bplrd.isSuccess), + tap((d) => console.log('8', d)), map((bplrd: RemoteData>) => bplrd.payload), + tap((d) => console.log('9', d)), map((bpl: PaginatedList) => bpl.page), + tap((d) => console.log('10', d)), map((bitstreams: Array) => bitstreams .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION'))))))) ); + this.proxyLicense.subscribe((b) => { + console.log('result', b); + }); + // get the license by following collection licenses link this.collectionDataService.findById(this.collectionId, true, true, followLink('licenses')).pipe( filter((collectionData: RemoteData) => isNotUndefined((collectionData.payload))), @@ -224,7 +247,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { (grantedFormControlModel as DynamicCheckboxModel).value = false; } - // simple workaround opposed to shimming themed custom dynamic form model component setTimeout(() => { let children = this.formWrapper.nativeElement.children; while (!!children && children.length > 0 && !children[0].classList.contains('tamu-control')) { @@ -266,6 +288,26 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { }); } + /** + * Open confirm modal and remove when confirmed. + * + * @param content element reference for modal + * @param bitstream proxy license bitstream + */ + public confirmRemoveProxy(content, bitstream): void { + this.modalService.open(content).result.then( + (result) => { + if (result === 'ok') { + this._removing_proxy.next(true); + this.bitstreamService.delete(bitstream.id).pipe(take(1)).subscribe((results) => { + this._removing_proxy.next(false); + // this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); + }); + } + } + ); + } + /** * Nothing to do here * @@ -281,8 +323,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { public onCompleteItem(workspaceitem: WorkspaceItem) { const { sections } = workspaceitem; if (sections && isNotEmpty(sections)) { - // save the selected license upon successful proxy license upload - this.submissionService.dispatchSave(this.submissionId, true); this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); } } From 10be18cb644e8cada22bece06155f75494f5fc65 Mon Sep 17 00:00:00 2001 From: William Welling Date: Fri, 19 Jan 2024 13:51:01 -0600 Subject: [PATCH 13/19] Use section upload service and files on workspace item for license step --- .../workspaceitem-section-license.model.ts | 6 ++ src/assets/i18n/en.json5 | 12 +++ .../license/section-license.component.ts | 83 +++++++++---------- src/themes/tamu/assets/i18n/en.json5 | 12 +-- 4 files changed, 65 insertions(+), 48 deletions(-) diff --git a/src/app/core/submission/models/workspaceitem-section-license.model.ts b/src/app/core/submission/models/workspaceitem-section-license.model.ts index 6fc4788b718..2f42ca51b9b 100644 --- a/src/app/core/submission/models/workspaceitem-section-license.model.ts +++ b/src/app/core/submission/models/workspaceitem-section-license.model.ts @@ -1,3 +1,4 @@ +import { WorkspaceitemSectionUploadFileObject } from './workspaceitem-section-upload-file.model'; /** * An interface to represent submission's license section data. @@ -22,4 +23,9 @@ export interface WorkspaceitemSectionLicenseObject { * TAMU Customization - A string representing which license has been selected */ selected?: string; + + /** + * TAMU Customization - A list of license files [[WorkspaceitemSectionUploadFileObject]] + */ + files?: WorkspaceitemSectionUploadFileObject[]; } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 3fa1a2dd236..da049d98bb1 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -5273,4 +5273,16 @@ "submission.sections.proxy-license.permission-upload-failed": "Proxy license permission upload failed", "submission.sections.proxy-license.permission-upload-drop-message": "Drop permission document to attach to the item", + + "submission.sections.proxy-license.upload-label": "Proxy Submission License: ", + + "submission.sections.proxy-license.upload-drop-message": "Drop permission document to attach to the item", + + "submission.sections.proxy-license.upload-instructions": "If you have a separate permission document from the copyright owner authorizing the release of this item, please attach it here.", + + "submission.sections.proxy-license.upload-successful": "Proxy license upload successful", + + "submission.sections.proxy-license.upload-failed": "Proxy license upload failed", + + "submission.sections.proxy-license.remove-successful": "Proxy license remove successful", } diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index fb1e279c44b..b3702a4efdd 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -1,5 +1,4 @@ import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@angular/core'; -import { ActivatedRoute, Data } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { DynamicCheckboxModel, DynamicFormLayout, DynamicRadioGroupModel, MATCH_DISABLED } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; @@ -12,14 +11,13 @@ import { CollectionDataService } from '../../../../../../app/core/data/collectio import { PaginatedList } from '../../../../../../app/core/data/paginated-list.model'; import { RemoteData } from '../../../../../../app/core/data/remote-data'; import { JsonPatchOperationsBuilder } from '../../../../../../app/core/json-patch/builder/json-patch-operations-builder'; -import { Bitstream } from '../../../../../../app/core/shared/bitstream.model'; import { Collection } from '../../../../../../app/core/shared/collection.model'; import { HALEndpointService } from '../../../../../../app/core/shared/hal-endpoint.service'; -import { Item } from '../../../../../../app/core/shared/item.model'; import { License } from '../../../../../../app/core/shared/license.model'; import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; -import { isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; +import { normalizeSectionData } from '../../../../../../app/core/submission/submission-response-parsing.service'; +import { isEmpty, isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; import { FormBuilderService } from '../../../../../../app/shared/form/builder/form-builder.service'; import { FormService } from '../../../../../../app/shared/form/form.service'; import { NotificationsService } from '../../../../../../app/shared/notifications/notifications.service'; @@ -31,7 +29,9 @@ import { SectionDataObject } from '../../../../../../app/submission/sections/mod import { renderSectionFor } from '../../../../../../app/submission/sections/sections-decorator'; import { SectionsType } from '../../../../../../app/submission/sections/sections-type'; import { SectionsService } from '../../../../../../app/submission/sections/sections.service'; +import { SectionUploadService } from '../../../../../../app/submission/sections/upload/section-upload.service'; import { SubmissionService } from '../../../../../../app/submission/submission.service'; +import parseSectionErrors from '../../../../../../app/submission/utils/parseSectionErrors'; import { SECTION_LICENSE_FORM_LAYOUT } from './section-license.model'; /** @@ -68,13 +68,13 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * i18n message label * @type {string} */ - public dropMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; + public dropMsg = 'submission.sections.proxy-license.upload-drop-message'; /** * i18n message label * @type {string} */ - public dropOverDocumentMsg = 'submission.sections.proxy-license.permission-upload-drop-message'; + public dropOverDocumentMsg = 'submission.sections.proxy-license.upload-drop-message'; public proxyLicense: Observable; @@ -117,12 +117,12 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { private _removing_proxy: BehaviorSubject; constructor( - private activatedRoute: ActivatedRoute, private authService: AuthService, private bitstreamService: BitstreamDataService, private halEndpointService: HALEndpointService, private modalService: NgbModal, private notificationsService: NotificationsService, + private sectionUploadService: SectionUploadService, protected changeDetectorRef: ChangeDetectorRef, protected collectionDataService: CollectionDataService, protected formBuilderService: FormBuilderService, @@ -170,36 +170,13 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { }) ); - // observe the proxy bitstream - this.proxyLicense = this.activatedRoute.data.pipe( - map((data: Data) => data.wsi), - tap((d) => console.log('1', d)), - filter((wsird: RemoteData) => !!wsird && wsird.isSuccess), - tap((d) => console.log('2', d)), - map((wsird: RemoteData) => wsird.payload), - tap((d) => console.log('3', d)), - switchMap((wi: WorkspaceItem) => wi.item.pipe( - tap((d) => console.log('4', d)), - filter((ird: RemoteData) => !!ird && ird.isSuccess), - tap((d) => console.log('5', d)), - map((ird: RemoteData) => ird.payload), - tap((d) => console.log('6', d)), - switchMap((item: Item) => this.bitstreamService - .findAllByItemAndBundleName(item, 'LICENSE', {}, true, true).pipe( - tap((d) => console.log('7', d)), - filter((bplrd: RemoteData>) => !!bplrd && bplrd.isSuccess), - tap((d) => console.log('8', d)), - map((bplrd: RemoteData>) => bplrd.payload), - tap((d) => console.log('9', d)), - map((bpl: PaginatedList) => bpl.page), - tap((d) => console.log('10', d)), - map((bitstreams: Array) => bitstreams - .find((bitstream: Bitstream) => bitstream.name.startsWith('PERMISSION'))))))) - ); - - this.proxyLicense.subscribe((b) => { - console.log('result', b); - }); + this.proxyLicense = this.sectionUploadService.getUploadedFileList(this.submissionId, this.sectionData.id) + .pipe( + tap(() => this._removing_proxy.next(false)), + filter((files) => !!files && files.length), + map((files) => files.find((file) => file.metadata['dc.description'] + && file.metadata['dc.description'].length > 0 + && file.metadata['dc.description'][0].value === 'Proxy license'))); // get the license by following collection licenses link this.collectionDataService.findById(this.collectionId, true, true, followLink('licenses')).pipe( @@ -292,16 +269,17 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * Open confirm modal and remove when confirmed. * * @param content element reference for modal - * @param bitstream proxy license bitstream + * @param proxy license bitstream */ - public confirmRemoveProxy(content, bitstream): void { + public confirmRemoveProxy(content, proxy): void { this.modalService.open(content).result.then( (result) => { if (result === 'ok') { this._removing_proxy.next(true); - this.bitstreamService.delete(bitstream.id).pipe(take(1)).subscribe((results) => { + this.bitstreamService.delete(proxy.uuid).pipe(take(1)).subscribe(() => { this._removing_proxy.next(false); - // this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); + this.sectionUploadService.removeUploadedFile(this.submissionId, this.sectionData.id, proxy.uuid); + this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.remove-successful')); }); } } @@ -322,8 +300,27 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { */ public onCompleteItem(workspaceitem: WorkspaceItem) { const { sections } = workspaceitem; + const { errors } = workspaceitem; + const errorsList = parseSectionErrors(errors); if (sections && isNotEmpty(sections)) { - this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.permission-upload-successful')); + Object.keys(sections) + .forEach((sectionId) => { + const sectionData = normalizeSectionData(sections[sectionId]); + const sectionErrors = errorsList[sectionId]; + this.sectionService.isSectionType(this.submissionId, sectionId, SectionsType.License) + .pipe(take(1)) + .subscribe((isLicence) => { + if (isLicence) { + // Look for errors on upload + if ((isEmpty(sectionErrors))) { + this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.upload-successful')); + } else { + this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.upload-failed')); + } + } + }); + this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData, sectionErrors, sectionErrors); + }); } } @@ -331,7 +328,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * Show error notification on upload failed */ public onUploadError() { - this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.permission-upload-failed')); + this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.upload-failed')); } } diff --git a/src/themes/tamu/assets/i18n/en.json5 b/src/themes/tamu/assets/i18n/en.json5 index aca6e21f32c..49c4f7fcbf6 100644 --- a/src/themes/tamu/assets/i18n/en.json5 +++ b/src/themes/tamu/assets/i18n/en.json5 @@ -31,14 +31,16 @@ "submission.sections.proxy-license.instructions": "Please select the license that best matches your situation, grant the license by selecting 'I accept the terms of this license.'; and then click '+Deposit'.", - "submission.sections.proxy-license.permission-upload-label": "Proxy Submission License: ", + "submission.sections.proxy-license.upload-label": "Proxy Submission License: ", - "submission.sections.proxy-license.permission-upload-drop-message": "Drop permission document to attach to the item", + "submission.sections.proxy-license.upload-drop-message": "Drop permission document to attach to the item", - "submission.sections.proxy-license.permission-upload-instructions": "If you have a separate permission document from the copyright owner authorizing the release of this item, please attach it here.", + "submission.sections.proxy-license.upload-instructions": "If you have a separate permission document from the copyright owner authorizing the release of this item, please attach it here.", - "submission.sections.proxy-license.permission-upload-successful": "Proxy license permission upload successful", + "submission.sections.proxy-license.upload-successful": "Proxy license upload successful", - "submission.sections.proxy-license.permission-upload-failed": "Proxy license permission upload failed", + "submission.sections.proxy-license.upload-failed": "Proxy license upload failed", + + "submission.sections.proxy-license.remove-successful": "Proxy license remove successful", } From 01d146992349fd1eba944f9ea0370e88647476ef Mon Sep 17 00:00:00 2001 From: William Welling Date: Fri, 19 Jan 2024 18:21:33 -0600 Subject: [PATCH 14/19] Subscribe to behavior subject directly in template --- .../license/section-license.component.ts | 45 ++++++------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index b3702a4efdd..94d2ee590ba 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -78,17 +78,11 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { public proxyLicense: Observable; - public get license(): Observable { - return this._license.asObservable(); - } + public license: BehaviorSubject; - public get selected(): Observable { - return this._selected.asObservable(); - } + public selected: BehaviorSubject; - public get removingProxy(): Observable { - return this._removing_proxy.asObservable(); - } + public removingProxy: BehaviorSubject; /** * The license label wrapper element reference @@ -110,12 +104,6 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { */ @ViewChild('formWrapper') private formWrapper: ElementRef; - private _license: BehaviorSubject; - - private _selected: BehaviorSubject; - - private _removing_proxy: BehaviorSubject; - constructor( private authService: AuthService, private bitstreamService: BitstreamDataService, @@ -150,9 +138,9 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { injectedSectionData, injectedSubmissionId ); - this._license = new BehaviorSubject(undefined); - this._selected = new BehaviorSubject(undefined); - this._removing_proxy = new BehaviorSubject(false); + this.license = new BehaviorSubject(undefined); + this.selected = new BehaviorSubject(undefined); + this.removingProxy = new BehaviorSubject(false); } ngOnInit(): void { @@ -172,13 +160,13 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { this.proxyLicense = this.sectionUploadService.getUploadedFileList(this.submissionId, this.sectionData.id) .pipe( - tap(() => this._removing_proxy.next(false)), + tap(() => this.removingProxy.next(false)), filter((files) => !!files && files.length), map((files) => files.find((file) => file.metadata['dc.description'] && file.metadata['dc.description'].length > 0 && file.metadata['dc.description'][0].value === 'Proxy license'))); - // get the license by following collection licenses link + // get the available licenses by following collection licenses link this.collectionDataService.findById(this.collectionId, true, true, followLink('licenses')).pipe( filter((collectionData: RemoteData) => isNotUndefined((collectionData.payload))), take(1), @@ -244,9 +232,9 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { control.parentNode.insertBefore(this.licenseWrapper.nativeElement, control.nextSibling); const license = getLicense(name); - this._license.next(license.text.replace(/\n/g, '
')); + this.license.next(license.text.replace(/\n/g, '
')); - this._selected.next(name); + this.selected.next(name); }); }) ); @@ -275,9 +263,9 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { this.modalService.open(content).result.then( (result) => { if (result === 'ok') { - this._removing_proxy.next(true); + this.removingProxy.next(true); this.bitstreamService.delete(proxy.uuid).pipe(take(1)).subscribe(() => { - this._removing_proxy.next(false); + this.removingProxy.next(false); this.sectionUploadService.removeUploadedFile(this.submissionId, this.sectionData.id, proxy.uuid); this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.remove-successful')); }); @@ -296,7 +284,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { }; /** - * Show success notification on upload successful + * Show success notification on upload successful and update section data */ public onCompleteItem(workspaceitem: WorkspaceItem) { const { sections } = workspaceitem; @@ -311,12 +299,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { .pipe(take(1)) .subscribe((isLicence) => { if (isLicence) { - // Look for errors on upload - if ((isEmpty(sectionErrors))) { - this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.upload-successful')); - } else { - this.notificationsService.error(null, this.translateService.get('submission.sections.proxy-license.upload-failed')); - } + this.notificationsService.success(null, this.translateService.get('submission.sections.proxy-license.upload-successful')); } }); this.sectionService.updateSectionData(this.submissionId, sectionId, sectionData, sectionErrors, sectionErrors); From 52a0e81c89cd3558f5217916d94a64632232007c Mon Sep 17 00:00:00 2001 From: William Welling Date: Fri, 19 Jan 2024 20:02:37 -0600 Subject: [PATCH 15/19] Remove unused import --- .../submission/sections/license/section-license.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 94d2ee590ba..251f7f0975a 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -17,7 +17,7 @@ import { License } from '../../../../../../app/core/shared/license.model'; import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; import { normalizeSectionData } from '../../../../../../app/core/submission/submission-response-parsing.service'; -import { isEmpty, isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; +import { isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; import { FormBuilderService } from '../../../../../../app/shared/form/builder/form-builder.service'; import { FormService } from '../../../../../../app/shared/form/form.service'; import { NotificationsService } from '../../../../../../app/shared/notifications/notifications.service'; From a8bd77ff48d97b217cbd7f490fc180702a73cb9d Mon Sep 17 00:00:00 2001 From: William Welling Date: Sat, 20 Jan 2024 22:08:40 -0600 Subject: [PATCH 16/19] Remove unnecessary themed component --- .../themed-section-licence.component.ts | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 src/app/submission/sections/license/themed-section-licence.component.ts diff --git a/src/app/submission/sections/license/themed-section-licence.component.ts b/src/app/submission/sections/license/themed-section-licence.component.ts deleted file mode 100644 index 3e5e4b1c50c..00000000000 --- a/src/app/submission/sections/license/themed-section-licence.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component } from '@angular/core'; -import { ThemedComponent } from '../../../shared/theme-support/themed.component'; -import { SubmissionSectionLicenseComponent } from './section-license.component'; - -/** - * Themed wrapper for SubmissionSectionLicenseComponent - */ -@Component({ - selector: 'ds-themed-section-license', - styleUrls: [], - templateUrl: './../../../shared/theme-support/themed.component.html' -}) -export class ThemedSubmissionSectionLicenseComponent extends ThemedComponent { - protected getComponentName(): string { - return 'SubmissionSectionLicenseComponent'; - } - - protected importThemedComponent(themeName: string): Promise { - return import(`../../../themes/${themeName}/app/submission/sections/section-license.component`); - } - - protected importUnthemedComponent(): Promise { - return import(`./section-license.component`); - } -} From b326c9b518f029d7a127dd22e20b4b686439e29e Mon Sep 17 00:00:00 2001 From: William Welling Date: Sat, 20 Jan 2024 22:10:10 -0600 Subject: [PATCH 17/19] Provide theme support for submission sections --- src/app/shared/testing/theme-service.stub.ts | 6 ++++++ .../section-container.component.spec.ts | 6 ++++++ .../container/section-container.component.ts | 21 ++++++++++++++++--- .../submission/sections/sections-decorator.ts | 19 +++++++++++++---- .../license/section-license.component.ts | 2 +- 5 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 src/app/shared/testing/theme-service.stub.ts diff --git a/src/app/shared/testing/theme-service.stub.ts b/src/app/shared/testing/theme-service.stub.ts new file mode 100644 index 00000000000..8c435d68409 --- /dev/null +++ b/src/app/shared/testing/theme-service.stub.ts @@ -0,0 +1,6 @@ +export class ThemeServiceStub { + + getThemeName = jasmine.createSpy('getThemeName'); + getThemeConfigFor = jasmine.createSpy('getThemeConfigFor'); + +} diff --git a/src/app/submission/sections/container/section-container.component.spec.ts b/src/app/submission/sections/container/section-container.component.spec.ts index d3f4a93762a..7eb542a69e9 100644 --- a/src/app/submission/sections/container/section-container.component.spec.ts +++ b/src/app/submission/sections/container/section-container.component.spec.ts @@ -15,6 +15,8 @@ import { SubmissionService } from '../../submission.service'; import { SectionsService } from '../sections.service'; import { SubmissionServiceStub } from '../../../shared/testing/submission-service.stub'; import { SectionsServiceStub } from '../../../shared/testing/sections-service.stub'; +import { ThemeService } from '../../../shared/theme-support/theme.service'; +import { ThemeServiceStub } from '../../../shared/testing/theme-service.stub'; import { SectionDataObject } from '../models/section-data.model'; import { mockSubmissionCollectionId, mockSubmissionId } from '../../../shared/mocks/submission.mock'; @@ -51,6 +53,7 @@ describe('SubmissionSectionContainerComponent test suite', () => { const submissionServiceStub: SubmissionServiceStub = new SubmissionServiceStub(); const sectionsServiceStub: SectionsServiceStub = new SectionsServiceStub(); + const themeServiceStub: ThemeServiceStub = new ThemeServiceStub(); const submissionId = mockSubmissionId; const collectionId = mockSubmissionCollectionId; @@ -60,6 +63,8 @@ describe('SubmissionSectionContainerComponent test suite', () => { sectionsServiceStub.getSectionState.and.returnValue(observableOf(sectionState)); sectionsServiceStub.getShownSectionErrors.and.returnValue(observableOf([])); submissionServiceStub.getActiveSectionId.and.returnValue(observableOf('traditionalpageone')); + themeServiceStub.getThemeName.and.returnValue('dspace'); + themeServiceStub.getThemeConfigFor.and.returnValue({ name: 'dspace' }); } // waitForAsync beforeEach @@ -78,6 +83,7 @@ describe('SubmissionSectionContainerComponent test suite', () => { providers: [ { provide: SectionsService, useValue: sectionsServiceStub }, { provide: SubmissionService, useValue: submissionServiceStub }, + { provide: ThemeService, useValue: themeServiceStub }, SubmissionSectionContainerComponent ], schemas: [CUSTOM_ELEMENTS_SCHEMA] diff --git a/src/app/submission/sections/container/section-container.component.ts b/src/app/submission/sections/container/section-container.component.ts index 3331629f332..4ac0e100481 100644 --- a/src/app/submission/sections/container/section-container.component.ts +++ b/src/app/submission/sections/container/section-container.component.ts @@ -1,9 +1,10 @@ import { Component, Injector, Input, OnInit, ViewChild } from '@angular/core'; -import { SectionsDirective } from '../sections.directive'; +import { ThemeService } from 'src/app/shared/theme-support/theme.service'; +import { AlertType } from '../../../shared/alert/alert-type'; import { SectionDataObject } from '../models/section-data.model'; import { rendersSectionType } from '../sections-decorator'; -import { AlertType } from '../../../shared/alert/alert-type'; +import { SectionsDirective } from '../sections.directive'; /** * This component represents a section that contains the submission license form. @@ -50,12 +51,17 @@ export class SubmissionSectionContainerComponent implements OnInit { */ @ViewChild('sectionRef') sectionRef: SectionsDirective; + // TAMU Customization - theme service to get active theme + private themeService: ThemeService; + /** * Initialize instance variables * * @param {Injector} injector */ constructor(private injector: Injector) { + // TAMU Customization - inject theme service + this.themeService = injector.get(ThemeService); } /** @@ -88,6 +94,15 @@ export class SubmissionSectionContainerComponent implements OnInit { * Find the correct component based on the section's type */ getSectionContent(): string { - return rendersSectionType(this.sectionData.sectionType); + // TAMU Customization - provide injected active theme to get themed section to render + let theme = this.themeService.getThemeName(); + let themeConfig = this.themeService.getThemeConfigFor(theme); + // get theme "root class" + while (!!themeConfig.extends) { + themeConfig = this.themeService.getThemeConfigFor(theme); + } + + return rendersSectionType(this.sectionData.sectionType, themeConfig.name); + // return rendersSectionType(this.sectionData.sectionType); } } diff --git a/src/app/submission/sections/sections-decorator.ts b/src/app/submission/sections/sections-decorator.ts index 7e7840adfd0..d7a7ac7bdd5 100644 --- a/src/app/submission/sections/sections-decorator.ts +++ b/src/app/submission/sections/sections-decorator.ts @@ -2,15 +2,26 @@ import { SectionsType } from './sections-type'; const submissionSectionsMap = new Map(); -export function renderSectionFor(sectionType: SectionsType) { +// TAMU Customization - map sections by theme +export function renderSectionFor(sectionType: SectionsType, theme: string = 'dspace') { return function decorator(objectElement: any) { if (!objectElement) { return; } - submissionSectionsMap.set(sectionType, objectElement); + let themedMap = submissionSectionsMap.get(theme); + if (themedMap === undefined) { + themedMap = new Map(); + submissionSectionsMap.set(theme, themedMap); + } + themedMap.set(sectionType, objectElement); }; } -export function rendersSectionType(sectionType: SectionsType) { - return submissionSectionsMap.get(sectionType); +// TAMU Customization - get sections mapped by theme +export function rendersSectionType(sectionType: SectionsType, theme: string = 'dspace') { + let themedMap = submissionSectionsMap.get(theme); + if (themedMap === undefined || !themedMap.has(sectionType)) { + themedMap = submissionSectionsMap.get('dspace'); + } + return themedMap.get(sectionType); } diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 251f7f0975a..61fb5be6bbf 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -43,7 +43,7 @@ import { SECTION_LICENSE_FORM_LAYOUT } from './section-license.model'; templateUrl: './section-license.component.html', // templateUrl: '../../../../../../app/submission/sections/license/section-license.component.html', }) -@renderSectionFor(SectionsType.License) +@renderSectionFor(SectionsType.License, 'tamu') export class SubmissionSectionLicenseComponent extends BaseComponent { /** From 23d5ded2ffe1a756f4267bd561b9bf24b8596cbe Mon Sep 17 00:00:00 2001 From: William Welling Date: Sun, 21 Jan 2024 01:03:23 -0600 Subject: [PATCH 18/19] Restore default config --- config/.gitignore | 1 + config/config.tamu.yml | 47 ++++++++++++++++++++++++++++++++++++++++++ config/config.yml | 44 +-------------------------------------- 3 files changed, 49 insertions(+), 43 deletions(-) create mode 100644 config/config.tamu.yml diff --git a/config/.gitignore b/config/.gitignore index a420ca43025..28bcb46ad31 100644 --- a/config/.gitignore +++ b/config/.gitignore @@ -1,2 +1,3 @@ config.*.yml !config.example.yml +!config.tamu.yml diff --git a/config/config.tamu.yml b/config/config.tamu.yml new file mode 100644 index 00000000000..0be7102650c --- /dev/null +++ b/config/config.tamu.yml @@ -0,0 +1,47 @@ +rest: + ssl: true + host: api-dev.library.tamu.edu + port: 443 + nameSpace: /dspace7 + +mediaViewer: + image: true + video: false + +themes: + - name: capstone + extends: tamu + # handle: '1969.1/94971' + uuid: '330feb1a-a3b8-4ba1-91cd-adb9369b6fb3' + - name: esl + extends: tamu + # handle: '1969.1/1656' + uuid: '7243d893-6c7e-44fc-aa74-ecfbf7dc771c' + - name: periodicals + extends: tamu + # regex: '1969.1\/94990|1969.1\/6062' + regex: '0e87eb5c-ce4a-4e74-9d33-fcbfb5066209|4d390df8-2edf-4633-bfde-5b2df685c459' + - name: image-gallery + extends: tamu + # regex: '1969.1\/91004|1969.1\/590|1969.1\/97046|1969.1\/86434|1969.1\/128952|1969.1\/148733|1969.1\/155981|1969.1\/188336|1969.1\/155981|1969.1\/188335|1969.1\/194556|1969.1\/195994' + regex: 'befb7166-392b-445b-b907-1f4363bb6dfb|ed211f67-86ad-41ff-9696-fe0e7e17e1cb|d61f515b-8153-4718-9b9d-1ce679c955a0|c431e202-fc5b-46c8-b188-00901e1e215a|7c2ac72f-fd7a-4f27-b701-eb6e0539a876|beea4d64-0ff6-4e58-9f7b-489e1d6c6f75|282ec515-7b66-4492-b4d0-ae66d76f516b|6d433be8-7a28-4dc7-a245-f8dfbb7a513c|282ec515-7b66-4492-b4d0-ae66d76f516b|a3923d8b-249c-4b7d-8459-0c83953f7d8f|7c61a02c-2176-4c5a-9dd8-919353159e91|a4116d8b-8135-4449-a1b0-3378d5c7ecad' + - name: tamu + headTags: + - tagName: link + attributes: + rel: icon + href: assets/tamu/images/favicons/favicon.ico + sizes: any + - tagName: link + attributes: + rel: icon + href: assets/tamu/images/favicons/favicon.svg + type: image/svg+xml + - tagName: link + attributes: + rel: apple-touch-icon + href: assets/tamu/images/favicons/apple-touch-icon.png + - tagName: link + attributes: + rel: manifest + href: assets/tamu/images/favicons/manifest.webmanifest diff --git a/config/config.yml b/config/config.yml index 62c6ae401b7..507379b4910 100644 --- a/config/config.yml +++ b/config/config.yml @@ -2,46 +2,4 @@ rest: ssl: true host: demo.dspace.org port: 443 - nameSpace: /server - -mediaViewer: - image: true - video: false - -themes: - - name: capstone - extends: tamu - # handle: '1969.1/94971' - uuid: '330feb1a-a3b8-4ba1-91cd-adb9369b6fb3' - - name: esl - extends: tamu - # handle: '1969.1/1656' - uuid: '7243d893-6c7e-44fc-aa74-ecfbf7dc771c' - - name: periodicals - extends: tamu - # regex: '1969.1\/94990|1969.1\/6062' - regex: '0e87eb5c-ce4a-4e74-9d33-fcbfb5066209|4d390df8-2edf-4633-bfde-5b2df685c459' - - name: image-gallery - extends: tamu - # regex: '1969.1\/91004|1969.1\/590|1969.1\/97046|1969.1\/86434|1969.1\/128952|1969.1\/148733|1969.1\/155981|1969.1\/188336|1969.1\/155981|1969.1\/188335|1969.1\/194556|1969.1\/195994' - regex: 'befb7166-392b-445b-b907-1f4363bb6dfb|ed211f67-86ad-41ff-9696-fe0e7e17e1cb|d61f515b-8153-4718-9b9d-1ce679c955a0|c431e202-fc5b-46c8-b188-00901e1e215a|7c2ac72f-fd7a-4f27-b701-eb6e0539a876|beea4d64-0ff6-4e58-9f7b-489e1d6c6f75|282ec515-7b66-4492-b4d0-ae66d76f516b|6d433be8-7a28-4dc7-a245-f8dfbb7a513c|282ec515-7b66-4492-b4d0-ae66d76f516b|a3923d8b-249c-4b7d-8459-0c83953f7d8f|7c61a02c-2176-4c5a-9dd8-919353159e91|a4116d8b-8135-4449-a1b0-3378d5c7ecad' - - name: tamu - headTags: - - tagName: link - attributes: - rel: icon - href: assets/tamu/images/favicons/favicon.ico - sizes: any - - tagName: link - attributes: - rel: icon - href: assets/tamu/images/favicons/favicon.svg - type: image/svg+xml - - tagName: link - attributes: - rel: apple-touch-icon - href: assets/tamu/images/favicons/apple-touch-icon.png - - tagName: link - attributes: - rel: manifest - href: assets/tamu/images/favicons/manifest.webmanifest + nameSpace: /server \ No newline at end of file From dd1156a2df0d4840ce261b8069bc1c39dda137f1 Mon Sep 17 00:00:00 2001 From: William Welling Date: Tue, 23 Jan 2024 16:06:23 -0600 Subject: [PATCH 19/19] Patch sections before proxy license upload --- .../sections/license/section-license.component.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/themes/tamu/app/submission/sections/license/section-license.component.ts b/src/themes/tamu/app/submission/sections/license/section-license.component.ts index 61fb5be6bbf..a1d32e34cc8 100644 --- a/src/themes/tamu/app/submission/sections/license/section-license.component.ts +++ b/src/themes/tamu/app/submission/sections/license/section-license.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@an import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { DynamicCheckboxModel, DynamicFormLayout, DynamicRadioGroupModel, MATCH_DISABLED } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, Observable, of } from 'rxjs'; +import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; import { AuthService } from '../../../../../../app/core/auth/auth.service'; @@ -16,6 +16,7 @@ import { HALEndpointService } from '../../../../../../app/core/shared/hal-endpoi import { License } from '../../../../../../app/core/shared/license.model'; import { WorkspaceitemSectionLicenseObject } from '../../../../../../app/core/submission/models/workspaceitem-section-license.model'; import { WorkspaceItem } from '../../../../../../app/core/submission/models/workspaceitem.model'; +import { SubmissionJsonPatchOperationsService } from '../../../../../../app/core/submission/submission-json-patch-operations.service'; import { normalizeSectionData } from '../../../../../../app/core/submission/submission-response-parsing.service'; import { isNotEmpty, isNotUndefined } from '../../../../../../app/shared/empty.util'; import { FormBuilderService } from '../../../../../../app/shared/form/builder/form-builder.service'; @@ -110,6 +111,7 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { private halEndpointService: HALEndpointService, private modalService: NgbModal, private notificationsService: NotificationsService, + private operationsService: SubmissionJsonPatchOperationsService, private sectionUploadService: SectionUploadService, protected changeDetectorRef: ChangeDetectorRef, protected collectionDataService: CollectionDataService, @@ -280,7 +282,13 @@ export class SubmissionSectionLicenseComponent extends BaseComponent { * @returns empty observable */ public onBeforeUpload = () => { - return of(); + const sub: Subscription = this.operationsService.jsonPatchByResourceType( + this.submissionService.getSubmissionObjectLinkName(), + this.submissionId, + 'sections') + .subscribe(); + this.subs.push(sub); + return sub; }; /**