Merge branch 'develop' into 2856

This commit is contained in:
Andreas Svanberg 2022-10-25 20:40:47 +02:00
commit 9c1481626a
404 changed files with 3199 additions and 2092 deletions
core
pom.xml
src/main/java
modules
se/su/dsv/scipro
DataInitializer.java
activityplan
checklist
daisyExternal
file
finalseminar
finalthesis
firstmeeting
forum
forummail
generalsystemsettings
grading
group
integration

@ -25,8 +25,8 @@
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
@ -38,16 +38,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<exclusions>
<exclusion>
<groupId>org.glassfish.hk2.external</groupId>
<artifactId>javax.inject</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
@ -88,53 +78,38 @@
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-core</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
<classifier>jpa</classifier>
</dependency>
<!-- JPA -->
<!-- Hibernate impl -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<scope>runtime</scope>
<exclusions>
<exclusion>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<scope>runtime</scope>
</dependency>
<!--Additional stuff-->
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<artifactId>jakarta.mail</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@ -149,20 +124,15 @@
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-jaxrs2</artifactId>
<version>0.5.0</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
<version>3.0.2</version>
<scope>runtime</scope>
</dependency>
@ -214,9 +184,29 @@
</testResources>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.5.0</version>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<classifier>jakarta</classifier>
</path>
<path>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>${jakarta.persistence-api.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>com.evolvedbinary.maven.mojohaus</groupId>
<artifactId>jaxb-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>xjc</id>

@ -0,0 +1,142 @@
package modules;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import com.google.inject.persist.UnitOfWork;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityTransaction;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;
class JakartaLocalTxnInterceptor implements MethodInterceptor {
@Inject
private JakartaPersistService emProvider = null;
@Inject
private UnitOfWork unitOfWork = null;
@Transactional
private static class Internal {
}
// Tracks if the unit of work was begun implicitly by this transaction.
private final ThreadLocal<Boolean> didWeStartWork = new ThreadLocal<>();
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
// Should we start a unit of work?
if (!emProvider.isWorking()) {
emProvider.begin();
didWeStartWork.set(true);
}
Transactional transactional = readTransactionMetadata(methodInvocation);
EntityManager em = this.emProvider.get();
// Allow 'joining' of transactions if there is an enclosing @Transactional method.
if (em.getTransaction().isActive()) {
return methodInvocation.proceed();
}
final EntityTransaction txn = em.getTransaction();
txn.begin();
Object result;
try {
result = methodInvocation.proceed();
} catch (Exception e) {
//commit transaction only if rollback didnt occur
if (rollbackIfNecessary(transactional, e, txn)) {
txn.commit();
}
//propagate whatever exception is thrown anyway
throw e;
} finally {
// Close the em if necessary (guarded so this code doesn't run unless catch fired).
if (null != didWeStartWork.get() && !txn.isActive()) {
didWeStartWork.remove();
unitOfWork.end();
}
}
//everything was normal so commit the txn (do not move into try block above as it
// interferes with the advised method's throwing semantics)
try {
txn.commit();
} finally {
//close the em if necessary
if (null != didWeStartWork.get()) {
didWeStartWork.remove();
unitOfWork.end();
}
}
//or return result
return result;
}
private Transactional readTransactionMetadata(MethodInvocation methodInvocation) {
Transactional transactional;
Method method = methodInvocation.getMethod();
Class<?> targetClass = methodInvocation.getThis().getClass();
transactional = method.getAnnotation(Transactional.class);
if (null == transactional) {
// If none on method, try the class.
transactional = targetClass.getAnnotation(Transactional.class);
}
if (null == transactional) {
// If there is no transactional annotation present, use the default
transactional = Internal.class.getAnnotation(Transactional.class);
}
return transactional;
}
/**
* Returns True if rollback DID NOT HAPPEN (i.e. if commit should continue).
*
* @param transactional The metadata annotaiton of the method
* @param e The exception to test for rollback
* @param txn A JPA Transaction to issue rollbacks on
*/
private boolean rollbackIfNecessary(
Transactional transactional, Exception e, EntityTransaction txn)
{
boolean commit = true;
//check rollback clauses
for (Class<? extends Exception> rollBackOn : transactional.rollbackOn()) {
//if one matched, try to perform a rollback
if (rollBackOn.isInstance(e)) {
commit = false;
//check ignore clauses (supercedes rollback clause)
for (Class<? extends Exception> exceptOn : transactional.ignore()) {
//An exception to the rollback clause was found, DON'T rollback
// (i.e. commit and throw anyway)
if (exceptOn.isInstance(e)) {
commit = true;
break;
}
}
//rollback only if nothing matched the ignore check
if (!commit) {
txn.rollback();
}
//otherwise continue to commit
break;
}
}
return commit;
}
}

@ -0,0 +1,42 @@
package modules;
import com.google.inject.Singleton;
import com.google.inject.persist.PersistModule;
import com.google.inject.persist.PersistService;
import com.google.inject.persist.UnitOfWork;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Objects;
public class JakartaPersistModule extends PersistModule {
private final String jpaUnit;
public JakartaPersistModule(String jpaUnit) {
this.jpaUnit = Objects.requireNonNull(jpaUnit, "JPA unit name must be a non-empty string.");
}
private MethodInterceptor transactionInterceptor;
@Override
protected void configurePersistence() {
bindConstant().annotatedWith(Jpa.class).to(jpaUnit);
bind(JakartaPersistService.class).in(Singleton.class);
bind(PersistService.class).to(JakartaPersistService.class);
bind(UnitOfWork.class).to(JakartaPersistService.class);
bind(EntityManager.class).toProvider(JakartaPersistService.class);
bind(EntityManagerFactory.class)
.toProvider(JakartaPersistService.EntityManagerFactoryProvider.class);
transactionInterceptor = new JakartaLocalTxnInterceptor();
requestInjection(transactionInterceptor);
}
@Override
protected MethodInterceptor getTransactionInterceptor() {
return transactionInterceptor;
}
}

@ -0,0 +1,99 @@
package modules;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.persist.PersistService;
import com.google.inject.persist.UnitOfWork;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
@Singleton
class JakartaPersistService implements Provider<EntityManager>, UnitOfWork, PersistService {
private final ThreadLocal<EntityManager> entityManager = new ThreadLocal<>();
private final String persistenceUnitName;
@Inject
public JakartaPersistService(@Jpa String persistenceUnitName) {
this.persistenceUnitName = persistenceUnitName;
}
@Override
public EntityManager get() {
if (!isWorking()) {
begin();
}
EntityManager em = entityManager.get();
Preconditions.checkState(
null != em,
"Requested EntityManager outside work unit. "
+ "Try calling UnitOfWork.begin() first, or use a PersistFilter if you "
+ "are inside a servlet environment.");
return em;
}
public boolean isWorking() {
return entityManager.get() != null;
}
@Override
public void begin() {
Preconditions.checkState(
null == entityManager.get(),
"Work already begun on this thread. Looks like you have called UnitOfWork.begin() twice"
+ " without a balancing call to end() in between.");
entityManager.set(emFactory.createEntityManager());
}
@Override
public void end() {
EntityManager em = entityManager.get();
// Let's not penalize users for calling end() multiple times.
if (null == em) {
return;
}
try {
em.close();
} finally {
entityManager.remove();
}
}
private volatile EntityManagerFactory emFactory;
@Override
public synchronized void start() {
Preconditions.checkState(null == emFactory, "Persistence service was already initialized.");
this.emFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
}
@Override
public synchronized void stop() {
Preconditions.checkState(emFactory.isOpen(), "Persistence service was already shut down.");
emFactory.close();
}
@Singleton
public static class EntityManagerFactoryProvider implements Provider<EntityManagerFactory> {
private final JakartaPersistService emProvider;
@Inject
public EntityManagerFactoryProvider(JakartaPersistService emProvider) {
this.emProvider = emProvider;
}
@Override
public EntityManagerFactory get() {
assert null != emProvider.emFactory;
return emProvider.emFactory;
}
}
}

