Welcome to Spring town.

This commit is contained in:
neviyn 2018-10-03 11:35:15 +01:00
parent 1ef05d3822
commit 2f115e2837
47 changed files with 486 additions and 1862 deletions

2
.gitignore vendored
View File

@ -257,7 +257,7 @@ local.properties
# End of https://www.gitignore.io/api/java,node,intellij+all,visualstudiocode,eclipse
backend/src/main/resources/assets
backend/src/main/resources/static
frontend/node
!maven-wrapper.jar
dependency-reduced-pom.xml

View File

@ -1,20 +0,0 @@
database:
# the name of your JDBC driver
driverClass: org.h2.Driver
# the JDBC URL
url: jdbc:h2:file:./sampledatabase.db
# any properties specific to your JDBC driver:
properties:
foreign_keys: true
hibernate.hbm2ddl.auto: update
server:
rootPath: /api/
requestLog:
appenders:
- type: console
queueSize: 2048
adminPassword: "testPassword"

View File

@ -1,198 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>backend</artifactId>
<groupId>uk.co.neviyn</groupId>
<artifactId>observationdatabase</artifactId>
<version>PRE-ALPHA</version>
<packaging>jar</packaging>
<name>observationdatabase</name>
<description>Training observation database</description>
<parent>
<groupId>uk.co.neviyn</groupId>
<artifactId>Observations</artifactId>
<version>0.0.1-SNAPSHOT</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<dropwizard.version>1.3.5</dropwizard.version>
<kotlin.version>1.2.71</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
<version>${dropwizard.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-hibernate</artifactId>
<version>${dropwizard.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-assets</artifactId>
<version>${dropwizard.version}</version>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-testing</artifactId>
<version>${dropwizard.version}</version>
<scope>test</scope>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-auth</artifactId>
<version>${dropwizard.version}</version>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.22.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.197</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy Vue.js frontend content</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>src/main/resources/assets</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<directory>${project.parent.basedir}/frontend/target/dist</directory>
<excludes>
<exclude>**/*.map</exclude>
</excludes>
</resource>
</resources>
</configuration>
</execution>
</executions>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<configuration>
<filesets>
<fileset>
<directory>src/main/resources/assets</directory>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
<plugin>jpa</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>uk.co.neviyn.observations.ObservationsApplication</mainClass>
</transformer>
</transformers>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<arguments>
<argument>server</argument>
<argument>configuration.yml</argument>
</arguments>
<mainClass>uk.co.neviyn.observations.ObservationsApplication</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy Vue.js frontend content</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>src/main/resources/static</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<directory>../frontend/target/dist</directory>
<excludes>
<exclude>**/*.map</exclude>
</excludes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<filesets>
<fileset>
<directory>src/main/resources/static</directory>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,65 +0,0 @@
package uk.co.neviyn.observations;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
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 uk.co.neviyn.observations.auth.SimpleAuthenticator;
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.core.User;
import uk.co.neviyn.observations.dao.ObservationDao;
import uk.co.neviyn.observations.dao.SiteDao;
import uk.co.neviyn.observations.dao.TutorDao;
import uk.co.neviyn.observations.resources.ObservationResource;
import uk.co.neviyn.observations.resources.SiteResource;
import uk.co.neviyn.observations.resources.TutorResource;
public class ObservationsApplication extends Application<ObservationsConfiguration> {
private final HibernateBundle<ObservationsConfiguration> hibernate =
new HibernateBundle<ObservationsConfiguration>(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);
}
@Override
public void initialize(Bootstrap<ObservationsConfiguration> 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();
jersey.register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new SimpleAuthenticator(
observationsConfiguration.getAdminPassword())
).setRealm("SECURITY").buildAuthFilter()));
jersey.register(new AuthValueFactoryProvider.Binder<>(User.class));
TutorDao tutorDao = new TutorDao(hibernate.getSessionFactory());
SiteDao siteDao = new SiteDao(hibernate.getSessionFactory());
ObservationDao observationDao = new ObservationDao(hibernate.getSessionFactory());
final TutorResource tutorResource = new TutorResource(tutorDao, siteDao);
jersey.register(tutorResource);
final ObservationResource observationResource =
new ObservationResource(observationDao, tutorDao, siteDao);
jersey.register(observationResource);
final SiteResource siteResource = new SiteResource(siteDao);
jersey.register(siteResource);
}
}

View File

@ -1,34 +0,0 @@
package uk.co.neviyn.observations;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
public class ObservationsConfiguration extends Configuration {
@Valid
@NotNull
private DataSourceFactory database = new DataSourceFactory();
@Valid
@NotNull
private String adminPassword;
@JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory factory) {
this.database = factory;
}
@JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
@JsonProperty("adminPassword")
public String getAdminPassword() {
return adminPassword;
}
}

View File

@ -1,34 +0,0 @@
package uk.co.neviyn.observations.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.joda.time.DateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AverageStats {
@NonNull
@JsonProperty
private double monitoring;
@NonNull
@JsonProperty
private double control;
@NonNull
@JsonProperty
private double conservatism;
@NonNull
@JsonProperty
private double teamwork;
@NonNull
@JsonProperty
private double knowledge;
@NonNull
@JsonProperty
private DateTime date;
}

View File

@ -1,76 +0,0 @@
package uk.co.neviyn.observations.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
import lombok.NonNull;
/**
* AverageStats in a format easily readable by Chart.js
*/
@Data
public class AverageStatsChartJs {
@NonNull
@JsonProperty
private List<String> labels = new ArrayList<>();
@NonNull
@JsonProperty
private List<Dataset> datasets = new ArrayList<>();
/**
* A list of AverageStats converted to a format compatible with Chart.js.
* @param inputData List of average stats.
*/
public AverageStatsChartJs(List<AverageStats> inputData) {
List<Double> monitoring = new ArrayList<>();
List<Double> control = new ArrayList<>();
List<Double> conservatism = new ArrayList<>();
List<Double> teamwork = new ArrayList<>();
List<Double> knowledge = new ArrayList<>();
for (AverageStats averageStats: inputData) {
labels.add(averageStats.getDate().toString("yyyy-MM-dd"));
monitoring.add(averageStats.getMonitoring());
control.add(averageStats.getControl());
conservatism.add(averageStats.getConservatism());
teamwork.add(averageStats.getTeamwork());
knowledge.add(averageStats.getKnowledge());
}
datasets.add(new Dataset("Monitoring", "#F90", monitoring));
datasets.add(new Dataset("Control", "#3F0", control));
datasets.add(new Dataset("Conservatism", "#33F", conservatism));
datasets.add(new Dataset("Teamwork", "#FF0", teamwork));
datasets.add(new Dataset("Knowledge", "#000", knowledge));
}
class Dataset {
@NonNull
@JsonProperty
private final String label;
@NonNull
@JsonProperty
private final String backgroundColor;
@NonNull
@JsonProperty
private final String borderColor;
@NonNull
@JsonProperty
private final List<Double> data;
@JsonProperty
private final boolean fill = false;
Dataset(String label, String color, List<Double> data) {
this.label = label;
this.backgroundColor = color;
this.borderColor = color;
this.data = data;
}
}
}

View File

