Email templates UI
This commit is contained in:
parent
0a70952cda
commit
1f801cb4bf
|
@ -0,0 +1,41 @@
|
|||
package eu.dnetlib.is.email;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import eu.dnetlib.common.controller.AbstractDnetController;
|
||||
import eu.dnetlib.common.model.EmailTemplate;
|
||||
import eu.dnetlib.notifications.mail.EmailService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/ajax/templates/email")
|
||||
public class EmailTemplateController extends AbstractDnetController {
|
||||
|
||||
@Autowired
|
||||
protected EmailService emailService;
|
||||
|
||||
@GetMapping("/")
|
||||
public List<EmailTemplate> listEmailTemplates() {
|
||||
return emailService.listEmailTemplates();
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public List<EmailTemplate> saveEmailTemplate(@RequestBody final EmailTemplate email) {
|
||||
emailService.saveEmailTemplate(email);
|
||||
return emailService.listEmailTemplates();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public List<EmailTemplate> deleteEmailTemplate(@PathVariable final String id) {
|
||||
emailService.deleteEmailTemplate(id);
|
||||
return emailService.listEmailTemplates();
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|||
import { SpinnerHttpInterceptor } from './common/spinner.service';
|
||||
import { MdstoresComponent, MdstoreInspectorComponent, MDStoreVersionsDialog, AddMDStoreDialog } from './mdstores/mdstores.component';
|
||||
import { CleanerTesterComponent } from './cleaner-tester/cleaner-tester.component';
|
||||
import { EmailsComponent } from './emails/emails.component';
|
||||
import { EmailDialog, EmailsComponent } from './emails/emails.component';
|
||||
import { WfsComponent } from './wfs/wfs.component';
|
||||
|
||||
@NgModule({
|
||||
|
@ -68,9 +68,10 @@ import { WfsComponent } from './wfs/wfs.component';
|
|||
MdstoreInspectorComponent,
|
||||
MDStoreVersionsDialog,
|
||||
AddMDStoreDialog,
|
||||
CleanerTesterComponent,
|
||||
EmailsComponent,
|
||||
WfsComponent
|
||||
CleanerTesterComponent,
|
||||
EmailsComponent,
|
||||
EmailDialog,
|
||||
WfsComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
|
@ -198,3 +198,10 @@ export interface MDStoreRecord {
|
|||
dateOfTransformation: string,
|
||||
provenance: any
|
||||
}
|
||||
|
||||
export interface EmailTemplate {
|
||||
id: string,
|
||||
description: string,
|
||||
subject: string,
|
||||
message: string
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { Page, DsmConf, ResourceType, Protocol, WfHistoryEntry, SimpleResource, Context, ContextNode, Vocabulary, VocabularyTerm, KeyValue, BrowseTerm, Datasource, MDStore, MDStoreVersion, MDStoreRecord } from './is.model';
|
||||
import { Page, DsmConf, ResourceType, Protocol, WfHistoryEntry, SimpleResource, Context, ContextNode, Vocabulary, VocabularyTerm, KeyValue, BrowseTerm, Datasource, MDStore, MDStoreVersion, MDStoreRecord, EmailTemplate } from './is.model';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
|
@ -328,6 +328,26 @@ export class ISService {
|
|||
});
|
||||
}
|
||||
|
||||
loadEmailTemplates(onSuccess: Function): void {
|
||||
this.client.get<void>('./ajax/templates/email/').subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error)
|
||||
});
|
||||
}
|
||||
|
||||
saveEmailTemplate(email: EmailTemplate, onSuccess: Function, relatedForm?: FormGroup): void {
|
||||
this.client.post<void>('./ajax/templates/email/', email).subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error, relatedForm)
|
||||
});
|
||||
}
|
||||
|
||||
deleteEmailTemplate(id: string, onSuccess: Function): void {
|
||||
this.client.delete<void>('./ajax/templates/email/' + encodeURIComponent(id)).subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error)
|
||||
});
|
||||
}
|
||||
|
||||
private showError(error: any, form?: FormGroup) {
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<form [formGroup]="emailForm" (ngSubmit)="onSubmit()">
|
||||
|
||||
<h1 mat-dialog-title *ngIf="emailForm.get('id')?.value">Edit Email Template</h1>
|
||||
<h1 mat-dialog-title *ngIf="!emailForm.get('id')?.value">New Email Template</h1>
|
||||
|
||||
<div mat-dialog-content>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;" *ngIf="emailForm.get('id')?.value">
|
||||
<mat-label>ID</mat-label>
|
||||
<input matInput formControlName="id" readonly="readonly" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Description</mat-label>
|
||||
<input matInput formControlName="description" />
|
||||
<mat-error *ngIf="emailForm.get('description')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Email: subject</mat-label>
|
||||
<input matInput formControlName="subject" />
|
||||
<mat-error *ngIf="emailForm.get('subject')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Email: message</mat-label>
|
||||
<textarea matInput formControlName="message" required rows="16" style="font-size: 0.8em;"></textarea>
|
||||
<mat-error *ngIf="emailForm.get('message')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-stroked-button color="primary" type="submit" [disabled]="!emailForm.valid">Submit</button>
|
||||
<button mat-stroked-button color="primary" mat-dialog-close>Close</button>
|
||||
<mat-error *ngIf="emailForm.errors?.['serverError']">
|
||||
{{ emailForm.errors?.['serverError'] }}
|
||||
</mat-error>
|
||||
</div>
|
||||
|
||||
</form>
|
|
@ -1 +1,42 @@
|
|||
<p>emails works!</p>
|
||||
<h2>Email Templates</h2>
|
||||
|
||||
<button mat-stroked-button color="primary" (click)="openAddEmailTemplateDialog()">
|
||||
<mat-icon fontIcon="add"></mat-icon>
|
||||
create a new template
|
||||
</button>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%; margin-top: 10px;">
|
||||
<mat-label>Filter</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event)" placeholder="Filter..." #input />
|
||||
</mat-form-field>
|
||||
|
||||
<table mat-table [dataSource]="emailsDatasource" matSort class="mat-elevation-z8">
|
||||
|
||||
<ng-container matColumnDef="id">
|
||||
<th mat-header-cell *matHeaderCellDef style="width: 25%;" mat-sort-header sortActionDescription="Sort by ID"> Id
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<a (click)="openEditEmailTemplateDialog(element)">{{element.id}}</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="description">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by Description"> Description </th>
|
||||
<td mat-cell *matCellDef="let element"> {{element.description}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="buttons">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: right;" style="width: 20%"></th>
|
||||
<td mat-cell *matCellDef="let element" class="table-buttons">
|
||||
<button mat-stroked-button color="warn" (click)="deleteEmailTemplate(element)">delete</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="colums"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: colums;"></tr>
|
||||
|
||||
<!-- Row shown when there is no matching data. -->
|
||||
<tr class="mat-row" *matNoDataRow>
|
||||
<td class="mat-cell" colspan="4" style="padding: 0 16px;">No data matching the filter "{{input.value}}"</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -1,10 +1,98 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { AfterViewInit, Component, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { EmailTemplate } from '../common/is.model';
|
||||
import { ISService } from '../common/is.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-emails',
|
||||
templateUrl: './emails.component.html',
|
||||
styleUrls: ['./emails.component.css']
|
||||
selector: 'app-emails',
|
||||
templateUrl: './emails.component.html',
|
||||
styleUrls: ['./emails.component.css']
|
||||
})
|
||||
export class EmailsComponent {
|
||||
export class EmailsComponent implements OnInit, AfterViewInit {
|
||||
emailsDatasource: MatTableDataSource<EmailTemplate> = new MatTableDataSource<EmailTemplate>([]);
|
||||
|
||||
colums: string[] = ['id', 'description', 'buttons'];
|
||||
|
||||
@ViewChild(MatSort) sort: MatSort | undefined
|
||||
|
||||
searchText: string = '';
|
||||
|
||||
constructor(public service: ISService, public route: ActivatedRoute, public dialog: MatDialog) { }
|
||||
|
||||
ngOnInit() { this.reload() }
|
||||
ngAfterViewInit() { if (this.sort) this.emailsDatasource.sort = this.sort; }
|
||||
reload() { this.service.loadEmailTemplates((data: EmailTemplate[]) => this.emailsDatasource.data = data); }
|
||||
|
||||
applyFilter(event: Event) {
|
||||
const filterValue = (event.target as HTMLInputElement).value.trim().toLowerCase();
|
||||
this.emailsDatasource.filter = filterValue;
|
||||
}
|
||||
|
||||
openAddEmailTemplateDialog(): void {
|
||||
const dialogRef = this.dialog.open(EmailDialog, {
|
||||
data: {
|
||||
id: '',
|
||||
description: '',
|
||||
subject: '',
|
||||
message: ''
|
||||
},
|
||||
width: '80%'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) this.reload();
|
||||
});
|
||||
}
|
||||
|
||||
openEditEmailTemplateDialog(email: EmailTemplate): void {
|
||||
const dialogRef = this.dialog.open(EmailDialog, {
|
||||
data: email,
|
||||
width: '80%'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) this.reload();
|
||||
});
|
||||
}
|
||||
|
||||
deleteEmailTemplate(email: EmailTemplate) {
|
||||
if (confirm('Are you sure?')) {
|
||||
this.service.deleteEmailTemplate(email.id, (data: void) => this.reload());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'email-dialog',
|
||||
templateUrl: './email-dialog.html',
|
||||
styleUrls: ['./emails.component.css']
|
||||
})
|
||||
export class EmailDialog {
|
||||
|
||||
emailForm = new FormGroup({
|
||||
id: new FormControl(''),
|
||||
description: new FormControl('', [Validators.required]),
|
||||
subject: new FormControl('', [Validators.required]),
|
||||
message: new FormControl('', [Validators.required])
|
||||
});
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<EmailDialog>, @Inject(MAT_DIALOG_DATA) public data: any, public service: ISService) {
|
||||
this.emailForm.get('id')?.setValue(data.id);
|
||||
this.emailForm.get('description')?.setValue(data.description);
|
||||
this.emailForm.get('subject')?.setValue(data.subject);
|
||||
this.emailForm.get('message')?.setValue(data.message);
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
const email = Object.assign({}, this.data, this.emailForm.value);
|
||||
this.service.saveEmailTemplate(email, (data: void) => this.dialogRef.close(1), this.emailForm);
|
||||
}
|
||||
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,8 +137,6 @@ export class VocabularyEditorComponent implements OnInit, AfterViewInit {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
|
|
@ -17,6 +17,9 @@ public class EmailTemplate implements Serializable {
|
|||
@Column(name = "id")
|
||||
private String id;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@Column(name = "subject")
|
||||
private String subject;
|
||||
|
||||
|
@ -31,6 +34,14 @@ public class EmailTemplate implements Serializable {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
|
|
@ -252,9 +252,10 @@ GROUP BY md.id,
|
|||
|
||||
-- Email Templates
|
||||
CREATE TABLE emails (
|
||||
id text PRIMARY KEY,
|
||||
subject text NOT NULL,
|
||||
message text NOT NULL
|
||||
id text PRIMARY KEY,
|
||||
description text NOT NULL,
|
||||
subject text NOT NULL,
|
||||
message text NOT NULL
|
||||
);
|
||||
|
||||
-- Workflows
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package eu.dnetlib.notifications.mail;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
|
@ -17,6 +19,7 @@ import javax.mail.Transport;
|
|||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -25,12 +28,13 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import eu.dnetlib.common.model.EmailTemplate;
|
||||
import eu.dnetlib.common.repository.EmailTemplateRepository;
|
||||
|
||||
@Service
|
||||
public class EmailDispatcher {
|
||||
public class EmailService {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EmailDispatcher.class);
|
||||
private static final Log log = LogFactory.getLog(EmailService.class);
|
||||
private final BlockingQueue<Message> queue = new LinkedBlockingQueue<>();
|
||||
|
||||
@Value("${dnet.configuration.mail.sender.email}")
|
||||
|
@ -78,6 +82,22 @@ public class EmailDispatcher {
|
|||
}).start();
|
||||
}
|
||||
|
||||
public List<EmailTemplate> listEmailTemplates() {
|
||||
return emailTemplateRepository.findAll();
|
||||
}
|
||||
|
||||
public void saveEmailTemplate(final EmailTemplate email) {
|
||||
if (StringUtils.isBlank(email.getId()) || email.getId().length() < 10) {
|
||||
email.setId("email-" + UUID.randomUUID());
|
||||
log.info("Saving new email with id: " + email.getId());
|
||||
}
|
||||
emailTemplateRepository.save(email);
|
||||
}
|
||||
|
||||
public void deleteEmailTemplate(final String id) {
|
||||
emailTemplateRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public void sendMail(final String to, final String subject, final String message) {
|
||||
try {
|
||||
final Session session = Session.getInstance(obtainProperties(), obtainAuthenticator());
|
||||
|
@ -132,9 +152,12 @@ public class EmailDispatcher {
|
|||
private Authenticator obtainAuthenticator() {
|
||||
if (this.smtpUser == null || this.smtpUser.isEmpty()) { return null; }
|
||||
|
||||
final String user = this.smtpUser;
|
||||
final String passwd = this.smtpPassword;
|
||||
|
||||
return new Authenticator() {
|
||||
|
||||
private final PasswordAuthentication authentication = new PasswordAuthentication(EmailDispatcher.this.smtpUser, EmailDispatcher.this.smtpPassword);
|
||||
private final PasswordAuthentication authentication = new PasswordAuthentication(user, passwd);
|
||||
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
|
@ -12,7 +12,7 @@ import eu.dnetlib.manager.wf.model.NotificationCondition;
|
|||
import eu.dnetlib.manager.wf.repository.WorkflowSubscriptionRepository;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.WorkflowProcess;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.WorkflowProcess.Status;
|
||||
import eu.dnetlib.notifications.mail.EmailDispatcher;
|
||||
import eu.dnetlib.notifications.mail.EmailService;
|
||||
|
||||
@Service
|
||||
public class EmailSender {
|
||||
|
@ -23,7 +23,7 @@ public class EmailSender {
|
|||
private WorkflowSubscriptionRepository wfSubscriptionRepository;
|
||||
|
||||
@Autowired
|
||||
private EmailDispatcher dispatcher;
|
||||
private EmailService emailService;
|
||||
|
||||
public void sendMails(final WorkflowProcess proc) {
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class EmailSender {
|
|||
try {
|
||||
final Map<String, Object> params = new HashMap<>();
|
||||
|
||||
dispatcher.sendStoredMail(s.getEmail(), s.getMessageId(), params);
|
||||
emailService.sendStoredMail(s.getEmail(), s.getMessageId(), params);
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Error sending mail to " + s.getEmail(), e);
|
||||
|
|
Loading…
Reference in New Issue