@ -0,0 +1,11 @@
package modules;
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
public @interface Jpa {
}

@ -9,6 +9,8 @@ import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepository;
import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepositoryImpl;
import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepo;
import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepoImpl;
import se.su.dsv.scipro.finalseminar.FinalSeminarRepository;
import se.su.dsv.scipro.finalseminar.FinalSeminarRepositoryImpl;
import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepository;
import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepositoryImpl;
import se.su.dsv.scipro.peer.CommentThreadRepo;
@ -50,5 +52,6 @@ public class RepositoryModule extends AbstractModule {
bind(CommentThreadRepo.class).to(CommentThreadRepoImpl.class);
bind(FooterLinkRepo.class).to(FooterLinkRepoImpl.class);
bind(FooterAddressRepo.class).to(FooterAddressRepoImpl.class);
bind(FinalSeminarRepository.class).to(FinalSeminarRepositoryImpl.class);
}
}

@ -17,7 +17,7 @@ import se.su.dsv.scipro.system.*;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;

@ -1,21 +1,22 @@
package se.su.dsv.scipro.activityplan;
import com.querydsl.core.annotations.QueryInit;
import jakarta.persistence.GenerationType;
import se.su.dsv.scipro.checklist.Checklist;
import se.su.dsv.scipro.file.FileReference;
import se.su.dsv.scipro.system.LazyDeletableDomainObject;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import jakarta.persistence.Cacheable;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import java.io.Serializable;
import java.util.*;
@ -23,7 +24,7 @@ import java.util.*;
@Cacheable(true)
public class Activity extends LazyDeletableDomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional=false)

@ -3,7 +3,7 @@ package se.su.dsv.scipro.activityplan;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.system.DomainObject;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Date;
import java.util.Objects;
import java.util.Set;
@ -13,7 +13,7 @@ import java.util.TreeSet;
@Cacheable(true)
public class ActivityPlan extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy= "activityPlan",cascade=CascadeType.PERSIST, orphanRemoval = true)

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class ActivityPlanServiceImpl extends AbstractServiceImpl<ActivityPlan,Long> implements ActivityPlanService {
@Inject

@ -3,7 +3,7 @@ package se.su.dsv.scipro.activityplan;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.*;
@Entity
@ -11,7 +11,7 @@ import java.util.*;
public class ActivityPlanTemplate extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OrderColumn(name = "numberInOrder")

@ -8,7 +8,7 @@ import se.su.dsv.scipro.system.User;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.List;

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class ActivityServiceImpl extends AbstractServiceImpl<Activity, Long> implements ActivityService {

@ -3,14 +3,14 @@ package se.su.dsv.scipro.activityplan;
import se.su.dsv.scipro.checklist.ChecklistTemplate;
import se.su.dsv.scipro.system.DomainObject;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
public class ActivityTemplate extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)

@ -5,7 +5,7 @@ import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.*;
@Entity
@ -14,7 +14,7 @@ import java.util.*;
public class Checklist extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)

