Converted to Hibernate.
This commit is contained in:
parent
7cbd354c38
commit
b4ca1a8fc7
@ -32,7 +32,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.dropwizard</groupId>
|
<groupId>io.dropwizard</groupId>
|
||||||
<artifactId>dropwizard-jdbi3</artifactId>
|
<artifactId>dropwizard-hibernate</artifactId>
|
||||||
<version>${dropwizard.version}</version>
|
<version>${dropwizard.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -2,11 +2,14 @@ package uk.co.neviyn.Observations;
|
|||||||
|
|
||||||
import io.dropwizard.Application;
|
import io.dropwizard.Application;
|
||||||
import io.dropwizard.assets.AssetsBundle;
|
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.jersey.setup.JerseyEnvironment;
|
||||||
import io.dropwizard.setup.Bootstrap;
|
import io.dropwizard.setup.Bootstrap;
|
||||||
import io.dropwizard.setup.Environment;
|
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.ObservationDao;
|
||||||
import uk.co.neviyn.Observations.dao.SiteDao;
|
import uk.co.neviyn.Observations.dao.SiteDao;
|
||||||
import uk.co.neviyn.Observations.dao.TutorDao;
|
import uk.co.neviyn.Observations.dao.TutorDao;
|
||||||
@ -16,6 +19,18 @@ import uk.co.neviyn.Observations.resources.SiteResource;
|
|||||||
|
|
||||||
public class ObservationsApplication extends Application<ObservationsConfiguration> {
|
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 {
|
public static void main(String[] args) throws Exception {
|
||||||
new ObservationsApplication().run(args);
|
new ObservationsApplication().run(args);
|
||||||
}
|
}
|
||||||
@ -23,27 +38,22 @@ public class ObservationsApplication extends Application<ObservationsConfigurati
|
|||||||
@Override
|
@Override
|
||||||
public void initialize(Bootstrap<ObservationsConfiguration> bootstrap) {
|
public void initialize(Bootstrap<ObservationsConfiguration> bootstrap) {
|
||||||
super.initialize(bootstrap);
|
super.initialize(bootstrap);
|
||||||
|
bootstrap.addBundle(hibernate);
|
||||||
bootstrap.addBundle(new AssetsBundle("/assets/", "/", "/index.html"));
|
bootstrap.addBundle(new AssetsBundle("/assets/", "/", "/index.html"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ObservationsConfiguration observationsConfiguration, Environment environment) {
|
public void run(ObservationsConfiguration observationsConfiguration, Environment environment) {
|
||||||
final JerseyEnvironment jersey = environment.jersey();
|
final JerseyEnvironment jersey = environment.jersey();
|
||||||
final JdbiFactory factory = new JdbiFactory();
|
TutorDao tutorDao = new TutorDao(hibernate.getSessionFactory());
|
||||||
final Jdbi jdbi = factory.build(environment, observationsConfiguration.getDataSourceFactory(), "database");
|
SiteDao siteDao = new SiteDao(hibernate.getSessionFactory());
|
||||||
TutorDao tutorDao = jdbi.onDemand(TutorDao.class);
|
ObservationDao observationDao = new ObservationDao(hibernate.getSessionFactory());
|
||||||
SiteDao siteDao = jdbi.onDemand(SiteDao.class);
|
|
||||||
ObservationDao observationDao = jdbi.onDemand(ObservationDao.class);
|
|
||||||
jersey.register(tutorDao);
|
jersey.register(tutorDao);
|
||||||
jersey.register(siteDao);
|
jersey.register(siteDao);
|
||||||
jersey.register(observationDao);
|
jersey.register(observationDao);
|
||||||
siteDao.createSiteTable();
|
|
||||||
tutorDao.createTutorTable();
|
|
||||||
observationDao.createObservationTable();
|
|
||||||
observationDao.createObservationTutorTable();
|
|
||||||
final TutorResource tutorResource = new TutorResource(tutorDao);
|
final TutorResource tutorResource = new TutorResource(tutorDao);
|
||||||
jersey.register(tutorResource);
|
jersey.register(tutorResource);
|
||||||
final ObservationResource observationResource = new ObservationResource(observationDao);
|
final ObservationResource observationResource = new ObservationResource(observationDao, tutorDao, siteDao);
|
||||||
jersey.register(observationResource);
|
jersey.register(observationResource);
|
||||||
final SiteResource siteResource = new SiteResource(siteDao);
|
final SiteResource siteResource = new SiteResource(siteDao);
|
||||||
jersey.register(siteResource);
|
jersey.register(siteResource);
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
package uk.co.neviyn.Observations.api;
|
package uk.co.neviyn.Observations.api;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jdbi.v3.core.mapper.RowMapper;
|
|
||||||
import org.jdbi.v3.core.statement.StatementContext;
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ -18,16 +14,9 @@ public class AverageStats {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private float monitoring, control, conservatism, teamwork, knowledge;
|
private double monitoring, control, conservatism, teamwork, knowledge;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private LocalDate date;
|
private LocalDate date;
|
||||||
|
|
||||||
public static class Mapper implements RowMapper<AverageStats> {
|
|
||||||
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")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class AverageStatsChartJs {
|
|||||||
private List<Dataset> datasets = new ArrayList<>();
|
private List<Dataset> datasets = new ArrayList<>();
|
||||||
|
|
||||||
public AverageStatsChartJs(List<AverageStats> inputData){
|
public AverageStatsChartJs(List<AverageStats> inputData){
|
||||||
List<Float> monitoring = new ArrayList<>(),
|
List<Double> monitoring = new ArrayList<>(),
|
||||||
control = new ArrayList<>(),
|
control = new ArrayList<>(),
|
||||||
conservatism = new ArrayList<>(),
|
conservatism = new ArrayList<>(),
|
||||||
teamwork = new ArrayList<>(),
|
teamwork = new ArrayList<>(),
|
||||||
@ -54,6 +54,6 @@ public class AverageStatsChartJs {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private final List<Float> data;
|
private final List<Double> data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
import uk.co.neviyn.Observations.core.ObservationEntry;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -12,11 +13,11 @@ public class NewObservation {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private int siteId;
|
private long siteId;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private List<Integer> tutorIds;
|
private List<Long> tutorIds;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
@ -28,6 +29,6 @@ public class NewObservation {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String rawData;
|
private List<ObservationEntry> rawData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -2,30 +2,30 @@ package uk.co.neviyn.Observations.core;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
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.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import lombok.*;
|
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 org.joda.time.DateTime;
|
||||||
import uk.co.neviyn.Observations.api.ObservationEntry;
|
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Entity
|
||||||
|
@Table(name = "OBSERVATION")
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
public class Observation {
|
public class Observation extends BaseEntity{
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private int id;
|
@ManyToOne
|
||||||
|
@JoinColumn(name="site_id", nullable=false)
|
||||||
|
private Site site;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private int siteId;
|
@ManyToMany(mappedBy = "observations")
|
||||||
|
private Set<Tutor> tutors;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
@ -41,49 +41,9 @@ public class Observation {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private List<ObservationEntry> rawData;
|
private List<ObservationEntry> observations;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private DateTime date;
|
private DateTime date;
|
||||||
|
|
||||||
public Observation(int siteId, String observed, int monitoring, int control, int conservatism, int teamwork,
|
|
||||||
int knowledge, List<ObservationEntry> 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<Observation> {
|
|
||||||
|
|
||||||
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")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
package uk.co.neviyn.Observations.api;
|
package uk.co.neviyn.Observations.core;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.*;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class ObservationEntry {
|
@AllArgsConstructor
|
||||||
|
public class ObservationEntry extends BaseEntity{
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
@ -1,32 +1,33 @@
|
|||||||
package uk.co.neviyn.Observations.core;
|
package uk.co.neviyn.Observations.core;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import java.sql.ResultSet;
|
import java.util.Set;
|
||||||
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.*;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Entity
|
||||||
|
@Table(name = "SITE")
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor(access = AccessLevel.PROTECTED)
|
public class Site extends BaseEntity {
|
||||||
public class Site {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonProperty
|
|
||||||
private int id;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
public static class Mapper implements RowMapper<Site> {
|
@JsonProperty
|
||||||
public Site map(ResultSet rs, StatementContext ctx) throws SQLException {
|
@OneToMany(mappedBy="site")
|
||||||
return new Site(rs.getInt("id"), rs.getString("name"));
|
private Set<Tutor> tutors;
|
||||||
}
|
|
||||||
|
@JsonProperty
|
||||||
|
@OneToMany(mappedBy = "site")
|
||||||
|
private Set<Observation> observations;
|
||||||
|
|
||||||
|
public Site(long id, String name) {
|
||||||
|
super(id);
|
||||||
|
this.name = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,38 @@
|
|||||||
package uk.co.neviyn.Observations.core;
|
package uk.co.neviyn.Observations.core;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import java.sql.ResultSet;
|
import lombok.*;
|
||||||
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 javax.persistence.*;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Entity
|
||||||
|
@Table(name = "TUTOR")
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor(access = AccessLevel.PROTECTED)
|
public class Tutor extends BaseEntity {
|
||||||
public class Tutor {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonProperty
|
|
||||||
private int id;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private int site;
|
@ManyToOne
|
||||||
|
@JoinColumn(name="site_id", nullable=false)
|
||||||
|
private Site site;
|
||||||
|
|
||||||
public static class Mapper implements RowMapper<Tutor>{
|
@JsonProperty
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "TUTOR_OBSERVATION",
|
||||||
|
joinColumns = { @JoinColumn(name = "tutor_id")},
|
||||||
|
inverseJoinColumns = { @JoinColumn(name = "observation_id")}
|
||||||
|
)
|
||||||
|
private Set<Observation> observations;
|
||||||
|
|
||||||
public Tutor map(ResultSet rs, StatementContext ctx) throws SQLException {
|
public Tutor(long id, String name) {
|
||||||
return new Tutor(rs.getInt("id"), rs.getString("name"), rs.getInt("site"));
|
super(id);
|
||||||
}
|
this.name = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,59 +1,40 @@
|
|||||||
package uk.co.neviyn.Observations.dao;
|
package uk.co.neviyn.Observations.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import io.dropwizard.hibernate.AbstractDAO;
|
||||||
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
|
import org.hibernate.SessionFactory;
|
||||||
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 uk.co.neviyn.Observations.api.AverageStats;
|
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.Observation;
|
||||||
|
import uk.co.neviyn.Observations.core.Site;
|
||||||
|
|
||||||
@RegisterRowMapper(Observation.Mapper.class)
|
import java.util.List;
|
||||||
public interface ObservationDao {
|
|
||||||
|
|
||||||
@SqlUpdate("CREATE TABLE IF NOT EXISTS observations (id INTEGER PRIMARY KEY, siteId INTEGER, " +
|
public class ObservationDao extends AbstractDAO<Observation> {
|
||||||
"observed TEXT, type TEXT, monitoring INTEGER, control INTEGER, conservatism INTEGER, teamwork INTEGER, " +
|
public ObservationDao(SessionFactory sessionFactory) {
|
||||||
"knowledge INTEGER, rawData BLOB, date DATE)")
|
super(sessionFactory);
|
||||||
void createObservationTable();
|
}
|
||||||
|
|
||||||
@SqlUpdate("CREATE TABLE IF NOT EXISTS observation_tutor (tutorId INT NOT NULL, observationId INT NOT NULL, " +
|
public Observation get(long id){
|
||||||
"FOREIGN KEY (tutorID) REFERENCES tutor(id), FOREIGN KEY (observationId) REFERENCES observations(id))")
|
return super.get(id);
|
||||||
void createObservationTutorTable();
|
}
|
||||||
|
|
||||||
@SqlUpdate("INSERT INTO observations (siteId, observed, type, monitoring, control, conservatism, teamwork, knowledge, " +
|
public Observation persist(Observation observation){
|
||||||
"rawData, date) VALUES (:siteId, :observed, :type, :monitoring, :control, :conservatism, :teamwork, :knowledge, " +
|
return super.persist(observation);
|
||||||
":serializeRawData, :date)")
|
}
|
||||||
@GetGeneratedKeys
|
|
||||||
int addObservation(@BindBean NewObservation observation, @Bind("date") DateTime date);
|
|
||||||
|
|
||||||
@SqlUpdate("INSERT INTO observation_tutor (tutorId, observationId) VALUES (:tutorId, :observationId)")
|
public List<Observation> listAll(){
|
||||||
void addObservationTutor(@Bind("observationId")int observationId, @Bind("tutorId")int tutorId);
|
return list(criteriaQuery());
|
||||||
|
}
|
||||||
|
|
||||||
@SqlQuery("SELECT * FROM observations WHERE date BETWEEN :startDate AND :endDate")
|
public List<AverageStats> averageStatsForAll(){
|
||||||
List<Observation> observationsBetweenDates(@Bind("startDate")DateTime startDate, @Bind("endDate")DateTime endDate);
|
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 " +
|
public List<AverageStats> averageStatsForSite(Site site){
|
||||||
"LEFT JOIN tutor ON observation_tutor.tutorId = tutor.id WHERE tutor.id = :tutorId")
|
final String hql = "select avg(observation.monitoring), avg(observation.control), avg(observation.conservatism), " +
|
||||||
List<Observation> observationsByTutor(@Bind("tutorId")int tutorId);
|
"avg(observation.teamwork), avg(observation.knowledge) from observation where observation.site = :site " +
|
||||||
|
"group by observation.date";
|
||||||
@SqlQuery("SELECT * FROM observations WHERE date BETWEEN :startDate AND :endDate " +
|
return currentSession().createQuery(hql, AverageStats.class).setParameter("site", site).list();
|
||||||
"LEFT JOIN observation_tutor ON observation_tutor.observationId = observations.id " +
|
}
|
||||||
"LEFT JOIN tutor ON observation_tutor.tutorId = tutor.id WHERE tutor.id = :tutorId")
|
|
||||||
List<Observation> 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<AverageStats> averageObservationScoresByDay();
|
|
||||||
|
|
||||||
@SqlQuery("SELECT MIN(date) FROM observations")
|
|
||||||
DateTime earliestEntryDate();
|
|
||||||
|
|
||||||
@SqlQuery("SELECT MAX(date) FROM observations")
|
|
||||||
DateTime latestEntryDate();
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
package uk.co.neviyn.Observations.dao;
|
package uk.co.neviyn.Observations.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import io.dropwizard.hibernate.AbstractDAO;
|
||||||
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
|
import org.hibernate.SessionFactory;
|
||||||
import org.jdbi.v3.sqlobject.customizer.Bind;
|
|
||||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
|
||||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
|
||||||
import uk.co.neviyn.Observations.core.Site;
|
import uk.co.neviyn.Observations.core.Site;
|
||||||
|
|
||||||
@RegisterRowMapper(Site.Mapper.class)
|
import java.util.List;
|
||||||
public interface SiteDao {
|
|
||||||
|
|
||||||
@SqlUpdate("CREATE TABLE IF NOT EXISTS site (id INTEGER PRIMARY KEY, name VARCHAR(100))")
|
public class SiteDao extends AbstractDAO<Site> {
|
||||||
void createSiteTable();
|
public SiteDao(SessionFactory sessionFactory) {
|
||||||
|
super(sessionFactory);
|
||||||
|
}
|
||||||
|
|
||||||
@SqlQuery("SELECT * FROM site")
|
public List<Site> listAll(){
|
||||||
List<Site> allSites();
|
return list(criteriaQuery());
|
||||||
|
}
|
||||||
|
|
||||||
@SqlQuery("SELECT * FROM site WHERE id = :id")
|
public Site get(long id){
|
||||||
Site getSiteById(@Bind("id") int id);
|
return super.get(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,21 @@
|
|||||||
package uk.co.neviyn.Observations.dao;
|
package uk.co.neviyn.Observations.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import io.dropwizard.hibernate.AbstractDAO;
|
||||||
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
|
import org.hibernate.SessionFactory;
|
||||||
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 uk.co.neviyn.Observations.core.Tutor;
|
import uk.co.neviyn.Observations.core.Tutor;
|
||||||
|
|
||||||
@RegisterRowMapper(Tutor.Mapper.class)
|
import java.util.List;
|
||||||
public interface TutorDao {
|
|
||||||
|
|
||||||
@SqlUpdate("CREATE TABLE IF NOT EXISTS tutor (id INTEGER PRIMARY KEY, " +
|
public class TutorDao extends AbstractDAO<Tutor> {
|
||||||
"name VARCHAR(100), site INT, FOREIGN KEY (site) REFERENCES site(id))")
|
public TutorDao(SessionFactory sessionFactory) {
|
||||||
void createTutorTable();
|
super(sessionFactory);
|
||||||
|
}
|
||||||
|
|
||||||
@SqlUpdate("INSERT INTO tutor(name, site) VALUES (:name, :site)")
|
public Tutor get(long id){
|
||||||
@GetGeneratedKeys("id")
|
return super.get(id);
|
||||||
int add(@BindBean Tutor tutor);
|
}
|
||||||
|
|
||||||
@SqlQuery("SELECT * FROM tutor WHERE site = :siteId")
|
|
||||||
List<Tutor> tutorsForSite(@Bind("siteId")int siteId);
|
|
||||||
|
|
||||||
@SqlQuery("SELECT * FROM tutor")
|
|
||||||
List<Tutor> allTutors();
|
|
||||||
|
|
||||||
|
public List<Tutor> listAll(){
|
||||||
|
return list(criteriaQuery());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package uk.co.neviyn.Observations.resources;
|
package uk.co.neviyn.Observations.resources;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
@ -10,6 +13,8 @@ import javax.ws.rs.Path;
|
|||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import io.dropwizard.hibernate.UnitOfWork;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.joda.time.DateTime;
|
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.AverageStatsChartJs;
|
||||||
import uk.co.neviyn.Observations.api.NewObservation;
|
import uk.co.neviyn.Observations.api.NewObservation;
|
||||||
import uk.co.neviyn.Observations.core.Observation;
|
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.ObservationDao;
|
||||||
|
import uk.co.neviyn.Observations.dao.SiteDao;
|
||||||
|
import uk.co.neviyn.Observations.dao.TutorDao;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@ -28,32 +38,44 @@ import uk.co.neviyn.Observations.dao.ObservationDao;
|
|||||||
public class ObservationResource {
|
public class ObservationResource {
|
||||||
|
|
||||||
private final ObservationDao dao;
|
private final ObservationDao dao;
|
||||||
|
private final TutorDao tutorDao;
|
||||||
|
private final SiteDao siteDao;
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
public int add(@NotNull @Valid NewObservation observation){
|
@UnitOfWork
|
||||||
final int observationId = dao.addObservation(observation, LocalDate.now().toDateTimeAtStartOfDay());
|
public long add(@NotNull @Valid NewObservation newObservation){
|
||||||
log.info("Created observation with ID " + observationId + " at " + DateTime.now().toString());
|
final DateTime submissionDate = LocalDate.now().toDateTimeAtStartOfDay();
|
||||||
for(int tutorId: observation.getTutorIds()){
|
Set<Tutor> tutors = new HashSet<>();
|
||||||
dao.addObservationTutor(observationId, tutorId);
|
for(long l: newObservation.getTutorIds()){
|
||||||
|
tutors.add(tutorDao.get(l));
|
||||||
}
|
}
|
||||||
return observationId;
|
final Site site = siteDao.get(newObservation.getSiteId());
|
||||||
}
|
Observation observation = new Observation();
|
||||||
|
observation.setSite(site);
|
||||||
@Path("/by/{tutorId}")
|
observation.setTutors(tutors);
|
||||||
@GET
|
observation.setObserved(newObservation.getObserved());
|
||||||
public List<Observation> observationsBy(@PathParam("tutorId") int tutorId){
|
observation.setType(TrainingType.valueOf(newObservation.getType()));
|
||||||
return dao.observationsByTutor(tutorId);
|
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")
|
@Path("/average/all")
|
||||||
@GET
|
@GET
|
||||||
public List<AverageStats> averageObservationScores(){
|
public List<AverageStats> averageObservationScores(){
|
||||||
return dao.averageObservationScoresByDay();
|
return dao.averageStatsForAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("/average/all/chartjs")
|
@Path("/average/all/chartjs")
|
||||||
@GET
|
@GET
|
||||||
public AverageStatsChartJs averageStatsChartJs(){
|
public AverageStatsChartJs averageStatsChartJs(){
|
||||||
return new AverageStatsChartJs(dao.averageObservationScoresByDay());
|
return new AverageStatsChartJs(dao.averageStatsForAll());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package uk.co.neviyn.Observations.resources;
|
package uk.co.neviyn.Observations.resources;
|
||||||
|
|
||||||
|
import io.dropwizard.hibernate.UnitOfWork;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import uk.co.neviyn.Observations.api.SelectOption;
|
import uk.co.neviyn.Observations.api.SelectOption;
|
||||||
|
import uk.co.neviyn.Observations.core.Tutor;
|
||||||
import uk.co.neviyn.Observations.dao.SiteDao;
|
import uk.co.neviyn.Observations.dao.SiteDao;
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
@ -9,6 +11,7 @@ import javax.ws.rs.Path;
|
|||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -20,7 +23,15 @@ public class SiteResource {
|
|||||||
|
|
||||||
@Path("/all")
|
@Path("/all")
|
||||||
@GET
|
@GET
|
||||||
public List<SelectOption<Integer>> allSites() {
|
@UnitOfWork
|
||||||
return dao.allSites().stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList());
|
public List<SelectOption<Long>> allSites() {
|
||||||
|
return dao.listAll().stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/{id}/tutors")
|
||||||
|
@GET
|
||||||
|
@UnitOfWork
|
||||||
|
public Set<Tutor> getSiteTutors(long id){
|
||||||
|
return dao.get(id).getTutors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ import javax.ws.rs.Produces;
|
|||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import io.dropwizard.hibernate.UnitOfWork;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import uk.co.neviyn.Observations.api.SelectOption;
|
import uk.co.neviyn.Observations.api.SelectOption;
|
||||||
import uk.co.neviyn.Observations.core.Tutor;
|
import uk.co.neviyn.Observations.core.Tutor;
|
||||||
@ -23,20 +25,11 @@ public class TutorResource {
|
|||||||
|
|
||||||
@Path("/all")
|
@Path("/all")
|
||||||
@GET
|
@GET
|
||||||
|
@UnitOfWork
|
||||||
public List<Tutor> allTutors() {
|
public List<Tutor> allTutors() {
|
||||||
List<Tutor> tutors = dao.allTutors();
|
List<Tutor> tutors = dao.listAll();
|
||||||
if (tutors != null && !tutors.isEmpty())
|
if (tutors != null && !tutors.isEmpty())
|
||||||
return tutors;
|
return tutors;
|
||||||
throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND);
|
throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("/site/{id}")
|
|
||||||
@GET
|
|
||||||
public List<SelectOption<Integer>> tutorsForSite(@PathParam("id") int siteId) {
|
|
||||||
List<Tutor> 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@ package uk.co.neviyn.Observations.api;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import io.dropwizard.jackson.Jackson;
|
import io.dropwizard.jackson.Jackson;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import uk.co.neviyn.Observations.core.ObservationEntry;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import static io.dropwizard.testing.FixtureHelpers.fixture;
|
import static io.dropwizard.testing.FixtureHelpers.fixture;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
@ -13,8 +15,8 @@ public class NewObservationTest {
|
|||||||
|
|
||||||
private static final ObjectMapper mapper = Jackson.newObjectMapper();
|
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.",
|
private final NewObservation newObservation = new NewObservation(1, Arrays.asList(1L, 2L, 3L), "A random thing made for testing.",
|
||||||
"INITIAL", 1, 2, 3, 4, 5, "{\"data\":\"Looks like there's nothing here.\"}");
|
"INITIAL", 1, 2, 3, 4, 5, Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum")));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void serializesToJson() throws Exception {
|
public void serializesToJson() throws Exception {
|
||||||
|
@ -5,7 +5,6 @@ import io.dropwizard.jackson.Jackson;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import uk.co.neviyn.Observations.api.ObservationEntry;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ import static org.junit.Assert.*;
|
|||||||
public class ObservationTest {
|
public class ObservationTest {
|
||||||
private static final ObjectMapper mapper = Jackson.newObjectMapper();
|
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")
|
4, 5, Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum")), DateTime.parse("2018-09-18T00:00:00.000Z")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -8,5 +8,5 @@
|
|||||||
"conservatism":3,
|
"conservatism":3,
|
||||||
"teamwork":4,
|
"teamwork":4,
|
||||||
"knowledge":5,
|
"knowledge":5,
|
||||||
"rawData":"{\"data\":\"Looks like there's nothing here.\"}"
|
"rawData":[{"type":"MONITORING","rating":5,"strengths":"some","improvements":"another sum"}]
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"id":1,
|
"id":0,
|
||||||
"siteId":1,
|
|
||||||
"observed":"Just a test observation",
|
"observed":"Just a test observation",
|
||||||
"type":"INITIAL",
|
"type":"INITIAL",
|
||||||
"monitoring":1,
|
"monitoring":1,
|
||||||
@ -8,7 +7,7 @@
|
|||||||
"conservatism":3,
|
"conservatism":3,
|
||||||
"teamwork":4,
|
"teamwork":4,
|
||||||
"knowledge":5,
|
"knowledge":5,
|
||||||
"rawData":[{
|
"observations":[{
|
||||||
"type": "MONITORING",
|
"type": "MONITORING",
|
||||||
"rating":5,
|
"rating":5,
|
||||||
"strengths":"some",
|
"strengths":"some",
|
||||||
|
@ -76,7 +76,7 @@ export default {
|
|||||||
...mapMutations(["setSite", "setDescription", "setType", "setTutors"]),
|
...mapMutations(["setSite", "setDescription", "setType", "setTutors"]),
|
||||||
getTutors: function() {
|
getTutors: function() {
|
||||||
if (this.site != null) {
|
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.tutorOptions = response.data;
|
||||||
this.loadingTutors = false;
|
this.loadingTutors = false;
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user