Skip to content

Commit

Permalink
Send invitation when presentation is scheduled
Browse files Browse the repository at this point in the history
  • Loading branch information
fabian-emilius committed Sep 10, 2024
1 parent 9bc3cec commit ca29e82
Show file tree
Hide file tree
Showing 22 changed files with 183 additions and 21 deletions.
1 change: 1 addition & 0 deletions .github/workflows/deploy_docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ jobs:
echo "STUDY_PROGRAMS=${{ vars.STUDY_PROGRAMS }}" >> .env.prod
echo "STUDY_DEGREES=${{ vars.STUDY_DEGREES }}" >> .env.prod
echo "GENDERS=${{ vars.GENDERS }}" >> .env.prod
echo "LANGUAGES=${{ vars.LANGUAGES }}" >> .env.prod
echo "CUSTOM_DATA=${{ vars.CUSTOM_DATA }}" >> .env.prod
echo "MAIL_SENDER=${{ vars.MAIL_SENDER }}" >> .env.prod
Expand Down
1 change: 1 addition & 0 deletions client/public/generate-runtime-env.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const ALLOWED_ENVIRONMENT_VARIABLES = [
'GENDERS',
'STUDY_DEGREES',
'STUDY_PROGRAMS',
'LANGUAGES',
'CUSTOM_DATA',
'CALDAV_URL',
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import { DataTable, DataTableColumn } from 'mantine-datatable'
import { IPublishedPresentation, IThesisPresentation } from '../../requests/responses/thesis'
import { formatDate, formatPresentationType } from '../../utils/format'
import { GLOBAL_CONFIG } from '../../config/global'

interface IPresentationsTableProps<T> {
presentations: T[] | undefined
Expand Down Expand Up @@ -46,6 +47,13 @@ const PresentationsTable = <T extends IThesisPresentation | IPublishedPresentati
</a>
),
},
{
accessor: 'language',
title: 'Language',
width: 120,
ellipsis: true,
render: (presentation) => GLOBAL_CONFIG.languages[presentation.language] ?? presentation.language,
},
{
accessor: 'scheduledAt',
title: 'Scheduled At',
Expand Down
5 changes: 5 additions & 0 deletions client/src/config/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ export const GLOBAL_CONFIG: IGlobalConfig = {
GUIDED_RESEARCH: 'Guided Research',
},

languages: getEnvironmentVariable<Record<string, string>>('LANGUAGES', true) || {
ENGLISH: 'English',
GERMAN: 'German',
},

custom_data: getEnvironmentVariable<Record<string, string>>('CUSTOM_DATA', true) || {
GITHUB: 'Github Profile',
},
Expand Down
1 change: 1 addition & 0 deletions client/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface IGlobalConfig {
study_degrees: Record<string, string>
thesis_types: Record<string, string>
custom_data: Record<string, string>
languages: Record<string, string>

privacy_text: string
imprint_text: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const CreatePresentationModal = (props: ICreatePresentationModalProps) => {
visibility: string
location: string
streamUrl: string
language: string | null
date: DateValue
}>({
mode: 'controlled',
Expand All @@ -34,6 +35,7 @@ const CreatePresentationModal = (props: ICreatePresentationModalProps) => {
visibility: 'PUBLIC',
location: '',
streamUrl: '',
language: null,
date: null,
},
validateInputOnBlur: true,
Expand All @@ -50,6 +52,7 @@ const CreatePresentationModal = (props: ICreatePresentationModalProps) => {
return 'Location or Stream URL is required'
}
},
language: isNotEmpty('Language is required'),
date: (value) => {
if (!value) {
return 'Date is required'
Expand Down Expand Up @@ -80,6 +83,7 @@ const CreatePresentationModal = (props: ICreatePresentationModalProps) => {
visibility: form.values.visibility,
location: form.values.location,
streamUrl: form.values.streamUrl,
language: form.values.language,
date: form.values.date,
},
})
Expand Down
2 changes: 2 additions & 0 deletions client/src/requests/responses/thesis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface IThesisPresentation {
type: string
location: string | null
streamUrl: string | null
language: string
scheduledAt: string
createdAt: string
createdBy: ILightUser
Expand Down Expand Up @@ -92,6 +93,7 @@ export interface IPublishedPresentation {
type: string
location: string | null
streamUrl: string | null
language: string
scheduledAt: string
thesis: IPublishedThesis
}
Expand Down
1 change: 1 addition & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ services:
- STUDY_PROGRAMS
- STUDY_DEGREES
- GENDERS
- LANGUAGES
- CUSTOM_DATA
- APPLICATION_TITLE
- CHAIR_NAME
Expand Down
1 change: 1 addition & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
| STUDY_PROGRAMS | client | `{"COMPUTER_SCIENCE":"Computer Science","INFORMATION_SYSTEMS":"Information Systems","GAMES_ENGINEERING":"Games Engineering","MANAGEMENT_AND_TECHNOLOGY":"Management and Technology","OTHER":"Other"}` | Available study programs |
| CUSTOM_DATA | client | `{"GITHUB":"Github Profile"}` | Additional data the user can add to the profile |
| THESIS_TYPES | client | `{"BACHELOR":"Bachelor Thesis","MASTER":"Master Thesis","INTERDISCIPLINARY_PROJECT":"Interdisciplinary Project","GUIDED_RESEARCH":"Guided Research"}` | Available thesis types |
| LANGUAGES | client | `{"ENGLISH":"English","GERMAN":"German"}` | Available languages for presentations |
| DEFAULT_SUPERVISOR_UUID | client | | The user UUID from the database if a default supervisor should be selected when creating topics or theses |
| PRIVACY | client | | Privacy content (Allows richtext format) |
| IMPRINT | client | | Imprint content (Allows richtext format) |
Expand Down
10 changes: 6 additions & 4 deletions server/mail-templates/application-created-student.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@
</p>
<br/>

<p><strong>You can find the submitted files in the attachment part of this email.</strong></p>

<p>We are currently experiencing a high volume of thesis applications, and each one requires careful review.
<p>
We are currently experiencing a high volume of thesis applications, and each one requires careful review.
While we aim to respond as quickly as possible, the combination of the application volume and the intensive teaching
and research commitments of our group may result in a response time of up to four weeks.
We appreciate your patience and understanding during this period.</p>
We appreciate your patience and understanding during this period.
</p>

<p><strong>You can find the submitted files in the attachment part of this email.</strong></p>
34 changes: 34 additions & 0 deletions server/mail-templates/thesis-presentation-invitation.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<p>Dear {{recipientName}},</p>

<p>
As part of their {{thesis.type}}'s thesis <strong>{{thesis.students}}</strong> will give their {{presentation.type}} presentation.
</p>

<p>
The presentation will be in {{presentation.language}}. Everybody is cordially invited to attend.
</p>

<p>
<strong>Title</strong><br />
{{thesis.title}}
</p>

<p>
<strong>Offline Location</strong><br />
{{presentation.location}}
</p>

<p>
<strong>Online Stream URL</strong><br />
{{presentation.streamUrl}}
</p>

<p>
<strong>Scheduled At</strong><br />
{{presentation.scheduledAt}}
</p>

<p>
<strong>Abstract</strong><br />
{{thesis.abstractText}}
</p>
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ public ResponseEntity<ThesisDto> createPresentation(
RequestValidator.validateNotNull(payload.visibility()),
RequestValidator.validateStringMaxLength(payload.location(), StringLimits.SHORTTEXT.getLimit()),
RequestValidator.validateStringMaxLength(payload.streamUrl(), StringLimits.SHORTTEXT.getLimit()),
RequestValidator.validateStringMaxLength(payload.language(), StringLimits.SHORTTEXT.getLimit()),
RequestValidator.validateNotNull(payload.date())
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ public record CreatePresentationPayload(
ThesisPresentationVisibility visibility,
String location,
String streamUrl,
String language,
Instant date
) { }
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public record PublishedPresentationDto (
ThesisPresentationType type,
String location,
String streamUrl,
String language,
Instant scheduledAt,
PublishedThesisDto thesis
) {
Expand All @@ -24,6 +25,7 @@ public static PublishedPresentationDto fromPresentationEntity(ThesisPresentation
presentation.getType(),
presentation.getLocation(),
presentation.getStreamUrl(),
presentation.getLanguage(),
presentation.getScheduledAt(),
PublishedThesisDto.fromThesisEntity(presentation.getThesis())
);
Expand Down
2 changes: 2 additions & 0 deletions server/src/main/java/thesistrack/ls1/dto/ThesisDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public record ThesisPresentationDto(
ThesisPresentationType type,
String location,
String streamUrl,
String language,
Instant scheduledAt,
Instant createdAt,
LightUserDto createdBy
Expand All @@ -99,6 +100,7 @@ public static ThesisPresentationDto fromPresentationEntity(ThesisPresentation pr
presentation.getType(),
presentation.getLocation(),
presentation.getStreamUrl(),
presentation.getLanguage(),
presentation.getScheduledAt(),
presentation.getCreatedAt(),
LightUserDto.fromUserEntity(presentation.getCreatedBy())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public class ThesisPresentation {
@Column(name = "stream_url")
private String streamUrl;

@Column(name = "language")
private String language;

@Column(name = "calendar_event")
private String calendarEvent;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ public interface UserRepository extends JpaRepository<User, UUID> {
)
Page<User> searchUsers(@Param("searchQuery") String searchQuery, @Param("groups") Set<String> groups, Pageable page);

@Query("SELECT DISTINCT u FROM User u LEFT JOIN UserGroup g ON (u.id = g.id.userId) WHERE g.id.group IN (\"supervisor\", \"advisor\", \"admin\")")
List<User> getChairMembers();
@Query("SELECT DISTINCT u FROM User u LEFT JOIN UserGroup g ON (u.id = g.id.userId) WHERE g.id.group IN :roles")
List<User> getRoleMembers(@Param("roles") Set<String> roles);
}
31 changes: 29 additions & 2 deletions server/src/main/java/thesistrack/ls1/service/MailingService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package thesistrack.ls1.service;

import jakarta.mail.util.ByteArrayDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
Expand All @@ -9,21 +10,25 @@
import thesistrack.ls1.utility.MailBuilder;
import thesistrack.ls1.utility.MailConfig;

import java.nio.charset.StandardCharsets;

@Service
public class MailingService {
private final JavaMailSender javaMailSender;
private final UploadService uploadService;
private final MailConfig config;
private final ThesisPresentationService thesisPresentationService;

@Autowired
public MailingService(
JavaMailSender javaMailSender,
UploadService uploadService,
MailConfig config
) {
MailConfig config,
ThesisPresentationService thesisPresentationService) {
this.javaMailSender = javaMailSender;
this.uploadService = uploadService;
this.config = config;
this.thesisPresentationService = thesisPresentationService;
}

public void sendApplicationCreatedEmail(Application application) {
Expand Down Expand Up @@ -156,6 +161,28 @@ public void sendPresentationDeletedEmail(User deletingUser, ThesisPresentation p
.send(javaMailSender, uploadService);
}

public void sendPresentationInvitation(ThesisPresentation presentation) {
MailBuilder builder = new MailBuilder(config, "Thesis Presentation Invitation", "thesis-presentation-invitation");
builder
.sendToChairMembers()
.sendToChairStudents()
.fillThesisPresentationPlaceholders(presentation);

for (ThesisRole role : presentation.getThesis().getRoles()) {
builder.addPrimarySender(role.getUser());
}

builder.addRawAttatchment(
"event.ics",
new ByteArrayDataSource(
thesisPresentationService.getPresentationEvent(presentation).toString().getBytes(StandardCharsets.UTF_8),
"application/octet-stream"
)
);

builder.send(javaMailSender, uploadService);
}

public void sendFinalSubmissionEmail(Thesis thesis) {
MailBuilder builder = new MailBuilder(config, "Thesis Submitted", "thesis-final-submission");
builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,8 @@ public ThesisPresentationService(CalendarService calendarService, ThesisReposito
}

public Calendar getPresentationCalendar() {
Calendar calendar = new Calendar();
Calendar calendar = createEmptyCalendar();

calendar.add(new ProdId("-//Thesis Track//Thesis Presentations//EN"));
calendar.add(ImmutableCalScale.GREGORIAN);
calendar.add(ImmutableMethod.PUBLISH);

List<ThesisPresentation> presentations = thesisPresentationRepository.findAllPresentations(
Expand All @@ -53,6 +51,14 @@ public Calendar getPresentationCalendar() {
return calendar;
}

public Calendar getPresentationEvent(ThesisPresentation presentation) {
Calendar calendar = createEmptyCalendar();

calendar.add(calendarService.createVEvent(presentation.getId().toString(), createPresentationCalendarEvent(presentation)));

return calendar;
}

@Transactional
public Thesis createPresentation(
User creatingUser,
Expand All @@ -61,6 +67,7 @@ public Thesis createPresentation(
ThesisPresentationVisibility visibility,
String location,
String streamUrl,
String language,
Instant date
) {
ThesisPresentation presentation = new ThesisPresentation();
Expand All @@ -70,6 +77,7 @@ public Thesis createPresentation(
presentation.setVisibility(visibility);
presentation.setLocation(location);
presentation.setStreamUrl(streamUrl);
presentation.setLanguage(language);
presentation.setScheduledAt(date);
presentation.setCreatedBy(creatingUser);
presentation.setCreatedAt(Instant.now());
Expand All @@ -79,6 +87,8 @@ public Thesis createPresentation(
if (visibility.equals(ThesisPresentationVisibility.PUBLIC)) {
presentation.setCalendarEvent(calendarService.createEvent(createPresentationCalendarEvent(presentation)));
presentation = thesisPresentationRepository.save(presentation);

mailingService.sendPresentationInvitation(presentation);
}

List<ThesisPresentation> presentations = thesis.getPresentations();
Expand Down Expand Up @@ -134,6 +144,15 @@ public ThesisPresentation findById(UUID thesisId, UUID presentationId) {
return presentation;
}

private Calendar createEmptyCalendar() {
Calendar calendar = new Calendar();

calendar.add(new ProdId("-//Thesis Track//Thesis Presentations//EN"));
calendar.add(ImmutableCalScale.GREGORIAN);

return calendar;
}

private CalendarService.CalendarEvent createPresentationCalendarEvent(ThesisPresentation presentation) {
String location = presentation.getLocation();
String streamUrl = presentation.getStreamUrl();
Expand All @@ -143,6 +162,7 @@ private CalendarService.CalendarEvent createPresentationCalendarEvent(ThesisPres
location == null || location.isBlank() ? streamUrl : location,
"Title: " + presentation.getThesis().getTitle() + "\n" +
(streamUrl != null && !streamUrl.isBlank() ? "Stream URL: " + streamUrl + "\n" : "") + "\n" +
"Language: " + presentation.getLanguage() + "\n" +
"Abstract:\n\n" + presentation.getThesis().getAbstractField(),
presentation.getScheduledAt(),
presentation.getScheduledAt().plus(60, ChronoUnit.MINUTES),
Expand Down
Loading

0 comments on commit ca29e82

Please sign in to comment.