@ -3,14 +3,14 @@ package se.su.dsv.scipro.checklist;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
@Table(name = "checklist_answer")
public class ChecklistAnswer extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class ChecklistAnswerServiceImpl extends AbstractServiceImpl<ChecklistAnswer, Long> implements ChecklistAnswerService {

@ -5,7 +5,7 @@ package se.su.dsv.scipro.checklist;
import se.su.dsv.scipro.system.DomainObject;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
@ -13,7 +13,7 @@ import java.util.Objects;
@Cacheable(true)
public class ChecklistCategory extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique=true)

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.GenericRepo;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class ChecklistCategoryRepoImpl extends GenericRepo<ChecklistCategory, Long> implements ChecklistCategoryRepo {
@Inject

@ -3,7 +3,7 @@ package se.su.dsv.scipro.checklist;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -13,7 +13,7 @@ import java.util.Objects;
@Cacheable(true)
public class ChecklistQuestion extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.GenericRepo;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class ChecklistQuestionRepoImpl extends GenericRepo<ChecklistQuestion, Long> implements ChecklistQuestionRepo {
@Inject

@ -7,7 +7,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class ChecklistServiceImpl extends AbstractServiceImpl<Checklist, Long> implements ChecklistService {
@Inject

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.ProjectType;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.*;
@Entity
@ -14,7 +14,7 @@ public class ChecklistTemplate extends DomainObject {
public static final int DEFAULT_TEMPLATE_NUMBER = 999;
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)

@ -8,7 +8,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.List;
import static com.querydsl.core.types.dsl.Expressions.allOf;

@ -1,9 +1,9 @@
package se.su.dsv.scipro.daisyExternal;
import com.google.inject.*;
import com.google.inject.Key;
import com.google.inject.PrivateModule;
import com.google.inject.Scopes;
import com.google.inject.name.Names;
import io.opentracing.Tracer;
import io.opentracing.noop.NoopTracerFactory;
import se.su.dsv.scipro.daisyExternal.http.DaisyAPI;
import se.su.dsv.scipro.daisyExternal.http.DaisyAPIImpl;
@ -16,12 +16,5 @@ public class DaisyExternalModule extends PrivateModule {
bind(DaisyAPI.class).to(DaisyAPIImpl.class).in(Scopes.SINGLETON);
expose(DaisyAPI.class);
expose(Tracer.class);
}
@Provides
@Singleton
public Tracer getTracer() {
return NoopTracerFactory.create();
}
}

@ -2,7 +2,7 @@ package se.su.dsv.scipro.daisyExternal.http;
import se.su.dsv.scipro.io.dto.*;
import javax.ws.rs.core.Response;
import jakarta.ws.rs.core.Response;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

@ -1,27 +1,41 @@
package se.su.dsv.scipro.daisyExternal.http;
import io.opentracing.Tracer;
import io.opentracing.contrib.jaxrs2.client.ClientTracingFeature;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import se.su.dsv.scipro.io.dto.*;
import se.su.dsv.scipro.io.dto.AddThesisAuthor;
import se.su.dsv.scipro.io.dto.CourseRegistration;
import se.su.dsv.scipro.io.dto.Employee;
import se.su.dsv.scipro.io.dto.ObjectFactory;
import se.su.dsv.scipro.io.dto.Person;
import se.su.dsv.scipro.io.dto.Program;
import se.su.dsv.scipro.io.dto.ProgramAdmission;
import se.su.dsv.scipro.io.dto.ProjectParticipant;
import se.su.dsv.scipro.io.dto.ResearchArea;
import se.su.dsv.scipro.io.dto.StudentProgramAdmission;
import se.su.dsv.scipro.io.dto.StudentProjectParticipant;
import se.su.dsv.scipro.io.dto.Thesis;
import se.su.dsv.scipro.io.dto.ThesisPublication;
import se.su.dsv.scipro.io.dto.ThesisRejection;
import se.su.dsv.scipro.io.dto.ThesisToBeCreated;
import se.su.dsv.scipro.io.dto.ThesisToBeUpdated;
import se.su.dsv.scipro.io.dto.Unit;
import se.su.dsv.scipro.io.dto.UserName;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import static javax.ws.rs.client.Entity.json;
import static javax.ws.rs.client.Entity.xml;
import static jakarta.ws.rs.client.Entity.xml;
public class DaisyAPIImpl implements DaisyAPI {
@ -41,18 +55,18 @@ public class DaisyAPIImpl implements DaisyAPI {
private final String baseUrl;
private final Client client;
private final ObjectFactory objectFactory;
@Inject
public DaisyAPIImpl(
@Named("daisy.api.url") final String baseUrl,
@Named("daisy.api.username") final String user,
@Named("daisy.api.password") final String password,
final Tracer tracer)
@Named("daisy.api.password") final String password)
{
this.baseUrl = baseUrl;
this.client = ClientBuilder.newClient()
.register(HttpAuthenticationFeature.basic(user, password))
.register(new ClientTracingFeature.Builder(tracer).build());
.register(HttpAuthenticationFeature.basic(user, password));
this.objectFactory = new ObjectFactory();
}
@Override
@ -60,7 +74,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return thesis()
.path(String.valueOf(projectId))
.path(CONTRIBUTOR)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -71,7 +85,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return thesis()
.path(String.valueOf(projectId))
.path(STUDENT)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -91,7 +105,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return units()
.path(String.valueOf(unitId))
.path(SUBUNITS)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -102,7 +116,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return person()
.path(String.valueOf(personId))
.path(USERNAMES)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -112,7 +126,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return person()
.path(String.valueOf(personId))
.path(RESEARCH_AREAS)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -122,7 +136,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return units()
.path(String.valueOf(unitId))
.path(SUPERVISORS)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -131,7 +145,7 @@ public class DaisyAPIImpl implements DaisyAPI {
public Optional<Person> findPersonById(Integer id) {
Response response = person()
.path(String.valueOf(id))
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(Response.class);
return response.getStatus() == 200
? Optional.of(response.readEntity(Person.class))
@ -143,7 +157,7 @@ public class DaisyAPIImpl implements DaisyAPI {
Response response = person()
.path(USERNAME)
.path(userName)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(Response.class);
return response.getStatus() == 200
? Optional.of(response.readEntity(Person.class))
@ -155,8 +169,8 @@ public class DaisyAPIImpl implements DaisyAPI {
return thesis()
.path(String.valueOf(projectIdentifier))
.path(CONTRIBUTOR)
.request(MediaType.APPLICATION_JSON_TYPE)
.post(json(contributor));
.request(MediaType.APPLICATION_XML_TYPE)
.post(xml(objectFactory.createProjectParticipant(contributor)));
}
@Override
@ -165,14 +179,14 @@ public class DaisyAPIImpl implements DaisyAPI {
.path(String.valueOf(projectId))
.path(CONTRIBUTOR)
.path(String.valueOf(personId))
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.delete();
}
@Override
public Response createProject(ThesisToBeCreated project) {
return thesis()
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.post(xml(project));
}
@ -189,7 +203,7 @@ public class DaisyAPIImpl implements DaisyAPI {
public Response deleteProject(Integer projectId) {
return thesis()
.path(String.valueOf(projectId))
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.delete();
}
@ -197,7 +211,7 @@ public class DaisyAPIImpl implements DaisyAPI {
public Response getStudent(Integer id) {
return student()
.path(String.valueOf(id))
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get();
}
@ -205,7 +219,7 @@ public class DaisyAPIImpl implements DaisyAPI {
public Program getProgram(Integer id) {
return program()
.path(String.valueOf(id))
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(Program.class);
}
@ -244,7 +258,7 @@ public class DaisyAPIImpl implements DaisyAPI {
.path(String.valueOf(courseId))
.path(STUDENT)
.path(String.valueOf(authorId))
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get();
return response.getStatus() == 200
? Optional.ofNullable(response.readEntity(String.class))
@ -255,7 +269,7 @@ public class DaisyAPIImpl implements DaisyAPI {
public List<Person> findByPersonnummer(final String personnummer) {
return person()
.queryParam("personnummer", personnummer)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -345,7 +359,7 @@ public class DaisyAPIImpl implements DaisyAPI {
public List<Program> getPrograms(final Integer responsibleDepartmentId) {
return program()
.queryParam("responsibleDepartment", responsibleDepartmentId)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -356,7 +370,7 @@ public class DaisyAPIImpl implements DaisyAPI {
.path(String.valueOf(program.getId()))
.path("admissions")
.queryParam("admissionSemester", admissionSemester.getId())
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
}
@ -380,7 +394,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return student()
.path(Integer.toString(studentId))
.path("programAdmissions")
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
} catch (NotFoundException ignored) {
@ -394,7 +408,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return student()
.path(Integer.toString(studentId))
.path("courseRegistrations")
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>() {
});
} catch (NotFoundException ignored) {
@ -407,7 +421,7 @@ public class DaisyAPIImpl implements DaisyAPI {
return target()
.path("employee")
.queryParam("department", departmentId)
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>(){});
}
@ -417,7 +431,7 @@ public class DaisyAPIImpl implements DaisyAPI {
.path("orgunit")
.path(Integer.toString(unitId))
.path("researchAreas")
.request(MediaType.APPLICATION_JSON_TYPE)
.request(MediaType.APPLICATION_XML_TYPE)
.get(new GenericType<>(){});
}

@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystems;
@ -34,7 +34,7 @@ public class FileDescription extends DomainObject {
public static final String FILE_ROOT = "/scipro-files";
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.GenericRepo;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class FileDescriptionRepoImpl extends GenericRepo<FileDescription, Long> implements FileDescriptionRepo {
@Inject

@ -1,12 +1,13 @@
package se.su.dsv.scipro.file;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.io.Serializable;
import java.util.*;
@ -24,7 +25,7 @@ import java.util.*;
@Table(name = "file_reference")
public class FileReference implements Serializable {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(cascade = CascadeType.PERSIST)

@ -5,7 +5,7 @@ import se.su.dsv.scipro.system.AbstractRepository;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
class FileReferenceRepositoryImpl extends AbstractRepository implements FileReferenceRepository {

@ -5,7 +5,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.io.InputStream;
public class FileServiceImpl extends AbstractServiceImpl<FileDescription, Long> implements FileService {

@ -3,7 +3,7 @@ package se.su.dsv.scipro.file;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.system.DomainObject;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
@ -11,7 +11,7 @@ import java.util.Objects;
public class ProjectFile extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne

@ -8,7 +8,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.*;
public class ProjectFileRepositoryImpl extends AbstractServiceImpl<ProjectFile, Long> implements ProjectFileRepository {

@ -10,7 +10,7 @@ import se.su.dsv.scipro.system.User;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.List;
import java.util.Optional;

@ -1,6 +1,7 @@
package se.su.dsv.scipro.finalseminar;
import com.querydsl.core.annotations.QueryInit;
import jakarta.persistence.GenerationType;
import se.su.dsv.scipro.data.dataobjects.Member;
import se.su.dsv.scipro.file.FileReference;
import se.su.dsv.scipro.project.Project;
@ -9,19 +10,19 @@ import se.su.dsv.scipro.system.LazyDeletableDomainObject;
import se.su.dsv.scipro.system.ProjectType;
import se.su.dsv.scipro.system.User;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import jakarta.persistence.Basic;
import jakarta.persistence.Cacheable;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.util.*;
@Entity
@ -35,7 +36,7 @@ public class FinalSeminar extends LazyDeletableDomainObject {
public static final String FINAL_SEMINAR = "finalSeminar";
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(optional = false)

@ -2,10 +2,10 @@ package se.su.dsv.scipro.finalseminar;
import se.su.dsv.scipro.project.Project;
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import jakarta.persistence.Cacheable;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.util.Objects;
@Entity

@ -6,7 +6,7 @@ import se.su.dsv.scipro.system.User;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.*;
public class FinalSeminarActiveParticipationRepositoryImpl extends AbstractRepository implements FinalSeminarActiveParticipationRepository {

@ -5,7 +5,7 @@ import se.su.dsv.scipro.system.User;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class FinalSeminarActiveParticipationServiceImpl extends AbstractServiceImpl<FinalSeminarActiveParticipation, Long> implements FinalSeminarActiveParticipationService {

@ -0,0 +1,13 @@
package se.su.dsv.scipro.finalseminar;
import se.su.dsv.scipro.system.Language;
public record FinalSeminarDetails(
String location,
int maxParticipants,
int maxOpponents,
Language presentationLanguage,
Language reportLanguage,
String extraInfo)
{
}

@ -1,21 +1,6 @@
package se.su.dsv.scipro.finalseminar;
import java.util.Date;
import java.time.LocalDateTime;
public final class FinalSeminarMovedEvent {
private final FinalSeminar finalSeminar;
private final Date to;
public FinalSeminarMovedEvent(final FinalSeminar finalSeminar, final Date to) {
this.finalSeminar = finalSeminar;
this.to = to;
}
public Date getTo() {
return (Date) to.clone();
}
public FinalSeminar getFinalSeminar() {
return finalSeminar;
}
public record FinalSeminarMovedEvent(FinalSeminar finalSeminar, LocalDateTime from, LocalDateTime to) {
}

@ -5,14 +5,14 @@ import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.report.OppositionReport;
import se.su.dsv.scipro.system.ProjectType;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import jakarta.persistence.Basic;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.util.*;
@Entity

@ -6,7 +6,7 @@ import se.su.dsv.scipro.system.User;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.*;
public class FinalSeminarOppositionRepoImpl extends GenericRepo<FinalSeminarOpposition,Long> implements FinalSeminarOppositionRepo {

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class FinalSeminarOppositionServiceImpl extends AbstractServiceImpl<FinalSeminarOpposition, Long> implements FinalSeminarOppositionService {
@Inject

@ -3,14 +3,14 @@ package se.su.dsv.scipro.finalseminar;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Objects;
@MappedSuperclass
public abstract class FinalSeminarParticipation extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)

@ -0,0 +1,5 @@
package se.su.dsv.scipro.finalseminar;
public interface FinalSeminarRepository {
FinalSeminar save(FinalSeminar finalSeminar);
}

@ -0,0 +1,28 @@
package se.su.dsv.scipro.finalseminar;
import com.google.inject.persist.Transactional;
import jakarta.persistence.EntityManager;
import se.su.dsv.scipro.system.AbstractRepository;
import javax.inject.Inject;
import javax.inject.Provider;
public class FinalSeminarRepositoryImpl extends AbstractRepository implements FinalSeminarRepository {
@Inject
protected FinalSeminarRepositoryImpl(Provider<EntityManager> em) {
super(em);
}
@Override
@Transactional
public FinalSeminar save(FinalSeminar finalSeminar) {
EntityManager entityManager = em();
if (entityManager.contains(finalSeminar)) {
return entityManager.merge(finalSeminar);
}
else {
entityManager.persist(finalSeminar);
return finalSeminar;
}
}
}

@ -3,9 +3,9 @@ package se.su.dsv.scipro.finalseminar;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.system.User;
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.Table;
import jakarta.persistence.Cacheable;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
@Entity
@Cacheable(true)

@ -6,7 +6,7 @@ import se.su.dsv.scipro.system.User;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;

@ -0,0 +1,17 @@
package se.su.dsv.scipro.finalseminar;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.util.Either;
import java.time.LocalDate;
import java.time.LocalDateTime;
public interface FinalSeminarScheduling {
Either<SchedulingError, FinalSeminar> schedule(Project project, LocalDateTime when, FinalSeminarDetails details);
LocalDate getEarliestSeminarDate();
Either<MovingError, FinalSeminar> move(FinalSeminar finalSeminar, LocalDateTime to);
FinalSeminar updateDetails(FinalSeminar finalSeminar, FinalSeminarDetails finalSeminarDetails);
}

@ -11,8 +11,7 @@ import java.util.Date;
import java.util.List;
import java.util.Objects;
public interface FinalSeminarService extends GenericService<FinalSeminar, Long>, FilteredService<FinalSeminar, Long, FinalSeminarService.Filter> {
Either<SchedulingError, FinalSeminar> move(FinalSeminar finalSeminar, Date to);
public interface FinalSeminarService extends GenericService<FinalSeminar, Long>, FilteredService<FinalSeminar, Long, FinalSeminarService.Filter>, FinalSeminarScheduling {
se.su.dsv.scipro.util.Either<OppositionRegistrationStatus, FinalSeminarOpposition> studentOppose(User student, FinalSeminar finalSeminar, Project project);
Either<OpposeError, FinalSeminarOpposition> oppose(User student, FinalSeminar finalSeminar, Project project);
void participate(User student, FinalSeminar finalSeminar, Project project);

@ -4,6 +4,7 @@ import com.google.common.eventbus.EventBus;
import com.google.inject.persist.Transactional;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.dsl.BooleanExpression;
import jakarta.persistence.EntityManager;
import org.springframework.data.domain.Pageable;
import se.su.dsv.scipro.file.FileReference;
import se.su.dsv.scipro.file.FileService;
@ -14,17 +15,21 @@ import se.su.dsv.scipro.project.Author;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.project.ProjectStatus;
import se.su.dsv.scipro.report.OppositionReportService;
import se.su.dsv.scipro.reviewing.RoughDraftApproval;
import se.su.dsv.scipro.reviewing.RoughDraftApprovalService;
import se.su.dsv.scipro.system.AbstractServiceImpl;
import se.su.dsv.scipro.system.User;
import se.su.dsv.scipro.util.Either;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import java.time.Clock;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Predicate;
import static com.querydsl.core.types.dsl.Expressions.allOf;
@ -46,6 +51,9 @@ public class FinalSeminarServiceImpl extends AbstractServiceImpl<FinalSeminar, L
private final FileService fileService;
private final FinalSeminarOppositionRepo finalSeminarOppositionRepository;
private final FinalSeminarActiveParticipationRepository finalSeminarActiveParticipationRepository;
private final FinalSeminarRepository finalSeminarRepository;
private final Clock clock;
private final RoughDraftApprovalService roughDraftApprovalService;
@Inject
public FinalSeminarServiceImpl(
@ -54,7 +62,10 @@ public class FinalSeminarServiceImpl extends AbstractServiceImpl<FinalSeminar, L
AuthorRepository authorRepository,
final FileService fileService,
FinalSeminarOppositionRepo finalSeminarOppositionRepository,
FinalSeminarActiveParticipationRepository finalSeminarActiveParticipationRepository)
FinalSeminarActiveParticipationRepository finalSeminarActiveParticipationRepository,
FinalSeminarRepository finalSeminarRepository,
Clock clock,
RoughDraftApprovalService roughDraftApprovalService)
{
super(em, FinalSeminar.class, QFinalSeminar.finalSeminar);
this.eventBus = eventBus;
@ -62,51 +73,98 @@ public class FinalSeminarServiceImpl extends AbstractServiceImpl<FinalSeminar, L
this.fileService = fileService;
this.finalSeminarOppositionRepository = finalSeminarOppositionRepository;
this.finalSeminarActiveParticipationRepository = finalSeminarActiveParticipationRepository;
this.finalSeminarRepository = finalSeminarRepository;
this.clock = clock;
this.roughDraftApprovalService = roughDraftApprovalService;
}
@Override
@Transactional
public <S extends FinalSeminar> S save(S finalSeminar) {
if (finalSeminar.getId()==null){
S saved = super.save(finalSeminar);
eventBus.post(new FinalSeminarCreatedEvent(saved));
return saved;
} else {
return super.save(finalSeminar);
public Either<SchedulingError, FinalSeminar> schedule(Project project, LocalDateTime when, FinalSeminarDetails details) {
if (project.isFinalSeminarRuleExempted()) {
return createSeminar(project, when, details);
}
SchedulingError violation = validateSchedulingRules(when.toLocalDate());
if (violation != null) return Either.left(violation);
boolean roughDraftApproved = roughDraftApprovalService.findBy(project)
.map(RoughDraftApproval::isApproved)
.orElse(Boolean.FALSE);
if (!roughDraftApproved) {
return Either.left(new RoughDraftNotApproved());
}
return createSeminar(project, when, details);
}
private MovingError validateSchedulingRules(LocalDate date) {
LocalDate earliestDate = getEarliestSeminarDate();
if (earliestDate.isAfter(date)) {
return new NotEnoughWorkDays(date, earliestDate);
}
if (nonWorkDayPeriodService.isNonWorkDay(date)) {
return new NonWorkDay(date);
}
return null;
}
@Override
public LocalDate getEarliestSeminarDate() {
FinalSeminarSettings settings = finalSeminarSettingsService.getInstance();
return daysService.workDaysAfter(LocalDate.now(clock), settings.getDaysAheadToCreate());
}
private Either<SchedulingError, FinalSeminar> createSeminar(
Project project,
LocalDateTime when,
FinalSeminarDetails details)
{
FinalSeminar finalSeminar = new FinalSeminar(project);
FinalSeminar persisted = setDetails(finalSeminar, when, details);
eventBus.post(new FinalSeminarCreatedEvent(persisted));
return Either.right(persisted);
}
private FinalSeminar setDetails(FinalSeminar finalSeminar, LocalDateTime when, FinalSeminarDetails details) {
Instant instant = when.atZone(clock.getZone()).toInstant();
finalSeminar.setStartDate(Date.from(instant));
return updateDetails(finalSeminar, details);
}
@Override
@Transactional
public Either<SchedulingError, FinalSeminar> move(final FinalSeminar finalSeminar, final Date to) {
final Date earliestCreationDate = daysService.workDaysAfter(new Date(),
finalSeminarSettingsService.getInstance().getDaysAheadToCreate());
Either<SchedulingError, FinalSeminar> move = tryMove(finalSeminar, to, earliestCreationDate, nonWorkDayPeriodService::isNonWorkDay);
move.foreach(seminar -> {
FinalSeminar moved = save(seminar);
eventBus.post(new FinalSeminarMovedEvent(moved, to));
});
return move;
}
static Either<SchedulingError, FinalSeminar> tryMove(FinalSeminar finalSeminar, Date to, Date earliest, Predicate<Date> isNonWorkDay) {
public Either<MovingError, FinalSeminar> move(FinalSeminar finalSeminar, LocalDateTime to) {
if (finalSeminar.getProject().isFinalSeminarRuleExempted()) {
finalSeminar.setStartDate(to);
finalSeminar.setCancelled(false);
return se.su.dsv.scipro.util.Either.right(finalSeminar);
}
else if (isNonWorkDay.test(to)) {
return se.su.dsv.scipro.util.Either.left(new NonWorkDay(to));
}
else if (to.before(earliest)) {
return se.su.dsv.scipro.util.Either.left(new NotEnoughWorkDays(to, earliest));
}
else {
finalSeminar.setStartDate(to);
finalSeminar.setCancelled(false);
return se.su.dsv.scipro.util.Either.right(finalSeminar);
return moveSeminar(finalSeminar, to);
}
MovingError violation = validateSchedulingRules(to.toLocalDate());
if (violation != null) return Either.left(violation);
return moveSeminar(finalSeminar, to);
}
private Either<MovingError, FinalSeminar> moveSeminar(FinalSeminar finalSeminar, LocalDateTime to) {
ZonedDateTime oldTime = finalSeminar.getStartDate().toInstant().atZone(clock.getZone());
Instant instant = to.atZone(clock.getZone()).toInstant();
finalSeminar.setStartDate(Date.from(instant));
finalSeminar.setCancelled(false);
FinalSeminar moved = finalSeminarRepository.save(finalSeminar);
eventBus.post(new FinalSeminarMovedEvent(moved, oldTime.toLocalDateTime(), to));
return Either.right(moved);
}
@Override
@Transactional
public FinalSeminar updateDetails(FinalSeminar finalSeminar, FinalSeminarDetails finalSeminarDetails) {
finalSeminar.setRoom(finalSeminarDetails.location());
finalSeminar.setExtraInfo(finalSeminarDetails.extraInfo());
finalSeminar.setMaxOpponents(finalSeminarDetails.maxOpponents());
finalSeminar.setMaxParticipants(finalSeminarDetails.maxParticipants());
finalSeminar.setPresentationLanguage(finalSeminarDetails.presentationLanguage());
finalSeminar.getProject().setLanguage(finalSeminarDetails.reportLanguage());
return finalSeminarRepository.save(finalSeminar);
}
@Override
@ -132,7 +190,7 @@ public class FinalSeminarServiceImpl extends AbstractServiceImpl<FinalSeminar, L
participation.setFinalSeminar(finalSeminar);
participation.setProject(project);
finalSeminar.addActiveParticipant(participation);
save(finalSeminar);
finalSeminarRepository.save(finalSeminar);
}
private boolean alreadyOpponent(User user, FinalSeminar finalSeminar) {
@ -209,7 +267,7 @@ public class FinalSeminarServiceImpl extends AbstractServiceImpl<FinalSeminar, L
opposition.setFinalSeminar(finalSeminar);
opposition.setProject(project);
finalSeminar.addOpposition(opposition);
save(finalSeminar);
finalSeminarRepository.save(finalSeminar);
return opposition;
});
}
@ -225,7 +283,7 @@ public class FinalSeminarServiceImpl extends AbstractServiceImpl<FinalSeminar, L
opposition.setFinalSeminar(finalSeminar);
opposition.setProject(project);
finalSeminar.addOpposition(opposition);
save(finalSeminar);
finalSeminarRepository.save(finalSeminar);
return se.su.dsv.scipro.util.Either.right(opposition);
}
}
@ -364,7 +422,7 @@ public class FinalSeminarServiceImpl extends AbstractServiceImpl<FinalSeminar, L
@Transactional
public FinalSeminar cancel(FinalSeminar finalSeminar) {
finalSeminar.setCancelled(true);
FinalSeminar cancelled = save(finalSeminar);
FinalSeminar cancelled = finalSeminarRepository.save(finalSeminar);
eventBus.post(new FinalSeminarCancelledEvent(cancelled));
return cancelled;
}
@ -447,7 +505,7 @@ public class FinalSeminarServiceImpl extends AbstractServiceImpl<FinalSeminar, L
seminar.setDocumentUploadDate(null);
fileService.delete(document);
FinalSeminar reloadedSeminar = save(seminar);
FinalSeminar reloadedSeminar = finalSeminarRepository.save(seminar);
eventBus.post(new FinalSeminarThesisDeletedEvent(reloadedSeminar));

@ -2,7 +2,7 @@ package se.su.dsv.scipro.finalseminar;
import se.su.dsv.scipro.system.DomainObject;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Objects;
@Entity

@ -5,7 +5,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class FinalSeminarSettingsServiceImpl extends AbstractServiceImpl<FinalSeminarSettings,Long> implements FinalSeminarSettingsService {

@ -0,0 +1,4 @@
package se.su.dsv.scipro.finalseminar;
public sealed interface MovingError extends SchedulingError permits NonWorkDay, NotEnoughWorkDays {
}

@ -0,0 +1,6 @@
package se.su.dsv.scipro.finalseminar;
import java.time.LocalDate;
public record NonWorkDay(LocalDate date) implements MovingError {
}

@ -0,0 +1,6 @@
package se.su.dsv.scipro.finalseminar;
import java.time.LocalDate;
public record NotEnoughWorkDays(LocalDate scheduling, LocalDate earliest) implements MovingError {
}

@ -0,0 +1,4 @@
package se.su.dsv.scipro.finalseminar;
public record RoughDraftNotApproved() implements SchedulingError {
}

@ -1,80 +1,6 @@
package se.su.dsv.scipro.finalseminar;
import java.util.Date;
import java.util.Objects;
import java.time.LocalDate;
interface SchedulingError {
}
final class NonWorkDay implements SchedulingError {
private final Date date;
NonWorkDay(Date date) {
this.date = date;
}
public Date date() {
return date;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof NonWorkDay)) {
return false;
}
NonWorkDay that = (NonWorkDay) o;
return Objects.equals(date, that.date);
}
@Override
public int hashCode() {
return Objects.hash(date);
}
@Override
public String toString() {
return "NonWorkDay{" +
"date=" + date +
'}';
}
}
final class NotEnoughWorkDays implements SchedulingError {
private final Date scheduling;
private final Date earliest;
NotEnoughWorkDays(Date scheduling, Date earliest) {
this.scheduling = scheduling;
this.earliest = earliest;
}
public Date scheduling() {
return scheduling;
}
public Date earliest() {
return earliest;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof NotEnoughWorkDays)) {
return false;
}
NotEnoughWorkDays that = (NotEnoughWorkDays) o;
return Objects.equals(scheduling, that.scheduling) && Objects.equals(earliest, that.earliest);
}
@Override
public int hashCode() {
return Objects.hash(scheduling, earliest);
}
@Override
public String toString() {
return "NotEnoughWorkDays{" +
"scheduling=" + scheduling +
", earliest=" + earliest +
'}';
}
public sealed interface SchedulingError permits MovingError, RoughDraftNotApproved {
}

@ -1,19 +1,20 @@
package se.su.dsv.scipro.finalthesis;
import jakarta.persistence.GenerationType;
import se.su.dsv.scipro.file.FileReference;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.system.DomainObject;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import jakarta.persistence.Table;
import java.util.*;
@Entity
@ -25,7 +26,7 @@ public class FinalThesis extends DomainObject {
}
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)

@ -16,7 +16,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.Date;
import java.util.List;

@ -7,7 +7,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.Date;
import java.util.Optional;

@ -4,14 +4,14 @@ import com.querydsl.core.annotations.QueryInit;
import se.su.dsv.scipro.activityplan.Activity;
import se.su.dsv.scipro.system.DomainObject;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Date;
@Entity
@Table(name = "project_first_meeting")
public final class ProjectFirstMeeting extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@QueryInit("activityPlan.project")

@ -6,7 +6,7 @@ import se.su.dsv.scipro.system.GenericRepo;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class AbstractThreadRepositoryImpl extends GenericRepo<ForumThread, Long> implements AbstractThreadRepository {

@ -9,7 +9,7 @@ import se.su.dsv.scipro.system.User;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import static com.querydsl.core.types.dsl.Expressions.allOf;

@ -1,14 +1,20 @@
package se.su.dsv.scipro.forum;
import se.su.dsv.scipro.forum.dataobjects.*;
import com.querydsl.jpa.impl.JPAQuery;
import jakarta.persistence.EntityManager;
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
import se.su.dsv.scipro.forum.dataobjects.ProjectThread;
import se.su.dsv.scipro.forum.dataobjects.QForumPost;
import se.su.dsv.scipro.forum.dataobjects.QForumThread;
import se.su.dsv.scipro.forum.dataobjects.QProjectThread;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.system.GenericRepo;
import se.su.dsv.scipro.util.Pair;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
import static com.querydsl.core.types.dsl.Expressions.allOf;
@ -26,10 +32,11 @@ public class ForumPostRepositoryImpl extends GenericRepo<ForumPost, Long> implem
@Override
public List<Pair<ProjectThread, ForumPost>> latestPost(Project project, int amount) {
return createQuery()
return new JPAQuery<>(em())
.select(QProjectThread.projectThread, QForumPost.forumPost)
.from(QForumPost.forumPost)
.innerJoin(QProjectThread.projectThread).on(QProjectThread.projectThread.forumThread.id.eq(QForumPost.forumPost.forumThread.id))
.from(QProjectThread.projectThread)
.innerJoin(QProjectThread.projectThread.forumThread)
.innerJoin(QForumThread.forumThread.posts, QForumPost.forumPost)
.where(QProjectThread.projectThread.project.eq(project))
.orderBy(QForumPost.forumPost.dateCreated.desc())
.limit(amount)

@ -2,9 +2,6 @@ package se.su.dsv.scipro.forum;
import com.google.common.eventbus.EventBus;
import com.google.inject.persist.Transactional;
import se.su.dsv.scipro.file.FileDescription;
import se.su.dsv.scipro.file.FileService;
import se.su.dsv.scipro.file.FileUpload;
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
import se.su.dsv.scipro.forum.dataobjects.GroupThread;
@ -16,18 +13,15 @@ import java.util.*;
public class GroupForumServiceImpl implements GroupForumService {
private final GroupThreadRepository groupThreadRepository;
private final FileService fileDescriptionService;
private final BasicForumService basicForumService;
private final EventBus eventBus;
@Inject
public GroupForumServiceImpl(
final GroupThreadRepository groupThreadRepository,
final FileService fileDescriptionService,
final BasicForumService basicForumService,
final EventBus eventBus) {
this.groupThreadRepository = groupThreadRepository;
this.fileDescriptionService = fileDescriptionService;
this.basicForumService = basicForumService;
this.eventBus = eventBus;
}
@ -38,11 +32,6 @@ public class GroupForumServiceImpl implements GroupForumService {
return groupThreadRepository.findOne(threadId);
}
@Transactional
private ForumPost createThreadReply(GroupThread thread, User user, String content, Set<Attachment> attachments) {
return createReply(thread, user, content, attachments);
}
@Override
@Transactional
public GroupThread createThread(Group group, User user, String subject, String content, Set<Attachment> fileUploads) {
@ -53,20 +42,13 @@ public class GroupForumServiceImpl implements GroupForumService {
groupThread = groupThreadRepository.save(groupThread);
createThreadReply(groupThread, user, content, fileUploads);
createReply(groupThread, user, content, fileUploads);
return groupThread;
}
private Set<FileDescription> storeFiles(final Set<FileUpload> fileUploads) {
Set<FileDescription> storedFiles = new HashSet<>();
for (FileUpload fileUpload : fileUploads){
storedFiles.add(fileDescriptionService.storeFile(fileUpload));
}
return storedFiles;
}
@Override
@Transactional
public void markRead(final User user, final GroupThread groupThread) {
basicForumService.setThreadRead(user, groupThread.getForumThread(), true);
}
@ -77,6 +59,7 @@ public class GroupForumServiceImpl implements GroupForumService {
}
@Override
@Transactional
public ForumPost createReply(final GroupThread groupThread, final User poster, final String content, final Set<Attachment> attachments) {
ForumPost reply = basicForumService.createReply(groupThread.getForumThread(), poster, content, attachments);
eventBus.post(new NewGroupForumReplyEvent(groupThread, reply));

@ -7,7 +7,7 @@ import se.su.dsv.scipro.system.GenericRepo;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.List;
public class GroupThreadRepositoryImpl extends GenericRepo<GroupThread, Long> implements GroupThreadRepository {

@ -80,6 +80,7 @@ public class ProjectForumServiceImpl implements ProjectForumService {
}
@Override
@Transactional
public void markRead(final User user, final ProjectThread thread) {
basicForumService.setThreadRead(user, thread.getForumThread(), true);
}

@ -7,7 +7,7 @@ import se.su.dsv.scipro.system.GenericRepo;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.List;
public class ProjectThreadRepositoryImpl extends GenericRepo<ProjectThread, Long> implements ProjectThreadRepository {

@ -1,19 +1,20 @@
package se.su.dsv.scipro.forum.dataobjects;
import jakarta.persistence.GenerationType;
import se.su.dsv.scipro.file.FileReference;
import se.su.dsv.scipro.system.LazyDeletableDomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.Lob;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.util.*;
@Entity
@ -21,7 +22,7 @@ import java.util.*;
public class ForumPost extends LazyDeletableDomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob

@ -2,7 +2,7 @@ package se.su.dsv.scipro.forum.dataobjects;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
@Entity

@ -2,9 +2,9 @@ package se.su.dsv.scipro.forum.dataobjects;
import se.su.dsv.scipro.system.User;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import jakarta.persistence.Embeddable;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.io.Serializable;
import java.util.Objects;

@ -3,7 +3,7 @@ package se.su.dsv.scipro.forum.dataobjects;
import se.su.dsv.scipro.system.LazyDeletableDomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -14,10 +14,10 @@ import java.util.Objects;
public class ForumThread extends LazyDeletableDomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "forumThread", cascade = CascadeType.ALL)
@OneToMany(mappedBy = "forumThread", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<ForumPost> posts = new ArrayList<>();
@Basic

@ -2,7 +2,7 @@ package se.su.dsv.scipro.forum.dataobjects;
import se.su.dsv.scipro.group.Group;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;
@ -11,7 +11,7 @@ import java.util.Objects;
public class GroupThread implements Serializable {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne

@ -2,7 +2,7 @@ package se.su.dsv.scipro.forum.dataobjects;
import se.su.dsv.scipro.project.Project;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;
@ -10,7 +10,7 @@ import java.util.Objects;
@Table(name = "project_thread")
public class ProjectThread implements Serializable {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(optional = false)

@ -2,7 +2,7 @@ package se.su.dsv.scipro.forum.dataobjects;
import se.su.dsv.scipro.project.Project;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
@ -10,7 +10,7 @@ import java.util.Objects;
public class ReviewerThread {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(optional = false)

@ -3,7 +3,7 @@ package se.su.dsv.scipro.forum.notifications;
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
import se.su.dsv.scipro.notifications.dataobject.NotificationEvent;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;

@ -5,7 +5,7 @@ import se.su.dsv.scipro.forum.dataobjects.ForumPost;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.Optional;
public class ForumNotificationRepositoryImpl implements ForumNotificationRepository {

@ -4,7 +4,7 @@ import se.su.dsv.scipro.mail.MailEvent;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
@ -12,7 +12,7 @@ import java.util.Objects;
@Inheritance(strategy = InheritanceType.JOINED)
public class ForumMail extends DomainObject {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)

@ -5,9 +5,9 @@ import org.slf4j.LoggerFactory;
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import jakarta.mail.MessagingException;
import jakarta.mail.Multipart;
import jakarta.mail.Part;
import java.io.IOException;
import java.util.ListIterator;

@ -4,10 +4,10 @@ import se.su.dsv.scipro.forum.dataobjects.GroupThread;
import se.su.dsv.scipro.mail.MailEvent;
import se.su.dsv.scipro.system.User;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.util.Objects;
@Entity

@ -4,10 +4,10 @@ import se.su.dsv.scipro.forum.dataobjects.ProjectThread;
import se.su.dsv.scipro.mail.MailEvent;
import se.su.dsv.scipro.system.User;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.util.Objects;
@Entity

@ -4,7 +4,7 @@ import se.su.dsv.scipro.system.GenericRepo;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class ForumMailRepositoryImpl extends GenericRepo<ForumMail, Long> implements ForumMailRepository {
@Inject

@ -2,10 +2,10 @@ package se.su.dsv.scipro.forummail;
import se.su.dsv.scipro.system.DomainObject;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import jakarta.persistence.Basic;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.Objects;
@Table(name="forum_mail_settings")

@ -5,7 +5,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class ForumMailSettingsServiceImpl extends AbstractServiceImpl<ForumMailSettings,Long> implements ForumMailSettingsService {

@ -1,17 +1,21 @@
package se.su.dsv.scipro.forummail;
import jakarta.mail.Flags;
import jakarta.mail.Folder;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.Multipart;
import jakarta.mail.Part;
import jakarta.mail.Session;
import jakarta.mail.Store;
import jakarta.mail.internet.MimeMessage;
import jakarta.mail.search.FlagTerm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.mail.*;
import javax.mail.internet.MimeMessage;
import javax.mail.search.FlagTerm;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.*;
public class IMAPReader implements ForumMailReader {
@ -30,22 +34,11 @@ public class IMAPReader implements ForumMailReader {
@Override
public void accept(MailHandler mailHandler) {
try {
Folder folder = null;
Store store = null;
try {
store = connectToIMAP();
folder = openFolder(store);
try (Store store = connectToIMAP(); Folder folder = openFolder(store)) {
List<ForumMailMessage> forumMailMessages = messagesAsList(folder.search(unreadOnly()));
for (ForumMailMessage forumMailMessage : forumMailMessages) {
mailHandler.accept(forumMailMessage);
}
} finally {
if (folder != null) {
folder.close(true);
}
if (store != null) {
store.close();
}
}
} catch (MessagingException | IOException e) {
LOGGER.info("Something went wrong while reading e-mail: ", e);

@ -1,7 +1,7 @@
package se.su.dsv.scipro.forummail;
import javax.mail.MessagingException;
import javax.mail.Part;
import jakarta.mail.MessagingException;
import jakarta.mail.Part;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;

@ -1,6 +1,6 @@
package se.su.dsv.scipro.forummail;
import javax.mail.Part;
import jakarta.mail.Part;
public interface MailContentParser {

@ -3,7 +3,7 @@ package se.su.dsv.scipro.generalsystemsettings;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.SystemModule;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.*;
@Entity

@ -5,7 +5,7 @@ import se.su.dsv.scipro.system.AbstractServiceImpl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
public class GeneralSystemSettingsServiceImpl extends AbstractServiceImpl<GeneralSystemSettings, Long> implements GeneralSystemSettingsService {

@ -12,4 +12,9 @@ public record Examination(
@JsonProperty("provkod") String provkod,
@JsonProperty("grades") List<Grade> grades)
{
public boolean isGraded() {
return grades.stream()
.filter(grade -> grade.type() == Grade.Type.PASSING)
.count() > 1;
}
}

@ -1,7 +1,5 @@
package se.su.dsv.scipro.grading;
import io.opentracing.Tracer;
import io.opentracing.contrib.jaxrs2.client.ClientTracingFeature;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -9,12 +7,12 @@ import se.su.dsv.scipro.util.Either;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.Response;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.*;
@ -27,13 +25,12 @@ public class GradingServiceImpl implements GradingService {
private final Client client;
@Inject
public GradingServiceImpl(@Named("service.grading.url") final String url, final Tracer tracer) {
public GradingServiceImpl(@Named("service.grading.url") final String url) {
this.url = url;
this.client = ClientBuilder.newBuilder()
.hostnameVerifier((hostname, sslSession) -> true)
.register(JacksonFeature.class)
.register(new ClientTracingFeature.Builder(tracer).build())
.build();
}

@ -5,7 +5,7 @@ import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.system.DomainObject;
import se.su.dsv.scipro.system.User;
import javax.persistence.*;
import jakarta.persistence.*;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@ -20,7 +20,7 @@ public class Group extends DomainObject {
public static final int STRING_MAX_LENGTH = 255;
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = STRING_MAX_LENGTH)

@ -10,7 +10,7 @@ import se.su.dsv.scipro.system.User;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.List;
public class GroupServiceImpl extends AbstractServiceImpl<Group, Long> implements GroupService, FilteredService<Group, Long, GroupService.Filter> {

@ -3,7 +3,7 @@ package se.su.dsv.scipro.integration.activityfinalseminar;
import se.su.dsv.scipro.activityplan.Activity;
import se.su.dsv.scipro.finalseminar.FinalSeminar;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;

@ -5,7 +5,7 @@ import se.su.dsv.scipro.system.GenericRepo;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.Optional;
public class ActivityFinalSeminarRepositoryImpl extends GenericRepo<ActivityFinalSeminar, Long> implements ActivityFinalSeminarRepository {

@ -5,12 +5,15 @@ import com.google.common.eventbus.Subscribe;
import se.su.dsv.scipro.activityplan.Action;
import se.su.dsv.scipro.activityplan.Activity;
import se.su.dsv.scipro.activityplan.ActivityPlanFacade;
import se.su.dsv.scipro.finalseminar.*;
import se.su.dsv.scipro.finalseminar.FinalSeminar;
import se.su.dsv.scipro.finalseminar.FinalSeminarCancelledEvent;
import se.su.dsv.scipro.finalseminar.FinalSeminarCreatedEvent;
import se.su.dsv.scipro.finalseminar.FinalSeminarDeletedEvent;
import se.su.dsv.scipro.finalseminar.FinalSeminarMovedEvent;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Date;
import java.util.Optional;
import java.util.*;
@Singleton
public class FinalSeminarActivityHandler {
@ -29,7 +32,7 @@ public class FinalSeminarActivityHandler {
@Subscribe
public void finalSeminarMoved(FinalSeminarMovedEvent finalSeminarMovedEvent) {
synchronizeFinalSeminarActivity(finalSeminarMovedEvent.getFinalSeminar(), finalSeminarMovedEvent.getTo());
synchronizeFinalSeminarActivity(finalSeminarMovedEvent.finalSeminar(), finalSeminarMovedEvent.finalSeminar().getStartDate());
}
@Subscribe

@ -3,7 +3,7 @@ package se.su.dsv.scipro.integration.activityforum;
import se.su.dsv.scipro.activityplan.Activity;
import se.su.dsv.scipro.forum.dataobjects.ProjectThread;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;

@ -6,7 +6,7 @@ import se.su.dsv.scipro.forum.dataobjects.ProjectThread;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import java.util.Optional;
public class ActivityThreadRepositoryImpl implements ActivityThreadRepository {

Some files were not shown because too many files have changed in this diff Show More