diff --git a/.gitignore b/.gitignore
index 549e00a..afd66da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,4 @@ build/
### VS Code ###
.vscode/
+src/main/resources/static/track.gpx
diff --git a/pom.xml b/pom.xml
index 9c045fb..ed25bf0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,6 +86,12 @@
+
+ io.jenetics
+ jpx
+ 3.1.0
+
+
diff --git a/src/main/java/codeurjc_students/ATRA/controller/ActivityController.java b/src/main/java/codeurjc_students/ATRA/controller/ActivityController.java
new file mode 100644
index 0000000..75bb206
--- /dev/null
+++ b/src/main/java/codeurjc_students/ATRA/controller/ActivityController.java
@@ -0,0 +1,38 @@
+package codeurjc_students.ATRA.controller;
+
+import codeurjc_students.ATRA.model.Activity;
+import codeurjc_students.ATRA.service.ActivityService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.security.Principal;
+
+
+@RestController
+@RequestMapping("/api/activities")
+public class ActivityController {
+
+ @Autowired
+ private ActivityService activityService;
+
+ public Activity getActivity(){
+ return null;
+ }
+
+ @PostMapping
+ public ResponseEntity createActivity(Principal principal){
+ activityService.newActivity("target\\classes\\static\\track.gpx", principal.getName());
+ return ResponseEntity.ok().build();
+ }
+
+ public ResponseEntity modifyActivity(){return null;}
+
+ public ResponseEntity deleteActivity(){
+ return null;
+ }
+
+}
+
diff --git a/src/main/java/codeurjc_students/ATRA/model/Activity.java b/src/main/java/codeurjc_students/ATRA/model/Activity.java
index 32b7737..42ae5c4 100644
--- a/src/main/java/codeurjc_students/ATRA/model/Activity.java
+++ b/src/main/java/codeurjc_students/ATRA/model/Activity.java
@@ -1,10 +1,18 @@
package codeurjc_students.ATRA.model;
+import codeurjc_students.ATRA.model.auxiliary.DataPoint;
import jakarta.persistence.*;
+import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
@Data
@Setter
@Getter
@@ -17,4 +25,16 @@ public class Activity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
+ private String name;
+ private String type;
+ private Instant startTime;
+
+ private Long user;
+
+ @ElementCollection
+ private List dataPoints = new ArrayList<>();
+
+ public void addDataPoint(DataPoint dataPoint) {
+ dataPoints.add(dataPoint);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/codeurjc_students/ATRA/model/auxiliary/DataPoint.java b/src/main/java/codeurjc_students/ATRA/model/auxiliary/DataPoint.java
new file mode 100644
index 0000000..a1e8cdc
--- /dev/null
+++ b/src/main/java/codeurjc_students/ATRA/model/auxiliary/DataPoint.java
@@ -0,0 +1,48 @@
+package codeurjc_students.ATRA.model.auxiliary;
+
+import codeurjc_students.ATRA.service.MapToStringConverter;
+import jakarta.persistence.*;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parallel to a GPX's trkpt, stores values for each metric at a specific time.
+ */
+@Data
+@Setter
+@Getter
+@Embeddable
+public class DataPoint {
+ private Instant _time;
+
+ private Double _lat;
+ private Double _long;
+ private Double _ele;
+
+ private int hr;
+ private int cad;
+
+ @Convert(converter = MapToStringConverter.class) //this means that, when serializing, it will be converted into a String
+ private Map other = new HashMap<>();
+
+ public void put(String key, String value){
+ switch (key) {
+ case "lat" : _lat = Double.valueOf(value); break;
+ case "long": _long = Double.valueOf(value); break;
+ case "ele" : _ele = Double.valueOf(value); break;
+
+ case "time" : _time = Instant.parse(value); break;
+
+ case "hr" : hr = Integer.parseInt(value); break;
+ case "cad" : cad = Integer.parseInt(value); break;
+
+ default: other.put(key,value);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/codeurjc_students/ATRA/service/ActivityService.java b/src/main/java/codeurjc_students/ATRA/service/ActivityService.java
index d2c4970..ed93de0 100644
--- a/src/main/java/codeurjc_students/ATRA/service/ActivityService.java
+++ b/src/main/java/codeurjc_students/ATRA/service/ActivityService.java
@@ -1,10 +1,20 @@
package codeurjc_students.ATRA.service;
import codeurjc_students.ATRA.model.Activity;
+import codeurjc_students.ATRA.model.User;
+import codeurjc_students.ATRA.model.auxiliary.DataPoint;
import codeurjc_students.ATRA.repository.ActivityRepository;
+import io.jenetics.jpx.GPX;
+import io.jenetics.jpx.WayPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.time.Instant;
import java.util.List;
import java.util.Optional;
@@ -12,26 +22,95 @@
public class ActivityService {
@Autowired
- private ActivityRepository repository;
+ private ActivityRepository activityRepository;
+
+ @Autowired
+ private UserService userService;
public Optional findById(long id) {
- return repository.findById(id);
+ return activityRepository.findById(id);
}
public boolean exists(long id) {
- return repository.existsById(id);
+ return activityRepository.existsById(id);
}
public List findAll() {
- return repository.findAll();
+ return activityRepository.findAll();
}
public void save(Activity activity) {
- repository.save(activity);
+ activityRepository.save(activity);
}
public void delete(long id) {
- repository.deleteById(id);
+ activityRepository.deleteById(id);
}
+
+
+ public Activity newActivity(String pathString, String username){
+ final GPX gpx;
+ try {
+ gpx = GPX.read(Paths.get(pathString));
+ } catch (IOException e) {throw new RuntimeException(e);}
+ List pts = gpx.getTracks().get(0).getSegments().get(0).getPoints();
+
+
+ Activity activity = new Activity();
+ //set user
+ Optional userOpt = userService.findByUserName(username);
+ if (userOpt.isEmpty()) return null; //or throw exception caught above
+ activity.setUser(userOpt.get().getId());
+
+ //process the metadata
+ gpx.getMetadata().ifPresent(metadata -> activity.setStartTime(metadata.getTime().get()));
+ activity.setName(gpx.getTracks().get(0).getName().get());
+ activity.setType(gpx.getTracks().get(0).getType().get());
+ //process the waypoints
+ for (WayPoint pt: pts) {
+ //add each waypoint to activity
+ addWayPoint(activity, pt);
+ }
+ activityRepository.save(activity);
+ return activity;
+ }
+
+ private void addWayPoint(Activity activity, WayPoint pt) {
+ //processes the WayPoint and adds it to activity in ATRA format
+ DataPoint dataPoint = new DataPoint();
+ //handle lat, long, ele
+ double latitude = pt.getLatitude().doubleValue();
+ double longitude = pt.getLongitude().doubleValue();
+ double elevation = (pt.getElevation().isPresent() ? pt.getElevation().get().doubleValue() : 0.0);
+
+ dataPoint.put("lat", Double.toString(latitude));
+ dataPoint.put("long", Double.toString(longitude));
+ dataPoint.put("ele", Double.toString(elevation));
+
+ //hanlde time
+ Optional timeOpt = pt.getTime();
+ timeOpt.ifPresent(instant -> dataPoint.put("time", instant.toString()));
+
+ //handle extensions
+ Optional extensions = pt.getExtensions();
+ if (extensions.isEmpty()) return;
+ Element element = extensions.get().getDocumentElement();
+
+ Node currentMetric = element.getFirstChild().getChildNodes().item(0);
+ while (currentMetric!=null) {
+ //extract the value
+ String metric = currentMetric.getNodeName();
+ String metricValue = currentMetric.getFirstChild().getNodeValue();
+
+ if (metric.startsWith("gpxtpx:")) metric = metric.substring(7);
+ else System.out.println("Found a metric that does not start with 'gpxtcx:'"); //ideally throw an exception or sth but for now this works
+
+ dataPoint.put(metric, metricValue);
+ currentMetric = currentMetric.getNextSibling();
+ }
+
+ activity.addDataPoint(dataPoint);
+ }
+
}
diff --git a/src/main/java/codeurjc_students/ATRA/service/MapToStringConverter.java b/src/main/java/codeurjc_students/ATRA/service/MapToStringConverter.java
new file mode 100644
index 0000000..5d41d4d
--- /dev/null
+++ b/src/main/java/codeurjc_students/ATRA/service/MapToStringConverter.java
@@ -0,0 +1,32 @@
+package codeurjc_students.ATRA.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.persistence.AttributeConverter;
+import jakarta.persistence.Converter;
+
+import java.util.Map;
+
+@Converter
+public class MapToStringConverter implements AttributeConverter