@ -1,57 +0,0 @@
package uk.co.neviyn.observations.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import uk.co.neviyn.observations.core.ObservationEntry;
@Data
@NoArgsConstructor
@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class NewObservation {
@NonNull
@JsonProperty
private long siteId;
@NonNull
@JsonProperty
private List<Long> tutorIds;
@NonNull
@JsonProperty
private String observed;
@NonNull
@JsonProperty
private String type;
@NonNull
@JsonProperty
private String whom;
@NonNull
@JsonProperty
private float monitoring;
@NonNull
@JsonProperty
private float control;
@NonNull
@JsonProperty
private float conservatism;
@NonNull
@JsonProperty
private float teamwork;
@NonNull
@JsonProperty
private float knowledge;
@NonNull
@JsonProperty
private List<ObservationEntry> rawData;
}

View File

@ -1,21 +0,0 @@
package uk.co.neviyn.observations.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SelectOption<T> {
@NonNull
@JsonProperty
private String text;
@NonNull
@JsonProperty
private T value;
}

View File

@ -1,21 +0,0 @@
package uk.co.neviyn.observations.auth;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;
import java.util.Optional;
import lombok.AllArgsConstructor;
import uk.co.neviyn.observations.core.User;
@AllArgsConstructor
public class SimpleAuthenticator implements Authenticator<BasicCredentials, User> {
private final String adminPassword;
@Override
public Optional<User> authenticate(BasicCredentials credentials) {
if (adminPassword.equals(credentials.getPassword())) {
return Optional.of(new User(credentials.getUsername()));
}
return Optional.empty();
}
}

View File

@ -1,86 +0,0 @@
package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.joda.time.DateTime;
@Entity
@Table(name = "OBSERVATION")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Observation implements Serializable {
@NonNull
@JsonProperty
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToOne
@JoinColumn(name = "site_id", nullable = false)
@JsonIgnore
@EqualsAndHashCode.Exclude
private Site site;
@ManyToMany(mappedBy = "observations")
@JsonIgnore
@EqualsAndHashCode.Exclude
private Set<Tutor> tutors;
@NonNull
@JsonProperty
private String observed;
@NonNull
@JsonProperty
private String whom;
@NonNull
@JsonProperty
private TrainingType type;
@NonNull
@JsonProperty
private float monitoring;
@NonNull
@JsonProperty
private float control;
@NonNull
@JsonProperty
private float conservatism;
@NonNull
@JsonProperty
private float teamwork;
@NonNull
@JsonProperty
private float knowledge;
@NonNull
@JsonProperty
@ElementCollection
private List<ObservationEntry> observations;
@NonNull
@JsonProperty
private DateTime date;
}

View File

@ -1,32 +0,0 @@
package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import javax.persistence.Embeddable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class ObservationEntry implements Serializable {
@NonNull
@JsonProperty
private String type;
@NonNull
@JsonProperty
private int rating;
@NonNull
@JsonProperty
private String strengths;
@NonNull
@JsonProperty
private String improvements;
}

View File

@ -1,47 +0,0 @@
package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Entity
@Table(name = "SITE")
@Data
@NoArgsConstructor
@Builder
@AllArgsConstructor
public class Site implements Serializable {
@NonNull
@JsonProperty
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@NonNull
@JsonProperty
private String name;
@OneToMany(mappedBy = "site")
@JsonIgnore
@EqualsAndHashCode.Exclude
private Set<Tutor> tutors;
@OneToMany(mappedBy = "site")
@JsonIgnore
@EqualsAndHashCode.Exclude
private Set<Observation> observations;
}

View File

@ -1,5 +0,0 @@
package uk.co.neviyn.observations.core;
public enum TrainingType {
INITIAL, CONTINUING
}

View File

@ -1,56 +0,0 @@
package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Entity
@Table(name = "TUTOR")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Tutor implements Serializable {
@NonNull
@JsonProperty
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@NonNull
@JsonProperty
private String name;
@ManyToOne
@JoinColumn(name = "site_id", nullable = false)
@JsonIgnore
@EqualsAndHashCode.Exclude
private Site site;
@ManyToMany
@JsonIgnore
@JoinTable(
name = "TUTOR_OBSERVATION",
joinColumns = { @JoinColumn(name = "tutor_id")},
inverseJoinColumns = { @JoinColumn(name = "observation_id")}
)
@EqualsAndHashCode.Exclude
private Set<Observation> observations;
}

View File

@ -1,15 +0,0 @@
package uk.co.neviyn.observations.core;
import java.security.Principal;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Principal {
private String name;
}

View File

@ -1,104 +0,0 @@
package uk.co.neviyn.observations.dao;
import io.dropwizard.hibernate.AbstractDAO;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.joda.time.DateTime;
import uk.co.neviyn.observations.api.AverageStats;
import uk.co.neviyn.observations.core.Observation;
import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.Tutor;
public class ObservationDao extends AbstractDAO<Observation> {
public ObservationDao(SessionFactory sessionFactory) {
super(sessionFactory);
}
public Observation get(long id) {
return super.get(id);
}
public Observation persist(Observation observation) {
return super.persist(observation);
}
public List<Observation> listAll() {
return currentSession().createQuery("from Observation", Observation.class).list();
}
public List<Observation> filteredList(Site site, Tutor tutor, DateTime startDate, DateTime endDate, String whom) {
final CriteriaBuilder builder = currentSession().getCriteriaBuilder();
CriteriaQuery<Observation> criteriaQuery = builder.createQuery(Observation.class);
Root<Observation> root = criteriaQuery.from(Observation.class);
List<Predicate> predicates = new ArrayList<>();
if (site != null) {
predicates.add(builder.equal(root.get("site"), site));
}
if (tutor != null) {
predicates.add(builder.equal(root.join("tutors"), tutor));
}
if (startDate != null) {
predicates.add(builder.greaterThanOrEqualTo(root.get("date"), startDate));
}
if (endDate != null) {
predicates.add(builder.lessThanOrEqualTo(root.get("date"), endDate));
}
if (whom != null) {
predicates.add(builder.equal(root.get("whom"), whom));
}
if (!predicates.isEmpty()) {
criteriaQuery.having(predicates.toArray(new Predicate[0]));
}
Query<Observation> query = currentSession().createQuery(criteriaQuery);
System.out.println(query.getQueryString());
return query.getResultList();
}
/**
* Generate the average observation stats with data constraints.
*
* @param site Restrict to a site.
* @param tutor Restrict to a tutor.
* @param startDate Restrict to after a certain date.
* @param endDate Restrict to before a certain date.
* @param whom Restrict to a particular person/group who was observed.
* @return Average observation scores per day.
*/
public List<AverageStats> averageStats(Site site, Tutor tutor, DateTime startDate, DateTime endDate, String whom) {
CriteriaBuilder builder = currentSession().getCriteriaBuilder();
CriteriaQuery<AverageStats> criteriaQuery = builder.createQuery(AverageStats.class);
Root<Observation> root = criteriaQuery.from(Observation.class);
criteriaQuery.multiselect(builder.avg(root.get("monitoring")), builder.avg(root.get("control")),
builder.avg(root.get("conservatism")), builder.avg(root.get("teamwork")), builder.avg(root.get("knowledge")),
root.get("date"));
criteriaQuery.groupBy(root.get("date"));
List<Predicate> predicates = new ArrayList<>();
if (site != null) {
predicates.add(builder.equal(root.get("site"), site));
}
if (tutor != null) {
predicates.add(builder.equal(root.join("tutors"), tutor));
}
if (startDate != null) {
predicates.add(builder.greaterThanOrEqualTo(root.get("date"), startDate));
}
if (endDate != null) {
predicates.add(builder.lessThanOrEqualTo(root.get("date"), endDate));
}
if (whom != null) {
predicates.add(builder.equal(root.get("whom"), whom));
}
if (!predicates.isEmpty()) {
criteriaQuery.having(predicates.toArray(new Predicate[0]));
}
Query<AverageStats> query = currentSession().createQuery(criteriaQuery);
System.out.println(query.getQueryString());
return query.getResultList();
}
}

