mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[CST-9636] Added unit tests and the logic to create file object from payload
This commit is contained in:
@@ -1,3 +1,92 @@
|
||||
<div class="container">
|
||||
Access control page!!!
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p>
|
||||
This form allows you to perform changes to the access condition of all the items owned by collection under this community.
|
||||
Changes can be performed on the access condition for the metadata (item) or for the content (bitstream).
|
||||
</p>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-12 col-md-6 border-right">
|
||||
<div class="d-flex align-items-center">
|
||||
<h4 class="mb-0 mr-4">Item's Metadata</h4>
|
||||
<ui-switch [(ngModel)]="state.item.toggleStatus"></ui-switch>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-3">Mode</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="itemMode" id="itemReplace" value="replace" [(ngModel)]="state.item.accessMode">
|
||||
<label class="form-check-label" for="itemReplace">Replace access conditions</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="itemMode" id="itemAdd" value="add" [(ngModel)]="state.item.accessMode">
|
||||
<label class="form-check-label" for="itemAdd">Add to existing ones</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<h5>Access conditions</h5>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
You have not specified any access conditions, the new items access conditions will be inherited from the owning collection.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ds-access-control-array-form
|
||||
#itemAccessCmp
|
||||
[dropdownOptions]="(dropdownData$ | async)?.itemAccessConditionOptions || []">
|
||||
</ds-access-control-array-form>
|
||||
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<h4 class="mb-0 mr-4">Bitstreams</h4>
|
||||
<ui-switch [(ngModel)]="state.bitstream.toggleStatus"></ui-switch>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-3">Mode</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="bitstreamMode" id="bitstreamReplace" value="replace" [(ngModel)]="state.bitstream.accessMode">
|
||||
<label class="form-check-label" for="bitstreamReplace">Replace access conditions</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="bitstreamMode" id="bitstreamAdd" value="add" [(ngModel)]="state.bitstream.accessMode">
|
||||
<label class="form-check-label" for="bitstreamAdd">Add to existing ones</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<h5>Access conditions</h5>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
You have not specified any access conditions, the new items access conditions will be inherited from the owning collection.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ds-access-control-array-form
|
||||
#bitstreamAccessCmp
|
||||
[dropdownOptions]="(dropdownData$ | async)?.bitstreamAccessConditionOptions || []">
|
||||
</ds-access-control-array-form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button class="btn btn-lg btn-outline-primary mr-3" (click)="reset()">Reset</button>
|
||||
<button class="btn btn-lg btn-primary" (click)="submit()">Execute</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,37 +1,56 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { shareReplay } from 'rxjs';
|
||||
import {
|
||||
AccessControlArrayFormComponent
|
||||
} from '../../../shared/access-control-array-form/access-control-array-form.component';
|
||||
import { CollectionAccessControlService } from './collection-access-control.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-collection-access-control',
|
||||
templateUrl: './collection-access-control.component.html',
|
||||
styleUrls: ['./collection-access-control.component.scss']
|
||||
styleUrls: ['./collection-access-control.component.scss'],
|
||||
providers: [CollectionAccessControlService]
|
||||
})
|
||||
export class CollectionAccessControlComponent<TDomain extends DSpaceObject> implements OnInit {
|
||||
export class CollectionAccessControlComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* The initial DSO object
|
||||
*/
|
||||
public dsoRD$: Observable<RemoteData<TDomain>>;
|
||||
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent;
|
||||
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
|
||||
|
||||
constructor(private collectionAccessControlService: CollectionAccessControlService) {}
|
||||
|
||||
state = initialState;
|
||||
|
||||
dropdownData$ = this.collectionAccessControlService.dropdownData$.pipe(
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {ActivatedRoute} route
|
||||
*/
|
||||
constructor(
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the component, setting up the collection
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.dsoRD$ = this.route.parent.parent.data.pipe(first(), map((data) => data.dso));
|
||||
reset() {
|
||||
this.bitstreamAccessCmp.reset();
|
||||
this.itemAccessCmp.reset();
|
||||
this.state = initialState;
|
||||
}
|
||||
|
||||
submit() {
|
||||
const bitstreamAccess = this.bitstreamAccessCmp.getValue();
|
||||
const itemAccess = this.itemAccessCmp.getValue();
|
||||
|
||||
console.log('bitstreamAccess', bitstreamAccess);
|
||||
console.log('itemAccess', itemAccess);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
item: {
|
||||
toggleStatus: false,
|
||||
accessMode: '',
|
||||
},
|
||||
bitstream: {
|
||||
toggleStatus: false,
|
||||
accessMode: '',
|
||||
},
|
||||
};
|
||||
|
@@ -0,0 +1,54 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AccessControlItem } from '../../../shared/access-control-array-form/access-control-array-form.component';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
export interface AccessControlDropdownDataResponse {
|
||||
id: string;
|
||||
itemAccessConditionOptions: AccessControlItem[];
|
||||
bitstreamAccessConditionOptions: AccessControlItem[];
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class CollectionAccessControlService {
|
||||
dropdownData$: Observable<AccessControlDropdownDataResponse> = of(accessControlDropdownData);
|
||||
}
|
||||
|
||||
const accessControlDropdownData: AccessControlDropdownDataResponse = {
|
||||
'id': 'default',
|
||||
'itemAccessConditionOptions': [
|
||||
{
|
||||
'name': 'openaccess'
|
||||
},
|
||||
{
|
||||
'name': 'administrator'
|
||||
},
|
||||
{
|
||||
'name': 'embargo',
|
||||
'hasStartDate': true,
|
||||
'maxStartDate': '2018-06-24T00:40:54.970+0000'
|
||||
},
|
||||
{
|
||||
'name': 'lease',
|
||||
'hasEndDate': true,
|
||||
'maxEndDate': '2017-12-24T00:40:54.970+0000'
|
||||
}
|
||||
],
|
||||
'bitstreamAccessConditionOptions': [
|
||||
{
|
||||
'name': 'openaccess'
|
||||
},
|
||||
{
|
||||
'name': 'administrator'
|
||||
},
|
||||
{
|
||||
'name': 'embargo',
|
||||
'hasStartDate': true,
|
||||
'maxStartDate': '2018-06-24T00:40:54.970+0000'
|
||||
},
|
||||
{
|
||||
'name': 'lease',
|
||||
'hasEndDate': true,
|
||||
'maxEndDate': '2017-12-24T00:40:54.970+0000'
|
||||
}
|
||||
]
|
||||
};
|
@@ -14,6 +14,10 @@ import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-
|
||||
import { FormModule } from '../../shared/form/form.module';
|
||||
import { ComcolModule } from '../../shared/comcol/comcol.module';
|
||||
import { CollectionAccessControlComponent } from './collection-access-control/collection-access-control.component';
|
||||
import {
|
||||
AccessControlArrayFormModule
|
||||
} from '../../shared/access-control-array-form/access-control-array-form.component';
|
||||
import { UiSwitchModule } from 'ngx-ui-switch';
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Collection page administrator functionality
|
||||
@@ -27,6 +31,8 @@ import { CollectionAccessControlComponent } from './collection-access-control/co
|
||||
ResourcePoliciesModule,
|
||||
FormModule,
|
||||
ComcolModule,
|
||||
AccessControlArrayFormModule,
|
||||
UiSwitchModule,
|
||||
],
|
||||
declarations: [
|
||||
EditCollectionPageComponent,
|
||||
|
@@ -1 +1,92 @@
|
||||
<p>community-access-control works!</p>
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p>
|
||||
This form allows you to perform changes to the access condition of all the items owned by collection under this community.
|
||||
Changes can be performed on the access condition for the metadata (item) or for the content (bitstream).
|
||||
</p>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-12 col-md-6 border-right">
|
||||
<div class="d-flex align-items-center">
|
||||
<h4 class="mb-0 mr-4">Item's Metadata</h4>
|
||||
<ui-switch [(ngModel)]="state.item.toggleStatus"></ui-switch>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-3">Mode</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="itemMode" id="itemReplace" value="replace" [(ngModel)]="state.item.accessMode">
|
||||
<label class="form-check-label" for="itemReplace">Replace access conditions</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="itemMode" id="itemAdd" value="add" [(ngModel)]="state.item.accessMode">
|
||||
<label class="form-check-label" for="itemAdd">Add to existing ones</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<h5>Access conditions</h5>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
You have not specified any access conditions, the new items access conditions will be inherited from the owning collection.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ds-access-control-array-form
|
||||
#itemAccessCmp
|
||||
[dropdownOptions]="(dropdownData$ | async)?.itemAccessConditionOptions || []">
|
||||
</ds-access-control-array-form>
|
||||
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<h4 class="mb-0 mr-4">Bitstreams</h4>
|
||||
<ui-switch [(ngModel)]="state.bitstream.toggleStatus"></ui-switch>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-3">Mode</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="bitstreamMode" id="bitstreamReplace" value="replace" [(ngModel)]="state.bitstream.accessMode">
|
||||
<label class="form-check-label" for="bitstreamReplace">Replace access conditions</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="bitstreamMode" id="bitstreamAdd" value="add" [(ngModel)]="state.bitstream.accessMode">
|
||||
<label class="form-check-label" for="bitstreamAdd">Add to existing ones</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<h5>Access conditions</h5>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
You have not specified any access conditions, the new items access conditions will be inherited from the owning collection.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ds-access-control-array-form
|
||||
#bitstreamAccessCmp
|
||||
[dropdownOptions]="(dropdownData$ | async)?.bitstreamAccessConditionOptions || []">
|
||||
</ds-access-control-array-form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button class="btn btn-lg btn-outline-primary mr-3" (click)="reset()">Reset</button>
|
||||
<button class="btn btn-lg btn-primary" (click)="submit()">Execute</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,15 +1,56 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { CommunityAccessControlService } from './community-access-control.service';
|
||||
import { shareReplay } from 'rxjs';
|
||||
import {
|
||||
AccessControlArrayFormComponent
|
||||
} from '../../../shared/access-control-array-form/access-control-array-form.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-community-access-control',
|
||||
templateUrl: './community-access-control.component.html',
|
||||
styleUrls: ['./community-access-control.component.scss']
|
||||
styleUrls: ['./community-access-control.component.scss'],
|
||||
providers: [CommunityAccessControlService]
|
||||
})
|
||||
export class CommunityAccessControlComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent;
|
||||
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
|
||||
|
||||
constructor(private communityAccessControlService: CommunityAccessControlService) {}
|
||||
|
||||
state = initialState;
|
||||
|
||||
dropdownData$ = this.communityAccessControlService.dropdownData$.pipe(
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.bitstreamAccessCmp.reset();
|
||||
this.itemAccessCmp.reset();
|
||||
this.state = initialState;
|
||||
}
|
||||
|
||||
submit() {
|
||||
const bitstreamAccess = this.bitstreamAccessCmp.getValue();
|
||||
const itemAccess = this.itemAccessCmp.getValue();
|
||||
|
||||
console.log('bitstreamAccess', bitstreamAccess);
|
||||
console.log('itemAccess', itemAccess);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
item: {
|
||||
toggleStatus: false,
|
||||
accessMode: '',
|
||||
},
|
||||
bitstream: {
|
||||
toggleStatus: false,
|
||||
accessMode: '',
|
||||
},
|
||||
};
|
||||
|
@@ -0,0 +1,54 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AccessControlItem } from '../../../shared/access-control-array-form/access-control-array-form.component';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
export interface AccessControlDropdownDataResponse {
|
||||
id: string;
|
||||
itemAccessConditionOptions: AccessControlItem[];
|
||||
bitstreamAccessConditionOptions: AccessControlItem[];
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class CommunityAccessControlService {
|
||||
dropdownData$: Observable<AccessControlDropdownDataResponse> = of(accessControlDropdownData);
|
||||
}
|
||||
|
||||
const accessControlDropdownData: AccessControlDropdownDataResponse = {
|
||||
'id': 'default',
|
||||
'itemAccessConditionOptions': [
|
||||
{
|
||||
'name': 'openaccess'
|
||||
},
|
||||
{
|
||||
'name': 'administrator'
|
||||
},
|
||||
{
|
||||
'name': 'embargo',
|
||||
'hasStartDate': true,
|
||||
'maxStartDate': '2018-06-24T00:40:54.970+0000'
|
||||
},
|
||||
{
|
||||
'name': 'lease',
|
||||
'hasEndDate': true,
|
||||
'maxEndDate': '2017-12-24T00:40:54.970+0000'
|
||||
}
|
||||
],
|
||||
'bitstreamAccessConditionOptions': [
|
||||
{
|
||||
'name': 'openaccess'
|
||||
},
|
||||
{
|
||||
'name': 'administrator'
|
||||
},
|
||||
{
|
||||
'name': 'embargo',
|
||||
'hasStartDate': true,
|
||||
'maxStartDate': '2018-06-24T00:40:54.970+0000'
|
||||
},
|
||||
{
|
||||
'name': 'lease',
|
||||
'hasEndDate': true,
|
||||
'maxEndDate': '2017-12-24T00:40:54.970+0000'
|
||||
}
|
||||
]
|
||||
};
|
@@ -11,6 +11,10 @@ import { CommunityFormModule } from '../community-form/community-form.module';
|
||||
import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-policies.module';
|
||||
import { ComcolModule } from '../../shared/comcol/comcol.module';
|
||||
import { CommunityAccessControlComponent } from './community-access-control/community-access-control.component';
|
||||
import { UiSwitchModule } from 'ngx-ui-switch';
|
||||
import {
|
||||
AccessControlArrayFormModule
|
||||
} from '../../shared/access-control-array-form/access-control-array-form.component';
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Community page administrator functionality
|
||||
@@ -23,6 +27,8 @@ import { CommunityAccessControlComponent } from './community-access-control/comm
|
||||
CommunityFormModule,
|
||||
ComcolModule,
|
||||
ResourcePoliciesModule,
|
||||
UiSwitchModule,
|
||||
AccessControlArrayFormModule,
|
||||
],
|
||||
declarations: [
|
||||
EditCommunityPageComponent,
|
||||
|
@@ -39,6 +39,10 @@ import { IdentifierDataComponent } from '../../shared/object-list/identifier-dat
|
||||
import { ItemRegisterDoiComponent } from './item-register-doi/item-register-doi.component';
|
||||
import { DsoSharedModule } from '../../dso-shared/dso-shared.module';
|
||||
import { ItemAccessControlComponent } from './item-access-control/item-access-control.component';
|
||||
import {
|
||||
AccessControlArrayFormModule
|
||||
} from '../../shared/access-control-array-form/access-control-array-form.component';
|
||||
import { UiSwitchModule } from 'ngx-ui-switch';
|
||||
|
||||
|
||||
/**
|
||||
@@ -56,6 +60,8 @@ import { ItemAccessControlComponent } from './item-access-control/item-access-co
|
||||
NgbModule,
|
||||
ItemVersionsModule,
|
||||
DsoSharedModule,
|
||||
AccessControlArrayFormModule,
|
||||
UiSwitchModule,
|
||||
],
|
||||
declarations: [
|
||||
EditItemPageComponent,
|
||||
|
@@ -1 +1,110 @@
|
||||
<p>item-access-control works!</p>
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p>
|
||||
This form allows you to perform changes to the access condition of all the items owned by collection under this community.
|
||||
Changes can be performed on the access condition for the metadata (item) or for the content (bitstream).
|
||||
</p>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-12 col-md-6 border-right">
|
||||
<div class="d-flex align-items-center">
|
||||
<h4 class="mb-0 mr-4">Item's Metadata</h4>
|
||||
<ui-switch [(ngModel)]="state.item.toggleStatus"></ui-switch>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-3">Mode</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="itemMode" id="itemReplace" value="replace" [(ngModel)]="state.item.accessMode">
|
||||
<label class="form-check-label" for="itemReplace">Replace access conditions</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="itemMode" id="itemAdd" value="add" [(ngModel)]="state.item.accessMode">
|
||||
<label class="form-check-label" for="itemAdd">Add to existing ones</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<h5>Access conditions</h5>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
You have not specified any access conditions, the new items access conditions will be inherited from the owning collection.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ds-access-control-array-form
|
||||
#itemAccessCmp
|
||||
[dropdownOptions]="(dropdownData$ | async)?.itemAccessConditionOptions || []">
|
||||
</ds-access-control-array-form>
|
||||
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<h4 class="mb-0 mr-4">Bitstreams</h4>
|
||||
<ui-switch [(ngModel)]="state.bitstream.toggleStatus"></ui-switch>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12">Limit the changes to specific bitstreams</div>
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="changesLimit" id="processAll" value="all" [(ngModel)]="state.bitstream.changesLimit">
|
||||
<label class="form-check-label" for="processAll">process all the bitstreams in the item</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="changesLimit" id="processSelected" value="selected" [(ngModel)]="state.bitstream.changesLimit">
|
||||
<label class="form-check-label" for="processSelected">
|
||||
{{ state.bitstream.selectedBitstreams.length }} bitstreams selected
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-3">Mode</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="bitstreamMode" id="bitstreamReplace" value="replace" [(ngModel)]="state.bitstream.accessMode">
|
||||
<label class="form-check-label" for="bitstreamReplace">Replace access conditions</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="bitstreamMode" id="bitstreamAdd" value="add" [(ngModel)]="state.bitstream.accessMode">
|
||||
<label class="form-check-label" for="bitstreamAdd">Add to existing ones</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<h5>Access conditions</h5>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
You have not specified any access conditions, the new items access conditions will be inherited from the owning collection.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ds-access-control-array-form
|
||||
#bitstreamAccessCmp
|
||||
[dropdownOptions]="(dropdownData$ | async)?.bitstreamAccessConditionOptions || []">
|
||||
</ds-access-control-array-form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button class="btn btn-lg btn-outline-primary mr-3" (click)="reset()">Reset</button>
|
||||
<button class="btn btn-lg btn-primary" (click)="submit()">Execute</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,15 +1,64 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import {
|
||||
AccessControlArrayFormComponent
|
||||
} from '../../../shared/access-control-array-form/access-control-array-form.component';
|
||||
import {
|
||||
CollectionAccessControlService
|
||||
} from '../../../collection-page/edit-collection-page/collection-access-control/collection-access-control.service';
|
||||
import { shareReplay } from 'rxjs';
|
||||
import { ItemAccessControlService } from './item-access-control.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-item-access-control',
|
||||
templateUrl: './item-access-control.component.html',
|
||||
styleUrls: ['./item-access-control.component.scss']
|
||||
styleUrls: ['./item-access-control.component.scss'],
|
||||
providers: [ItemAccessControlService]
|
||||
})
|
||||
export class ItemAccessControlComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent;
|
||||
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
|
||||
|
||||
constructor(private itemAccessControlService: ItemAccessControlService) {}
|
||||
|
||||
state = initialState;
|
||||
|
||||
dropdownData$ = this.itemAccessControlService.dropdownData$.pipe(
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.bitstreamAccessCmp.reset();
|
||||
this.itemAccessCmp.reset();
|
||||
this.state = initialState;
|
||||
}
|
||||
|
||||
submit() {
|
||||
const bitstreamAccess = this.bitstreamAccessCmp.getValue();
|
||||
const itemAccess = this.itemAccessCmp.getValue();
|
||||
|
||||
this.itemAccessControlService.execute({
|
||||
bitstreamAccess,
|
||||
itemAccess,
|
||||
state: this.state
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
item: {
|
||||
toggleStatus: false,
|
||||
accessMode: '',
|
||||
},
|
||||
bitstream: {
|
||||
toggleStatus: false,
|
||||
accessMode: '',
|
||||
changesLimit: '', // 'all' | 'selected'
|
||||
selectedBitstreams: []
|
||||
},
|
||||
};
|
||||
|
@@ -0,0 +1,71 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AccessControlItem } from '../../../shared/access-control-array-form/access-control-array-form.component';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
export interface AccessControlDropdownDataResponse {
|
||||
id: string;
|
||||
itemAccessConditionOptions: AccessControlItem[];
|
||||
bitstreamAccessConditionOptions: AccessControlItem[];
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ItemAccessControlService {
|
||||
dropdownData$: Observable<AccessControlDropdownDataResponse> = of(accessControlDropdownData);
|
||||
|
||||
|
||||
execute(payload: any) {
|
||||
console.log('execute', payload);
|
||||
|
||||
const blob = new Blob([JSON.stringify(payload, null, 2)], {
|
||||
type: 'application/json',
|
||||
});
|
||||
|
||||
const file = new File([blob], 'data.json', {
|
||||
type: 'application/json',
|
||||
});
|
||||
|
||||
const url = URL.createObjectURL(file);
|
||||
window.open(url, '_blank');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const accessControlDropdownData: AccessControlDropdownDataResponse = {
|
||||
'id': 'default',
|
||||
'itemAccessConditionOptions': [
|
||||
{
|
||||
'name': 'openaccess'
|
||||
},
|
||||
{
|
||||
'name': 'administrator'
|
||||
},
|
||||
{
|
||||
'name': 'embargo',
|
||||
'hasStartDate': true,
|
||||
'maxStartDate': '2018-06-24T00:40:54.970+0000'
|
||||
},
|
||||
{
|
||||
'name': 'lease',
|
||||
'hasEndDate': true,
|
||||
'maxEndDate': '2017-12-24T00:40:54.970+0000'
|
||||
}
|
||||
],
|
||||
'bitstreamAccessConditionOptions': [
|
||||
{
|
||||
'name': 'openaccess'
|
||||
},
|
||||
{
|
||||
'name': 'administrator'
|
||||
},
|
||||
{
|
||||
'name': 'embargo',
|
||||
'hasStartDate': true,
|
||||
'maxStartDate': '2018-06-24T00:40:54.970+0000'
|
||||
},
|
||||
{
|
||||
'name': 'lease',
|
||||
'hasEndDate': true,
|
||||
'maxEndDate': '2017-12-24T00:40:54.970+0000'
|
||||
}
|
||||
]
|
||||
};
|
@@ -0,0 +1,68 @@
|
||||
<form [formGroup]="form">
|
||||
<ng-container *ngFor="let control of accessControl.controls; let i = index">
|
||||
<div [formGroup]="$any(control)"
|
||||
class="mt-3" data-testId="access-control-item"
|
||||
style="display: grid; grid-template-columns: 1fr 1fr 1fr 50px; grid-gap: 5px">
|
||||
|
||||
<div>
|
||||
<select id="accesscontroloption" formControlName="itemName" class="form-control">
|
||||
<option value=""></option>
|
||||
<option *ngFor="let option of dropdownOptions" [value]="option.name">
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="input-group">
|
||||
<input
|
||||
class="form-control"
|
||||
placeholder="yyyy-mm-dd"
|
||||
name="dp"
|
||||
formControlName="startDate"
|
||||
[minDate]="control | maxStartDate: dropdownOptions"
|
||||
ngbDatepicker
|
||||
#d="ngbDatepicker"
|
||||
/>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary fas fa-calendar" (click)="d.toggle()"
|
||||
type="button"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="input-group">
|
||||
<input
|
||||
class="form-control"
|
||||
placeholder="yyyy-mm-dd"
|
||||
name="dp"
|
||||
formControlName="endDate"
|
||||
[maxDate]="control | maxEndDate: dropdownOptions"
|
||||
ngbDatepicker
|
||||
#d1="ngbDatepicker"
|
||||
/>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary fas fa-calendar" (click)="d1.toggle()"
|
||||
type="button">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="button" (click)="removeAccessControlItem(i)" class="btn btn-outline-danger">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
|
||||
<button type="button" id="add-btn" class="btn btn-outline-primary mt-3"
|
||||
(click)="addAccessControlItem()">
|
||||
<i class="fas fa-plus"></i>
|
||||
Add more
|
||||
</button>
|
||||
|
||||
</form>
|
@@ -0,0 +1,101 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AccessControlArrayFormComponent, AccessControlItemValue } from './access-control-array-form.component';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { SharedBrowseByModule } from '../browse-by/shared-browse-by.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ControlMaxStartDatePipe } from './control-max-start-date.pipe';
|
||||
import { ControlMaxEndDatePipe } from './control-max-end-date.pipe';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
fdescribe('AccessControlArrayFormComponent', () => {
|
||||
let component: AccessControlArrayFormComponent;
|
||||
let fixture: ComponentFixture<AccessControlArrayFormComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ CommonModule, ReactiveFormsModule, SharedBrowseByModule, TranslateModule, NgbDatepickerModule ],
|
||||
declarations: [ AccessControlArrayFormComponent, ControlMaxStartDatePipe, ControlMaxEndDatePipe ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AccessControlArrayFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.dropdownOptions = [{name: 'Option1'}, {name: 'Option2'}];
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have only one empty control access item in the form', () => {
|
||||
const accessControlItems = fixture.debugElement.queryAll(By.css('[data-testId="access-control-item"]'));
|
||||
expect(accessControlItems.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should add access control item', () => {
|
||||
component.addAccessControlItem();
|
||||
expect(component.accessControl.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should remove access control item', () => {
|
||||
component.removeAccessControlItem(0);
|
||||
expect(component.accessControl.length).toEqual(0);
|
||||
|
||||
component.addAccessControlItem();
|
||||
component.removeAccessControlItem(0);
|
||||
expect(component.accessControl.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should set access control item value', () => {
|
||||
const item: AccessControlItemValue = { itemName: 'item1', startDate: '2022-01-01', endDate: '2022-02-01' };
|
||||
component.addAccessControlItem(item.itemName);
|
||||
component.accessControl.controls[0].patchValue(item);
|
||||
expect(component.form.value.accessControl[0]).toEqual(item);
|
||||
});
|
||||
|
||||
it('should reset form value', () => {
|
||||
const item: AccessControlItemValue = { itemName: 'item1', startDate: '2022-01-01', endDate: '2022-02-01' };
|
||||
component.addAccessControlItem(item.itemName);
|
||||
component.accessControl.controls[1].patchValue(item);
|
||||
component.reset();
|
||||
expect(component.form.value.accessControl[1].value).toEqual(undefined);
|
||||
});
|
||||
|
||||
|
||||
it('should display a select dropdown with options', () => {
|
||||
const selectElement: DebugElement = fixture.debugElement.query(By.css('select#accesscontroloption'));
|
||||
expect(selectElement).toBeTruthy();
|
||||
|
||||
const options = selectElement.nativeElement.querySelectorAll('option');
|
||||
expect(options.length).toEqual(3); // 2 options + default empty option
|
||||
|
||||
expect(options[0].value).toEqual('');
|
||||
expect(options[1].value).toEqual('Option1');
|
||||
expect(options[2].value).toEqual('Option2');
|
||||
});
|
||||
|
||||
it('should add new access control items when clicking "Add more" button', () => {
|
||||
const addButton: DebugElement = fixture.debugElement.query(By.css('button#add-btn'));
|
||||
addButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
const accessControlItems = fixture.debugElement.queryAll(By.css('[data-testId="access-control-item"]'));
|
||||
expect(accessControlItems.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should remove access control items when clicking remove button', () => {
|
||||
const removeButton: DebugElement = fixture.debugElement.query(By.css('button.btn-outline-danger'));
|
||||
removeButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
const accessControlItems = fixture.debugElement.queryAll(By.css('[data-testId="access-control-item"]'));
|
||||
expect(accessControlItems.length).toEqual(0);
|
||||
});
|
||||
});
|
@@ -0,0 +1,88 @@
|
||||
import { Component, Input, NgModule, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormArray, FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SharedBrowseByModule } from '../browse-by/shared-browse-by.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ControlMaxStartDatePipe } from './control-max-start-date.pipe';
|
||||
import { ControlMaxEndDatePipe } from './control-max-end-date.pipe';
|
||||
|
||||
// type of the dropdown item that comes from backend
|
||||
export interface AccessControlItem {
|
||||
name: string
|
||||
hasStartDate?: boolean
|
||||
maxStartDate?: string
|
||||
hasEndDate?: boolean
|
||||
maxEndDate?: string
|
||||
}
|
||||
|
||||
// will be used on the form value
|
||||
export interface AccessControlItemValue {
|
||||
itemName: string | null; // item name
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}
|
||||
|
||||
export interface AccessControlArrayFormValue {
|
||||
accessControl: AccessControlItemValue[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ds-access-control-array-form',
|
||||
templateUrl: './access-control-array-form.component.html',
|
||||
styleUrls: [ './access-control-array-form.component.scss' ]
|
||||
})
|
||||
export class AccessControlArrayFormComponent implements OnInit {
|
||||
@Input() dropdownOptions: AccessControlItem[] = [];
|
||||
@Input() accessControlItems: AccessControlItemValue[] = [];
|
||||
|
||||
form = this.fb.group({
|
||||
accessControl: this.fb.array([])
|
||||
});
|
||||
|
||||
constructor(private fb: FormBuilder) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.accessControlItems.length === 0) {
|
||||
this.addAccessControlItem();
|
||||
} else {
|
||||
for (const item of this.accessControlItems) {
|
||||
this.addAccessControlItem(item.itemName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get accessControl() {
|
||||
return this.form.get('accessControl') as FormArray;
|
||||
}
|
||||
|
||||
addAccessControlItem(itemName: string = null) {
|
||||
this.accessControl.push(this.fb.group({
|
||||
itemName,
|
||||
startDate: null,
|
||||
endDate: null
|
||||
}));
|
||||
}
|
||||
|
||||
removeAccessControlItem(index: number) {
|
||||
this.accessControl.removeAt(index);
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.form.value;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.accessControl.reset([]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule, ReactiveFormsModule, SharedBrowseByModule, TranslateModule, NgbDatepickerModule ],
|
||||
declarations: [ AccessControlArrayFormComponent, ControlMaxStartDatePipe, ControlMaxEndDatePipe ],
|
||||
exports: [ AccessControlArrayFormComponent ],
|
||||
})
|
||||
export class AccessControlArrayFormModule {
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { AbstractControl } from '@angular/forms';
|
||||
import { NgbDateStruct } from '@ng-bootstrap/ng-bootstrap/datepicker/ngb-date-struct';
|
||||
import { AccessControlItem } from './access-control-array-form.component';
|
||||
|
||||
@Pipe({
|
||||
// eslint-disable-next-line @angular-eslint/pipe-prefix
|
||||
name: 'maxEndDate',
|
||||
pure: false
|
||||
})
|
||||
export class ControlMaxEndDatePipe implements PipeTransform {
|
||||
transform(control: AbstractControl, dropdownOptions: AccessControlItem[]): NgbDateStruct | null {
|
||||
const { itemName } = control.value;
|
||||
const item = dropdownOptions.find((x) => x.name === itemName);
|
||||
if (!item?.hasEndDate) {
|
||||
return null;
|
||||
}
|
||||
const date = new Date(item.maxEndDate);
|
||||
return {
|
||||
year: date.getFullYear(),
|
||||
month: date.getMonth() + 1,
|
||||
day: date.getDate()
|
||||
} as NgbDateStruct;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { AbstractControl } from '@angular/forms';
|
||||
import { NgbDateStruct } from '@ng-bootstrap/ng-bootstrap/datepicker/ngb-date-struct';
|
||||
import { AccessControlItem } from './access-control-array-form.component';
|
||||
|
||||
@Pipe({
|
||||
// eslint-disable-next-line @angular-eslint/pipe-prefix
|
||||
name: 'maxStartDate',
|
||||
pure: false
|
||||
})
|
||||
export class ControlMaxStartDatePipe implements PipeTransform {
|
||||
transform(control: AbstractControl, dropdownOptions: AccessControlItem[]): NgbDateStruct | null {
|
||||
const { itemName } = control.value;
|
||||
const item = dropdownOptions.find((x) => x.name === itemName);
|
||||
if (!item?.hasStartDate) {
|
||||
return null;
|
||||
}
|
||||
const date = new Date(item.maxStartDate);
|
||||
return {
|
||||
year: date.getFullYear(),
|
||||
month: date.getMonth() + 1,
|
||||
day: date.getDate()
|
||||
} as NgbDateStruct;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user