[develop-16-deposit | WIP | ADDED ] initial implementation for deposit functionality

This commit is contained in:
argirok 2024-09-10 09:36:07 +03:00
parent 57628f6af7
commit 15a3563a3f
10 changed files with 625 additions and 3 deletions

View File

@ -0,0 +1,462 @@
import {Component, Input, ViewChild} from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router";
import {Subscriber, Subscription} from "rxjs";
import {Meta, Title} from "@angular/platform-browser";
import {UserManagementService} from "../../services/user-management.service";
import {properties} from "../../../../environments/environment";
import {HttpClient, HttpHeaders, HttpParams} from "@angular/common/http";
import {ResultLandingInfo} from "../../utils/entities/resultLandingInfo";
import {MatDialog} from "@angular/material/dialog";
import {LoginErrorCodes} from "../../login/utils/guardHelper.class";
import {UserInfo} from "os";
import {User} from "../../login/utils/helper.class";
import {error} from "protractor";
declare var UIkit: any;
@Component({
selector: 'deposition',
template: `
<div class="uk-section uk-container">
<a *ngIf="!authorized" (click)="openGrantModal('Grant Openaire')"
class="uk-button uk-button-primary">Authorize</a>
<!-- <ng-container *ngIf="authorized">-->
<form class=" ">
<div class="uk-float-left">
<span class="js-upload" uk-form-custom>
<input id="exampleInputFile" class="uk-width-medium" type="file" (change)="fileChangeEvent($event)"/>
<span class="uk-link " style="text-decoration: underline;">Upload a file to deposit </span>
</span>
</div>
</form>
<!-- </ng-container>-->
<!-- <div>{{code}}</div>-->
<!-- <button (click)="getToken()">getToken by code</button>
<button (click)="getTokenByRefresh()">getToken by refresh</button>-->
<button (click)="getInfo(null)">get info</button>
<button (click)="checkAccess(null)">get info</button>
<!--<button (click)="start()">create space</button>
<button (click)="deposit()">deposit</button>
<button (click)="meta()">Update meta</button>-->
<div *ngIf="orcidMessage">{{orcidMessage}}</div>
<div *ngIf="message" [innerHTML]="message"></div>
<div *ngIf="showLoading" class="uk-animation-fade uk-margin-top uk-width-1-1" role="alert">
<span class="loading-gif uk-align-center"></span>
</div>
<modal-alert #grantModal [overflowBody]=false (alertOutput)="authorize()">
<div>
<!-- <div>{{requestGrantMessage}}</div>-->
</div>
</modal-alert>
<modal-alert #depositInfoModal>
<ng-container *ngIf="space">
<!-- <div><a [href]="space.links.html" target="_blank">{{space.metadata.title}}</a></div>-->
<div>Your file has been deposited in Zenodo with the main metadata of this record. You can view the new record
<a [href]="space.links.html" target="_blank">here</a>, edit and publish it.
</div>
<div>The preserved DOI is {{space.metadata.prereserve_doi.doi}}.</div>
</ng-container>
</modal-alert>
</div>
`
})
export class DepositionComponent {
authorized = false;
@Input() result: ResultLandingInfo;
//JK9mqlayFu793ylUmCtiU8yZRbl1pBYD3uWrZ3Dg
// Client Secret
// Mr1L2SK1La4vpGXSyqMFqo551YVM4koNKPFIM1vdRw8sTb5AlD89KZwGLaqN
// zenodo
//sandbox
// api = "https://zenodo.org/";
// client_id= "xxXNLIu088eSAHAbERWEK8CCeIICELUpIDba9Gfh";
// client_secret ="";
//sandbox
api = "https://sandbox.zenodo.org/";
client_id = "JK9mqlayFu793ylUmCtiU8yZRbl1pBYD3uWrZ3Dg";
client_secret = "Mr1L2SK1La4vpGXSyqMFqo551YVM4koNKPFIM1vdRw8sTb5AlD89KZwGLaqN";
redirect_uri = "http://localhost:4300/deposit"//"https://scoobydoo.di.uoa.gr:4300";
authorizeUrl = this.api + "oauth/authorize?response_type=code&client_id=" +
this.client_id + "&scope=deposit%3Awrite+deposit%3Aactions&state=step1&redirect_uri=" +
encodeURIComponent(this.redirect_uri);
/*authorizeByRefreshUrl = this.api + "oauth/authorize?response_type=token&client_id=" +
this.client_id + "&scope=deposit%3Awrite+deposit%3Aactions&state=step1&redirect_uri=" +
encodeURIComponent(this.redirect_uri)*/
filesToUpload: Array<File>;
depositService = "http://localhost:8182/";
public subscriptions: Subscription[] = [];
public showLoading: boolean = false;
public message: string = "";
public orcidMessage: string = "";
public source: string = "";
public code: string = "";
public gotToken: boolean = false;
public space = null;
public window: any;
user//: User;
userTokens;
@ViewChild('grantModal') grantModal;
@ViewChild('depositInfoModal') depositInfoModal;
constructor(private route: ActivatedRoute,
private _router: Router,
private userManagementService: UserManagementService,
private _meta: Meta, private _title: Title, private _http: HttpClient/*, private dialog: MatDialog*/) {
}
ngOnInit() {
// this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
// this.user = user;
//TODO remove later
this.user = {};
this.user.id = "034130792470362";
this.user.firstname = "Argiro";
this.user.lastname = "Kokogiannaki";
this.user.email = "argirok@di.uoa.gr"
if (this.user) {
console.log(this.user)
this.isAuthorizedBefore();
} else {
this.authorized = false;
}
// }));
this.subscriptions.push(this.route.queryParams.subscribe(params => {
if (params['code']) {
this.code = params['code'];
localStorage.setItem('deposit_code', this.code);
} else if (localStorage.getItem('deposit_code')) {
this.code = localStorage.getItem('deposit_code');
}
// if(this.code){
// this.authorized = true;
// }
this.gotToken = false;
}));
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscriber) {
subscription.unsubscribe();
}
});
}
isAuthorizedBefore() {
this._http.get(this.depositService + "deposit/user/token?aaiId=" + this.user.id).subscribe(res => {
console.log(res)
if (res) {
this.authorized = true;
this.userTokens = res;
}
})
}
authorize() {
this.window = window.open(/*this.userTokens.zenodoRefresh?this.authorizeByRefreshUrl:*/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) {
let user = {
id: self.user.id,
firstName: self.user.firstname,
lastName: self.user.lastname,
email: self.user.email,
zenodoToken: ev.data['access_token'],
zenodoDuration: ev.data['expires_in'],
zenodoRefresh: ev.data['refresh_token'],
zenodoUserId: ev.data['user']['id'],
code: ev.data['code']
};
self._http.post(self.depositService + "deposit/user/save", user).subscribe(res => {
if (res) {
self.authorized = true;
self.userTokens = res;
}
})
/* if (ev.isTrusted && ev.origin == location.origin && ev.data == 'success') {
self.authorized = true;
UIkit.notification({
message: 'Thank you for <strong>authorizing OpenAIRE to deposit</strong> to your Zenodo account!',
status: 'success',
timeout: 6000,
pos: 'bottom-right'
});
localStorage.setItem('deposit_token', '');
localStorage.setItem('deposit_refresh', '');
localStorage.setItem('deposit_code', '');
/!*if (self.currentAction == "add") {
self.saveWorkPreparation();
} else if (self.currentAction == "delete") {
self.deleteWorks();
} else if (self.currentAction == "update") {
self.updateWorkPreparation();
}*!/
}*/
}
}
}
openGrantModal(title: string) {
// if(this.isMobile) {
// this.grantFsModal.okButton = false;
// this.grantFsModal.title = title;
// this.grantFsModal.open();
// } else {
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();
}
// the following method uses client ID and client Secret, which are sessitive data.
// Our API should return the response, without revealing the call to ORCID.
/*public getToken() {
this.showLoading = true;
console.log(this.code)
this._http.get(properties.utilsService + "/deposit/getToken?code=" + this.code).subscribe(res => {
console.log(res)
localStorage.setItem('deposit_token', res['access_token']);
localStorage.setItem('deposit_refresh', res['refresh_token']);
})
}
public getTokenByRefresh() {
this.showLoading = true;
console.log(this.code, localStorage.getItem('deposit_refresh'))
this._http.get(properties.utilsService + "/deposit/getToken?refresh_token=" + localStorage.getItem('deposit_refresh')).subscribe(res => {
console.log(res)
localStorage.setItem('deposit_token', res['access_token']);
localStorage.setItem('deposit_refresh', res['refresh_token']);
})
}*/
public getInfo(func) {
if (this.userTokens.zenodoToken) {
/* this._http.get("http://localhost:8000/deposit/info?token=" + localStorage.getItem('deposit_token')).subscribe(res => {
console.log(res)
})*/
this._http.get(this.api + "api/deposit/depositions?access_token=" + this.userTokens.zenodoToken).subscribe(res => {
console.log(res)
alert(res)
if(func) {
func();
}
}, error => {
console.log(error)
console.log(this.userTokens)
// if(this.userTokens.zenodoRefresh){
this.getAccessByRefresh(func);
// }else{
// this.authorize();
// }
})
} else {
console.log("no token")
this.authorize();
}
}
public start() {
this.space = null;
console.log(this.userTokens.zenodoToken)
if (this.userTokens.zenodoToken) {
let record = this.resultInfoToZenodoRecord();
console.log(record)
this._http.post(this.api + "api/deposit/depositions?access_token=" + this.userTokens.zenodoToken, {
"metadata": record
/*,
"submitted": true*/
}).subscribe(res => {
console.log(res)
this.space = res;
// this.meta();
console.log(res)
this.depositFile();
}, error => {
console.error(error.message)
})
}
}
private resultInfoToZenodoRecord() {
let record = {
"upload_type": this.result.resultType,
title: this.result.title,
publication_date: this.result.date,
creators: [],
description: this.result.description
}
if (this.result.resultType == 'publication' && this.result.types[0]) {
record['publication_type'] = this.result.types[0];
}
for (let author of this.result.authors) {
record.creators.push({name: author.fullName, orcid: author.orcid})
}
return record;
}
public deposit() {
console.log(this.userTokens.zenodoToken)
if (this.userTokens.zenodoToken) {
this._http.get(this.api + "api/deposit/depositions/73262?access_token=" +this.userTokens.zenodoToken, {}).subscribe(res => {
//http://localhost:8000
this._http.post(properties.utilsService/* "http://localhost:8000"*/ + "/deposit/upload?token=" + this.userTokens.zenodoToken, res).subscribe(res => {
console.log(res)
})
// this.depositFile(res['links']['bucket'],localStorage.getItem('deposit_token'))
// console.log(res)
})
}
}
private publish() {
let record = this.resultInfoToZenodoRecord();
console.log(record)
//uncomment to get and save DOI - published can't be deleted
this._http.post(this.api + "api/deposit/depositions/" + this.space.id + "/actions/publish?access_token=" + this.userTokens.zenodoToken, {}).subscribe(res => {
console.log(res)
}, error => {
console.error(error.message)
})
}
fileChangeEvent(fileInput: any) {
this.filesToUpload = <Array<File>>fileInput.target.files;
if (this.filesToUpload.length == 0) {
// this.errorMessage = "There is no selected file to upload.";
return;
}
this.start();
}
depositFile() {
const formData: FormData = new FormData();
formData.append('file', this.filesToUpload[0]);
const fileName = this.filesToUpload[0].name; // Replace with file name
let url = `${this.space.links.bucket}/${fileName}`;
const data = {
name: fileName,
...formData
};
const headers = new HttpHeaders({
'Content-type': 'application/octet-stream'
});
let params = new HttpParams();
params = params.set('access_token', this.userTokens.zenodoToken);
this._http.put(url, {
name: fileName,
...formData
}, {headers, params}).subscribe((res) => {
console.log(res);
this.depositInfoModal.cancelButton = false;
this.depositInfoModal.okButton = true;
this.depositInfoModal.okButtonLeft = false;
this.depositInfoModal.alertTitle = "Deposit info";
this.depositInfoModal.open();
console.log(this.space)
// this.publish();
}, error => {
console.log(error.headers)
console.error(error.data)
this.deleteSpace();
});
/* });
}*/
}
deleteSpace() {
this._http.delete(this.api + "api/deposit/depositions/" + this.space.id + "?access_token=" + this.userTokens.zenodoToken,
).subscribe(res => {
console.log(res)
}, error => {
console.error(error.message)
UIkit.notification({
message: 'An error occured while uploading your file. The deposition may not be completed.',
status: 'danger',
timeout: 6000,
pos: 'bottom-right'
});
})
}
checkAccess(func){
if(!this.user){
//TODO redirect
}else{
if(this.userTokens){
this.getInfo(func);
}else{
this.authorize();
}
}
}
getAccessByRefresh(func){
/*
this._http.get(this.depositService + "deposit/zenodo/getTokenByRefresh?token=" + this.userTokens.zenodoRefresh).subscribe(res => {
console.log(res)
/!*localStorage.setItem('deposit_token', res['access_token']);
localStorage.setItem('deposit_refresh', res['refresh_token']);
this.message = "<div>Thank you for authorizing OpenAIRE to use your Zenodo account for deposit!</div>" +
"<div class='uk-margin-small-top'>This window will automatically close and you will be ready to deposit.</div>";
if(window && window.opener) {
window.opener.postMessage(res,"*");
window.close();
}
setTimeout(() => {
this.message += "<div class='uk-margin-top'>If this window does not close automatically, please close it and continue!</div>";
}, 3000);*!/
}, error =>{
console.log(error);
})*/
this.authorize();
}
}