View File

@ -1,24 +0,0 @@
package uk.co.neviyn.observations.dao;
import io.dropwizard.hibernate.AbstractDAO;
import java.util.List;
import org.hibernate.SessionFactory;
import uk.co.neviyn.observations.core.Site;
public class SiteDao extends AbstractDAO<Site> {
public SiteDao(SessionFactory sessionFactory) {
super(sessionFactory);
}
public List<Site> listAll() {
return currentSession().createQuery("from Site", Site.class).list();
}
public Site get(long id) {
return super.get(id);
}
public Site persist(Site site) {
return super.persist(site);
}
}

View File

@ -1,24 +0,0 @@
package uk.co.neviyn.observations.dao;
import io.dropwizard.hibernate.AbstractDAO;
import java.util.List;
import org.hibernate.SessionFactory;
import uk.co.neviyn.observations.core.Tutor;
public class TutorDao extends AbstractDAO<Tutor> {
public TutorDao(SessionFactory sessionFactory) {
super(sessionFactory);
}
public Tutor get(long id) {
return super.get(id);
}
public List<Tutor> listAll() {
return currentSession().createQuery("from Tutor", Tutor.class).list();
}
public Tutor persist(Tutor tutor) {
return super.persist(tutor);
}
}

View File

@ -1,143 +0,0 @@
package uk.co.neviyn.observations.resources;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
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)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/observation")
@Slf4j
public class ObservationResource {
private final ObservationDao dao;
private final TutorDao tutorDao;
private final SiteDao siteDao;
/**
* Create a new Observation.
*
* @param newObservation New observation data.
* @return ID of newly created observation.
*/
@POST
@UnitOfWork
public long add(@NotNull NewObservation newObservation) {
log.info(newObservation.toString());
final DateTime submissionDate = LocalDate.now().toDateTimeAtStartOfDay();
Set<Tutor> tutors = new HashSet<>();
for (long l : newObservation.getTutorIds()) {
tutors.add(tutorDao.get(l));
}
final Site site = siteDao.get(newObservation.getSiteId());
Observation observation = Observation.builder().site(site).tutors(tutors).observed(newObservation.getObserved())
.type(TrainingType.valueOf(newObservation.getType())).monitoring(newObservation.getMonitoring())
.control(newObservation.getControl()).conservatism(newObservation.getConservatism())
.teamwork(newObservation.getTeamwork()).knowledge(newObservation.getKnowledge())
.observations(newObservation.getRawData()).date(submissionDate).whom(newObservation.getWhom()).build();
for (Tutor t : tutors) {
t.getObservations().add(observation);
}
observation = dao.persist(observation);
log.info("Created observation with ID " + observation.getId());
return observation.getId();
}
@GET
@UnitOfWork
public List<Observation> observations(@QueryParam("site") Integer siteId, @QueryParam("tutor") Integer tutorId,
@QueryParam("startDate") String startDate, @QueryParam("endDate") String endDate,
@QueryParam("whom") String whom) {
Site site = null;
Tutor tutor = null;
DateTime start = null;
DateTime end = null;
try {
site = siteDao.get(siteId);
} catch (Exception e) {
log.warn("Couldn't get site with ID " + siteId);
}
try {
tutor = tutorDao.get(tutorId);
} catch (Exception e) {
log.warn("Couldn't get tutor with ID " + tutorId);
}
try {
start = DateTime.parse(startDate);
} catch (Exception e) {
log.warn("Couldn't get a valid date from " + startDate);
}
try {
end = DateTime.parse(endDate);
} catch (Exception e) {
log.warn("Couldn't get a valid date from " + endDate);
}
return dao.filteredList(site, tutor, start, end, whom);
}
/**
* Get a Chart.js compatible llist of average observation scores grouped by day.
*
* @param siteId Only observations for site.
* @param tutorId Only observations for tutor.
* @param startDate Only observations after startDate.
* @param endDate Only observations before endDate.
* @param whom Only observations of whom.
* @return Chart.js stats object.
*/
@Path("/average")
@GET
@UnitOfWork
public AverageStatsChartJs averageObservationScores(@QueryParam("site") Integer siteId,
@QueryParam("tutor") Integer tutorId, @QueryParam("startDate") String startDate,
@QueryParam("endDate") String endDate, @QueryParam("whom") String whom) {
Site site = null;
Tutor tutor = null;
DateTime start = null;
DateTime end = null;
try {
site = siteDao.get(siteId);
} catch (Exception e) {
log.warn("Couldn't get site with ID " + siteId);
}
try {
tutor = tutorDao.get(tutorId);
} catch (Exception e) {
log.warn("Couldn't get tutor with ID " + tutorId);
}
try {
start = DateTime.parse(startDate);
} catch (Exception e) {
log.warn("Couldn't get a valid date from " + startDate);
}
try {
end = DateTime.parse(endDate);
} catch (Exception e) {
log.warn("Couldn't get a valid date from " + endDate);
}
return new AverageStatsChartJs(dao.averageStats(site, tutor, start, end, whom));
}
}

View File

@ -1,68 +0,0 @@
package uk.co.neviyn.observations.resources;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.List;
import java.util.stream.Collectors;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import uk.co.neviyn.observations.api.SelectOption;
import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.User;
import uk.co.neviyn.observations.dao.SiteDao;
@RequiredArgsConstructor
@Produces(MediaType.APPLICATION_JSON)
@Path("/site")
@Slf4j
public class SiteResource {
private final SiteDao dao;
/**
* Add a new Site.
* @param user Authorization account.
* @param name Name of Site to add.
* @return Newly created site object.
*/
@POST
@UnitOfWork
public Site add(@Auth User user, String name) {
Site site = dao.persist(Site.builder().name(name).build());
log.info("Created site '" + site.getName() + "' with id " + site.getId());
return site;
}
/**
* List all known Sites.
* @return List of all Sites.
*/
@Path("/all")
@GET
@UnitOfWork
public List<SelectOption<Long>> allSites() {
return dao.listAll().stream().map(x ->
new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList()
);
}
/**
* A List of all the Tutors registered to Site.
* @param id ID of site.
* @return List of Tutors, compatible with a HTML select object.
*/
@Path("/{id}/tutors")
@GET
@UnitOfWork
public List<SelectOption<Long>> getSiteTutors(@PathParam("id") long id) {
return dao.get(id).getTutors().stream().map(x ->
new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList()
);
}
}

View File

