Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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