Skip to content

Commit

Permalink
Merge pull request #77 from ls1intum/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
valentin-boehm authored Dec 16, 2023
2 parents 3b8ec27 + 042ce29 commit c55bb00
Show file tree
Hide file tree
Showing 42 changed files with 1,070 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Buil
.requestMatchers(mvc.pattern("/api/activate")).permitAll()
.requestMatchers(mvc.pattern("/api/account/reset-password/init")).permitAll()
.requestMatchers(mvc.pattern("/api/account/reset-password/finish")).permitAll()
.requestMatchers(mvc.pattern("/api/public/**")).permitAll()
.requestMatchers(mvc.pattern("/api/admin/**")).hasAuthority(AuthoritiesConstants.ADMIN)
.requestMatchers(mvc.pattern("/api/**")).authenticated()
.requestMatchers(mvc.pattern("/websocket/**")).authenticated()
Expand Down
56 changes: 56 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/ScheduleSubscriber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package de.tum.cit.ase.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;

@Entity
@Table(name = "schedule_subscriber")
public class ScheduleSubscriber {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "schedule_id", nullable = false)
@JsonIgnore
private SimulationSchedule schedule;

@Column(name = "email", nullable = false)
private String email;

@Column(name = "subscription_key", nullable = false, length = 20)
private String key;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public SimulationSchedule getSchedule() {
return schedule;
}

