[Library | Trunk]: Create subscriber invite and subscribers components.
git-svn-id: https://svn.driver.research-infrastructures.eu/driver/dnet40/modules/uoa-services-library/trunk/ng-openaire-library/src/app@60274 d315682c-612b-4755-9ff5-7f18f6832af3
This commit is contained in:
parent
83493a1abc
commit
7d147b89e7
|
@ -1,211 +1,252 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient, HttpHeaders} from "@angular/common/http";
|
||||
import { CommunityInfo } from './communityInfo';
|
||||
import {CommunityInfo} from './communityInfo';
|
||||
import {EnvProperties} from '../../utils/properties/env-properties';
|
||||
import {map} from "rxjs/operators";
|
||||
import {BehaviorSubject, from, Subscriber} from "rxjs";
|
||||
import {properties} from "../../../../environments/environment";
|
||||
import {HelperFunctions} from "../../utils/HelperFunctions.class";
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class CommunityService {
|
||||
|
||||
|
||||
public community: BehaviorSubject<CommunityInfo> = null;
|
||||
private promise: Promise<boolean> = null;
|
||||
|
||||
private sub;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
this.community = new BehaviorSubject(null);
|
||||
}
|
||||
sub;
|
||||
|
||||
ngOnDestroy() {
|
||||
this.clearSubscriptions();
|
||||
}
|
||||
clearSubscriptions(){
|
||||
|
||||
clearSubscriptions() {
|
||||
if (this.sub instanceof Subscriber) {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove these functions
|
||||
getCommunityByService(properties: EnvProperties, url: string) {
|
||||
this.promise = new Promise<any>(resolve => {
|
||||
this.sub = this.getCommunity(properties, url).subscribe(res => {
|
||||
this.community.next(res);
|
||||
resolve();
|
||||
},
|
||||
error => {
|
||||
this.community.error(error);
|
||||
resolve();
|
||||
})
|
||||
this.community.next(res);
|
||||
resolve();
|
||||
},
|
||||
error => {
|
||||
this.community.error(error);
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async getCommunityByStateAsync(properties: EnvProperties, url: string) {
|
||||
if(!this.promise) {
|
||||
|
||||
async getCommunityByStateAsync(properties: EnvProperties, url: string) {
|
||||
if (!this.promise) {
|
||||
this.getCommunityByService(properties, url);
|
||||
}
|
||||
|
||||
|
||||
await this.promise;
|
||||
this.clearSubscriptions();
|
||||
return this.community.getValue();
|
||||
}
|
||||
|
||||
|
||||
public getCommunityAsObservable() {
|
||||
return this.community.asObservable();
|
||||
}
|
||||
|
||||
setCommunity(community: CommunityInfo) {
|
||||
this.community.next(community);
|
||||
}
|
||||
|
||||
private formalize(element: any) {
|
||||
return HelperFunctions.copy(element);
|
||||
}
|
||||
|
||||
getCommunityByState(properties: EnvProperties, url: string) {
|
||||
return from(this.getCommunityByStateAsync(properties, url));
|
||||
}
|
||||
|
||||
|
||||
getCommunity(properties: EnvProperties, url: string) {
|
||||
return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
|
||||
.pipe(map(res => this.parseCommunity(res)));
|
||||
return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
|
||||
.pipe(map(res => this.parseCommunity(res)));
|
||||
}
|
||||
|
||||
|
||||
// TODO remove NEW from function names
|
||||
getCommunityNew(communityId: string) {
|
||||
if(!this.community.value || this.community.value.communityId !== communityId) {
|
||||
this.promise = new Promise<any>((resolve, reject) => {
|
||||
this.sub = this.http.get<CommunityInfo>(properties.communityAPI + communityId)
|
||||
.pipe(map(community => this.formalize(this.parseCommunity(community)))).subscribe(community => {
|
||||
this.community.next(community);
|
||||
resolve();
|
||||
},
|
||||
error => {
|
||||
this.community.next(null);
|
||||
reject();
|
||||
})
|
||||
});
|
||||
}
|
||||
return from(this.getCommunityAsync());
|
||||
}
|
||||
|
||||
async getCommunityAsync() {
|
||||
await this.promise;
|
||||
this.clearSubscriptions();
|
||||
return this.community.getValue();
|
||||
}
|
||||
|
||||
updateCommunity(url: string, community: any) {
|
||||
//const headers = new Headers({'Content-Type': 'application/json'});
|
||||
//const options = new RequestOptions({headers: headers});
|
||||
|
||||
const options = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
};
|
||||
|
||||
const body = JSON.stringify(community);
|
||||
return this.http.post(url, body, options);
|
||||
/*.map(res => res.json())*/
|
||||
//const headers = new Headers({'Content-Type': 'application/json'});
|
||||
//const options = new RequestOptions({headers: headers});
|
||||
|
||||
const options = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
};
|
||||
|
||||
const body = JSON.stringify(community);
|
||||
return this.http.post(url, body, options);
|
||||
/*.map(res => res.json())*/
|
||||
}
|
||||
|
||||
|
||||
async isCommunityManagerByStateAsync(properties: EnvProperties, url: string, manager: string) {
|
||||
if(!this.promise) {
|
||||
if (!this.promise) {
|
||||
this.getCommunityByService(properties, url);
|
||||
}
|
||||
|
||||
|
||||
await this.promise;
|
||||
let community: CommunityInfo = this.community.getValue();
|
||||
return (community.managers.indexOf(manager) !== -1);
|
||||
}
|
||||
|
||||
|
||||
isCommunityManagerByState(properties: EnvProperties, url: string, manager: string) {
|
||||
return from(this.isCommunityManagerByStateAsync(properties, url, manager));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
isCommunityManager(properties: EnvProperties, url: string, manager: string) {
|
||||
return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
|
||||
//.map(res => <any> res.json())
|
||||
.pipe(map(res => this.parseCommunity(res)))
|
||||
.pipe(map(community => community.managers.indexOf(manager) !== -1));
|
||||
//.map(res => <any> res.json())
|
||||
.pipe(map(res => this.parseCommunity(res)))
|
||||
.pipe(map(community => community.managers.indexOf(manager) !== -1));
|
||||
}
|
||||
|
||||
|
||||
async isTypeByStateAsync(properties: EnvProperties, url: string, type: string) {
|
||||
if(!this.promise) {
|
||||
if (!this.promise) {
|
||||
this.getCommunityByService(properties, url);
|
||||
}
|
||||
|
||||
|
||||
await this.promise;
|
||||
let community: CommunityInfo = this.community.getValue();
|
||||
return (community && community.type && community.type === type);
|
||||
}
|
||||
|
||||
|
||||
isRITypeByState(properties: EnvProperties, url: string) {
|
||||
return from(this.isTypeByStateAsync(properties, url, "ri"));
|
||||
}
|
||||
|
||||
|
||||
isCommunityTypeByState(properties: EnvProperties, url: string) {
|
||||
return from(this.isTypeByStateAsync(properties, url, "community"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
isRIType(properties: EnvProperties, url: string) {
|
||||
return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
|
||||
//.map(res => <any> res.json())
|
||||
.pipe(map(res => this.parseCommunity(res)))
|
||||
.pipe(map(community => (community && community.type && community.type === 'ri')));
|
||||
//.map(res => <any> res.json())
|
||||
.pipe(map(res => this.parseCommunity(res)))
|
||||
.pipe(map(community => (community && community.type && community.type === 'ri')));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
isCommunityType(properties: EnvProperties, url: string) {
|
||||
return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
|
||||
//.map(res => <any> res.json())
|
||||
.pipe(map(res => this.parseCommunity(res)))
|
||||
.pipe(map(community => (community && community.type && community.type === 'community')));
|
||||
return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
|
||||
//.map(res => <any> res.json())
|
||||
.pipe(map(res => this.parseCommunity(res)))
|
||||
.pipe(map(community => (community && community.type && community.type === 'community')));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
* @deprecated
|
||||
*/
|
||||
isSubscribedToCommunity(pid: string, email: string, url: string) {
|
||||
return this.http.get(url + '/'+ properties.adminToolsPortalType +'/' + pid + '/subscribers')
|
||||
//.map(res => ((<any>res === '') ? {} : <any> res.json()))
|
||||
.pipe(map(res => {
|
||||
if (res['subscribers'] && res['subscribers'] != null) {
|
||||
|
||||
for (let i = 0; i < res['subscribers'].length; i++ ) {
|
||||
if (res['subscribers'][i] != null && res['subscribers'][i].email === email) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
private parseCommunity(data: any): CommunityInfo {
|
||||
|
||||
const resData = Array.isArray(data) ? data[0] : data;
|
||||
|
||||
const community: CommunityInfo = new CommunityInfo();
|
||||
community['title'] = resData.name;
|
||||
community['shortTitle'] = resData.shortName;
|
||||
community['communityId'] = resData.id;
|
||||
community['queryId'] = resData.queryId;
|
||||
community['logoUrl'] = resData.logoUrl;
|
||||
community['description'] = resData.description;
|
||||
community['date'] = resData.creationDate;
|
||||
community['zenodoCommunity'] = resData.zenodoCommunity;
|
||||
community['status'] = 'all';
|
||||
if (resData.hasOwnProperty('status')) {
|
||||
community['status'] = resData.status;
|
||||
const status = ['all', 'hidden', 'manager'];
|
||||
if (status.indexOf(community['status']) === -1) {
|
||||
community['status'] = 'hidden';
|
||||
return this.http.get(url + '/' + properties.adminToolsPortalType + '/' + pid + '/subscribers')
|
||||
//.map(res => ((<any>res === '') ? {} : <any> res.json()))
|
||||
.pipe(map(res => {
|
||||
if (res['subscribers'] && res['subscribers'] != null) {
|
||||
|
||||
for (let i = 0; i < res['subscribers'].length; i++) {
|
||||
if (res['subscribers'][i] != null && res['subscribers'][i].email === email) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resData.type != null) {
|
||||
community['type'] = resData.type;
|
||||
}
|
||||
|
||||
if (resData.managers != null) {
|
||||
if (community['managers'] === undefined) {
|
||||
community['managers'] = new Array<string>();
|
||||
}
|
||||
|
||||
const managers = resData.managers;
|
||||
const length = Array.isArray(managers) ? managers.length : 1;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const manager = Array.isArray(managers) ? managers[i] : managers;
|
||||
community.managers[i] = manager;
|
||||
}
|
||||
}
|
||||
|
||||
if (resData.subjects != null) {
|
||||
if (community['subjects'] === undefined) {
|
||||
community['subjects'] = new Array<string>();
|
||||
}
|
||||
|
||||
const subjects = resData.subjects;
|
||||
const length = Array.isArray(subjects) ? subjects.length : 1;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const subject = Array.isArray(subjects) ? subjects[i] : subjects;
|
||||
community.subjects[i] = subject;
|
||||
}
|
||||
}
|
||||
return community;
|
||||
return false;
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
private parseCommunity(data: any): CommunityInfo {
|
||||
|
||||
const resData = Array.isArray(data) ? data[0] : data;
|
||||
|
||||
const community: CommunityInfo = new CommunityInfo();
|
||||
community['title'] = resData.name;
|
||||
community['shortTitle'] = resData.shortName;
|
||||
community['communityId'] = resData.id;
|
||||
community['queryId'] = resData.queryId;
|
||||
community['logoUrl'] = resData.logoUrl;
|
||||
community['description'] = resData.description;
|
||||
community['date'] = resData.creationDate;
|
||||
community['zenodoCommunity'] = resData.zenodoCommunity;
|
||||
community['status'] = 'all';
|
||||
if (resData.hasOwnProperty('status')) {
|
||||
community['status'] = resData.status;
|
||||
const status = ['all', 'hidden', 'manager'];
|
||||
if (status.indexOf(community['status']) === -1) {
|
||||
community['status'] = 'hidden';
|
||||
}
|
||||
}
|
||||
if (resData.type != null) {
|
||||
community['type'] = resData.type;
|
||||
}
|
||||
|
||||
if (resData.managers != null) {
|
||||
if (community['managers'] === undefined) {
|
||||
community['managers'] = new Array<string>();
|
||||
}
|
||||
|
||||
const managers = resData.managers;
|
||||
const length = Array.isArray(managers) ? managers.length : 1;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const manager = Array.isArray(managers) ? managers[i] : managers;
|
||||
community.managers[i] = manager;
|
||||
}
|
||||
}
|
||||
|
||||
if (resData.subjects != null) {
|
||||
if (community['subjects'] === undefined) {
|
||||
community['subjects'] = new Array<string>();
|
||||
}
|
||||
|
||||
const subjects = resData.subjects;
|
||||
const length = Array.isArray(subjects) ? subjects.length : 1;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const subject = Array.isArray(subjects) ? subjects[i] : subjects;
|
||||
community.subjects[i] = subject;
|
||||
}
|
||||
}
|
||||
return community;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,14 +12,16 @@
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div [class.uk-invisible]="loadActive || loadPending" class="uk-width-1-5@l uk-width-1-3@m uk-width-1-1 uk-flex uk-flex-right@m uk-flex-center">
|
||||
<div [class.uk-invisible]="loadActive || loadPending"
|
||||
class="uk-width-1-5@l uk-width-1-3@m uk-width-1-1 uk-flex uk-flex-right@m uk-flex-center">
|
||||
<a *ngIf="exists" class="uk-text-uppercase uk-flex uk-flex-middle" (click)="openInviteModal()">
|
||||
<button class="uk-icon-button large uk-button-secondary">
|
||||
<icon name="person_add"></icon>
|
||||
</button>
|
||||
<button class="uk-button uk-button-link uk-margin-small-left uk-text-secondary">Invite {{role}}</button>
|
||||
</a>
|
||||
<a *ngIf="!exists && isPortalAdmin" class="uk-text-uppercase uk-flex uk-flex-middle" (click)="openCreateRoleModal()">
|
||||
<a *ngIf="!exists && isPortalAdmin" class="uk-text-uppercase uk-flex uk-flex-middle"
|
||||
(click)="openCreateRoleModal()">
|
||||
<button class="uk-icon-button large uk-button-secondary">
|
||||
<icon name="person_add"></icon>
|
||||
</button>
|
||||
|
@ -32,7 +34,7 @@
|
|||
<div *ngIf="loadActive || loadPending" class="uk-margin-large-top">
|
||||
<loading></loading>
|
||||
</div>
|
||||
<div *ngIf="!loadActive && !loadPending" class="uk-margin-medium-top">
|
||||
<div *ngIf="!loadActive && !loadPending">
|
||||
<div *ngIf="(showActive && active.length == 0) || (!showActive && pending.length == 0)"
|
||||
class="uk-card uk-card-default uk-padding-large uk-text-center uk-margin-bottom uk-text-bold">
|
||||
<div *ngIf="showActive">No {{role}}s for {{name}}</div>
|
||||
|
|
|
@ -8,8 +8,6 @@ import {properties} from "../../../../../environments/environment";
|
|||
import {Session, User} from "../../../login/utils/helper.class";
|
||||
import {UserManagementService} from "../../../services/user-management.service";
|
||||
import {Router} from "@angular/router";
|
||||
import {LoginErrorCodes} from "../../../login/utils/guardHelper.class";
|
||||
import {Composer} from "../../../utils/email/composer";
|
||||
import {StringUtils} from "../../../utils/string-utils.class";
|
||||
|
||||
declare var UIkit;
|
||||
|
|
|
@ -2,7 +2,6 @@ import {NgModule} from '@angular/core';
|
|||
import {CommonModule} from '@angular/common';
|
||||
import {RoleUsersComponent} from './role-users.component';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {EmailService} from "../../../utils/email/email.service";
|
||||
import {AlertModalModule} from "../../../utils/modal/alertModal.module";
|
||||
import {LoadingModule} from "../../../utils/loading/loading.module";
|
||||
import {IconsService} from "../../../utils/icons/icons.service";
|
||||
|
@ -15,8 +14,7 @@ import {SafeHtmlPipeModule} from "../../../utils/pipes/safeHTMLPipe.module";
|
|||
@NgModule({
|
||||
imports: [CommonModule, AlertModalModule, ReactiveFormsModule, LoadingModule, IconsModule, InputModule, PageContentModule, SafeHtmlPipeModule],
|
||||
declarations: [RoleUsersComponent],
|
||||
exports: [RoleUsersComponent],
|
||||
providers: [EmailService]
|
||||
exports: [RoleUsersComponent]
|
||||
})
|
||||
export class RoleUsersModule {
|
||||
constructor(private iconsService: IconsService) {
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<div page-content>
|
||||
<div header>
|
||||
<ng-content></ng-content>
|
||||
<div [class.uk-invisible]="loading" class="uk-flex uk-flex-right@m uk-flex-center uk-flex-wrap uk-flex-middle uk-grid" uk-grid>
|
||||
<div search-input [control]="filterForm.controls.keyword" [showSearch]="false" placeholder="Search"
|
||||
[bordered]="true" colorClass="uk-text-secondary" toggleTitle="locate subscribers"></div>
|
||||
<div>
|
||||
<a *ngIf="exists" class="uk-text-uppercase uk-flex uk-flex-middle" [class.uk-disabled]="!subscriberInvite || subscriberInvite.loading" (click)="openInviteModal()">
|
||||
<button class="uk-icon-button large uk-button-secondary">
|
||||
<icon name="person_add"></icon>
|
||||
</button>
|
||||
<button class="uk-button uk-button-link uk-margin-small-left uk-text-secondary">Invite Subscribers</button>
|
||||
</a>
|
||||
<a *ngIf="!exists && isPortalAdmin" class="uk-text-uppercase uk-flex uk-flex-middle" (click)="openCreateRoleModal()">
|
||||
<button class="uk-icon-button large uk-button-secondary">
|
||||
<icon name="person_add"></icon>
|
||||
</button>
|
||||
<button class="uk-button uk-button-link uk-margin-small-left uk-text-secondary">Create Group</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div inner>
|
||||
<div *ngIf="loading" class="uk-margin-large-top">
|
||||
<loading></loading>
|
||||
</div>
|
||||
<div *ngIf="!loading">
|
||||
<div *ngIf="showSubscribers.length == 0"
|
||||
class="uk-card uk-card-default uk-padding-large uk-text-center uk-margin-bottom uk-text-bold">
|
||||
<div>No subscribers for {{name}}</div>
|
||||
</div>
|
||||
<div *ngIf="showSubscribers.length > 0">
|
||||
<no-load-paging *ngIf="showSubscribers.length > pageSize" [type]="'subscribers'"
|
||||
(pageChange)="updatePage($event)"
|
||||
[page]="page" [pageSize]="pageSize"
|
||||
[totalResults]="showSubscribers.length">
|
||||
</no-load-paging>
|
||||
<div class="uk-margin-medium-top uk-margin-medium-bottom">
|
||||
<div class="uk-card uk-card-default uk-card-body uk-text-small uk-margin-bottom"
|
||||
*ngFor="let item of showSubscribers.slice((page - 1)*pageSize, page*pageSize)">
|
||||
<div class="uk-grid uk-grid-divider uk-flex uk-flex-middle" uk-grid>
|
||||
<div class="uk-width-3-4@l uk-width-1-2@m">
|
||||
<div class="uk-padding-small uk-padding-remove-horizontal">
|
||||
<span class="uk-text-muted">Email: </span>
|
||||
<span class="uk-text-bold">{{item.email}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-width-expand">
|
||||
<div class="uk-padding-small uk-padding-remove-horizontal uk-flex uk-flex-center">
|
||||
<a (click)="openDeleteModal(item)" class="uk-button action uk-flex uk-flex-middle">
|
||||
<icon name="remove_circle_outline" ratio="0.7" [flex]="true"></icon>
|
||||
<span class="uk-margin-small-left">Remove subscriber</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<no-load-paging *ngIf="showSubscribers.length > pageSize" [type]="'subscribers'"
|
||||
(pageChange)="updatePage($event)"
|
||||
[page]="page" [pageSize]="pageSize"
|
||||
[totalResults]="showSubscribers.length">
|
||||
</no-load-paging>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<modal-alert *ngIf="user" #inviteModal (alertOutput)="subscriberInvite.invite()" [okDisabled]="!subscriberInvite.valid" [large]="true">
|
||||
<div class="uk-padding uk-padding-remove-horizontal">
|
||||
<subscriber-invite #subscriberInvite [user]="user"></subscriber-invite>
|
||||
</div>
|
||||
</modal-alert>
|
||||
<modal-alert #deleteModal (alertOutput)="deleteSubscriber()">
|
||||
<div *ngIf="selectedUser" class="uk-padding-small uk-padding-remove-horizontal">
|
||||
Are you sure you want to remove <span class="uk-text-bold">{{selectedUser}}</span> from subscribers?
|
||||
</div>
|
||||
</modal-alert>
|
||||
<modal-alert #createRoleModal (alertOutput)="createGroup()" [okDisabled]="roleFb && roleFb.invalid">
|
||||
<div *ngIf="roleFb" class="uk-padding uk-padding-remove-horizontal">
|
||||
<div class="uk-grid" uk-grid [formGroup]="roleFb">
|
||||
<div dashboard-input [formInput]="roleFb.get('name')"
|
||||
label="Name"
|
||||
placeholder="Write a name..." class="uk-width-1-1"></div>
|
||||
<div dashboard-input [formInput]="roleFb.get('description')"
|
||||
label="Description"
|
||||
type="textarea"
|
||||
placeholder="Write a description..." class="uk-width-1-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</modal-alert>
|
|
@ -0,0 +1,184 @@
|
|||
import {Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild} from '@angular/core';
|
||||
import {Subscription} from 'rxjs/Rx';
|
||||
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
|
||||
import {AlertModal} from "../../../utils/modal/alert";
|
||||
import {UserRegistryService} from "../../../services/user-registry.service";
|
||||
import {EnvProperties} from "../../../utils/properties/env-properties";
|
||||
import {properties} from "../../../../../environments/environment";
|
||||
import {Session, User} from "../../../login/utils/helper.class";
|
||||
import {UserManagementService} from "../../../services/user-management.service";
|
||||
import {Router} from "@angular/router";
|
||||
import {Composer} from "../../../utils/email/composer";
|
||||
import {SubscriberInviteComponent} from "../../../sharedComponents/subscriber-invite/subscriber-invite.component";
|
||||
|
||||
declare var UIkit;
|
||||
|
||||
@Component({
|
||||
selector: 'subscribers',
|
||||
templateUrl: 'subscribers.component.html'
|
||||
})
|
||||
export class SubscribersComponent implements OnInit, OnDestroy, OnChanges {
|
||||
|
||||
@Input()
|
||||
public id: string;
|
||||
@Input()
|
||||
public type: string;
|
||||
@Input()
|
||||
public name: string;
|
||||
@Input()
|
||||
public link: string;
|
||||
@Input()
|
||||
public message: string = null;
|
||||
public user: User = null;
|
||||
public subscribers: any[];
|
||||
public showSubscribers: any[];
|
||||
public subs: any[] = [];
|
||||
public loading: boolean = true;
|
||||
public selectedUser: string = null;
|
||||
public properties: EnvProperties = properties;
|
||||
public exists: boolean = true;
|
||||
public roleFb: FormGroup;
|
||||
/* Paging */
|
||||
page: number = 1;
|
||||
pageSize: number = 10;
|
||||
/* Search */
|
||||
filterForm: FormGroup;
|
||||
@ViewChild('inviteModal') inviteModal: AlertModal;
|
||||
@ViewChild('deleteModal') deleteModal: AlertModal;
|
||||
@ViewChild('createRoleModal') createRoleModal: AlertModal;
|
||||
@ViewChild('subscriberInvite') subscriberInvite: SubscriberInviteComponent;
|
||||
|
||||
constructor(private userRegistryService: UserRegistryService,
|
||||
private userManagementService: UserManagementService,
|
||||
private router: Router,
|
||||
private fb: FormBuilder) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.filterForm = this.fb.group({
|
||||
keyword: this.fb.control('')
|
||||
});
|
||||
this.subs.push(this.filterForm.get('keyword').valueChanges.subscribe(value => {
|
||||
this.filterBySearch(value);
|
||||
}));
|
||||
this.updateList();
|
||||
this.userManagementService.getUserInfo().subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.role) {
|
||||
this.updateList();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subs.forEach(sub => {
|
||||
if (sub instanceof Subscription) {
|
||||
sub.unsubscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateList() {
|
||||
this.loading = true;
|
||||
this.subs.push(this.userRegistryService.getActiveEmail(this.type, this.id, 'member').subscribe(users => {
|
||||
this.subscribers = users;
|
||||
this.filterBySearch(this.filterForm.value.keyword);
|
||||
this.loading = false;
|
||||
this.exists = true;
|
||||
}, error => {
|
||||
this.subscribers = [];
|
||||
this.showSubscribers = [];
|
||||
if (error.status === 404) {
|
||||
this.exists = false;
|
||||
}
|
||||
this.loading = false;
|
||||
}));
|
||||
}
|
||||
|
||||
openDeleteModal(item: any) {
|
||||
this.selectedUser = item.email;
|
||||
this.deleteModal.alertTitle = 'Delete subscriber';
|
||||
this.deleteModal.open();
|
||||
}
|
||||
|
||||
openInviteModal() {
|
||||
if(this.subscriberInvite && !this.subscriberInvite.loading) {
|
||||
this.inviteModal.alertTitle = 'Invite users to subscribe';
|
||||
this.inviteModal.okButtonLeft = false;
|
||||
this.inviteModal.okButtonText = 'Send';
|
||||
this.subscriberInvite.reset();
|
||||
this.inviteModal.open();
|
||||
}
|
||||
}
|
||||
|
||||
openCreateRoleModal() {
|
||||
this.createRoleModal.alertTitle = 'Create group';
|
||||
this.createRoleModal.okButtonLeft = false;
|
||||
this.createRoleModal.okButtonText = 'create';
|
||||
this.roleFb = this.fb.group({
|
||||
name: this.fb.control(Session.mapType(this.type) + '.' + this.id, Validators.required),
|
||||
description: this.fb.control('', Validators.required)
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.roleFb.get('name').disable();
|
||||
}, 0);
|
||||
this.createRoleModal.open();
|
||||
}
|
||||
|
||||
deleteSubscriber() {
|
||||
this.loading = true;
|
||||
this.userRegistryService.remove(this.type, this.id, this.selectedUser, 'member').subscribe(() => {
|
||||
this.subscribers = this.subscribers.filter(user => user.email != this.selectedUser);
|
||||
this.filterBySearch(this.filterForm.value.keyword);
|
||||
this.userManagementService.updateUserInfo();
|
||||
UIkit.notification(this.selectedUser + ' <b>is no longer</b> subscribed to ' + this.name + ' Dashboard', {
|
||||
status: 'success',
|
||||
timeout: 6000,
|
||||
pos: 'bottom-right'
|
||||
});
|
||||
this.loading = false;
|
||||
}, error => {
|
||||
UIkit.notification('An error has occurred. Please try again later', {
|
||||
status: 'danger',
|
||||
timeout: 6000,
|
||||
pos: 'bottom-right'
|
||||
});
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
createGroup() {
|
||||
this.loading = true;
|
||||
this.roleFb.get('name').enable();
|
||||
this.userRegistryService.createRole(this.type, this.id, this.roleFb.value).subscribe(() => {
|
||||
UIkit.notification('Group has been <b> successfully created</b>', {
|
||||
status: 'success',
|
||||
timeout: 6000,
|
||||
pos: 'bottom-right'
|
||||
});
|
||||
this.updateList();
|
||||
}, error => {
|
||||
UIkit.notification('An error has occurred. Please try again later', {
|
||||
status: 'danger',
|
||||
timeout: 6000,
|
||||
pos: 'bottom-right'
|
||||
});
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
public get isPortalAdmin() {
|
||||
return Session.isPortalAdministrator(this.user) || Session.isCurator(this.type, this.user);
|
||||
}
|
||||
|
||||
public updatePage($event) {
|
||||
this.page = $event.value;
|
||||
}
|
||||
|
||||
private filterBySearch(value: any) {
|
||||
this.showSubscribers = this.subscribers.filter(subscriber => !value || subscriber.email.includes(value));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {SubscribersComponent} from './subscribers.component';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {AlertModalModule} from "../../../utils/modal/alertModal.module";
|
||||
import {LoadingModule} from "../../../utils/loading/loading.module";
|
||||
import {IconsService} from "../../../utils/icons/icons.service";
|
||||
import {person_add, remove_circle_outline} from "../../../utils/icons/icons";
|
||||
import {IconsModule} from "../../../utils/icons/icons.module";
|
||||
import {InputModule} from "../../../sharedComponents/input/input.module";
|
||||
import {PageContentModule} from "../../sharedComponents/page-content/page-content.module";
|
||||
import {SafeHtmlPipeModule} from "../../../utils/pipes/safeHTMLPipe.module";
|
||||
import {NoLoadPaging} from "../../../searchPages/searchUtils/no-load-paging.module";
|
||||
import {SearchInputModule} from "../../../sharedComponents/search-input/search-input.module";
|
||||
import {SubscriberInviteModule} from "../../../sharedComponents/subscriber-invite/subscriber-invite.module";
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, AlertModalModule, ReactiveFormsModule, LoadingModule, IconsModule, InputModule, PageContentModule, SafeHtmlPipeModule, NoLoadPaging, SearchInputModule, SubscriberInviteModule],
|
||||
declarations: [SubscribersComponent],
|
||||
exports: [SubscribersComponent]
|
||||
})
|
||||
export class SubscribersModule {
|
||||
constructor(private iconsService: IconsService) {
|
||||
this.iconsService.registerIcons([remove_circle_outline, person_add]);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,10 @@
|
|||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.uk-grid-small .left {
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
.left + .input-box {
|
||||
padding-left: 41px;
|
||||
}
|
||||
|
@ -23,3 +27,8 @@
|
|||
.right + .input-box {
|
||||
padding-right: 41px;
|
||||
}
|
||||
|
||||
.input-message {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ export interface Option {
|
|||
template: `
|
||||
<div *ngIf="label && type != 'checkbox'" class="uk-text-bold uk-form-label uk-margin-small-bottom">{{label + (required ? ' *' : '')}}</div>
|
||||
<div *ngIf="hint" class="uk-margin-bottom uk-text-small uk-form-hint">{{hint}}</div>
|
||||
<div class="uk-grid uk-flex uk-flex-middle" uk-grid>
|
||||
<div class="uk-grid uk-flex uk-flex-middle" [class.uk-grid-small]="gridSmall" uk-grid>
|
||||
<ng-content></ng-content>
|
||||
<div [class.uk-hidden]="hideControl" class="uk-width-expand@m uk-position-relative" [class.uk-flex-first]="!extraLeft">
|
||||
<div [class.uk-hidden]="hideControl" class="uk-width-expand uk-position-relative" [class.uk-flex-first]="!extraLeft">
|
||||
<ng-template [ngIf]="icon && formControl.enabled">
|
||||
<span class="uk-text-muted" [ngClass]="iconLeft?('left'):'right'">
|
||||
<icon [name]="icon"></icon>
|
||||
|
@ -52,8 +52,9 @@ export interface Option {
|
|||
</mat-form-field>
|
||||
</div>
|
||||
</ng-template>
|
||||
<span *ngIf="formControl.invalid && formControl.errors.error" class="uk-text-small uk-text-danger">{{formControl.errors.error}}</span>
|
||||
<span *ngIf="warning" class="uk-text-small uk-text-warning">{{warning}}</span>
|
||||
<span *ngIf="formControl.invalid && formControl.errors.error" class="uk-text-danger input-message">{{formControl.errors.error}}</span>
|
||||
<span *ngIf="warning" class="uk-text-warning input-message">{{warning}}</span>
|
||||
<span *ngIf="note" class="input-message">{{note}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<mat-checkbox *ngIf="type === 'checkbox'" [formControl]="formControl">{{label}}</mat-checkbox>
|
||||
|
@ -70,10 +71,12 @@ export class InputComponent implements OnInit, OnDestroy, OnChanges {
|
|||
@Input('placeholder') placeholder = '';
|
||||
@ViewChild('select') select: MatSelect;
|
||||
@Input() extraLeft: boolean = true;
|
||||
@Input() gridSmall: boolean = false;
|
||||
@Input() hideControl: boolean = false;
|
||||
@Input() icon: string = null;
|
||||
@Input() iconLeft: boolean = false;
|
||||
@Input() warning: string = null;
|
||||
@Input() note: string = null;
|
||||
public required: boolean = false;
|
||||
private initValue: any;
|
||||
private subscriptions: any[] = [];
|
||||
|
|
|
@ -40,14 +40,14 @@ import {MatAutocompleteTrigger} from '@angular/material/autocomplete';
|
|||
<span [ngClass]="colorClass" class="icon-bg">
|
||||
<icon class="uk-position-center" name="search"></icon>
|
||||
</span>
|
||||
<span class="uk-text-uppercase overlay">search</span>
|
||||
<span class="uk-text-uppercase overlay">{{toggleTitle}}</span>
|
||||
</button>
|
||||
<button [disabled]="loading" class="search uk-flex uk-flex-middle uk-hidden@m"
|
||||
(mousedown)="$event.preventDefault()" (click)="search()">
|
||||
<span [ngClass]="colorClass" class="icon-bg">
|
||||
<icon class="uk-position-center" name="search"></icon>
|
||||
</span>
|
||||
<span class="uk-text-uppercase overlay">search</span>
|
||||
<span class="uk-text-uppercase overlay">{{toggleTitle}}</span>
|
||||
</button>
|
||||
</div>`
|
||||
})
|
||||
|
@ -68,6 +68,8 @@ export class SearchInputComponent {
|
|||
colorClass: string = 'portal-color';
|
||||
@Input()
|
||||
bordered: boolean = false;
|
||||
@Input()
|
||||
toggleTitle: string = 'search';
|
||||
@ViewChild('input') input: ElementRef;
|
||||
@ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger;
|
||||
@Output()
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.field-label {
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
import {Component, Input, OnDestroy, OnInit} from "@angular/core";
|
||||
import {AbstractControl, FormBuilder, FormGroup, ValidationErrors, Validators} from "@angular/forms";
|
||||
import {Subscriber} from "rxjs";
|
||||
import {StringUtils} from "../../utils/string-utils.class";
|
||||
import {Email} from "../../utils/email/email";
|
||||
import {Body} from "../../utils/email/body";
|
||||
import {CommunityService} from "../../connect/community/community.service";
|
||||
import {Composer} from "../../utils/email/composer";
|
||||
import {User} from "../../login/utils/helper.class";
|
||||
import {EmailService} from "../../utils/email/email.service";
|
||||
import {properties} from "../../../../environments/environment";
|
||||
|
||||
declare var UIkit;
|
||||
|
||||
@Component({
|
||||
selector: 'subscriber-invite',
|
||||
template: `
|
||||
<div class="uk-grid uk-child-width-1-1" uk-grid [formGroup]="inviteForm">
|
||||
<div dashboard-input [formInput]="inviteForm.get('name')" [gridSmall]="true">
|
||||
<div class="uk-text-bold field-label">
|
||||
From *:
|
||||
</div>
|
||||
</div>
|
||||
<div dashboard-input [formInput]="inviteForm.get('recipients')" [gridSmall]="true" note="Separate multiple emails with a comma">
|
||||
<div class="uk-text-bold field-label uk-margin-bottom">
|
||||
To *:
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-grid uk-grid-small" uk-grid>
|
||||
<div class="uk-text-bold field-label">
|
||||
Message *:
|
||||
</div>
|
||||
<div class="uk-width-expand">
|
||||
<ckeditor class="form-control" formControlName="message" id="message"
|
||||
debounce="400"
|
||||
[config]="{ extraAllowedContent: '* [uk-*](*) ; span', disallowedContent: 'script; *[on*]', removeButtons: 'Save,NewPage,DocProps,Preview,Print',
|
||||
extraPlugins: 'divarea'}"></ckeditor>
|
||||
<div class="uk-margin-top">
|
||||
{{body.signature}}
|
||||
<span *ngIf="body.fromName == ''" class="uk-text-muted">
|
||||
<i>{{body.fromMessage}}...</i>
|
||||
</span>
|
||||
<span *ngIf="body.fromName !=''">
|
||||
{{body.fromMessage}}
|
||||
<b>{{body.fromName}}</b>
|
||||
</span><br>
|
||||
<a href="https://www.openaire.eu">www.openaire.eu</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styleUrls: ['subscriber-invite.component.css']
|
||||
})
|
||||
export class SubscriberInviteComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
public user: User;
|
||||
public inviteForm: FormGroup;
|
||||
public email: Email;
|
||||
public body: Body;
|
||||
public loading: boolean = false;
|
||||
private subscriptions: any[] = [];
|
||||
|
||||
constructor(private fb: FormBuilder,
|
||||
private emailService: EmailService,
|
||||
private communityService: CommunityService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsubscribe();
|
||||
}
|
||||
|
||||
unsubscribe() {
|
||||
this.subscriptions.forEach(subscription => {
|
||||
if(subscription instanceof Subscriber) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.unsubscribe();
|
||||
this.inviteForm = this.fb.group({
|
||||
name: this.fb.control('', Validators.required),
|
||||
recipients: this.fb.control('', [Validators.required, this.emailsValidator]),
|
||||
message: this.fb.control('', Validators.required)
|
||||
});
|
||||
this.subscriptions.push(this.communityService.getCommunityAsObservable().subscribe(community => {
|
||||
this.inviteForm.get('name').enable();
|
||||
this.inviteForm.get('name').setValue(this.user.fullname);
|
||||
this.inviteForm.get('name').disable();
|
||||
this.body = Composer.initializeInvitationsBody(community.communityId, community.title, this.user.fullname);
|
||||
this.email = Composer.initializeInvitationsEmail(community.title);
|
||||
this.inviteForm.get('message').setValue(this.body.paragraphs);
|
||||
}));
|
||||
}
|
||||
|
||||
emailsValidator(control: AbstractControl): ValidationErrors | null {
|
||||
if (control.value === '' || !control.value || StringUtils.validateEmails(control.value)) {
|
||||
return null;
|
||||
}
|
||||
return { emails: true };
|
||||
}
|
||||
|
||||
invite() {
|
||||
this.loading = true;
|
||||
this.parseRecipients();
|
||||
this.body.paragraphs = this.inviteForm.value.message;
|
||||
this.email.body = Composer.formatEmailBodyForInvitation(this.body);
|
||||
this.subscriptions.push(this.emailService.sendEmail(properties, this.email).subscribe(res => {
|
||||
if(res['success']) {
|
||||
UIkit.notification('Invitation to subscribe has been <b>sent</b>', {
|
||||
status: 'success',
|
||||
timeout: 6000,
|
||||
pos: 'bottom-right'
|
||||
});
|
||||
} else {
|
||||
UIkit.notification('An error has occurred. Please try again later', {
|
||||
status: 'danger',
|
||||
timeout: 6000,
|
||||
pos: 'bottom-right'
|
||||
});
|
||||
}
|
||||
this.loading = false;
|
||||
},error => {
|
||||
UIkit.notification('An error has occurred. Please try again later', {
|
||||
status: 'danger',
|
||||
timeout: 6000,
|
||||
pos: 'bottom-right'
|
||||
});
|
||||
this.loading = false;
|
||||
}));
|
||||
}
|
||||
|
||||
public parseRecipients() {
|
||||
// remove spaces
|
||||
let emails = this.inviteForm.get('recipients').value.replace(/\s/g, '');
|
||||
// remove commas
|
||||
emails = emails.split(",");
|
||||
|
||||
// remove empty fields
|
||||
for (let i = 0; i < emails.length; i++) {
|
||||
if (!(emails[i] == "")) {
|
||||
this.email.recipients.push(emails[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get valid() {
|
||||
return this.inviteForm && this.inviteForm.valid;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import {NgModule} from "@angular/core";
|
||||
import {CommonModule} from "@angular/common";
|
||||
import {SubscriberInviteComponent} from "./subscriber-invite.component";
|
||||
import {InputModule} from "../input/input.module";
|
||||
import {CKEditorModule} from "ng2-ckeditor";
|
||||
import {ReactiveFormsModule} from "@angular/forms";
|
||||
import {EmailService} from "../../utils/email/email.service";
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, InputModule, CKEditorModule, ReactiveFormsModule],
|
||||
declarations: [SubscriberInviteComponent],
|
||||
exports: [SubscriberInviteComponent],
|
||||
providers: [EmailService]
|
||||
})
|
||||
export class SubscriberInviteModule {
|
||||
|
||||
}
|
|
@ -242,4 +242,23 @@ export class Composer {
|
|||
email.recipient = recipient;
|
||||
return email;
|
||||
}
|
||||
|
||||
public static composeEmailForCommunityDashboard(name: string, recipient: string, role: "manager" | "member") {
|
||||
let email: Email = new Email();
|
||||
email.subject = 'OpenAIRE Monitor Dashboard | ' + name;
|
||||
email.body = '<p>Dear ((__user__)),</p>' +
|
||||
'<p>You have been invited to be a ' + role +' of the OpenAIRE Monitor Dashboard for the ' + name + '.</p>' +
|
||||
'<p>Click <a href="((__link__))">this URL</a> and use the verification code below to accept the invitation.</p>' +
|
||||
'<p>The verification code is <b>((__code__))</b>.</p>' +
|
||||
(role === "manager"?
|
||||
'<p>As a manager of the OpenAIRE Monitor Dashboard, you will have access to the administration part of the dashboard, ' +
|
||||
'where you will be able to customize and manage the profile of the ' + name + '.</p>':
|
||||
'<p>As a member of the OpenAIRE Monitor Dashboard, you will have access to the restricted access areas of the profile for the ' + name + '.') +
|
||||
'<p>Please contact us at <a href="mailto:' + properties.helpdeskEmail+'">' + properties.helpdeskEmail +
|
||||
'</a> if you have any questions or concerns.</p>' +
|
||||
'<p>Kind Regards<br>The OpenAIRE Team</p>' +
|
||||
'<p><a href="' + properties.domain + '">OpenAIRE Monitor</a></p>'
|
||||
email.recipient = recipient;
|
||||
return email;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {UrlSegment} from '@angular/router';
|
||||
import {ValidatorFn, Validators} from "@angular/forms";
|
||||
import {AbstractControl, ValidatorFn, Validators} from "@angular/forms";
|
||||
|
||||
export class Dates {
|
||||
public static yearMin = 1800;
|
||||
|
@ -214,6 +214,12 @@ export class StringUtils {
|
|||
return decodeURIComponent(params);
|
||||
}
|
||||
|
||||
public static validateEmails(emails: string): boolean {
|
||||
return (emails.split(',')
|
||||
.map(email => Validators.email(<AbstractControl>{ value: email.trim() }))
|
||||
.find(_ => _ !== null) === undefined);
|
||||
}
|
||||
|
||||
public static b64DecodeUnicode(str) {
|
||||
return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) {
|
||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
|
|
Loading…
Reference in New Issue