Added improved submission model.
This commit is contained in:
parent
184491b9ea
commit
080c44c467
|
@ -6,6 +6,8 @@ import nl.andrewlalis.gymboard_api.domains.api.dto.ExerciseSubmissionResponse;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.dto.GymResponse;
|
import nl.andrewlalis.gymboard_api.domains.api.dto.GymResponse;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.service.GymService;
|
import nl.andrewlalis.gymboard_api.domains.api.service.GymService;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.service.submission.ExerciseSubmissionService;
|
import nl.andrewlalis.gymboard_api.domains.api.service.submission.ExerciseSubmissionService;
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.auth.model.User;
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -37,8 +39,9 @@ public class GymController {
|
||||||
@PostMapping(path = "/submissions")
|
@PostMapping(path = "/submissions")
|
||||||
public ExerciseSubmissionResponse createSubmission(
|
public ExerciseSubmissionResponse createSubmission(
|
||||||
@PathVariable String compoundId,
|
@PathVariable String compoundId,
|
||||||
|
@AuthenticationPrincipal User user,
|
||||||
@RequestBody ExerciseSubmissionPayload payload
|
@RequestBody ExerciseSubmissionPayload payload
|
||||||
) {
|
) {
|
||||||
return submissionService.createSubmission(CompoundGymId.parse(compoundId), payload);
|
return submissionService.createSubmission(CompoundGymId.parse(compoundId), user.getId(), payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package nl.andrewlalis.gymboard_api.domains.api.dto;
|
package nl.andrewlalis.gymboard_api.domains.api.dto;
|
||||||
|
|
||||||
public record ExerciseSubmissionPayload(
|
public record ExerciseSubmissionPayload(
|
||||||
String name,
|
|
||||||
String exerciseShortName,
|
String exerciseShortName,
|
||||||
float weight,
|
float weight,
|
||||||
String weightUnit,
|
String weightUnit,
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
package nl.andrewlalis.gymboard_api.domains.api.dto;
|
package nl.andrewlalis.gymboard_api.domains.api.dto;
|
||||||
|
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.model.exercise.ExerciseSubmission;
|
import nl.andrewlalis.gymboard_api.domains.api.model.exercise.ExerciseSubmission;
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.auth.dto.UserResponse;
|
||||||
import nl.andrewlalis.gymboard_api.util.StandardDateFormatter;
|
import nl.andrewlalis.gymboard_api.util.StandardDateFormatter;
|
||||||
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
public record ExerciseSubmissionResponse(
|
public record ExerciseSubmissionResponse(
|
||||||
String id,
|
String id,
|
||||||
String createdAt,
|
String createdAt,
|
||||||
GymSimpleResponse gym,
|
GymSimpleResponse gym,
|
||||||
ExerciseResponse exercise,
|
ExerciseResponse exercise,
|
||||||
|
UserResponse user,
|
||||||
|
String performedAt,
|
||||||
String videoFileId,
|
String videoFileId,
|
||||||
String submitterName,
|
|
||||||
double rawWeight,
|
double rawWeight,
|
||||||
String weightUnit,
|
String weightUnit,
|
||||||
double metricWeight,
|
double metricWeight,
|
||||||
|
@ -23,8 +23,9 @@ public record ExerciseSubmissionResponse(
|
||||||
StandardDateFormatter.format(submission.getCreatedAt()),
|
StandardDateFormatter.format(submission.getCreatedAt()),
|
||||||
new GymSimpleResponse(submission.getGym()),
|
new GymSimpleResponse(submission.getGym()),
|
||||||
new ExerciseResponse(submission.getExercise()),
|
new ExerciseResponse(submission.getExercise()),
|
||||||
|
new UserResponse(submission.getUser()),
|
||||||
|
StandardDateFormatter.format(submission.getPerformedAt()),
|
||||||
submission.getVideoFileId(),
|
submission.getVideoFileId(),
|
||||||
submission.getSubmitterName(),
|
|
||||||
submission.getRawWeight().doubleValue(),
|
submission.getRawWeight().doubleValue(),
|
||||||
submission.getWeightUnit().name(),
|
submission.getWeightUnit().name(),
|
||||||
submission.getMetricWeight().doubleValue(),
|
submission.getMetricWeight().doubleValue(),
|
||||||
|
|
|
@ -3,9 +3,11 @@ package nl.andrewlalis.gymboard_api.domains.api.model.exercise;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.model.Gym;
|
import nl.andrewlalis.gymboard_api.domains.api.model.Gym;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.model.WeightUnit;
|
import nl.andrewlalis.gymboard_api.domains.api.model.WeightUnit;
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.auth.model.User;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
|
@ -24,6 +26,12 @@ public class ExerciseSubmission {
|
||||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||||
private Exercise exercise;
|
private Exercise exercise;
|
||||||
|
|
||||||
|
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private LocalDateTime performedAt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the video file that was submitted for this submission. It lives
|
* The id of the video file that was submitted for this submission. It lives
|
||||||
* on the <em>gymboard-cdn</em> service as a stored file, which can be
|
* on the <em>gymboard-cdn</em> service as a stored file, which can be
|
||||||
|
@ -32,9 +40,6 @@ public class ExerciseSubmission {
|
||||||
@Column(nullable = false, updatable = false, length = 26)
|
@Column(nullable = false, updatable = false, length = 26)
|
||||||
private String videoFileId;
|
private String videoFileId;
|
||||||
|
|
||||||
@Column(nullable = false, updatable = false, length = 63)
|
|
||||||
private String submitterName;
|
|
||||||
|
|
||||||
@Column(nullable = false, precision = 7, scale = 2)
|
@Column(nullable = false, precision = 7, scale = 2)
|
||||||
private BigDecimal rawWeight;
|
private BigDecimal rawWeight;
|
||||||
|
|
||||||
|
@ -50,12 +55,13 @@ public class ExerciseSubmission {
|
||||||
|
|
||||||
public ExerciseSubmission() {}
|
public ExerciseSubmission() {}
|
||||||
|
|
||||||
public ExerciseSubmission(String id, Gym gym, Exercise exercise, String videoFileId, String submitterName, BigDecimal rawWeight, WeightUnit unit, BigDecimal metricWeight, int reps) {
|
public ExerciseSubmission(String id, Gym gym, Exercise exercise, User user, LocalDateTime performedAt, String videoFileId, BigDecimal rawWeight, WeightUnit unit, BigDecimal metricWeight, int reps) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.gym = gym;
|
this.gym = gym;
|
||||||
this.exercise = exercise;
|
this.exercise = exercise;
|
||||||
this.videoFileId = videoFileId;
|
this.videoFileId = videoFileId;
|
||||||
this.submitterName = submitterName;
|
this.user = user;
|
||||||
|
this.performedAt = performedAt;
|
||||||
this.rawWeight = rawWeight;
|
this.rawWeight = rawWeight;
|
||||||
this.weightUnit = unit;
|
this.weightUnit = unit;
|
||||||
this.metricWeight = metricWeight;
|
this.metricWeight = metricWeight;
|
||||||
|
@ -82,8 +88,12 @@ public class ExerciseSubmission {
|
||||||
return videoFileId;
|
return videoFileId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSubmitterName() {
|
public User getUser() {
|
||||||
return submitterName;
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getPerformedAt() {
|
||||||
|
return performedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getRawWeight() {
|
public BigDecimal getRawWeight() {
|
||||||
|
|
|
@ -32,7 +32,13 @@ public class CdnClient {
|
||||||
.GET()
|
.GET()
|
||||||
.build();
|
.build();
|
||||||
HttpResponse<String> response = httpClient.send(req, HttpResponse.BodyHandlers.ofString());
|
HttpResponse<String> response = httpClient.send(req, HttpResponse.BodyHandlers.ofString());
|
||||||
return objectMapper.readValue(response.body(), responseType);
|
if (response.statusCode() == 200) {
|
||||||
|
return objectMapper.readValue(response.body(), responseType);
|
||||||
|
} else if (response.statusCode() == 404) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
throw new IOException("Request failed with code " + response.statusCode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T postFile(String urlPath, Path filePath, String contentType, Class<T> responseType) throws IOException, InterruptedException {
|
public <T> T postFile(String urlPath, Path filePath, String contentType, Class<T> responseType) throws IOException, InterruptedException {
|
||||||
|
|
|
@ -6,6 +6,14 @@ public record UploadsClient(CdnClient client) {
|
||||||
public record FileUploadResponse(String id) {}
|
public record FileUploadResponse(String id) {}
|
||||||
public record VideoProcessingTaskStatusResponse(String status) {}
|
public record VideoProcessingTaskStatusResponse(String status) {}
|
||||||
|
|
||||||
|
public record FileMetadataResponse(
|
||||||
|
String filename,
|
||||||
|
String mimeType,
|
||||||
|
long size,
|
||||||
|
String uploadedAt,
|
||||||
|
boolean availableForDownload
|
||||||
|
) {}
|
||||||
|
|
||||||
public FileUploadResponse uploadVideo(Path filePath, String contentType) throws Exception {
|
public FileUploadResponse uploadVideo(Path filePath, String contentType) throws Exception {
|
||||||
return client.postFile("/uploads/video", filePath, contentType, FileUploadResponse.class);
|
return client.postFile("/uploads/video", filePath, contentType, FileUploadResponse.class);
|
||||||
}
|
}
|
||||||
|
@ -13,4 +21,8 @@ public record UploadsClient(CdnClient client) {
|
||||||
public VideoProcessingTaskStatusResponse getVideoProcessingStatus(String id) throws Exception {
|
public VideoProcessingTaskStatusResponse getVideoProcessingStatus(String id) throws Exception {
|
||||||
return client.get("/uploads/video/" + id + "/status", VideoProcessingTaskStatusResponse.class);
|
return client.get("/uploads/video/" + id + "/status", VideoProcessingTaskStatusResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FileMetadataResponse getFileMetadata(String id) throws Exception {
|
||||||
|
return client.get("/files/" + id + "/metadata", FileMetadataResponse.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import nl.andrewlalis.gymboard_api.domains.api.model.Gym;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.model.WeightUnit;
|
import nl.andrewlalis.gymboard_api.domains.api.model.WeightUnit;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.model.exercise.Exercise;
|
import nl.andrewlalis.gymboard_api.domains.api.model.exercise.Exercise;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.model.exercise.ExerciseSubmission;
|
import nl.andrewlalis.gymboard_api.domains.api.model.exercise.ExerciseSubmission;
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.auth.dao.UserRepository;
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.auth.model.User;
|
||||||
import nl.andrewlalis.gymboard_api.util.ULID;
|
import nl.andrewlalis.gymboard_api.util.ULID;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -19,6 +21,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service which handles the rather mundane tasks associated with exercise
|
* Service which handles the rather mundane tasks associated with exercise
|
||||||
|
@ -29,15 +33,17 @@ public class ExerciseSubmissionService {
|
||||||
private static final Logger log = LoggerFactory.getLogger(ExerciseSubmissionService.class);
|
private static final Logger log = LoggerFactory.getLogger(ExerciseSubmissionService.class);
|
||||||
|
|
||||||
private final GymRepository gymRepository;
|
private final GymRepository gymRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
private final ExerciseRepository exerciseRepository;
|
private final ExerciseRepository exerciseRepository;
|
||||||
private final ExerciseSubmissionRepository exerciseSubmissionRepository;
|
private final ExerciseSubmissionRepository exerciseSubmissionRepository;
|
||||||
private final ULID ulid;
|
private final ULID ulid;
|
||||||
|
|
||||||
public ExerciseSubmissionService(GymRepository gymRepository,
|
public ExerciseSubmissionService(GymRepository gymRepository,
|
||||||
ExerciseRepository exerciseRepository,
|
UserRepository userRepository, ExerciseRepository exerciseRepository,
|
||||||
ExerciseSubmissionRepository exerciseSubmissionRepository,
|
ExerciseSubmissionRepository exerciseSubmissionRepository,
|
||||||
ULID ulid) {
|
ULID ulid) {
|
||||||
this.gymRepository = gymRepository;
|
this.gymRepository = gymRepository;
|
||||||
|
this.userRepository = userRepository;
|
||||||
this.exerciseRepository = exerciseRepository;
|
this.exerciseRepository = exerciseRepository;
|
||||||
this.exerciseSubmissionRepository = exerciseSubmissionRepository;
|
this.exerciseSubmissionRepository = exerciseSubmissionRepository;
|
||||||
this.ulid = ulid;
|
this.ulid = ulid;
|
||||||
|
@ -53,11 +59,14 @@ public class ExerciseSubmissionService {
|
||||||
/**
|
/**
|
||||||
* Handles the creation of a new exercise submission.
|
* Handles the creation of a new exercise submission.
|
||||||
* @param id The gym id.
|
* @param id The gym id.
|
||||||
|
* @param userId The user's id.
|
||||||
* @param payload The submission data.
|
* @param payload The submission data.
|
||||||
* @return The saved submission.
|
* @return The saved submission.
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public ExerciseSubmissionResponse createSubmission(CompoundGymId id, ExerciseSubmissionPayload payload) {
|
public ExerciseSubmissionResponse createSubmission(CompoundGymId id, String userId, ExerciseSubmissionPayload payload) {
|
||||||
|
User user = userRepository.findById(userId)
|
||||||
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.FORBIDDEN));
|
||||||
Gym gym = gymRepository.findByCompoundId(id)
|
Gym gym = gymRepository.findByCompoundId(id)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
|
||||||
Exercise exercise = exerciseRepository.findById(payload.exerciseShortName())
|
Exercise exercise = exerciseRepository.findById(payload.exerciseShortName())
|
||||||
|
@ -76,8 +85,9 @@ public class ExerciseSubmissionService {
|
||||||
ulid.nextULID(),
|
ulid.nextULID(),
|
||||||
gym,
|
gym,
|
||||||
exercise,
|
exercise,
|
||||||
|
user,
|
||||||
|
LocalDateTime.now(),
|
||||||
payload.videoFileId(),
|
payload.videoFileId(),
|
||||||
payload.name(),
|
|
||||||
rawWeight,
|
rawWeight,
|
||||||
weightUnit,
|
weightUnit,
|
||||||
metricWeight,
|
metricWeight,
|
||||||
|
|
|
@ -1,61 +1,124 @@
|
||||||
package nl.andrewlalis.gymboard_api.util.sample_data;
|
package nl.andrewlalis.gymboard_api.util.sample_data;
|
||||||
|
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.api.dao.GymRepository;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.dao.exercise.ExerciseRepository;
|
import nl.andrewlalis.gymboard_api.domains.api.dao.exercise.ExerciseRepository;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.dto.CompoundGymId;
|
import nl.andrewlalis.gymboard_api.domains.api.dao.exercise.ExerciseSubmissionRepository;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.dto.ExerciseSubmissionPayload;
|
import nl.andrewlalis.gymboard_api.domains.api.model.Gym;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.model.WeightUnit;
|
import nl.andrewlalis.gymboard_api.domains.api.model.WeightUnit;
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.api.model.exercise.Exercise;
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.api.model.exercise.ExerciseSubmission;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.service.cdn_client.CdnClient;
|
import nl.andrewlalis.gymboard_api.domains.api.service.cdn_client.CdnClient;
|
||||||
import nl.andrewlalis.gymboard_api.domains.api.service.submission.ExerciseSubmissionService;
|
import nl.andrewlalis.gymboard_api.domains.api.service.submission.ExerciseSubmissionService;
|
||||||
import nl.andrewlalis.gymboard_api.util.CsvUtil;
|
import nl.andrewlalis.gymboard_api.domains.auth.dao.UserRepository;
|
||||||
|
import nl.andrewlalis.gymboard_api.domains.auth.model.User;
|
||||||
|
import nl.andrewlalis.gymboard_api.util.ULID;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Profile;
|
import org.springframework.context.annotation.Profile;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.time.Duration;
|
||||||
import java.util.Set;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Profile("development")
|
@Profile("development")
|
||||||
public class SampleSubmissionGenerator implements SampleDataGenerator {
|
public class SampleSubmissionGenerator implements SampleDataGenerator {
|
||||||
|
private final GymRepository gymRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
private final ExerciseRepository exerciseRepository;
|
private final ExerciseRepository exerciseRepository;
|
||||||
private final ExerciseSubmissionService submissionService;
|
private final ExerciseSubmissionService submissionService;
|
||||||
|
private final ExerciseSubmissionRepository submissionRepository;
|
||||||
|
private final ULID ulid;
|
||||||
|
|
||||||
@Value("${app.cdn-origin}")
|
@Value("${app.cdn-origin}")
|
||||||
private String cdnOrigin;
|
private String cdnOrigin;
|
||||||
|
|
||||||
public SampleSubmissionGenerator(ExerciseRepository exerciseRepository, ExerciseSubmissionService submissionService) {
|
public SampleSubmissionGenerator(GymRepository gymRepository, UserRepository userRepository, ExerciseRepository exerciseRepository, ExerciseSubmissionService submissionService, ExerciseSubmissionRepository submissionRepository, ULID ulid) {
|
||||||
|
this.gymRepository = gymRepository;
|
||||||
|
this.userRepository = userRepository;
|
||||||
this.exerciseRepository = exerciseRepository;
|
this.exerciseRepository = exerciseRepository;
|
||||||
this.submissionService = submissionService;
|
this.submissionService = submissionService;
|
||||||
|
this.submissionRepository = submissionRepository;
|
||||||
|
this.ulid = ulid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generate() throws Exception {
|
public void generate() throws Exception {
|
||||||
final CdnClient cdnClient = new CdnClient(cdnOrigin);
|
final CdnClient cdnClient = new CdnClient(cdnOrigin);
|
||||||
CsvUtil.load(Path.of("sample_data", "submissions.csv"), r -> {
|
|
||||||
var exercise = exerciseRepository.findById(r.get("exercise-short-name")).orElseThrow();
|
|
||||||
BigDecimal weight = new BigDecimal(r.get("raw-weight"));
|
|
||||||
WeightUnit unit = WeightUnit.parse(r.get("weight-unit"));
|
|
||||||
int reps = Integer.parseInt(r.get("reps"));
|
|
||||||
String name = r.get("submitter-name");
|
|
||||||
CompoundGymId gymId = CompoundGymId.parse(r.get("gym-id"));
|
|
||||||
String videoFilename = r.get("video-filename");
|
|
||||||
|
|
||||||
var video = cdnClient.uploads.uploadVideo(Path.of("sample_data", videoFilename), "video/mp4");
|
List<String> videoIds = new ArrayList<>();
|
||||||
submissionService.createSubmission(gymId, new ExerciseSubmissionPayload(
|
var video1 = cdnClient.uploads.uploadVideo(Path.of("sample_data", "sample_video_curl.mp4"), "video/mp4");
|
||||||
name,
|
var video2 = cdnClient.uploads.uploadVideo(Path.of("sample_data", "sample_video_ohp.mp4"), "video/mp4");
|
||||||
exercise.getShortName(),
|
videoIds.add(video1.id());
|
||||||
weight.floatValue(),
|
videoIds.add(video2.id());
|
||||||
unit.name(),
|
|
||||||
reps,
|
List<Gym> gyms = gymRepository.findAll();
|
||||||
video.id()
|
List<User> users = userRepository.findAll();
|
||||||
));
|
List<Exercise> exercises = exerciseRepository.findAll();
|
||||||
});
|
|
||||||
|
final int count = 10000;
|
||||||
|
final LocalDateTime earliestSubmission = LocalDateTime.now().minusYears(3);
|
||||||
|
final LocalDateTime latestSubmission = LocalDateTime.now();
|
||||||
|
|
||||||
|
Random random = new Random(1);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
generateRandomSubmission(
|
||||||
|
gyms,
|
||||||
|
users,
|
||||||
|
exercises,
|
||||||
|
videoIds,
|
||||||
|
earliestSubmission,
|
||||||
|
latestSubmission,
|
||||||
|
random
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateRandomSubmission(
|
||||||
|
List<Gym> gyms,
|
||||||
|
List<User> users,
|
||||||
|
List<Exercise> exercises,
|
||||||
|
List<String> videoIds,
|
||||||
|
LocalDateTime earliestSubmission,
|
||||||
|
LocalDateTime latestSubmission,
|
||||||
|
Random random
|
||||||
|
) {
|
||||||
|
LocalDateTime time = randomTime(earliestSubmission, latestSubmission, random);
|
||||||
|
BigDecimal metricWeight = new BigDecimal(random.nextInt(20, 250));
|
||||||
|
BigDecimal rawWeight = new BigDecimal(metricWeight.toString());
|
||||||
|
WeightUnit weightUnit = WeightUnit.KILOGRAMS;
|
||||||
|
if (random.nextDouble() > 0.5) {
|
||||||
|
weightUnit = WeightUnit.POUNDS;
|
||||||
|
rawWeight = metricWeight.multiply(new BigDecimal("2.2046226218"));
|
||||||
|
}
|
||||||
|
|
||||||
|
submissionRepository.save(new ExerciseSubmission(
|
||||||
|
ulid.nextULID(),
|
||||||
|
randomChoice(gyms, random),
|
||||||
|
randomChoice(exercises, random),
|
||||||
|
randomChoice(users, random),
|
||||||
|
time,
|
||||||
|
randomChoice(videoIds, random),
|
||||||
|
rawWeight,
|
||||||
|
weightUnit,
|
||||||
|
metricWeight,
|
||||||
|
random.nextInt(13)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Class<? extends SampleDataGenerator>> dependencies() {
|
public Collection<Class<? extends SampleDataGenerator>> dependencies() {
|
||||||
return Set.of(SampleExerciseGenerator.class, SampleUserGenerator.class);
|
return Set.of(SampleExerciseGenerator.class, SampleUserGenerator.class, SampleGymGenerator.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T randomChoice(List<T> items, Random rand) {
|
||||||
|
return items.get(rand.nextInt(items.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalDateTime randomTime(LocalDateTime start, LocalDateTime end, Random rand) {
|
||||||
|
Duration dur = Duration.between(start, end);
|
||||||
|
return start.plusSeconds(rand.nextLong(dur.toSeconds() + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Exercise } from 'src/api/main/exercises';
|
||||||
import { api } from 'src/api/main/index';
|
import { api } from 'src/api/main/index';
|
||||||
import { getGymCompoundId, GymRoutable } from 'src/router/gym-routing';
|
import { getGymCompoundId, GymRoutable } from 'src/router/gym-routing';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
|
import {User} from "src/api/main/auth";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data that's sent when creating a submission.
|
* The data that's sent when creating a submission.
|
||||||
|
@ -33,8 +34,9 @@ export interface ExerciseSubmission {
|
||||||
createdAt: DateTime;
|
createdAt: DateTime;
|
||||||
gym: SimpleGym;
|
gym: SimpleGym;
|
||||||
exercise: Exercise;
|
exercise: Exercise;
|
||||||
|
user: User;
|
||||||
|
performedAt: DateTime;
|
||||||
videoFileId: string;
|
videoFileId: string;
|
||||||
submitterName: string;
|
|
||||||
rawWeight: number;
|
rawWeight: number;
|
||||||
weightUnit: WeightUnit;
|
weightUnit: WeightUnit;
|
||||||
metricWeight: number;
|
metricWeight: number;
|
||||||
|
@ -43,7 +45,7 @@ export interface ExerciseSubmission {
|
||||||
|
|
||||||
export function parseSubmission(data: any): ExerciseSubmission {
|
export function parseSubmission(data: any): ExerciseSubmission {
|
||||||
data.createdAt = DateTime.fromISO(data.createdAt);
|
data.createdAt = DateTime.fromISO(data.createdAt);
|
||||||
console.log(data);
|
data.performedAt = DateTime.fromISO(data.performedAt);
|
||||||
return data as ExerciseSubmission;
|
return data as ExerciseSubmission;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { GymSearchResult } from 'src/api/search/models';
|
import {GymSearchResult, UserSearchResult} from 'src/api/search/models';
|
||||||
|
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: 'http://localhost:8081',
|
baseURL: 'http://localhost:8081',
|
||||||
|
@ -15,3 +15,14 @@ export async function searchGyms(
|
||||||
const response = await api.get('/search/gyms?q=' + query);
|
const response = await api.get('/search/gyms?q=' + query);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for users using the given query, and eventually returns results.
|
||||||
|
* Note that only users whose accounts are not private will be included in
|
||||||
|
* search results.
|
||||||
|
* @param query The query to use.
|
||||||
|
*/
|
||||||
|
export async function searchUsers(query: string): Promise<Array<UserSearchResult>> {
|
||||||
|
const response = await api.get('/search/users?q=' + query);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
icon="person"
|
icon="person"
|
||||||
>
|
>
|
||||||
<q-list>
|
<q-list>
|
||||||
|
<q-item clickable v-close-popup :to="'/users/' + authStore.user?.id">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{ $t('accountMenuItem.myAccount') }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
<q-item clickable v-close-popup @click="api.auth.logout(authStore)">
|
<q-item clickable v-close-popup @click="api.auth.logout(authStore)">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ $t('accountMenuItem.logOut') }}</q-item-label>
|
<q-item-label>{{ $t('accountMenuItem.logOut') }}</q-item-label>
|
||||||
|
|
|
@ -41,6 +41,7 @@ export default {
|
||||||
},
|
},
|
||||||
accountMenuItem: {
|
accountMenuItem: {
|
||||||
logIn: 'Login',
|
logIn: 'Login',
|
||||||
|
myAccount: 'My Account',
|
||||||
logOut: 'Log out',
|
logOut: 'Log out',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<template>
|
||||||
|
<q-page>
|
||||||
|
<StandardCenteredPage v-if="user">
|
||||||
|
<h3>{{ user?.name }}</h3>
|
||||||
|
<p>{{ user?.email }}</p>
|
||||||
|
<p v-if="isOwnUser">This is your account!</p>
|
||||||
|
</StandardCenteredPage>
|
||||||
|
</q-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import StandardCenteredPage from 'components/StandardCenteredPage.vue';
|
||||||
|
import {onMounted, ref, Ref} from 'vue';
|
||||||
|
import {User} from 'src/api/main/auth';
|
||||||
|
import api from 'src/api/main';
|
||||||
|
import {useRoute} from 'vue-router';
|
||||||
|
import {useAuthStore} from 'stores/auth-store';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user that this page displays information about.
|
||||||
|
*/
|
||||||
|
const user: Ref<User | undefined> = ref();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag that tells whether this user is the currently authenticated user.
|
||||||
|
*/
|
||||||
|
const isOwnUser = ref(false);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const userId = route.params.userId as string;
|
||||||
|
user.value = await api.auth.fetchUser(userId, authStore);
|
||||||
|
isOwnUser.value = user.value.id === authStore.user?.id;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -12,6 +12,7 @@ import RegisterPage from 'pages/auth/RegisterPage.vue';
|
||||||
import RegistrationSuccessPage from 'pages/auth/RegistrationSuccessPage.vue';
|
import RegistrationSuccessPage from 'pages/auth/RegistrationSuccessPage.vue';
|
||||||
import ActivationPage from 'pages/auth/ActivationPage.vue';
|
import ActivationPage from 'pages/auth/ActivationPage.vue';
|
||||||
import SubmissionPage from 'pages/SubmissionPage.vue';
|
import SubmissionPage from 'pages/SubmissionPage.vue';
|
||||||
|
import UserPage from 'pages/UserPage.vue';
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
// Auth-related pages, which live outside the main layout.
|
// Auth-related pages, which live outside the main layout.
|
||||||
|
@ -27,6 +28,7 @@ const routes: RouteRecordRaw[] = [
|
||||||
children: [
|
children: [
|
||||||
{ path: '', component: IndexPage },
|
{ path: '', component: IndexPage },
|
||||||
{ path: 'testing', component: TestingPage },
|
{ path: 'testing', component: TestingPage },
|
||||||
|
{ path: 'users/:userId', component: UserPage },
|
||||||
{
|
{
|
||||||
path: 'gyms/:countryCode/:cityShortName/:gymShortName',
|
path: 'gyms/:countryCode/:cityShortName/:gymShortName',
|
||||||
component: GymPage,
|
component: GymPage,
|
||||||
|
|
Loading…
Reference in New Issue