From 7155acc998f1ec76c85b5f6f3a62826143d1220a Mon Sep 17 00:00:00 2001 From: argirok Date: Thu, 10 Oct 2024 13:30:20 +0300 Subject: [PATCH] [develop-16-deposit | WIP ] add my upload page, add deposit table component, add deposit info classes, add checks for user if allowed to deposit --- .../deposit-file/deposit-file.component.ts | 374 +++++++++--------- deposit/deposit-file/deposit-file.module.ts | 2 + deposit/my-uploads/my-uploads.component.ts | 185 +++++++++ deposit/utils/depositRecord.class.ts | 29 ++ deposit/utils/depositRecordTable.component.ts | 95 +++++ .../entity-actions.component.ts | 16 +- 6 files changed, 492 insertions(+), 209 deletions(-) create mode 100644 deposit/my-uploads/my-uploads.component.ts create mode 100644 deposit/utils/depositRecord.class.ts create mode 100644 deposit/utils/depositRecordTable.component.ts diff --git a/deposit/deposit-file/deposit-file.component.ts b/deposit/deposit-file/deposit-file.component.ts index 1586029f..fedfe81b 100644 --- a/deposit/deposit-file/deposit-file.component.ts +++ b/deposit/deposit-file/deposit-file.component.ts @@ -7,117 +7,108 @@ import {HttpClient, HttpHeaders, HttpParams} from "@angular/common/http"; import {ResultLandingInfo} from "../../utils/entities/resultLandingInfo"; import {properties} from 'src/environments/environment'; import {AlertModal} from "../../utils/modal/alert"; +import {Session} from "../../login/utils/helper.class"; +import {DepositRecord, ZenodoRecord} from "../utils/depositRecord.class"; declare var UIkit: any; @Component({ selector: 'deposition', template: ` - -
-
You have already upload the following files:
- -
-
-
{{record.depositDate}} View - in Zenodo - -
-
{{record.filenames.join(', ')}} -
- + + + + Upload a file + + + +
+ +
+
+ + This will upload to the Zenodo Sandbox instance, used for testing purposes + +
+ DOIs created in this instance are not real and will not resolve.
-
-
-
-
- Upload files to a Zenodo record, using basic metadata (title, description, authors, publication date) from this record. -
-
-
+
+
You have already upload the following files:
+ +
+
+
{{record.depositDate}} View + in Zenodo + +
+
{{record.filenames.join(', ')}} +
+ +
+
+
+
+
+ Upload files to a Zenodo record, using basic metadata (title, description, authors, publication date) from + this record. +
+ +
Upload files to deposit +
+
- -
- - - -
- Your file has been uploaded to Zenodo in draft mode.
- Please visit Zenodo to review the metadata, make any necessary edits, and publish the record.

- Note that it has been uploaded with license - {{space.metadata.license}}, classified as - {{space.metadata.upload_type}}, and is set with - {{space.metadata.access_right}} access rights. - -
-
The preserved DOI is {{space.metadata.prereserve_doi.doi}}.
-
-
-
- - - - - - - - - - - - - - -
Title{{space.metadata.title}}
Publication date{{space.metadata.publication_date}}
Description{{space.metadata.description.substring(0,250)}}...
Access right{{space.metadata.access_right}}
Creators - {{creator.name}}{{', '}}
License{{space.metadata.license}}
Upload type{{space.metadata.upload_type}}
Related identifiers - {{identifier.identifier + ' - ' }} - {{identifier.relation}} {{' - ' + identifier.resource_type}} - {{', '}}
Journal{{space.metadata.journal_title}} - {{',volume '+ space.metadata.journal_volume}} - {{',issue '+ space.metadata.journal_issue}}
Publisher{{space.metadata.imprint_publisher}}
Language{{space.metadata.language}}
Grants - {{grant.id}} - {{', '}} -
Files{{space.files.join(", ")}}
-
+ +
- Cancel Continue to Zenodo + Your file has been uploaded to Zenodo in draft mode.
+ Please visit Zenodo to review the metadata, make any necessary edits, and publish the record.

+ Note that it has been uploaded with license + {{space.metadata.license}}, classified as + {{space.metadata.upload_type}}, and is set with + {{space.metadata.access_right}} access rights. - -
-
- - - - - - + + + ` }) @@ -126,7 +117,10 @@ export class DepositionComponent { properties = properties; @Input() result: ResultLandingInfo; @ViewChild('deleteModal') deleteModal: AlertModal; - + @ViewChild('depositModal') depositModal; + @Input() showTooltip: boolean = true; + @Input() compactView: boolean = false; // if true, do not show label for actions + @Input() isMobile: boolean = false; authorizeUrl = this.properties.zenodoDepositAPI + /* "oauth/authorize?response_type=code&client_id=" +*/ "oauth/authorize?response_type=token&client_id=" + this.properties.zenodoDepositClientId + "&scope=deposit%3Awrite+deposit%3Aactions&state=step1&redirect_uri=" + @@ -144,14 +138,14 @@ export class DepositionComponent { public code: string = ""; public gotToken: boolean = false; public space = null; - public mongoRecord = null; - public prevMongoRecords = null; + public mongoRecord: DepositRecord = null; + public prevMongoRecords: DepositRecord [] = null; public window: any; user//: User; + isAllowedToUpload: boolean = false; userTokens; funders; - // @ViewChild('grantModal') grantModal; - @ViewChild('depositInfoModal') depositInfoModal; + constructor(private route: ActivatedRoute, private _router: Router, @@ -162,31 +156,29 @@ export class DepositionComponent { ngOnInit() { this.getFunders(); this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { - //testing - /* this.space = {}; - this.space.links = [] - this.space.metadata = this.resultInfoToZenodoRecord(); - this.space.metadata.prereserve_doi = {doi:"123"} - this.space.files = [];*/ + if (this.depositModal) { + this.depositModal.open(); + } this.user = user; if (this.user) { + this.checkUserAccess(); this.isAuthorizedBefore(); - }else if(properties.environment == 'development'){ + } else if (properties.environment == 'development') { //TODO remove later this.user = {}; this.user.id = "034130792470362"; this.user.firstname = "Argiro"; this.user.lastname = "Kokogiannaki"; this.user.email = "argirok@di.uoa.gr" + this.user.role = ['PORTAL_ADMINISTRATOR']; + this.checkUserAccess(); this.isAuthorizedBefore(); } else { this.authorized = false; } - // this.getPrevUploads(); })); - } ngOnDestroy() { @@ -210,13 +202,9 @@ export class DepositionComponent { authorize() { this.window = window.open(this.authorizeUrl, '_blank', 'location=yes,height=700,width=540,left=500,top=100,scrollbars=yes,status=yes'); - // this.requestGrant = false; - // this.closeGrantModal(); - let self = this; window.onmessage = function (ev) { if (ev.isTrusted && ev.origin == location.origin) { - console.log(ev.data) let user = { _id: self.user.id, firstName: self.user.firstname, @@ -224,10 +212,9 @@ export class DepositionComponent { email: self.user.email, zenodoToken: ev.data['access_token'], zenodoDuration: ev.data['expires_in'], - zenodoRefresh: ev.data['refresh_token']?ev.data['refresh_token']:"", + zenodoRefresh: ev.data['refresh_token'] ? ev.data['refresh_token'] : "", zenodoUserId: ev.data['user']['id'], - code: ev.data['code']?ev.data['code']:"" - + code: ev.data['code'] ? ev.data['code'] : "" }; self._http.post(self.properties.depositAPI + "deposit/user/save", user).subscribe(res => { @@ -243,19 +230,6 @@ export class DepositionComponent { } } -/* openGrantModal(title: string) { - this.grantModal.cancelButton = true; - this.grantModal.okButton = true; - this.grantModal.okButtonText = "Grant OpenAIRE"; - this.grantModal.okButtonLeft = false; - this.grantModal.alertTitle = title; - this.grantModal.open(); - } - - closeGrantModal() { - this.grantModal.cancel(); - }*/ - public getInfo(func) { if (this.userTokens.zenodoToken) { this._http.get(this.properties.zenodoDepositAPI + "api/deposit/depositions?access_token=" + this.userTokens.zenodoToken).subscribe(res => { @@ -299,19 +273,19 @@ export class DepositionComponent { this.filesToUpload = []; }, error => { console.error(error) - if(error.status == '400'){ + if (error.status == '400') { this.showLoading = false; - this.errorMessage = "Zenodo API:
" +error.error.message + "
"; - if(error.error.errors) { + this.errorMessage = "Zenodo API:
" + error.error.message + "
"; + if (error.error.errors) { for (let err of error.error.errors) { if (err.field && err.messages && err.messages.length > 0) { this.errorMessage += err.field + ": " + err.messages.join(", ") + "
"; } } } - }else if(error.status == 401 || error.status == 403){ + } else if (error.status == 401 || error.status == 403) { this.authorize(); - }else{ + } else { this.showLoading = false; this.errorMessage = "Zenodo API:
" + error.error.message; } @@ -319,26 +293,24 @@ export class DepositionComponent { } } - private resultInfoToZenodoRecord() { - let record = { - "upload_type": this.result.resultType, - title: this.result.title, - publication_date: this.result.date, - creators: [], - description: this.result.description, - imprint_publisher: this.result.publisher, - related_identifiers: [] - } + private resultInfoToZenodoRecord(): ZenodoRecord { + let record: ZenodoRecord = new ZenodoRecord(); + record.upload_type = this.result.resultType; + record.title = this.result.title; + record.publication_date = this.result.date; + record.description = this.result.description; + record.imprint_publisher = this.result.publisher; + /*if(this.result.languages){ // metadata.language: Language must be either ISO-639-1 or 639-2 compatible. record['language'] = this.result.languages[0]; }*/ - if(this.result.journal && this.result.journal){ - record['journal_title'] = this.result.journal.journal; + if (this.result.journal && this.result.journal) { + record['journal_title'] = this.result.journal.journal; record['journal_volume'] = this.result.journal.volume; - record['journal_issue'] = this.result.journal.issue; + record['journal_issue'] = this.result.journal.issue; } - if(this.result.identifiers) { + if (this.result.identifiers) { for (let pidType of this.result.identifiers.keys()) { for (let pid of this.result.identifiers.get(pidType)) { record.related_identifiers.push({ @@ -349,16 +321,16 @@ export class DepositionComponent { } } } - if(this.result.fundedByProjects && this.funders){ - record['grants']=[]; - for(let project of this.result.fundedByProjects){ - if(project.funderShortname == 'EC') { + if (this.result.fundedByProjects && this.funders) { + record['grants'] = []; + for (let project of this.result.fundedByProjects) { + if (project.funderShortname == 'EC') { record['grants'].push({id: '10.13039/501100000780::' + project.code}) - }else{ - for(let funder of this.funders){ - if((project.funderShortname == funder.legalShortName || project.funderName == funder.legalName ) && funder.pids){ - for(let pid of funder.pids){ - if(pid.type == 'FundRef'){ + } else { + for (let funder of this.funders) { + if ((project.funderShortname == funder.legalShortName || project.funderName == funder.legalName) && funder.pids) { + for (let pid of funder.pids) { + if (pid.type == 'FundRef') { record['grants'].push({id: '10.13039/' + pid.value + '::' + project.code}) break; } @@ -369,12 +341,12 @@ export class DepositionComponent { } } } - record['imprint_publisher']=this.result.publisher; + record['imprint_publisher'] = this.result.publisher; /* if (this.result.resultType == 'publication' && this.result.types[0]) { //has to be match to their vocabulary record['publication_type'] = this.result.types[0]; }*/ - if(this.result.authors) { + if (this.result.authors) { for (let author of this.result.authors) { record.creators.push({name: author.fullName, orcid: author.orcid}) } @@ -422,55 +394,60 @@ export class DepositionComponent { }); } - saveRecord(record, files, res) { - let mongoRecord = { + saveRecord(record: ZenodoRecord, files, res) { + let mongoRecord: DepositRecord = new DepositRecord(); + mongoRecord.aaiId = this.user.id; + mongoRecord.record = record; + mongoRecord.openAIREId = this.result.relcanId; + mongoRecord.recordId = this.space.record_id; + mongoRecord.ownerId = this.userTokens.zenodoUserId; - aaiId: this.user.id, - title: record.title, - description: record.description, - type: record["upload_type"], - date: record.publication_date, - authors: [], - filenames: [], - pids: [], - openAIREId: this.result.relcanId, - recordId: this.space.record_id, - ownerId: this.userTokens.zenodoUserId - }; for (let file of files) { mongoRecord.filenames.push(file.name) } - for (let pidtype of this.result.identifiers.keys()) { - for (let pid of this.result.identifiers.get(pidtype)) { - if (mongoRecord.pids.indexOf(pid) == -1) { - mongoRecord.pids.push(pid) + if (this.result.identifiers) { + for (let pidtype of this.result.identifiers.keys()) { + for (let pid of this.result.identifiers.get(pidtype)) { + if (mongoRecord.pids.indexOf(pid) == -1) { + mongoRecord.pids.push(pid) + } } } } - for (let author of record.creators) { - mongoRecord.authors.push({name: author.name, orcid: author.orcid ? author.orcid : ""}) - } + this._http.post(this.properties.depositAPI + "deposit/record/save", mongoRecord).subscribe(res => { - this.mongoRecord = res; + if (res instanceof DepositRecord) { + this.mongoRecord = res; + } }) } + public openDepositModal() { + // this.depositClicked = true; + this.depositModal.cancelButton = false; + this.depositModal.okButton = false; + this.depositModal.alertTitle = "Deposit"; + this.depositModal.open(); + } + deleteSpace() { this._http.delete(this.properties.zenodoDepositAPI + "api/deposit/depositions/" + this.space.id + "?access_token=" + this.userTokens.zenodoToken, ).subscribe(res => { this.space = null; this._http.delete(this.properties.depositAPI + "deposit/record/delete?id=" + this.mongoRecord._id).subscribe(res => { - this.depositInfoModal.cancel() + this.openDepositModal(); }) }, error => { console.error(error.message) UIkit.notification({ - message: 'An error occured while uploading your file. The deposition may not be completed.', + message: 'An error occurred while deleting the record', status: 'danger', timeout: 6000, pos: 'bottom-right' }); + + this.openDepositModal(); }) } @@ -495,19 +472,6 @@ export class DepositionComponent { }) } - getPrevUploads() { - let pids = []; - for (let pidtype of this.result.identifiers.keys()) { - for (let pid of this.result.identifiers.get(pidtype)) { - if (pids.indexOf(pid) == -1) { - pids.push(pid) - } - } - } - this._http.get(this.properties.depositAPI + "deposit/record/get?aaiId=" + this.user.id + (pids.length > 0 ? "&pid=" + pids.join("&pid=") : "") + "&openaireId=" + this.result.relcanId).subscribe(res => { - this.prevMongoRecords = res; - }) - } promtToDelete() { @@ -516,10 +480,26 @@ export class DepositionComponent { this.deleteModal.okButtonText = 'Yes'; this.deleteModal.open(); } - getFunders(){ - let fundersMap = {}; - this._http.get("https://services.openaire.eu/openaire/funders").subscribe(res => { + + getFunders() { + this._http.get(properties.fundersApi).subscribe(res => { this.funders = res; }) } + + checkUserAccess() { + this.isAllowedToUpload = false; + if (Session.isPortalAdministrator(this.user)) { + this.isAllowedToUpload = true; + return; + } + if (this.user && this.user.orcid) { + for (let author of this.result.authors) { + if (author.fullName.toLowerCase().indexOf(this.user.lastname.toLowerCase()) != -1) { + this.isAllowedToUpload = true; + return; + } + } + } + } } diff --git a/deposit/deposit-file/deposit-file.module.ts b/deposit/deposit-file/deposit-file.module.ts index e1925450..20558b75 100644 --- a/deposit/deposit-file/deposit-file.module.ts +++ b/deposit/deposit-file/deposit-file.module.ts @@ -4,6 +4,7 @@ import {DepositionComponent} from "./deposit-file.component"; import {AlertModalModule} from "../../utils/modal/alertModal.module"; import {LoadingModule} from "../../utils/loading/loading.module"; import {IconsModule} from "../../utils/icons/icons.module"; +import {DepositRecordTableComponent} from "../utils/depositRecordTable.component"; @NgModule({ imports: [ @@ -11,6 +12,7 @@ import {IconsModule} from "../../utils/icons/icons.module"; AlertModalModule, LoadingModule, IconsModule, + DepositRecordTableComponent ], declarations: [ DepositionComponent diff --git a/deposit/my-uploads/my-uploads.component.ts b/deposit/my-uploads/my-uploads.component.ts new file mode 100644 index 00000000..0f42e2e9 --- /dev/null +++ b/deposit/my-uploads/my-uploads.component.ts @@ -0,0 +1,185 @@ +import {Component, ViewChild} from '@angular/core'; +import {ActivatedRoute, Router, RouterModule} from "@angular/router"; +import {Subscriber, Subscription} from "rxjs"; +import {Meta, Title} from "@angular/platform-browser"; +import {UserManagementService} from "../../services/user-management.service"; +import {HttpClient} from "@angular/common/http"; +import {properties} from 'src/environments/environment'; +import {AlertModal} from "../../utils/modal/alert"; +import {DepositRecord} from "../utils/depositRecord.class"; +import {CommonModule} from "@angular/common"; +import {DepositRecordTableComponent} from "../utils/depositRecordTable.component"; +import {RouterHelper} from "../../utils/routerHelper.class"; +import {OpenaireEntities} from "../../utils/properties/searchFields"; + +declare var UIkit: any; + +@Component({ + selector: 'my-uploads', + standalone: true, + template: ` +
+
+ + + Discover {{openaireEntities.RESULTS | lowercase}} related to you + + + +

+ My uploads +

+ +
+ +
+ +
No uploads yet.
+
+
+
+ + +
+
+ + + + `, + imports: [CommonModule, DepositRecordTableComponent, RouterModule] +}) + +export class MyUploadsComponent { + properties = properties; + + @ViewChild('deleteModal') deleteModal: AlertModal; + + public subscriptions: Subscription[] = []; + + public showLoading: boolean = true; + public message: string = ""; + public errorMessage: string = ""; + + public selectedRecord = null; + + public depositRecords: DepositRecord [] = null; + + user//: User; + public openaireEntities = OpenaireEntities; + + public routerHelper: RouterHelper = new RouterHelper(); + public authorNameParam: any = null; + + constructor(private route: ActivatedRoute, + private _router: Router, + private userManagementService: UserManagementService, + private _meta: Meta, private _title: Title, private _http: HttpClient) { + } + + ngOnInit() { + this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { + this.user = user; + if (this.user) { + this.getUserUploads(); + this.authorNameParam = this.routerHelper.createQueryParams(['f0', 'fv0'], ['resultauthor', this.user.fullname]); + } else if (properties.environment == 'development') { + //TODO remove later + this.user = {}; + this.user.id = "034130792470362"; + this.user.firstname = "Argiro"; + this.user.lastname = "Kokogiannaki"; + this.user.fullname = "Argiro Kokogiannaki"; + this.user.email = "argirok@di.uoa.gr" + this.user.role = ['PORTAL_ADMINISTRATOR']; + + this.getUserUploads(); + this.authorNameParam = this.routerHelper.createQueryParams(['f0', 'fv0'], ['resultauthor', this.user.fullname]); + } else { + + } + })); + + + } + + ngOnDestroy() { + this.subscriptions.forEach(subscription => { + if (subscription instanceof Subscriber) { + subscription.unsubscribe(); + } + }); + } + + + deleteSpace(record) { + /* this._http.delete(this.properties.zenodoDepositAPI + "api/deposit/depositions/" + this.space.id + "?access_token=" + this.userTokens.zenodoToken, + ).subscribe(res => { + this.space = null;*/ + this._http.delete(this.properties.depositAPI + "deposit/record/delete?id=" + record._id).subscribe(res => { + + }) + /*}, error => { + console.error(error.message) + UIkit.notification({ + message: 'An error occurred while deleting the record', + status: 'danger', + timeout: 6000, + pos: 'bottom-right' + }); + + + })*/ + } + + + getUserUploads() { + this.showLoading = true; + this._http.get(this.properties.depositAPI + "deposit/record/user?aaiId=" + this.user.id).subscribe(res => { + this.depositRecords = res; + this.showLoading = false; + }) + } + + promtToDelete() { + + this.deleteModal.alertTitle = 'Delete Confirmation'; + this.deleteModal.message = 'This action will delete your deposited file and its record in Zenodo. Are you sure you want to proceed?'; + this.deleteModal.okButtonText = 'Yes'; + this.deleteModal.open(); + } + +} diff --git a/deposit/utils/depositRecord.class.ts b/deposit/utils/depositRecord.class.ts new file mode 100644 index 00000000..b89f0af7 --- /dev/null +++ b/deposit/utils/depositRecord.class.ts @@ -0,0 +1,29 @@ +export class DepositRecord{ + _id:string; + aaiId: string; + record:any | ZenodoRecord; + filenames: string[] = []; + pids: string[] = []; + openAIREId: string; + recordId: string; + ownerId: string; + depositDate: string; +} + +export class ZenodoRecord{ + //https://developers.zenodo.org/#representation + title?:string; + publication_date?:string; + description?:string; + access_right?:string; + creators:{name:string,orcid?:string}[] = []; + license?:string; + upload_type:string; + related_identifiers:{identifier:string, relation:string, resource_type:string}[] = []; + journal_title?:string; + journal_volume?:string; + journal_issue?:string; + imprint_publisher?:string; + language?:string; + grants:{id:string}[] =[]; +} diff --git a/deposit/utils/depositRecordTable.component.ts b/deposit/utils/depositRecordTable.component.ts new file mode 100644 index 00000000..196f47a6 --- /dev/null +++ b/deposit/utils/depositRecordTable.component.ts @@ -0,0 +1,95 @@ +import {Component, Input} from '@angular/core'; +import {properties} from 'src/environments/environment'; +import {ZenodoRecord} from "../utils/depositRecord.class"; +import {CommonModule} from "@angular/common"; + +declare var UIkit: any; + +@Component({ + selector: 'deposit-record-table', + standalone: true, + template: ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Title{{record.title}}
Publication date{{record.publication_date}}
Description{{record.description.substring(0, 250)}}...
Access right{{record.access_right}}
Creators + {{creator.name}}{{', '}}
License{{record.license}}
Upload type{{record.upload_type}}
Related identifiers + {{identifier.identifier + ' - ' }} + {{identifier.relation}} {{' - ' + identifier.resource_type}} + {{', '}}
Journal{{record.journal_title}} + {{',volume ' + record.journal_volume}} + {{',issue ' + record.journal_issue}}
Publisher{{record.imprint_publisher}}
Language{{record.language}}
Grants + {{grant.id}} + {{', '}} +
Files{{files.join(", ")}}
+ `, + imports: [CommonModule] +}) + +export class DepositRecordTableComponent { + properties = properties; + + @Input() record: ZenodoRecord; + @Input() files: string[]; + @Input() style: string = 'uk-border'; + + + constructor() { + } + + +} diff --git a/utils/entity-actions/entity-actions.component.ts b/utils/entity-actions/entity-actions.component.ts index b9789764..8f9e86dc 100644 --- a/utils/entity-actions/entity-actions.component.ts +++ b/utils/entity-actions/entity-actions.component.ts @@ -36,12 +36,7 @@ import {EnvProperties} from "../properties/env-properties";
- - - ` }) export class EntityActionsComponent implements OnInit { @@ -117,7 +109,7 @@ export class EntityActionsComponent implements OnInit { @ViewChild('citeModal') citeModal; @ViewChild('embedResultsModal') embedResultsModal; @ViewChild('addThisModal') addThisModal; - @ViewChild('depositModal') depositModal; + // @ViewChild('depositModal') depositModal; properties: EnvProperties = properties; openaireEntities = OpenaireEntities; @@ -162,13 +154,13 @@ export class EntityActionsComponent implements OnInit { this.addThisModal.alertTitle = "Share this " + this.getTypeName() + " in your social networks"; this.addThisModal.open(); } - public openDepositModal() { + /*public openDepositModal() { // this.depositClicked = true; this.depositModal.cancelButton = false; this.depositModal.okButton = false; this.depositModal.alertTitle = "Deposit"; this.depositModal.open(); - } + }*/ public openEmbedResultsModal() { this.embedResultsModal.cancelButton = false;