@ -1,91 +0,0 @@
package uk.co.neviyn.observations.resources;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.List;
import java.util.Set;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.core.User;
import uk.co.neviyn.observations.dao.SiteDao;
import uk.co.neviyn.observations.dao.TutorDao;
@RequiredArgsConstructor
@Produces(MediaType.APPLICATION_JSON)
@Path("/tutor")
@Slf4j
public class TutorResource {
private final TutorDao dao;
private final SiteDao siteDao;
/**
* Create a new Tutor.
* @param user Authorization account.
* @param newTutor Details of new Tutor.
* @return Newly created Tutor object.
*/
@POST
@UnitOfWork
public Tutor add(@Auth User user, NewTutor newTutor) {
final Site site = siteDao.get(newTutor.siteId);
final Tutor tutor = Tutor.builder().name(newTutor.name).site(site).build();
site.getTutors().add(tutor);
log.info("Created tutor '" + tutor.getName() + "' with id "
+ tutor.getId() + " at site " + site.getId());
return dao.persist(tutor);
}
/**
* Get a List of all Tutors.
* @return List of all Tutors.
*/
@Path("/all")
@GET
@UnitOfWork
public List<Tutor> allTutors() {
List<Tutor> tutors = dao.listAll();
if (tutors != null && !tutors.isEmpty()) {
return tutors;
}
throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND);
}
/**
* Get a list of all observations by a tutor.
* @param id Tutor ID.
* @return List of tutors' observations.
*/
@Path("/{id}/observations")
@GET
@UnitOfWork
public Set<Observation> getTutorObservation(@PathParam("id") long id) {
return dao.get(id).getObservations();
}
@AllArgsConstructor
@NoArgsConstructor
static class NewTutor {
@JsonProperty
long siteId;
@NonNull
@JsonProperty
String name;
}
}

View File

@ -0,0 +1,59 @@
package uk.co.neviyn.observationdatabase
import org.joda.time.LocalDate
data class NameValue(
val text: String,
val value: Long
)
data class NewSite(
val name: String
)
data class NewTutor(
val name: String,
val siteId: Long
)
data class SimpleObservation(
val date: LocalDate,
val type: TrainingType,
val observed: String,
val whom: String,
val entries: List<Entry>
){
constructor(observation: Observation) : this(observation.date, observation.type,
observation.observed, observation.whom, observation.entries)
}
data class NewObservation(
val site: Long,
val type: TrainingType,
val observed: String,
val whom: String,
val entries: List<Entry>,
val tutors: List<Long>
)
data class ObservationsRequest(
val site: Long?,
val tutor: Long?,
val whom: String?,
val startDate: LocalDate,
val endDate: LocalDate
)
data class ChartData(
val labels: List<String>,
val datasets: List<ChartDataset>
)
data class ChartDataset(
val label: String,
val backgroundColor: String,
val borderColor: String,
val data: List<Double>
){
constructor(label: String, color: String, data: List<Double>): this(label, color, color, data)
}

View File

@ -0,0 +1,149 @@
package uk.co.neviyn.observationdatabase
import org.joda.time.LocalDate
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*
import javax.validation.Valid
@RestController
@RequestMapping("/api")
class Controller {
@Autowired
lateinit var siteRepository: SiteRepository
@Autowired
lateinit var tutorRepository: TutorRepository
@Autowired
lateinit var observationRepository: ObservationRepository
@GetMapping("/site")
fun getAllSites(): List<NameValue> = siteRepository.findAll().map { NameValue(it.name, it.id) }
@PostMapping("/site")
fun addSite(@Valid @RequestBody newSite: NewSite): NameValue {
val site = siteRepository.save(Site(name = newSite.name))
return NameValue(site.name, site.id)
}
@GetMapping("/site/{id}/tutors")
fun getTutorsForSite(@PathVariable(value = "id") id: Long): List<NameValue> =
siteRepository.findById(id).map { site ->
site.tutors.map { NameValue(it.name, it.id) }
}.get()
@GetMapping
fun getAllTutors(): List<NameValue> = tutorRepository.findAll().map { NameValue(it.name, it.id) }
@PostMapping("/tutor")
fun addTutor(@Valid @RequestBody newTutor: NewTutor): NameValue? {
var nameValue: NameValue? = null
siteRepository.findById(newTutor.siteId).ifPresent {
val tutor = tutorRepository.save(Tutor(name = newTutor.name, site = it))
it.tutors.add(tutor)
siteRepository.save(it)
nameValue = NameValue(tutor.name, tutor.id)
}
return nameValue
}
@GetMapping("/tutor/{id}/observations")
fun getObservationsForTutor(@PathVariable(value = "id") id: Long): List<SimpleObservation> =
tutorRepository.findById(id).map { tutor ->
tutor.observations.map { SimpleObservation(it) }
}.get()
@PostMapping("/observation")
fun addObservation(@Valid @RequestBody newObservation: NewObservation): Long {
val site = siteRepository.findById(newObservation.site).get()
val tutors = tutorRepository.findAllById(newObservation.tutors).toSet()
val overallScores = newObservation.entries.asSequence().groupBy { it.type }
.map { entry -> entry.key to entry.value.asSequence().mapNotNull { it.rating }.average() }
.map { it.first to if(it.second > 0) it.second else null }.toList()
.toMap()
var observation = Observation(
site = site,
date = LocalDate.now(),
type = newObservation.type,
observed = newObservation.observed,
whom = newObservation.whom,
monitoring = overallScores[RatingCategory.MONITORING],
conservatism = overallScores[RatingCategory.CONSERVATISM],
control = overallScores[RatingCategory.CONTROL],
teamwork = overallScores[RatingCategory.TEAMWORK],
knowledge = overallScores[RatingCategory.KNOWLEDGE],
entries = newObservation.entries,
tutors = tutors
)
observation = observationRepository.save(observation)
tutors.forEach {
it.observations.add(observation)
tutorRepository.save(it)
}
return observation.id
}
@GetMapping("/observations")
fun getObservations(@Valid @RequestBody observationsRequest: ObservationsRequest): List<Observation>? {
if (observationsRequest.tutor != null) {
val tutor = tutorRepository.findById(observationsRequest.tutor).get()
return if (observationsRequest.whom == null) {
observationRepository.findByTutorsAndDateBetween(tutor = tutor,
startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate)
} else {
observationRepository.findByTutorsAndWhomAndDateBetween(tutor = tutor,
whom = observationsRequest.whom,
startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate)
}
}
if (observationsRequest.site != null) {
val site = siteRepository.findById(observationsRequest.site).get()
return if (observationsRequest.whom == null) {
observationRepository.findBySiteAndDateBetween(site = site,
startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate)
} else {
observationRepository.findBySiteAndWhomAndDateBetween(site = site,
whom = observationsRequest.whom,
startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate)
}
}
return null
}
@GetMapping("/observations/chartdata")
fun getObservationsChartData(@Valid @RequestBody observationsRequest: ObservationsRequest): ChartData? {
val data = getObservations(observationsRequest) ?: return null
val groupedData = data.asSequence().groupBy { it.date }.map{ entry -> AverageData(
entry.value.asSequence().mapNotNull { it.monitoring }.average(),
entry.value.asSequence().mapNotNull { it.control }.average(),
entry.value.asSequence().mapNotNull { it.conservatism }.average(),
entry.value.asSequence().mapNotNull { it.teamwork }.average(),
entry.value.asSequence().mapNotNull { it.knowledge }.average(),
entry.key
)}.toList()
val dates = groupedData.map { it.date.toString("yyyy-MM-dd") }
return ChartData(
labels = dates,
datasets = listOf(
ChartDataset("Monitoring", "#F90", groupedData.map { it.monitoring }),
ChartDataset("Control", "#3F0", groupedData.map { it.control }),
ChartDataset("Conservatism", "#33F", groupedData.map { it.conservatism }),
ChartDataset("Teamwork", "#FF0", groupedData.map { it.teamwork }),
ChartDataset("Knowledge", "#000", groupedData.map { it.knowledge })
)
)
}
}
data class AverageData(
val monitoring: Double,
val control: Double,
val conservatism: Double,
val teamwork: Double,
val knowledge: Double,
val date: LocalDate
)

