diff --git a/backend/pom.xml b/backend/pom.xml index 8246cb7..2b07314 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -32,7 +32,7 @@ io.dropwizard - dropwizard-jdbi3 + dropwizard-hibernate ${dropwizard.version} diff --git a/backend/src/main/java/uk/co/neviyn/Observations/ObservationsApplication.java b/backend/src/main/java/uk/co/neviyn/Observations/ObservationsApplication.java index f7efe74..3ebdeea 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/ObservationsApplication.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/ObservationsApplication.java @@ -2,11 +2,14 @@ package uk.co.neviyn.Observations; import io.dropwizard.Application; import io.dropwizard.assets.AssetsBundle; -import io.dropwizard.jdbi3.JdbiFactory; +import io.dropwizard.db.DataSourceFactory; +import io.dropwizard.hibernate.HibernateBundle; import io.dropwizard.jersey.setup.JerseyEnvironment; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; -import org.jdbi.v3.core.Jdbi; +import uk.co.neviyn.Observations.core.Observation; +import uk.co.neviyn.Observations.core.Site; +import uk.co.neviyn.Observations.core.Tutor; import uk.co.neviyn.Observations.dao.ObservationDao; import uk.co.neviyn.Observations.dao.SiteDao; import uk.co.neviyn.Observations.dao.TutorDao; @@ -16,6 +19,18 @@ import uk.co.neviyn.Observations.resources.SiteResource; public class ObservationsApplication extends Application { + private final HibernateBundle hibernate = new HibernateBundle( + Observation.class, + Tutor.class, + Site.class + ) { + @Override + public DataSourceFactory getDataSourceFactory(ObservationsConfiguration configuration) { + return configuration.getDataSourceFactory(); + } + }; + + public static void main(String[] args) throws Exception { new ObservationsApplication().run(args); } @@ -23,27 +38,22 @@ public class ObservationsApplication extends Application bootstrap) { super.initialize(bootstrap); + bootstrap.addBundle(hibernate); bootstrap.addBundle(new AssetsBundle("/assets/", "/", "/index.html")); } @Override public void run(ObservationsConfiguration observationsConfiguration, Environment environment) { final JerseyEnvironment jersey = environment.jersey(); - final JdbiFactory factory = new JdbiFactory(); - final Jdbi jdbi = factory.build(environment, observationsConfiguration.getDataSourceFactory(), "database"); - TutorDao tutorDao = jdbi.onDemand(TutorDao.class); - SiteDao siteDao = jdbi.onDemand(SiteDao.class); - ObservationDao observationDao = jdbi.onDemand(ObservationDao.class); + TutorDao tutorDao = new TutorDao(hibernate.getSessionFactory()); + SiteDao siteDao = new SiteDao(hibernate.getSessionFactory()); + ObservationDao observationDao = new ObservationDao(hibernate.getSessionFactory()); jersey.register(tutorDao); jersey.register(siteDao); jersey.register(observationDao); - siteDao.createSiteTable(); - tutorDao.createTutorTable(); - observationDao.createObservationTable(); - observationDao.createObservationTutorTable(); final TutorResource tutorResource = new TutorResource(tutorDao); jersey.register(tutorResource); - final ObservationResource observationResource = new ObservationResource(observationDao); + final ObservationResource observationResource = new ObservationResource(observationDao, tutorDao, siteDao); jersey.register(observationResource); final SiteResource siteResource = new SiteResource(siteDao); jersey.register(siteResource); diff --git a/backend/src/main/java/uk/co/neviyn/Observations/api/AverageStats.java b/backend/src/main/java/uk/co/neviyn/Observations/api/AverageStats.java index d93042c..ed993a6 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/api/AverageStats.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/api/AverageStats.java @@ -1,14 +1,10 @@ package uk.co.neviyn.Observations.api; import com.fasterxml.jackson.annotation.JsonProperty; -import java.sql.ResultSet; -import java.sql.SQLException; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import org.jdbi.v3.core.mapper.RowMapper; -import org.jdbi.v3.core.statement.StatementContext; import org.joda.time.LocalDate; @Data @@ -18,16 +14,9 @@ public class AverageStats { @NonNull @JsonProperty - private float monitoring, control, conservatism, teamwork, knowledge; + private double monitoring, control, conservatism, teamwork, knowledge; @NonNull @JsonProperty private LocalDate date; - - public static class Mapper implements RowMapper { - public AverageStats map(ResultSet rs, StatementContext ctx) throws SQLException { - return new AverageStats(rs.getFloat("monitoring"), rs.getFloat("control"), rs.getFloat("conservatism"), - rs.getFloat("teamwork"), rs.getFloat("knowledge"), new LocalDate(rs.getDate("date"))); - } - } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/api/AverageStatsChartJs.java b/backend/src/main/java/uk/co/neviyn/Observations/api/AverageStatsChartJs.java index 2ff320e..96d82fa 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/api/AverageStatsChartJs.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/api/AverageStatsChartJs.java @@ -22,7 +22,7 @@ public class AverageStatsChartJs { private List datasets = new ArrayList<>(); public AverageStatsChartJs(List inputData){ - List monitoring = new ArrayList<>(), + List monitoring = new ArrayList<>(), control = new ArrayList<>(), conservatism = new ArrayList<>(), teamwork = new ArrayList<>(), @@ -54,6 +54,6 @@ public class AverageStatsChartJs { @NonNull @JsonProperty - private final List data; + private final List data; } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/api/NewObservation.java b/backend/src/main/java/uk/co/neviyn/Observations/api/NewObservation.java index 0fc967a..5842339 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/api/NewObservation.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/api/NewObservation.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; import lombok.*; +import uk.co.neviyn.Observations.core.ObservationEntry; @Data @NoArgsConstructor @@ -12,11 +13,11 @@ public class NewObservation { @NonNull @JsonProperty - private int siteId; + private long siteId; @NonNull @JsonProperty - private List tutorIds; + private List tutorIds; @NonNull @JsonProperty @@ -28,6 +29,6 @@ public class NewObservation { @NonNull @JsonProperty - private String rawData; + private List rawData; } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/core/BaseEntity.java b/backend/src/main/java/uk/co/neviyn/Observations/core/BaseEntity.java new file mode 100644 index 0000000..1f34e27 --- /dev/null +++ b/backend/src/main/java/uk/co/neviyn/Observations/core/BaseEntity.java @@ -0,0 +1,23 @@ +package uk.co.neviyn.Observations.core; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +@Data +@MappedSuperclass +@NoArgsConstructor +@AllArgsConstructor +class BaseEntity { + @NonNull + @JsonProperty + @Id + @GeneratedValue + private long id; +} diff --git a/backend/src/main/java/uk/co/neviyn/Observations/core/Observation.java b/backend/src/main/java/uk/co/neviyn/Observations/core/Observation.java index 4fffc4a..6898648 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/core/Observation.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/core/Observation.java @@ -2,30 +2,30 @@ package uk.co.neviyn.Observations.core; import com.fasterxml.jackson.annotation.JsonProperty; -import java.io.Serializable; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.List; +import java.util.Set; import lombok.*; -import org.apache.commons.lang3.SerializationUtils; -import org.jdbi.v3.core.mapper.RowMapper; -import org.jdbi.v3.core.statement.StatementContext; import org.joda.time.DateTime; -import uk.co.neviyn.Observations.api.ObservationEntry; +import javax.persistence.*; + +@EqualsAndHashCode(callSuper = true) +@Entity +@Table(name = "OBSERVATION") @Data @NoArgsConstructor -@AllArgsConstructor -public class Observation { +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public class Observation extends BaseEntity{ - @NonNull @JsonProperty - private int id; + @ManyToOne + @JoinColumn(name="site_id", nullable=false) + private Site site; - @NonNull @JsonProperty - private int siteId; + @ManyToMany(mappedBy = "observations") + private Set tutors; @NonNull @JsonProperty @@ -41,49 +41,9 @@ public class Observation { @NonNull @JsonProperty - private List rawData; + private List observations; @NonNull @JsonProperty private DateTime date; - - public Observation(int siteId, String observed, int monitoring, int control, int conservatism, int teamwork, - int knowledge, List rawData) { - this.siteId = siteId; - this.observed = observed; - this.monitoring = monitoring; - this.control = control; - this.conservatism = conservatism; - this.teamwork = teamwork; - this.knowledge = knowledge; - this.rawData = rawData; - } - - private Observation(int id, int siteId, String observed, String type, int monitoring, int control, int conservatism, - int teamwork, int knowledge, byte[] rawData, DateTime date) { - this.id = id; - this.siteId = siteId; - this.observed = observed; - this.type = TrainingType.valueOf(type.toUpperCase()); - this.monitoring = monitoring; - this.control = control; - this.conservatism = conservatism; - this.teamwork = teamwork; - this.knowledge = knowledge; - this.rawData = SerializationUtils.deserialize(rawData); - this.date = date; - } - - public byte[] serializeRawData(){ - return SerializationUtils.serialize((Serializable) rawData); - } - - public static class Mapper implements RowMapper { - - public Observation map(ResultSet rs, StatementContext ctx) throws SQLException { - return new Observation(rs.getInt("id"), rs.getInt("siteId"), rs.getString("observed"), rs.getString("type"), - rs.getInt("monitoring"), rs.getInt("control"), rs.getInt("conservatism"), rs.getInt("teamwork"), - rs.getInt("knowledge"), rs.getBytes("rawData"), new DateTime(rs.getDate("date"))); - } - } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/api/ObservationEntry.java b/backend/src/main/java/uk/co/neviyn/Observations/core/ObservationEntry.java similarity index 63% rename from backend/src/main/java/uk/co/neviyn/Observations/api/ObservationEntry.java rename to backend/src/main/java/uk/co/neviyn/Observations/core/ObservationEntry.java index 060c1fc..7238f15 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/api/ObservationEntry.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/core/ObservationEntry.java @@ -1,15 +1,13 @@ -package uk.co.neviyn.Observations.api; +package uk.co.neviyn.Observations.core; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.NonNull; +import lombok.*; +@EqualsAndHashCode(callSuper = true) @Data -@AllArgsConstructor @NoArgsConstructor -public class ObservationEntry { +@AllArgsConstructor +public class ObservationEntry extends BaseEntity{ @NonNull @JsonProperty diff --git a/backend/src/main/java/uk/co/neviyn/Observations/core/Site.java b/backend/src/main/java/uk/co/neviyn/Observations/core/Site.java index cc7297f..3ea673a 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/core/Site.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/core/Site.java @@ -1,32 +1,33 @@ package uk.co.neviyn.Observations.core; import com.fasterxml.jackson.annotation.JsonProperty; -import java.sql.ResultSet; -import java.sql.SQLException; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import org.jdbi.v3.core.mapper.RowMapper; -import org.jdbi.v3.core.statement.StatementContext; +import java.util.Set; +import lombok.*; + +import javax.persistence.*; + +@EqualsAndHashCode(callSuper = true) +@Entity +@Table(name = "SITE") @Data @NoArgsConstructor -@AllArgsConstructor(access = AccessLevel.PROTECTED) -public class Site { - - @NonNull - @JsonProperty - private int id; +public class Site extends BaseEntity { @NonNull @JsonProperty private String name; - public static class Mapper implements RowMapper { - public Site map(ResultSet rs, StatementContext ctx) throws SQLException { - return new Site(rs.getInt("id"), rs.getString("name")); - } + @JsonProperty + @OneToMany(mappedBy="site") + private Set tutors; + + @JsonProperty + @OneToMany(mappedBy = "site") + private Set observations; + + public Site(long id, String name) { + super(id); + this.name = name; } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/core/Tutor.java b/backend/src/main/java/uk/co/neviyn/Observations/core/Tutor.java index 894794b..6bf5de8 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/core/Tutor.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/core/Tutor.java @@ -1,37 +1,38 @@ package uk.co.neviyn.Observations.core; import com.fasterxml.jackson.annotation.JsonProperty; -import java.sql.ResultSet; -import java.sql.SQLException; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import org.jdbi.v3.core.mapper.RowMapper; -import org.jdbi.v3.core.statement.StatementContext; +import lombok.*; +import javax.persistence.*; +import java.util.Set; + +@EqualsAndHashCode(callSuper = true) +@Entity +@Table(name = "TUTOR") @Data @NoArgsConstructor -@AllArgsConstructor(access = AccessLevel.PROTECTED) -public class Tutor { - - @NonNull - @JsonProperty - private int id; +public class Tutor extends BaseEntity { @NonNull @JsonProperty private String name; - @NonNull @JsonProperty - private int site; + @ManyToOne + @JoinColumn(name="site_id", nullable=false) + private Site site; - public static class Mapper implements RowMapper{ + @JsonProperty + @ManyToMany + @JoinTable( + name = "TUTOR_OBSERVATION", + joinColumns = { @JoinColumn(name = "tutor_id")}, + inverseJoinColumns = { @JoinColumn(name = "observation_id")} + ) + private Set observations; - public Tutor map(ResultSet rs, StatementContext ctx) throws SQLException { - return new Tutor(rs.getInt("id"), rs.getString("name"), rs.getInt("site")); - } + public Tutor(long id, String name) { + super(id); + this.name = name; } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/dao/ObservationDao.java b/backend/src/main/java/uk/co/neviyn/Observations/dao/ObservationDao.java index d22feee..e67ba09 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/dao/ObservationDao.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/dao/ObservationDao.java @@ -1,59 +1,40 @@ package uk.co.neviyn.Observations.dao; -import java.util.List; -import org.jdbi.v3.sqlobject.config.RegisterRowMapper; -import org.jdbi.v3.sqlobject.customizer.Bind; -import org.jdbi.v3.sqlobject.customizer.BindBean; -import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys; -import org.jdbi.v3.sqlobject.statement.SqlQuery; -import org.jdbi.v3.sqlobject.statement.SqlUpdate; -import org.joda.time.DateTime; +import io.dropwizard.hibernate.AbstractDAO; +import org.hibernate.SessionFactory; import uk.co.neviyn.Observations.api.AverageStats; -import uk.co.neviyn.Observations.api.NewObservation; import uk.co.neviyn.Observations.core.Observation; +import uk.co.neviyn.Observations.core.Site; -@RegisterRowMapper(Observation.Mapper.class) -public interface ObservationDao { +import java.util.List; - @SqlUpdate("CREATE TABLE IF NOT EXISTS observations (id INTEGER PRIMARY KEY, siteId INTEGER, " + - "observed TEXT, type TEXT, monitoring INTEGER, control INTEGER, conservatism INTEGER, teamwork INTEGER, " + - "knowledge INTEGER, rawData BLOB, date DATE)") - void createObservationTable(); +public class ObservationDao extends AbstractDAO { + public ObservationDao(SessionFactory sessionFactory) { + super(sessionFactory); + } - @SqlUpdate("CREATE TABLE IF NOT EXISTS observation_tutor (tutorId INT NOT NULL, observationId INT NOT NULL, " + - "FOREIGN KEY (tutorID) REFERENCES tutor(id), FOREIGN KEY (observationId) REFERENCES observations(id))") - void createObservationTutorTable(); + public Observation get(long id){ + return super.get(id); + } - @SqlUpdate("INSERT INTO observations (siteId, observed, type, monitoring, control, conservatism, teamwork, knowledge, " + - "rawData, date) VALUES (:siteId, :observed, :type, :monitoring, :control, :conservatism, :teamwork, :knowledge, " + - ":serializeRawData, :date)") - @GetGeneratedKeys - int addObservation(@BindBean NewObservation observation, @Bind("date") DateTime date); + public Observation persist(Observation observation){ + return super.persist(observation); + } - @SqlUpdate("INSERT INTO observation_tutor (tutorId, observationId) VALUES (:tutorId, :observationId)") - void addObservationTutor(@Bind("observationId")int observationId, @Bind("tutorId")int tutorId); + public List listAll(){ + return list(criteriaQuery()); + } - @SqlQuery("SELECT * FROM observations WHERE date BETWEEN :startDate AND :endDate") - List observationsBetweenDates(@Bind("startDate")DateTime startDate, @Bind("endDate")DateTime endDate); + public List averageStatsForAll(){ + final String hql = "select avg(observation.monitoring), avg(observation.control), avg(observation.conservatism), " + + "avg(observation.teamwork), avg(observation.knowledge) from observation where group by observation.date"; + return currentSession().createQuery(hql, AverageStats.class).list(); + } - @SqlQuery("SELECT * FROM observations LEFT JOIN observation_tutor ON observation_tutor.observationId = observations.id " + - "LEFT JOIN tutor ON observation_tutor.tutorId = tutor.id WHERE tutor.id = :tutorId") - List observationsByTutor(@Bind("tutorId")int tutorId); - - @SqlQuery("SELECT * FROM observations WHERE date BETWEEN :startDate AND :endDate " + - "LEFT JOIN observation_tutor ON observation_tutor.observationId = observations.id " + - "LEFT JOIN tutor ON observation_tutor.tutorId = tutor.id WHERE tutor.id = :tutorId") - List observationsByTutorBetweenDates(@Bind("tutorId")int tutorId, @Bind("startDate")DateTime startDate, - @Bind("endDate")DateTime endDate); - - @SqlQuery("SELECT AVG(monitoring) as monitoring, AVG(control) as control, AVG(conservatism) as conservatism, " + - "AVG(teamwork) as teamwork, AVG(knowledge) as knowledge, date FROM observations GROUP BY date ORDER BY date") - @RegisterRowMapper(AverageStats.Mapper.class) - List averageObservationScoresByDay(); - - @SqlQuery("SELECT MIN(date) FROM observations") - DateTime earliestEntryDate(); - - @SqlQuery("SELECT MAX(date) FROM observations") - DateTime latestEntryDate(); + public List averageStatsForSite(Site site){ + final String hql = "select avg(observation.monitoring), avg(observation.control), avg(observation.conservatism), " + + "avg(observation.teamwork), avg(observation.knowledge) from observation where observation.site = :site " + + "group by observation.date"; + return currentSession().createQuery(hql, AverageStats.class).setParameter("site", site).list(); + } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/dao/SiteDao.java b/backend/src/main/java/uk/co/neviyn/Observations/dao/SiteDao.java index a682c4e..a0329b9 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/dao/SiteDao.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/dao/SiteDao.java @@ -1,21 +1,21 @@ package uk.co.neviyn.Observations.dao; -import java.util.List; -import org.jdbi.v3.sqlobject.config.RegisterRowMapper; -import org.jdbi.v3.sqlobject.customizer.Bind; -import org.jdbi.v3.sqlobject.statement.SqlQuery; -import org.jdbi.v3.sqlobject.statement.SqlUpdate; +import io.dropwizard.hibernate.AbstractDAO; +import org.hibernate.SessionFactory; import uk.co.neviyn.Observations.core.Site; -@RegisterRowMapper(Site.Mapper.class) -public interface SiteDao { +import java.util.List; - @SqlUpdate("CREATE TABLE IF NOT EXISTS site (id INTEGER PRIMARY KEY, name VARCHAR(100))") - void createSiteTable(); +public class SiteDao extends AbstractDAO { + public SiteDao(SessionFactory sessionFactory) { + super(sessionFactory); + } - @SqlQuery("SELECT * FROM site") - List allSites(); + public List listAll(){ + return list(criteriaQuery()); + } - @SqlQuery("SELECT * FROM site WHERE id = :id") - Site getSiteById(@Bind("id") int id); + public Site get(long id){ + return super.get(id); + } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/dao/TutorDao.java b/backend/src/main/java/uk/co/neviyn/Observations/dao/TutorDao.java index a9ba41f..a988dc1 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/dao/TutorDao.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/dao/TutorDao.java @@ -1,29 +1,21 @@ package uk.co.neviyn.Observations.dao; -import java.util.List; -import org.jdbi.v3.sqlobject.config.RegisterRowMapper; -import org.jdbi.v3.sqlobject.customizer.Bind; -import org.jdbi.v3.sqlobject.customizer.BindBean; -import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys; -import org.jdbi.v3.sqlobject.statement.SqlQuery; -import org.jdbi.v3.sqlobject.statement.SqlUpdate; +import io.dropwizard.hibernate.AbstractDAO; +import org.hibernate.SessionFactory; import uk.co.neviyn.Observations.core.Tutor; -@RegisterRowMapper(Tutor.Mapper.class) -public interface TutorDao { +import java.util.List; - @SqlUpdate("CREATE TABLE IF NOT EXISTS tutor (id INTEGER PRIMARY KEY, " + - "name VARCHAR(100), site INT, FOREIGN KEY (site) REFERENCES site(id))") - void createTutorTable(); +public class TutorDao extends AbstractDAO { + public TutorDao(SessionFactory sessionFactory) { + super(sessionFactory); + } - @SqlUpdate("INSERT INTO tutor(name, site) VALUES (:name, :site)") - @GetGeneratedKeys("id") - int add(@BindBean Tutor tutor); - - @SqlQuery("SELECT * FROM tutor WHERE site = :siteId") - List tutorsForSite(@Bind("siteId")int siteId); - - @SqlQuery("SELECT * FROM tutor") - List allTutors(); + public Tutor get(long id){ + return super.get(id); + } + public List listAll(){ + return list(criteriaQuery()); + } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/resources/ObservationResource.java b/backend/src/main/java/uk/co/neviyn/Observations/resources/ObservationResource.java index 74566ff..d75a959 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/resources/ObservationResource.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/resources/ObservationResource.java @@ -1,6 +1,9 @@ package uk.co.neviyn.Observations.resources; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; @@ -10,6 +13,8 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; + +import io.dropwizard.hibernate.UnitOfWork; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; @@ -18,7 +23,12 @@ import uk.co.neviyn.Observations.api.AverageStats; import uk.co.neviyn.Observations.api.AverageStatsChartJs; import uk.co.neviyn.Observations.api.NewObservation; import uk.co.neviyn.Observations.core.Observation; +import uk.co.neviyn.Observations.core.Site; +import uk.co.neviyn.Observations.core.TrainingType; +import uk.co.neviyn.Observations.core.Tutor; import uk.co.neviyn.Observations.dao.ObservationDao; +import uk.co.neviyn.Observations.dao.SiteDao; +import uk.co.neviyn.Observations.dao.TutorDao; @RequiredArgsConstructor @Produces(MediaType.APPLICATION_JSON) @@ -28,32 +38,44 @@ import uk.co.neviyn.Observations.dao.ObservationDao; public class ObservationResource { private final ObservationDao dao; + private final TutorDao tutorDao; + private final SiteDao siteDao; @POST - public int add(@NotNull @Valid NewObservation observation){ - final int observationId = dao.addObservation(observation, LocalDate.now().toDateTimeAtStartOfDay()); - log.info("Created observation with ID " + observationId + " at " + DateTime.now().toString()); - for(int tutorId: observation.getTutorIds()){ - dao.addObservationTutor(observationId, tutorId); + @UnitOfWork + public long add(@NotNull @Valid NewObservation newObservation){ + final DateTime submissionDate = LocalDate.now().toDateTimeAtStartOfDay(); + Set tutors = new HashSet<>(); + for(long l: newObservation.getTutorIds()){ + tutors.add(tutorDao.get(l)); } - return observationId; - } - - @Path("/by/{tutorId}") - @GET - public List observationsBy(@PathParam("tutorId") int tutorId){ - return dao.observationsByTutor(tutorId); + final Site site = siteDao.get(newObservation.getSiteId()); + Observation observation = new Observation(); + observation.setSite(site); + observation.setTutors(tutors); + observation.setObserved(newObservation.getObserved()); + observation.setType(TrainingType.valueOf(newObservation.getType())); + observation.setMonitoring(newObservation.getMonitoring()); + observation.setControl(newObservation.getControl()); + observation.setConservatism(newObservation.getConservatism()); + observation.setTeamwork(newObservation.getTeamwork()); + observation.setKnowledge(newObservation.getKnowledge()); + observation.setObservations(newObservation.getRawData()); + observation.setDate(submissionDate); + observation = dao.persist(observation); + log.info("Created observation with ID " + observation.getId() + " at " + DateTime.now().toString()); + return observation.getId(); } @Path("/average/all") @GET public List averageObservationScores(){ - return dao.averageObservationScoresByDay(); + return dao.averageStatsForAll(); } @Path("/average/all/chartjs") @GET public AverageStatsChartJs averageStatsChartJs(){ - return new AverageStatsChartJs(dao.averageObservationScoresByDay()); + return new AverageStatsChartJs(dao.averageStatsForAll()); } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/resources/SiteResource.java b/backend/src/main/java/uk/co/neviyn/Observations/resources/SiteResource.java index 40599d2..d03ac31 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/resources/SiteResource.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/resources/SiteResource.java @@ -1,7 +1,9 @@ package uk.co.neviyn.Observations.resources; +import io.dropwizard.hibernate.UnitOfWork; import lombok.RequiredArgsConstructor; import uk.co.neviyn.Observations.api.SelectOption; +import uk.co.neviyn.Observations.core.Tutor; import uk.co.neviyn.Observations.dao.SiteDao; import javax.ws.rs.GET; @@ -9,6 +11,7 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @RequiredArgsConstructor @@ -20,7 +23,15 @@ public class SiteResource { @Path("/all") @GET - public List> allSites() { - return dao.allSites().stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList()); + @UnitOfWork + public List> allSites() { + return dao.listAll().stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList()); + } + + @Path("/{id}/tutors") + @GET + @UnitOfWork + public Set getSiteTutors(long id){ + return dao.get(id).getTutors(); } } diff --git a/backend/src/main/java/uk/co/neviyn/Observations/resources/TutorResource.java b/backend/src/main/java/uk/co/neviyn/Observations/resources/TutorResource.java index 0f86590..148c268 100644 --- a/backend/src/main/java/uk/co/neviyn/Observations/resources/TutorResource.java +++ b/backend/src/main/java/uk/co/neviyn/Observations/resources/TutorResource.java @@ -9,6 +9,8 @@ import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; + +import io.dropwizard.hibernate.UnitOfWork; import lombok.RequiredArgsConstructor; import uk.co.neviyn.Observations.api.SelectOption; import uk.co.neviyn.Observations.core.Tutor; @@ -23,20 +25,11 @@ public class TutorResource { @Path("/all") @GET + @UnitOfWork public List allTutors() { - List tutors = dao.allTutors(); + List tutors = dao.listAll(); if (tutors != null && !tutors.isEmpty()) return tutors; throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND); } - - @Path("/site/{id}") - @GET - public List> tutorsForSite(@PathParam("id") int siteId) { - List tutors = dao.tutorsForSite(siteId); - if (tutors != null && !tutors.isEmpty()) { - return tutors.stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList()); - } - throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND); - } } diff --git a/backend/src/test/java/uk/co/neviyn/Observations/api/NewObservationTest.java b/backend/src/test/java/uk/co/neviyn/Observations/api/NewObservationTest.java index 1f3d8bf..8a3f6e2 100644 --- a/backend/src/test/java/uk/co/neviyn/Observations/api/NewObservationTest.java +++ b/backend/src/test/java/uk/co/neviyn/Observations/api/NewObservationTest.java @@ -3,8 +3,10 @@ package uk.co.neviyn.Observations.api; import com.fasterxml.jackson.databind.ObjectMapper; import io.dropwizard.jackson.Jackson; import org.junit.Test; +import uk.co.neviyn.Observations.core.ObservationEntry; import java.util.Arrays; +import java.util.Collections; import static io.dropwizard.testing.FixtureHelpers.fixture; import static org.junit.Assert.*; @@ -13,8 +15,8 @@ public class NewObservationTest { private static final ObjectMapper mapper = Jackson.newObjectMapper(); - private final NewObservation newObservation = new NewObservation(1, Arrays.asList(1, 2, 3), "A random thing made for testing.", - "INITIAL", 1, 2, 3, 4, 5, "{\"data\":\"Looks like there's nothing here.\"}"); + private final NewObservation newObservation = new NewObservation(1, Arrays.asList(1L, 2L, 3L), "A random thing made for testing.", + "INITIAL", 1, 2, 3, 4, 5, Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum"))); @Test public void serializesToJson() throws Exception { diff --git a/backend/src/test/java/uk/co/neviyn/Observations/core/ObservationTest.java b/backend/src/test/java/uk/co/neviyn/Observations/core/ObservationTest.java index 5490a5c..f16f873 100644 --- a/backend/src/test/java/uk/co/neviyn/Observations/core/ObservationTest.java +++ b/backend/src/test/java/uk/co/neviyn/Observations/core/ObservationTest.java @@ -5,7 +5,6 @@ import io.dropwizard.jackson.Jackson; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.junit.Test; -import uk.co.neviyn.Observations.api.ObservationEntry; import java.util.Collections; @@ -16,7 +15,7 @@ import static org.junit.Assert.*; public class ObservationTest { private static final ObjectMapper mapper = Jackson.newObjectMapper(); - private final Observation observation = new Observation(1, 1, "Just a test observation", TrainingType.INITIAL, 1, 2, 3, + private final Observation observation = new Observation(null, null, "Just a test observation", TrainingType.INITIAL, 1, 2, 3, 4, 5, Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum")), DateTime.parse("2018-09-18T00:00:00.000Z") ); diff --git a/backend/src/test/resources/fixtures/NewObservation.json b/backend/src/test/resources/fixtures/NewObservation.json index 237a7fa..1fe1e4e 100644 --- a/backend/src/test/resources/fixtures/NewObservation.json +++ b/backend/src/test/resources/fixtures/NewObservation.json @@ -8,5 +8,5 @@ "conservatism":3, "teamwork":4, "knowledge":5, - "rawData":"{\"data\":\"Looks like there's nothing here.\"}" + "rawData":[{"type":"MONITORING","rating":5,"strengths":"some","improvements":"another sum"}] } \ No newline at end of file diff --git a/backend/src/test/resources/fixtures/Observation.json b/backend/src/test/resources/fixtures/Observation.json index 0594395..653b743 100644 --- a/backend/src/test/resources/fixtures/Observation.json +++ b/backend/src/test/resources/fixtures/Observation.json @@ -1,6 +1,5 @@ { - "id":1, - "siteId":1, + "id":0, "observed":"Just a test observation", "type":"INITIAL", "monitoring":1, @@ -8,7 +7,7 @@ "conservatism":3, "teamwork":4, "knowledge":5, - "rawData":[{ + "observations":[{ "type": "MONITORING", "rating":5, "strengths":"some", diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home.vue index 5622934..950e730 100644 --- a/frontend/src/views/Home.vue +++ b/frontend/src/views/Home.vue @@ -76,7 +76,7 @@ export default { ...mapMutations(["setSite", "setDescription", "setType", "setTutors"]), getTutors: function() { if (this.site != null) { - Vue.axios.get("/api/tutor/site/" + this.site).then(response => { + Vue.axios.get("/api/site/" + this.site + "/tutors").then(response => { this.tutorOptions = response.data; this.loadingTutors = false; });