View File

@ -0,0 +1,20 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {DepositionComponent} from "./deposit-file.component";
import {AlertModalModule} from "../../utils/modal/alertModal.module";
@NgModule({
imports: [
CommonModule,
AlertModalModule,
],
declarations: [
DepositionComponent
],
providers: [],
exports: [
DepositionComponent
]
})
export class DepositFileModule {
}

View File

@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import {DepositComponent} from "./deposit.component";
import {LoginGuard} from "../../login/loginGuard.guard";
import {PreviousRouteRecorder} from "../../utils/piwik/previousRouteRecorder.guard";
@NgModule({
imports: [
RouterModule.forChild([
{ path: '', component: DepositComponent,
// canActivate: [LoginGuard],
canDeactivate: [PreviousRouteRecorder] }
])
]
})
export class DepositRoutingModule { }

View File

@ -0,0 +1,101 @@
import { Component } from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router";
import {Subscriber, Subscription} from "rxjs";
import {properties} from "../../../../environments/environment";
import {Meta, Title} from "@angular/platform-browser";
import {RouterHelper} from "../../utils/routerHelper.class";
import {UserManagementService} from "../../services/user-management.service";
import {HttpClient} from "@angular/common/http";
@Component({
selector: 'deposit',
template: `
<div class="uk-section uk-container">
<div *ngIf="depositMessage">{{depositMessage}}</div>
<div *ngIf="message" [innerHTML]="message"></div>
<div *ngIf="showLoading" class="uk-animation-fade uk-margin-top uk-width-1-1" role="alert">
<loading></loading>
</div>
</div>
`
})
export class DepositComponent {
public subscriptions: Subscription[] = [];
public showLoading: boolean = false;
public message: string = "";
public depositMessage: string = "";
public source: string = "";
public code: string = "";
public gotToken: boolean = false;
public routerHelper:RouterHelper = new RouterHelper();
depositService = "http://localhost:8182/";
constructor(private route: ActivatedRoute,
private _router: Router,
private userManagementService: UserManagementService,
private _meta: Meta, private _title: Title, private _http: HttpClient) {}
ngOnInit() {
var description = "Openaire, Deposit, Zenodo";
this.updateTitle("Connect with Zenodo");
this.updateDescription(description);
this.updateUrl( properties.domain + properties.baseLink + this.route.url);
this.subscriptions.push(this.route.queryParams.subscribe(params => {
this.gotToken = false;
this.code = params['code'];
if (this.code) {
this.getToken();
} else {
this.message = "No code provided to authorize OpenAIRE to deposit in your Zenodo account. Please try again!"
}
}));
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscriber) {
subscription.unsubscribe();
}
});
}
public getToken() {
this.showLoading = true;
console.log(this.code)
// this._http.get(properties.utilsService + "/deposit/getToken?code=" + this.code).subscribe(res => {
this._http.get(this.depositService + "deposit/zenodo/getTokenByCode?code=" + this.code).subscribe(res => {
console.log(res)
res["code"] = this.code
this.message = "<div>Thank you for authorizing OpenAIRE to use your Zenodo account for deposit!</div>" +
"<div class='uk-margin-small-top'>This window will automatically close and you will be ready to deposit.</div>";
if(window && window.opener) {
window.opener.postMessage(res,"*");
window.close();
}
setTimeout(() => {
this.message += "<div class='uk-margin-top'>If this window does not close automatically, please close it and continue!</div>";
}, 3000);
})
}
private updateTitle(title: string) {
this._title.setTitle(title);
this._meta.updateTag({content: title}, "property='og:title'");
}
private updateDescription(description: string) {
this._meta.updateTag({content: description}, "name='description'");
this._meta.updateTag({content: description}, "property='og:description'");
}
private updateUrl(url: string) {
this._meta.updateTag({content: url}, "property='og:url'");
}
}