View File

@ -0,0 +1,81 @@
package uk.co.neviyn.observationdatabase
import com.fasterxml.jackson.annotation.JsonProperty
import org.joda.time.LocalDate
import javax.persistence.*
@Entity
data class Site(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val name: String){
@OneToMany(fetch = FetchType.LAZY)
val tutors: MutableSet<Tutor> = mutableSetOf()
}
@Entity
data class Tutor(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val name: String,
@ManyToOne(fetch = FetchType.LAZY)
val site: Site
){
@ManyToMany
@JoinTable(name = "tutor_observations",
joinColumns = [JoinColumn(name =" tutor_id", referencedColumnName = "id")],
inverseJoinColumns = [JoinColumn(name = "observation_id", referencedColumnName = "id")])
val observations: MutableSet<Observation> = mutableSetOf()
}
enum class TrainingType {
INITIAL, CONTINUING
}
enum class RatingCategory {
MONITORING, CONTROL, CONSERVATISM, TEAMWORK, KNOWLEDGE
}
@Entity
data class Observation(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
@ManyToOne
val site: Site,
@Column(nullable = false)
val date: LocalDate,
@Column(nullable = false)
val type: TrainingType,
@Column(nullable = false)
val observed: String,
@Column(nullable = false)
val whom: String,
val monitoring: Double?,
val control: Double?,
val conservatism: Double?,
val teamwork: Double?,
val knowledge: Double?,
@ElementCollection
val entries: List<Entry>,
@ManyToMany(mappedBy = "observations")
val tutors: Set<Tutor>
)
@Embeddable
data class Entry(
@Column(nullable = false)
@JsonProperty
val type: RatingCategory,
@Column(nullable = false)
@JsonProperty
val rating: Int,
@Column(nullable = false)
@JsonProperty
val strengths: String,
@Column(nullable = false)
@JsonProperty
val improvements: String
)

View File

@ -0,0 +1,11 @@
package uk.co.neviyn.observationdatabase
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class ObservationDatabaseApplication
fun main(args: Array<String>) {
runApplication<ObservationDatabaseApplication>(*args)
}

View File

@ -0,0 +1,23 @@
package uk.co.neviyn.observationdatabase
import org.joda.time.LocalDate
import org.springframework.data.jpa.repository.JpaSpecificationExecutor
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
@Repository
interface SiteRepository: CrudRepository<Site, Long>
@Repository
interface TutorRepository: CrudRepository<Tutor, Long>
@Repository
interface ObservationRepository: CrudRepository<Observation, Long>, JpaSpecificationExecutor<Observation> {
fun findBySiteAndDateBetween(site: Site, startDate: LocalDate, endDate: LocalDate): List<Observation>
fun findByTutorsAndDateBetween(tutor: Tutor, startDate: LocalDate, endDate: LocalDate): List<Observation>
fun findBySiteAndWhomAndDateBetween(site: Site, whom: String, startDate: LocalDate, endDate: LocalDate): List<Observation>
fun findByTutorsAndWhomAndDateBetween(tutor: Tutor, whom: String, startDate: LocalDate, endDate: LocalDate): List<Observation>
}

View File

@ -0,0 +1 @@
spring.jpa.properties.jadira.usertype.autoRegisterUserTypes = true

View File