public void setSchedule(SimulationSchedule schedule) {
this.schedule = schedule;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}
}
41 changes: 41 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/Simulation.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ public class Simulation {
@JsonIgnore
private Set<SimulationSchedule> schedules;

// Instructor credentials, only used for EXISTING_COURSE_UNPREPARED_EXAM or EXISTING_COURSE_CREATE_EXAM on PRODUCTION
// The credentials are optional, but required for scheduled simulations
// They must NEVER be sent to the client!
@Column(name = "instructor_username")
private String instructorUsername;

@Column(name = "instructor_password")
private String instructorPassword;

public Long getId() {
return id;
}
Expand Down Expand Up @@ -159,6 +168,38 @@ public void setNumberOfCommitsAndPushesTo(int numberOfCommitsAndPushesTo) {
this.numberOfCommitsAndPushesTo = numberOfCommitsAndPushesTo;
}

public Set<SimulationSchedule> getSchedules() {
return schedules;
}

public void setSchedules(Set<SimulationSchedule> schedules) {
this.schedules = schedules;
}

public String getInstructorUsername() {
return instructorUsername;
}

public void setInstructorUsername(String instructorUsername) {
this.instructorUsername = instructorUsername;
}

public String getInstructorPassword() {
return instructorPassword;
}

public void setInstructorPassword(String instructorPassword) {
this.instructorPassword = instructorPassword;
}

public boolean instructorCredentialsProvided() {
if (mode == Mode.CREATE_COURSE_AND_EXAM) {
// For this mode we need admin credentials, not instructor credentials
return false;
}
return instructorUsername != null && instructorPassword != null;
}

public enum Mode {
/**
* We create a temporary course and exam, prepare the exam and delete everything afterwards.
Expand Down
100 changes: 100 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/SimulationResultForSummary.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package de.tum.cit.ase.domain;

import de.tum.cit.ase.util.TimeLogUtil;

public class SimulationResultForSummary {

public String avgTotal;
public String avgAuthentication;
public String avgGetStudentExam;
public String avgStartStudentExam;
public String avgSubmitExercise;
public String avgSubmitStudentExam;
public String avgClone;
public String avgPush;

public static SimulationResultForSummary from(SimulationRun run) {
SimulationResultForSummary result = new SimulationResultForSummary();
result.avgTotal =
TimeLogUtil.formatDuration(
run
.getStats()
.stream()
.filter((SimulationStats stats) -> stats.getRequestType().equals(RequestType.TOTAL))
.findFirst()
.orElseThrow()
.getAvgResponseTime()
);
result.avgAuthentication =
TimeLogUtil.formatDuration(
run
.getStats()
.stream()
.filter((SimulationStats stats) -> stats.getRequestType().equals(RequestType.AUTHENTICATION))
.findFirst()
.orElseThrow()
.getAvgResponseTime()
);
result.avgGetStudentExam =
TimeLogUtil.formatDuration(
run
.getStats()
.stream()
.filter((SimulationStats stats) -> stats.getRequestType().equals(RequestType.GET_STUDENT_EXAM))
.findFirst()
.orElseThrow()
.getAvgResponseTime()
);
result.avgStartStudentExam =
TimeLogUtil.formatDuration(
run
.getStats()
.stream()
.filter((SimulationStats stats) -> stats.getRequestType().equals(RequestType.START_STUDENT_EXAM))
.findFirst()
.orElseThrow()
.getAvgResponseTime()
);
result.avgSubmitExercise =
TimeLogUtil.formatDuration(
run
.getStats()
.stream()
.filter((SimulationStats stats) -> stats.getRequestType().equals(RequestType.SUBMIT_EXERCISE))
.findFirst()
.orElseThrow()
.getAvgResponseTime()
);
result.avgSubmitStudentExam =
TimeLogUtil.formatDuration(
run
.getStats()
.stream()
.filter((SimulationStats stats) -> stats.getRequestType().equals(RequestType.SUBMIT_STUDENT_EXAM))
.findFirst()
.orElseThrow()
.getAvgResponseTime()
);
result.avgClone =
TimeLogUtil.formatDuration(
run
.getStats()
.stream()
.filter((SimulationStats stats) -> stats.getRequestType().equals(RequestType.CLONE))
.findFirst()
.orElseThrow()
.getAvgResponseTime()
);
result.avgPush =
TimeLogUtil.formatDuration(
run
.getStats()
.stream()
.filter((SimulationStats stats) -> stats.getRequestType().equals(RequestType.PUSH))
.findFirst()
.orElseThrow()
.getAvgResponseTime()
);
return result;
}
}
11 changes: 11 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/SimulationRun.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public class SimulationRun {
@Transient
private ArtemisAccountDTO adminAccount;

@Transient
private SimulationSchedule schedule;

public Long getId() {
return id;
}
Expand Down Expand Up @@ -91,6 +94,14 @@ public void setAdminAccount(ArtemisAccountDTO adminAccount) {
this.adminAccount = adminAccount;
}

public SimulationSchedule getSchedule() {
return schedule;
}

public void setSchedule(SimulationSchedule schedule) {
this.schedule = schedule;
}

public enum Status {
QUEUED,
RUNNING,
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/SimulationSchedule.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.persistence.*;
import java.time.DayOfWeek;
import java.time.ZonedDateTime;
import java.util.Set;

@Entity
@Table(name = "simulation_schedule")
Expand Down Expand Up @@ -39,6 +40,10 @@ public class SimulationSchedule {
@Column(name = "day_of_week")
private DayOfWeek dayOfWeek;

@OneToMany(mappedBy = "schedule", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<ScheduleSubscriber> subscribers;

public Long getId() {
return id;
}
Expand Down Expand Up @@ -103,6 +108,14 @@ public void setDayOfWeek(DayOfWeek dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}

public Set<ScheduleSubscriber> getSubscribers() {
return subscribers;
}

public void setSubscribers(Set<ScheduleSubscriber> subscribers) {
this.subscribers = subscribers;
}

public enum Cycle {
DAILY,
WEEKLY,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package de.tum.cit.ase.repository;

import de.tum.cit.ase.domain.LogMessage;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

public interface LogMessageRepository extends JpaRepository<LogMessage, Long> {}
@Repository
public interface LogMessageRepository extends JpaRepository<LogMessage, Long> {
@Query(value = "select log from LogMessage log where log.simulationRun.id = :#{#simulationRunId} and log.isError = true")
List<LogMessage> findBySimulationRunIdAndErrorIsTrue(@Param("simulationRunId") long simulationRunId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package de.tum.cit.ase.repository;

import de.tum.cit.ase.domain.ScheduleSubscriber;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface ScheduleSubscriberRepository extends JpaRepository<ScheduleSubscriber, Long> {
@Query(value = "select subscriber from ScheduleSubscriber subscriber where subscriber.key = :#{#key}")
Optional<ScheduleSubscriber> findByKey(@Param("key") String key);
}
59 changes: 58 additions & 1 deletion src/main/java/de/tum/cit/ase/service/MailService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.tum.cit.ase.service;

import de.tum.cit.ase.domain.User;
import de.tum.cit.ase.domain.*;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -33,6 +33,10 @@ public class MailService {

private static final String BASE_URL = "baseUrl";

private static final String SUBSCRIPTION_KEY = "subscriptionKey";

private static final String SIMULATION_NAME = "simulationName";

private final JHipsterProperties jHipsterProperties;

private final JavaMailSender javaMailSender;
Expand Down Expand Up @@ -115,4 +119,57 @@ public void sendPasswordResetMail(User user) {
log.debug("Sending password reset email to '{}'", user.getEmail());
self.sendEmailFromTemplate(user, "mail/passwordResetEmail", "email.reset.title");
}

@Async
public void sendSubscribedMail(ScheduleSubscriber subscriber) {
log.debug("Sending subscription confirmation email to '{}'", subscriber.getEmail());
Locale locale = Locale.forLanguageTag("en");
Context context = new Context(locale);
context.setVariable("subscriber", subscriber);
context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
String content = templateEngine.process("mail/scheduleSubscriptionEmail", context);
String subject = "Artemis-Benchmarking - Subscription to simulation schedule";
self.sendEmail(subscriber.getEmail(), subject, content, false, true);
}

@Async
public void sendRunResultMail(SimulationRun run, SimulationSchedule schedule) {
SimulationResultForSummary result = SimulationResultForSummary.from(run);
Locale locale = Locale.forLanguageTag("en");
Context context = new Context(locale);
context.setVariable("run", run);
context.setVariable("result", result);
context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
String subject = "Artemis-Benchmarking - Result for scheduled run";
schedule
.getSubscribers()
.forEach(subscriber -> {
context.setVariable("subscriber", subscriber);
String content = templateEngine.process("mail/subscriptionResultEmail", context);
log.debug("Sending result email to '{}'", subscriber.getEmail());
self.sendEmail(subscriber.getEmail(), subject, content, false, true);
});
}

@Async
public void sendRunFailureMail(SimulationRun run, SimulationSchedule schedule, LogMessage errorLogMessage) {
Locale locale = Locale.forLanguageTag("en");
Context context = new Context(locale);
context.setVariable("run", run);
if (errorLogMessage != null) {
context.setVariable("error", errorLogMessage.getMessage());
} else {
context.setVariable("error", "No error message found.");
}
context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
String subject = "Artemis-Benchmarking - Scheduled run failed";
schedule
.getSubscribers()
.forEach(subscriber -> {
context.setVariable("subscriber", subscriber);
String content = templateEngine.process("mail/subscriptionFailureEmail", context);
log.debug("Sending result email to '{}'", subscriber.getEmail());
self.sendEmail(subscriber.getEmail(), subject, content, false, true);
});
}
}
Loading

0 comments on commit c55bb00

Please sign in to comment.