Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions client/e2e/application-review-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getBody,
getToAddresses,
assertSentFromApp,
assertEmailFooter,
findBySubject,
} from './mailpit'

Expand Down Expand Up @@ -62,6 +63,7 @@ test.describe('Application Review Workflow', () => {
const rejectionEmail = findBySubject(newEmails, 'Thesis Application Rejection')
expect(rejectionEmail, 'Rejection email with correct subject should be sent').toBeDefined()
assertSentFromApp(rejectionEmail!)
assertEmailFooter(rejectionEmail!)
expect(getToAddresses(rejectionEmail!)).toContain('student4@test.local')

// Body should greet the student by first name and reference the topic title
Expand Down Expand Up @@ -131,6 +133,7 @@ test.describe('Application Review Workflow', () => {
const acceptanceEmail = findBySubject(newEmails, 'Thesis Application Acceptance')
expect(acceptanceEmail, 'Acceptance email should be sent').toBeDefined()
assertSentFromApp(acceptanceEmail!)
assertEmailFooter(acceptanceEmail!)
expect(getToAddresses(acceptanceEmail!)).toContain('student5@test.local')

// Body should greet student, mention the supervisor, and include a thesis link
Expand All @@ -143,6 +146,7 @@ test.describe('Application Review Workflow', () => {
const thesisEmail = findBySubject(newEmails, 'Thesis Created')
expect(thesisEmail, 'Thesis creation email should be sent').toBeDefined()
assertSentFromApp(thesisEmail!)
assertEmailFooter(thesisEmail!)
expect(getToAddresses(thesisEmail!)).toContain('student5@test.local')

// Body should contain the thesis title and a link to the thesis
Expand Down
3 changes: 3 additions & 0 deletions client/e2e/application-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
getBody,
getToAddresses,
assertSentFromApp,
assertEmailFooter,
findBySubject,
} from './mailpit'

Expand Down Expand Up @@ -131,6 +132,7 @@ test.describe('Application Workflow - Student submits application', () => {
const studentEmail = findBySubject(newStudentEmails, 'Thesis Application Confirmation')
expect(studentEmail, 'Student confirmation email should be sent').toBeDefined()
assertSentFromApp(studentEmail!)
assertEmailFooter(studentEmail!)
expect(getToAddresses(studentEmail!)).toContain('student@test.local')

const studentBody = getBody(studentEmail!)
Expand All @@ -151,6 +153,7 @@ test.describe('Application Workflow - Student submits application', () => {
'Examiner (examiner@test.local) should receive "New Thesis Application" email',
).toBeDefined()
assertSentFromApp(examinerChairEmail!)
assertEmailFooter(examinerChairEmail!)

const examinerBody = getBody(examinerChairEmail!)
expect(examinerBody, 'Examiner email should mention the applicant').toContain('Student')
Expand Down
13 changes: 13 additions & 0 deletions client/e2e/mailpit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,19 @@ export function assertBodyContains(message: MailpitMessage, expectedText: string
expect(body, `Expected email body to contain "${expectedText}"`).toContain(expectedText)
}

/**
* Assert that the email contains the standard footer with notification settings link.
*/
export function assertEmailFooter(message: MailpitMessage): void {
const body = getBody(message)
expect(body, 'Expected email to contain notification settings link').toContain(
'notification settings in Thesis Management',
)
expect(body, 'Expected email to contain /settings/notifications link').toContain(
'/settings/notifications',
)
}

/**
* Assert that the email was sent from the application sender.
* Verifies the From header matches the expected format: "ThesisManagement <...@...>"
Expand Down
2 changes: 2 additions & 0 deletions client/e2e/presentation-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getBody,
getToAddresses,
assertSentFromApp,
assertEmailFooter,
} from './mailpit'

// Thesis d000-0003 is in ASSESSED state, assigned to student3, has abstract text set
Expand Down Expand Up @@ -170,6 +171,7 @@ test.describe.serial('Presentation Workflow', () => {
'New Presentation scheduled',
)
assertSentFromApp(privateEmail)
assertEmailFooter(privateEmail)
expect(getToAddresses(privateEmail)).toContain('student3@test.local')

const body = getBody(privateEmail)
Expand Down
3 changes: 3 additions & 0 deletions client/e2e/proposal-feedback-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getBody,
getToAddresses,
assertSentFromApp,
assertEmailFooter,
hasAttachment,
} from './mailpit'

Expand Down Expand Up @@ -58,6 +59,7 @@ test.describe('Proposal Upload - Student uploads proposal', () => {
const proposalEmail = newEmails.find((e) => getSubject(e) === 'Thesis Proposal Added')
expect(proposalEmail, 'Proposal upload email with correct subject should be sent').toBeDefined()
assertSentFromApp(proposalEmail!)
assertEmailFooter(proposalEmail!)
expect(getToAddresses(proposalEmail!)).toContain('supervisor@test.local')

// Body should reference the thesis title, the uploader name, and include a link
Expand Down Expand Up @@ -126,6 +128,7 @@ test.describe('Proposal Feedback - Supervisor requests changes', () => {
'Change request email with correct subject should be sent',
).toBeDefined()
assertSentFromApp(changeRequestEmail!)
assertEmailFooter(changeRequestEmail!)
expect(getToAddresses(changeRequestEmail!)).toContain('student2@test.local')

// Body should greet the student, reference the thesis title, mention the reviewer,
Expand Down
2 changes: 2 additions & 0 deletions client/e2e/thesis-grading-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getBody,
getToAddresses,
assertSentFromApp,
assertEmailFooter,
} from './mailpit'

// Thesis d000-0003: ASSESSED state, student3, supervisor2, examiner2 (DSA group)
Expand Down Expand Up @@ -181,6 +182,7 @@ test.describe.serial('Thesis Grading Workflow', () => {
const gradeEmail = newEmails.find((e) => getSubject(e) === 'Final Grade available for Thesis')
expect(gradeEmail, 'Final grade email should be sent').toBeDefined()
assertSentFromApp(gradeEmail!)
assertEmailFooter(gradeEmail!)
expect(getToAddresses(gradeEmail!)).toContain('student3@test.local')

// Body should contain: greeting, thesis title, examiner name, final grade,
Expand Down
2 changes: 2 additions & 0 deletions client/e2e/thesis-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getBody,
getToAddresses,
assertSentFromApp,
assertEmailFooter,
} from './mailpit'

test.describe('Thesis Workflow - Examiner creates a thesis', () => {
Expand Down Expand Up @@ -66,6 +67,7 @@ test.describe('Thesis Workflow - Examiner creates a thesis', () => {
const creationEmail = newEmails.find((e) => getSubject(e) === 'Thesis Created')
expect(creationEmail, 'Thesis creation email should be sent').toBeDefined()
assertSentFromApp(creationEmail!)
assertEmailFooter(creationEmail!)
expect(getToAddresses(creationEmail!)).toContain('student4@test.local')

// Body should contain: greeting, thesis title, examiner/supervisor/student names, and link
Expand Down
1 change: 1 addition & 0 deletions client/src/requests/responses/researchGroupSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface IResearchGroupSettingsPhase {

export interface IResearchGroupSettingsEmail {
applicationNotificationEmail?: string | null
emailSignature?: string | null
}

export interface IResearchGroupSettingsWritingGuide {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ public ResponseEntity<ResearchGroupSettingsDTO> createOrUpdateRejectSettings(@Pa
String validatedEmail = RequestValidator.validateEmailAllowNull(
newSettings.emailSettings().applicationNotificationEmail() == null ? null : newSettings.emailSettings().applicationNotificationEmail().trim());
toSave.setApplicationNotificationEmail(validatedEmail);
String signature = newSettings.emailSettings().emailSignature();
toSave.setEmailSignature(signature != null && !signature.trim().isEmpty() ? signature.trim() : null);
Comment thread
krusche marked this conversation as resolved.
}
if (newSettings.writingGuideSettings() != null) {
String link = newSettings.writingGuideSettings().scientificWritingGuideLink();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package de.tum.cit.aet.thesis.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import de.tum.cit.aet.thesis.entity.ResearchGroupSettings;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record ResearchGroupSettingsEmailDTO(
String applicationNotificationEmail
String applicationNotificationEmail,
String emailSignature
) {
public static ResearchGroupSettingsEmailDTO fromEntity(ResearchGroupSettings settings) {
return new ResearchGroupSettingsEmailDTO(settings.getApplicationNotificationEmail());
return new ResearchGroupSettingsEmailDTO(settings.getApplicationNotificationEmail(), settings.getEmailSignature());
}
Comment thread
krusche marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@ public class ResearchGroupSettings {

@Column(name = "include_application_data_in_email", nullable = false)
private boolean includeApplicationDataInEmail = false;

@Column(name = "email_signature")
private String emailSignature;
}
Loading
Loading