@ -1,7 +0,0 @@
____ __ __ _
/ __ \/ / ___ ___ _____ _____ _/ /_(_)__ ___ ___
/ /_/ / _ \(_-</ -_) __/ |/ / _ `/ __/ / _ \/ _ \(_-<
\____/_.__/___/\__/_/ |___/\_,_/\__/_/\___/_//_/___/
DUNGENESS B TRAINING OBSERVATIONS DATABASE
BY NATHAN CANNON (nathan.cannon@edf-energy.com)

View File

@ -1,33 +0,0 @@
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.assertEquals;
public class NewObservationTest {
private static final ObjectMapper mapper = Jackson.newObjectMapper();
private final NewObservation newObservation = NewObservation.builder().siteId(1).tutorIds(Arrays.asList(1L, 2L, 3L))
.observed("A random thing made for testing.").whom("Group A").type("INITIAL").monitoring(1).control(2).conservatism(3)
.teamwork(4).knowledge(5).rawData(Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum"))).build();
@Test
public void serializesToJson() throws Exception {
final String expected = mapper.writeValueAsString(mapper.readValue(fixture("fixtures/NewObservation.json"), NewObservation.class));
assertEquals(expected, mapper.writeValueAsString(newObservation));
}
@Test
public void deserializesFromJson() throws Exception {
assertEquals(newObservation, mapper.readValue(fixture("fixtures/NewObservation.json"), NewObservation.class));
}
}

View File

@ -1,34 +0,0 @@
package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.dropwizard.jackson.Jackson;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.junit.Test;
import java.util.Collections;
import static io.dropwizard.testing.FixtureHelpers.fixture;
import static org.junit.Assert.assertEquals;
@Slf4j
public class ObservationTest {
private static final ObjectMapper mapper = Jackson.newObjectMapper();
private final Observation observation = Observation.builder().observed("Just a test observation").type(TrainingType.INITIAL)
.monitoring(1).control(2).conservatism(3).teamwork(4).knowledge(5).whom("Group A")
.observations(Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum")))
.date(DateTime.parse("2018-09-18T00:00:00.000Z")).build();
@Test
public void serializesToJson() throws Exception {
final String expected = mapper.writeValueAsString(mapper.readValue(fixture("fixtures/Observation.json"), Observation.class));
assertEquals(expected, mapper.writeValueAsString(observation));
}
@Test
public void deserializesFromJson() throws Exception {
assertEquals(observation, mapper.readValue(fixture("fixtures/Observation.json"), Observation.class));
}
}

View File

@ -1,12 +0,0 @@
package uk.co.neviyn.observations.dao;
import io.dropwizard.testing.junit.DAOTestRule;
import org.junit.Rule;
import uk.co.neviyn.observations.core.Observation;
import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.Tutor;
public abstract class DaoTestBase {
@Rule
public DAOTestRule testRule = DAOTestRule.newBuilder().addEntityClass(Observation.class).addEntityClass(Site.class).addEntityClass(Tutor.class).build();
}

View File

@ -1,219 +0,0 @@
package uk.co.neviyn.observations.dao;
import org.apache.commons.lang3.SerializationUtils;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import uk.co.neviyn.observations.api.AverageStats;
import uk.co.neviyn.observations.core.Observation;
import uk.co.neviyn.observations.core.ObservationEntry;
import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.TrainingType;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.*;
public class ObservationDaoTest extends DaoTestBase {
private ObservationDao dao;
private SiteDao siteDao;
private final Site site = Site.builder().name("Test site").build();
private final Observation observation = Observation.builder().observed("Just a test observation").type(TrainingType.INITIAL)
.site(site).monitoring(1f).control(2f).conservatism(3f).teamwork(4f).knowledge(5f).whom("Group A")
.observations(Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum")))
.date(DateTime.parse("2018-09-18T00:00:00.000Z")).build();
@Before
public void setUp() {
dao = new ObservationDao(testRule.getSessionFactory());
siteDao = new SiteDao(testRule.getSessionFactory());
testRule.inTransaction(() -> siteDao.persist(site));
}
@Test
public void persistAndGet() {
Observation insert = testRule.inTransaction(() -> dao.persist(observation));
assertNotNull(insert);
assertTrue(insert.getId() > 0);
assertNotNull(dao.get(insert.getId()));
}
@Test
public void listAll() {
int numberOfObservations = 5;
testRule.inTransaction(() -> {
for (int i = 0; i < numberOfObservations; i++) {
// Make actual copies, otherwise they will merely overwrite.
dao.persist(SerializationUtils.clone(observation));
}
});
List<Observation> observations = dao.listAll();
assertNotNull(observations);
assertEquals(numberOfObservations, observations.size());
}
@Test
public void listAllWithNoObservations() {
List<Observation> observations = dao.listAll();
assertNotNull(observations);
assertEquals(0, observations.size());
}
@Test
public void averageStatsNoParam() {
Observation otherEntry = SerializationUtils.clone(observation);
otherEntry.setMonitoring(5);
otherEntry.setControl(5);
otherEntry.setConservatism(5);
otherEntry.setTeamwork(5);
Observation differentDay = SerializationUtils.clone(observation);
differentDay.setDate(DateTime.parse("2018-09-20"));
testRule.inTransaction(() -> {
dao.persist(observation);
dao.persist(otherEntry);
dao.persist(differentDay);
});
List<AverageStats> stats = dao.averageStats(null, null, null, null, null);
assertNotNull(stats);
assertEquals(2, stats.size());
final AverageStats statObject = stats.get(0);
assertEquals(3, statObject.getMonitoring(), 0);
assertEquals(3.5, statObject.getControl(), 0);
assertEquals(4, statObject.getConservatism(), 0);
assertEquals(4.5, statObject.getTeamwork(), 0);
assertEquals(5, statObject.getKnowledge(), 0);
}
@Test
public void averageStatsWithSite() {
Observation otherEntry = SerializationUtils.clone(observation);
otherEntry.setMonitoring(5);
otherEntry.setControl(5);
otherEntry.setConservatism(5);
otherEntry.setTeamwork(5);
Observation differentDay = SerializationUtils.clone(observation);
differentDay.setDate(DateTime.parse("2018-09-20"));
testRule.inTransaction(() -> {
dao.persist(observation);
dao.persist(otherEntry);
dao.persist(differentDay);
});
List<AverageStats> stats = dao.averageStats(site, null, null, null, null);
assertNotNull(stats);
assertEquals(2, stats.size());
final AverageStats statObject = stats.get(0);
assertEquals(3, statObject.getMonitoring(), 0);
assertEquals(3.5, statObject.getControl(), 0);
assertEquals(4, statObject.getConservatism(), 0);
assertEquals(4.5, statObject.getTeamwork(), 0);
assertEquals(5, statObject.getKnowledge(), 0);
}
@Test
public void averageStatsWithStartDate() {
Observation otherEntry = SerializationUtils.clone(observation);
otherEntry.setMonitoring(5);
otherEntry.setControl(5);
otherEntry.setConservatism(5);
otherEntry.setTeamwork(5);
Observation differentDay = SerializationUtils.clone(observation);
differentDay.setDate(DateTime.parse("2018-09-20"));
testRule.inTransaction(() -> {
dao.persist(observation);
dao.persist(otherEntry);
dao.persist(differentDay);
});
List<AverageStats> stats = dao.averageStats(null, null, DateTime.parse("2018-09-01").withTimeAtStartOfDay(), null, null);
assertNotNull(stats);
assertEquals(2, stats.size());
// Change one observation to outside range
differentDay.setDate(DateTime.parse("2018-08-20"));
testRule.inTransaction(() -> {
dao.persist(differentDay);
});
stats = dao.averageStats(null, null, DateTime.parse("2018-09-01").withTimeAtStartOfDay(), null, null);
assertNotNull(stats);
assertEquals(1, stats.size());
}
@Test
public void averageStatsWithEndDate() {
Observation otherEntry = SerializationUtils.clone(observation);
otherEntry.setMonitoring(5);
otherEntry.setControl(5);
otherEntry.setConservatism(5);
otherEntry.setTeamwork(5);
Observation differentDay = SerializationUtils.clone(observation);
differentDay.setDate(DateTime.parse("2018-09-20"));
testRule.inTransaction(() -> {
dao.persist(observation);
dao.persist(otherEntry);
dao.persist(differentDay);
});
List<AverageStats> stats = dao.averageStats(null, null, null, DateTime.parse("2018-10-01").withTimeAtStartOfDay(), null);
assertNotNull(stats);
assertEquals(2, stats.size());
// Change one observation to outside range
differentDay.setDate(DateTime.parse("2018-10-20"));
testRule.inTransaction(() -> {
dao.persist(differentDay);
});
stats = dao.averageStats(null, null, null, DateTime.parse("2018-10-01").withTimeAtStartOfDay(), null);
assertNotNull(stats);
assertEquals(1, stats.size());
}
@Test
public void averageStatsWithBothDate() {
Observation otherEntry = SerializationUtils.clone(observation);
otherEntry.setMonitoring(5);
otherEntry.setControl(5);
otherEntry.setConservatism(5);
otherEntry.setTeamwork(5);
otherEntry.setDate(DateTime.parse("2018-08-20"));
Observation differentDay = SerializationUtils.clone(observation);
differentDay.setDate(DateTime.parse("2018-10-20"));
testRule.inTransaction(() -> {
dao.persist(observation);
dao.persist(otherEntry);
dao.persist(differentDay);
});
List<AverageStats> stats = dao.averageStats(site, null, null, null, null);
assertNotNull(stats);
assertEquals(3, stats.size());
stats = dao.averageStats(null, null, DateTime.parse("2018-09-01").withTimeAtStartOfDay(), DateTime.parse("2018-10-01").withTimeAtStartOfDay(), null);
assertNotNull(stats);
System.out.println(stats.toString());
assertEquals(1, stats.size());
}
@Test
public void averageStatsWithWhom() {
Observation otherEntry = SerializationUtils.clone(observation);
otherEntry.setMonitoring(5);
otherEntry.setControl(5);
otherEntry.setConservatism(5);
otherEntry.setTeamwork(5);
Observation differentDay = SerializationUtils.clone(observation);
differentDay.setDate(DateTime.parse("2018-09-20"));
testRule.inTransaction(() -> {
dao.persist(observation);
dao.persist(otherEntry);
dao.persist(differentDay);
});
List<AverageStats> stats = dao.averageStats(null, null, null, null, "Group A");
assertNotNull(stats);
assertEquals(2, stats.size());
differentDay.setWhom("Group B");
testRule.inTransaction(() -> {
dao.persist(differentDay);
});
stats = dao.averageStats(null, null, null, null, "Group A");
assertNotNull(stats);
assertEquals(1, stats.size());
}
}

View File

@ -1,46 +0,0 @@
package uk.co.neviyn.observations.dao;
import org.junit.Before;
import org.junit.Test;
import uk.co.neviyn.observations.core.Site;
import java.util.List;
import static org.junit.Assert.*;
public class SiteDaoTest extends DaoTestBase{
private SiteDao dao;
@Before
public void setUp() {
dao = new SiteDao(testRule.getSessionFactory());
}
@Test
public void listAll() {
testRule.inTransaction(() -> {
dao.persist(Site.builder().name("Site A").build());
dao.persist(Site.builder().name("Site B").build());
dao.persist(Site.builder().name("Site C").build());
});
List<Site> result = dao.listAll();
assertNotNull(result);
assertEquals(3, result.size());
}
@Test
public void listAllWithNoObservations() {
List<Site> sites = dao.listAll();
assertNotNull(sites);
assertEquals(0, sites.size());
}
@Test
public void persistAndGet() {
Site insert = testRule.inTransaction(() -> dao.persist(Site.builder().name("Test Site").build()));
assertNotNull(insert);
assertTrue(insert.getId() > 0);
assertNotNull(dao.get(insert.getId()));
}
}

View File

@ -1,51 +0,0 @@
package uk.co.neviyn.observations.dao;
import org.junit.Before;
import org.junit.Test;
import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.Tutor;
import java.util.List;
import static org.junit.Assert.*;
public class TutorDaoTest extends DaoTestBase{
private TutorDao dao;
private SiteDao siteDao;
private final Site site = Site.builder().name("Test site").build();
@Before
public void setUp() {
dao = new TutorDao(testRule.getSessionFactory());
siteDao = new SiteDao(testRule.getSessionFactory());
testRule.inTransaction(() -> siteDao.persist(site));
}
@Test
public void listAll() {
testRule.inTransaction(() -> {
dao.persist(Tutor.builder().name("Mr Test").site(site).build());
dao.persist(Tutor.builder().name("Mr Test2").site(site).build());
dao.persist(Tutor.builder().name("Mr Test3").site(site).build());
});
List<Tutor> result = dao.listAll();
assertNotNull(result);
assertEquals(3, result.size());
}
@Test
public void listAllWithNoObservations() {
List<Tutor> tutors = dao.listAll();
assertNotNull(tutors);
assertEquals(0, tutors.size());
}
@Test
public void persistAndGet() {
Tutor insert = testRule.inTransaction(() -> dao.persist(Tutor.builder().name("Mr Test").site(site).build()));
assertNotNull(insert);
assertTrue(insert.getId() > 0);
assertNotNull(dao.get(insert.getId()));
}
}

View File

@ -1,69 +0,0 @@
package uk.co.neviyn.observations.resources;
import io.dropwizard.testing.junit.ResourceTestRule;
import org.junit.After;
import org.junit.ClassRule;
import org.junit.Test;
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.Tutor;
import uk.co.neviyn.observations.dao.ObservationDao;
import uk.co.neviyn.observations.dao.SiteDao;
import uk.co.neviyn.observations.dao.TutorDao;
import javax.ws.rs.client.Entity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import static org.mockito.Mockito.*;
public class ObservationResourceTest {
private static final ObservationDao dao = mock(ObservationDao.class);
private static final SiteDao siteDao = mock(SiteDao.class);
private static final TutorDao tutorDao = mock(TutorDao.class);
@ClassRule
public static final ResourceTestRule resources = ResourceTestRule.builder()
.addResource(new ObservationResource(dao, tutorDao, siteDao))
.build();
@After
public void tearDown() {
reset(dao);
reset(siteDao);
reset(tutorDao);
}
@Test
public void add() {
final Site testSite = Site.builder().id(1).name("Test Site").build();
final List<Tutor> tutors = Arrays.asList(Tutor.builder().id(1).name("Mr A").observations(new HashSet<>()).build(), Tutor.builder().id(2).name("Mr B").observations(new HashSet<>()).build());
when(siteDao.get(1)).thenReturn(testSite);
when(tutorDao.get(1)).thenReturn(tutors.get(0));
when(tutorDao.get(2)).thenReturn(tutors.get(1));
resources.target("/observation").request().post(Entity.json(NewObservation.builder().type("INITIAL")
.conservatism(1f).control(2f).knowledge(3f).monitoring(4f).teamwork(5f).siteId(1).tutorIds(Arrays.asList(1L, 2L))
.observed("").whom("Group A").rawData(new ArrayList<>()).build()));
verify(dao, times(1)).persist(any(Observation.class));
}
@Test
public void averageObservationScores() {
}
@Test
public void averageStatsChartJs() {
}
@Test
public void averageObservationScoresForSite() {
}
@Test
public void averageObservationScoresForSiteChartJs() {
}
}

View File

@ -1,74 +0,0 @@
package uk.co.neviyn.observations.resources;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
import io.dropwizard.testing.junit.ResourceTestRule;
import org.junit.After;
import org.junit.ClassRule;
import org.junit.Test;
import uk.co.neviyn.observations.api.SelectOption;
import uk.co.neviyn.observations.auth.SimpleAuthenticator;
import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.Tutor;
import uk.co.neviyn.observations.core.User;
import uk.co.neviyn.observations.dao.SiteDao;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.GenericType;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.*;
public class SiteResourceTest {
private static final SiteDao dao = mock(SiteDao.class);
private final String httpAuth = "Basic dGVzdDpURVNUUFc=";
@ClassRule
public static final ResourceTestRule resources = ResourceTestRule.builder()
.addResource(new AuthDynamicFeature(
new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new SimpleAuthenticator("TESTPW"))
.setRealm("SECURITY")
.buildAuthFilter()
))
.addProvider(new AuthValueFactoryProvider.Binder<>(User.class))
.addResource(new SiteResource(dao))
.build();
@After
public void tearDown() {
reset(dao);
}
@Test
public void add() {
resources.target("/site").request().header("Authorization", httpAuth).post(Entity.json("New Site"));
verify(dao, times(1)).persist(Site.builder().name("New Site").tutors(new HashSet<>()).build());
}
@Test
public void allSites() {
when(dao.listAll()).thenReturn(Arrays.asList(Site.builder().id(1).name("Site 1").build(), Site.builder().id(2).name("Site 2").build()));
List<SelectOption<Long>> sites = resources.target("/site/all").request().get(new GenericType<List<SelectOption<Long>>>() {
});
assertNotNull(sites);
assertEquals(2, sites.size());
}
@Test
public void getSiteTutors() {
Set<Tutor> tutors = new HashSet<>(Arrays.asList(Tutor.builder().id(1).name("Test 1").build(), Tutor.builder().id(2).name("Test 2").build()));
when(dao.get(1)).thenReturn(Site.builder().id(1).name("Site").tutors(tutors).build());
List<SelectOption<Long>> result = resources.target("/site/1/tutors").request().get(new GenericType<List<SelectOption<Long>>>() {
});
assertNotNull(result);
assertEquals(2, result.size());
}
}

View File

@ -1,68 +0,0 @@
package uk.co.neviyn.observations.resources;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
import io.dropwizard.testing.junit.ResourceTestRule;
import org.junit.After;
import org.junit.ClassRule;
import org.junit.Test;
import uk.co.neviyn.observations.auth.SimpleAuthenticator;
import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.Tutor;
import uk.co.neviyn.observations.core.User;
import uk.co.neviyn.observations.dao.SiteDao;
import uk.co.neviyn.observations.dao.TutorDao;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.GenericType;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
public class TutorResourceTest {
private static final TutorDao dao = mock(TutorDao.class);
private static final SiteDao siteDao = mock(SiteDao.class);
private final String httpAuth = "Basic dGVzdDpURVNUUFc=";
@ClassRule
public static final ResourceTestRule resources = ResourceTestRule.builder()
.addResource(new AuthDynamicFeature(
new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new SimpleAuthenticator("TESTPW"))
.setRealm("SECURITY")
.buildAuthFilter()
))
.addProvider(new AuthValueFactoryProvider.Binder<>(User.class))
.addResource(new TutorResource(dao, siteDao))
.build();
@After
public void tearDown() {
reset(dao);
reset(siteDao);
}
@Test
public void add() {
final Site testSite = Site.builder().id(1).name("Test Site").tutors(new HashSet<>()).build();
when(siteDao.get(1)).thenReturn(testSite);
resources.target("/tutor").request().header("Authorization", httpAuth).post(Entity.json(new TutorResource.NewTutor(1, "Mr X")));
verify(dao, times(1)).persist(Tutor.builder().name("Mr X").site(testSite).build());
}
@Test
public void allTutors() {
List<Tutor> tutors = Arrays.asList(Tutor.builder().id(1).name("Mr A").build(), Tutor.builder().id(2).name("Mr B").build());
when(dao.listAll()).thenReturn(tutors);
List<Tutor> result = resources.target("/tutor/all").request().get(new GenericType<List<Tutor>>() {
});
for (Tutor t : result) {
assertTrue(tutors.contains(t));
}
}
}

View File

@ -0,0 +1,16 @@
package uk.co.neviyn.observationdatabase
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner
@RunWith(SpringRunner::class)
@SpringBootTest
class ObservationdatabaseApplicationTests {
@Test
fun contextLoads() {
}
}

View File

@ -1,13 +0,0 @@
{
"siteId":1,
"tutorIds":[1,2,3],
"observed":"A random thing made for testing.",
"whom": "Group A",
"type":"INITIAL",
"monitoring":1,
"control":2,
"conservatism":3,
"teamwork":4,
"knowledge":5,
"rawData":[{"type":"MONITORING","rating":5,"strengths":"some","improvements":"another sum"}]
}

View File

@ -1,18 +0,0 @@
{
"id":0,
"observed":"Just a test observation",
"whom": "Group A",
"type":"INITIAL",
"monitoring":1,
"control":2,
"conservatism":3,
"teamwork":4,
"knowledge":5,
"observations":[{
"type": "MONITORING",
"rating":5,
"strengths":"some",
"improvements":"another sum"
}],
"date":"2018-09-18T00:00:00.000Z"
}

View File

@ -92,7 +92,7 @@ export default {
mounted() {
this.resetStore();
Vue.axios
.get("/site/all")
.get("/site")
.then(response => {
this.siteOptions = response.data;
this.loaded = true;

View File

@ -40,10 +40,10 @@ export default {
var form = document.getElementById("submission-form");
if (form.checkValidity()) {
Vue.axios
.post("/site", this.siteName)
.post("/site", { 'name':this.siteName })
.then(response => {
this.alertVariant = "success";
this.alertText = "Successfully added " + response.data.name;
this.alertText = "Successfully added " + response.data.text;
this.showAlert();
})
.catch(error => {

View File

@ -38,7 +38,7 @@ export default {
},
mounted() {
Vue.axios
.get("/site/all")
.get("/site")
.then(response => {
this.siteOptions = response.data;
})
@ -67,12 +67,12 @@ export default {
if (form.checkValidity()) {
Vue.axios
.post("/tutor", {
siteId: this.siteSelection,
name: this.tutorName
'siteId': this.siteSelection,
'name': this.tutorName
})
.then(response => {
this.alertVariant = "success";
this.alertText = "Successfully added " + response.data.name;
this.alertText = "Successfully added " + response.data.text;
this.showAlert();
})
.catch(error => {

View File

@ -199,17 +199,12 @@ export default {
if (form.checkValidity()) {
Vue.axios
.post("/observation", {
siteId: this.site,
tutorIds: this.tutors,
site: this.site,
tutors: this.tutors,
observed: this.description,
whom: this.whom,
type: this.type,
monitoring: this.totals[0],
control: this.totals[1],
conservatism: this.totals[2],
teamwork: this.totals[3],
knowledge: this.totals[4],
rawData: JSON.parse(JSON.stringify(this.observations))
entries: JSON.parse(JSON.stringify(this.observations))
})
.then(function(response) {
console.log(response);

View File

@ -103,14 +103,12 @@ export default {
methods: {
getFilteredAverage: function() {
Vue.axios
.get("/observation/average", {
params: {
.get("/observations/chartdata", {
site: this.siteSelection,
tutor: this.tutorSelection,
startDate: moment(this.startDate).format("YYYY-MM-DD"),
endDate: moment(this.endDate).format("YYYY-MM-DD"),
whom: this.whom
}
})
.then(response => {
this.chartData = response.data;

View File

@ -26,22 +26,31 @@
</b-col>
</b-row>
<b-container v-if="observationData != null">
<b-row v-for="(observation, index) in observationData" v-bind:key="index">
<b-col cols="3">
<p>Category: {{ observation.type }}</p>
<p>Rating: {{ observation.rating }}</p>
</b-col>
<b-col>
<b-form-group label="Strengths">
<b-form-textarea :value="item.strengths" readonly>
</b-form-textarea>
</b-form-group>
<b-form-group label="Areas of Improvement">
<b-form-textarea :value="item.improvements" readonly>
</b-form-textarea>
</b-form-group>
</b-col>
</b-row>
<b-container v-for="(observation, index) in observationData" v-bind:key="index">
<b-row>
<b-col>
<p>{{ observation.date }}-{{ observation.type }}/{{ observation.observed }}-{{ obsevation.whom }}</p>
</b-col>
</b-row>
<b-row v-for="(entry, index) in observation.observations" v-bind:key="index">
<b-row>
<b-col cols="3">
<p>{{ entry.type }}</p>
<p>{{ entry.rating }}</p>
</b-col>
<b-col>
<b-form-group label="Strengths">
<b-form-textarea :value="entry.strengths" readonly>
</b-form-textarea>
</b-form-group>
<b-form-group label="Areas of Improvement">
<b-form-textarea :value="entry.improvements" readonly>
</b-form-textarea>
</b-form-group>
</b-col>
</b-row>
</b-row>
</b-container>
</b-container>
</b-container>
</template>
@ -78,14 +87,12 @@ export default {
methods: {
getFiltered: function() {
Vue.axios
.get("/observation", {
params: {
.get("/observations", {
site: this.siteSelection,
tutor: this.tutorSelection,
startDate: moment(this.startDate).format("YYYY-MM-DD"),
endDate: moment(this.endDate).format("YYYY-MM-DD"),
whom: this.whom
}
})
.then(response => {
this.chartData = response.data;
@ -96,12 +103,12 @@ export default {
this.$refs.errorModal.show();
});
},
changeStartDate: function(e) {
this.startDate = e.date;
},
changeEndDate: function(e) {
this.endDate = e.date;
}
changeStartDate: function(e) {
this.startDate = e.date;
},
changeEndDate: function(e) {
this.endDate = e.date;
}
}
};
</script>