View File

@ -0,0 +1,16 @@
import {NgModule} from '@angular/core';
import {DepositRoutingModule} from "./deposit-routing.module";
import {DepositComponent} from "./deposit.component";
import {LoadingModule} from "../../utils/loading/loading.module";
import {CommonModule} from "@angular/common";
@NgModule({
imports: [CommonModule, DepositRoutingModule, LoadingModule],
declarations:[DepositComponent],
exports: [DepositComponent]
})
export class DepositModule {
}

View File

@ -11,7 +11,7 @@ import * as url from "url";
@Injectable()
export class ErrorInterceptorService implements HttpInterceptor {
private static UNAUTHORIZED_WHITELIST = [properties.orcidAPIURL, properties.registryUrl? (properties.registryUrl + 'verification/'):null, properties.eoscDataTransferAPI].filter(value => !!value);
private static UNAUTHORIZED_WHITELIST = [properties.orcidAPIURL, properties.registryUrl? (properties.registryUrl + 'verification/'):null, properties.eoscDataTransferAPI, "https://sandbox.zenodo.org/"].filter(value => !!value);
private url: string = null;
constructor(private router: Router) {

View File

@ -77,7 +77,7 @@
</div>
</div>
<div class="uk-width-expand">
<entity-actions [cite]="true" [share]="true" [linking]="true"
<entity-actions [cite]="true" [share]="true" [linking]="true" [deposit]="true" [depositFile]="properties.environment == 'development' && properties.adminToolsPortalType == 'explore'"
[type]="resultLandingInfo.resultType"
[result]="resultLandingInfo" [id]="resultLandingInfo.objIdentifier">
<!-- ORCID -->

View File

@ -39,6 +39,7 @@ import {EntityActionsModule} from "../../utils/entity-actions/entity-actions.mod
import {ResultLandingRoutingModule} from "./resultLanding-routing.module";
import {OrcidCoreModule} from "../../orcid/orcid-core.module";
import {SearchTabModule} from "../../utils/tabs/contents/search-tab.module";
import {DepositionComponent} from "../../deposit/deposit-file/deposit-file.component";
@NgModule({
imports: [

View File

@ -51,6 +51,9 @@ import {EnvProperties} from "../properties/env-properties";
<span *ngIf="!compactView" class="uk-margin-xsmall-left">Embed</span>
</a>
</div>
<ng-container *ngIf="depositFile">
<deposition [result]="result"></deposition>
</ng-container>
<ng-content></ng-content>
</div>
<modal-alert *ngIf="cite" #citeModal>
@ -92,6 +95,7 @@ export class EntityActionsComponent implements OnInit {
@Input() share: boolean = false;
@Input() cite: boolean = false;
@Input() deposit: boolean = false;
@Input() depositFile: boolean = false;
@Input() embed: boolean = false;
@Input() url: string;
@Input() isMobile: boolean = false;

View File

@ -7,9 +7,10 @@ import {AlertModalModule} from "../modal/alertModal.module";
import {CiteThisModule} from "../../landingPages/landing-utils/citeThis/citeThis.module";
import {LandingModule} from "../../landingPages/landing-utils/landing.module";
import {InputModule} from "../../sharedComponents/input/input.module";
import {DepositFileModule} from "../../deposit/deposit-file/deposit-file.module";
@NgModule({
imports: [CommonModule, IconsModule, AlertModalModule, CiteThisModule, LandingModule, RouterModule, InputModule],
imports: [CommonModule, IconsModule, AlertModalModule, CiteThisModule, LandingModule, RouterModule, InputModule, DepositFileModule],
declarations: [EntityActionsComponent],
exports: [EntityActionsComponent]
})