diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 000000000..13e9b5ac6
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,8 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(git checkout:*)",
+ "Bash(mvn -B spring-boot:run)"
+ ]
+ }
+}
diff --git a/.github/workflows/github-ci-cd.yml b/.github/workflows/github-ci-cd.yml
index af0b0753d..1526921fd 100644
--- a/.github/workflows/github-ci-cd.yml
+++ b/.github/workflows/github-ci-cd.yml
@@ -1,53 +1,101 @@
# GitHub Actions CI/CD pipeline for a Java project using Maven
# File path should be: .github/workflows/github-ci-cd.yml
+#
+# Testy podzielone są na stage'e zgodnie z laboratoriami:
+# - lab02 -> DatabaseSchemaTest (encje z LAB02)
+# - lab03-entities -> Lab03EntitiesTest (encje z LAB03, STAGE 1)
+#
+# Stage'e testowe są niezależne (brak `needs:` między nimi), więc niepowodzenie
+# jednego nie przerywa pozostałych — widzisz pełny obraz, które laboratorium
+# już zielenie się, a które jeszcze nie. Job `package` buduje JAR tylko,
+# gdy wszystkie stage'e są zielone.
name: Java CI with Maven
+
permissions:
contents: read
- security-events: write
+
on:
push:
- branches: [ "master" ]
+ branches: [ "**" ]
pull_request:
- branches: [ "master" ]
+ branches: [ "**" ]
jobs:
- build:
+ lab02:
+ name: LAB02 — schema (DatabaseSchemaTest)
runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v5
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ cache: maven
+
+ - name: Run LAB02 tests
+ run: mvn -B test -Dtest=DatabaseSchemaTest -DfailIfNoTests=false --file pom.xml
+
+ - name: Publish LAB02 test results
+ if: always()
+ uses: actions/upload-artifact@v5
+ with:
+ name: surefire-lab02
+ path: target/surefire-reports/
+ if-no-files-found: ignore
+ retention-days: 7
+ lab03-entities:
+ name: LAB03-1 — entities (Lab03EntitiesTest)
+ runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
- name: Set up JDK 17
- id: setup-jdk
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- - name: Build with Maven
- run: mvn -B package --file pom.xml
- publish-job:
+
+ - name: Run LAB03-1 tests
+ run: mvn -B test -Dtest=Lab03EntitiesTest -DfailIfNoTests=false --file pom.xml
+
+ - name: Publish LAB03-1 test results
+ if: always()
+ uses: actions/upload-artifact@v5
+ with:
+ name: surefire-lab03-entities
+ path: target/surefire-reports/
+ if-no-files-found: ignore
+ retention-days: 7
+
+ package:
+ name: Package JAR
runs-on: ubuntu-latest
- needs: build
+ needs: [ lab02, lab03-entities ]
steps:
- - uses: actions/checkout@v5
- - uses: actions/setup-java@v5
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
- - run: mvn --batch-mode --update-snapshots verify
- - name: Prepare staging
- id: prepare-staging
- run: |
- mkdir -p staging
- find target -maxdepth 1 -type f -name '*.jar' ! -name '*SNAPSHOT*' -exec cp {} staging/ \;
- if [ -n "$(ls -A staging 2>/dev/null)" ]; then
- echo "found=true" >> $GITHUB_OUTPUT
- else
- echo "found=false" >> $GITHUB_OUTPUT
- fi
- - name: Upload package
- if: steps.prepare-staging.outputs.found == 'true'
+ cache: maven
+
+ - name: Build JAR
+ run: mvn -B -DskipTests package --file pom.xml
+
+ - name: Upload JAR artifact
+ if: success()
uses: actions/upload-artifact@v5
with:
- name: Package
- path: staging
\ No newline at end of file
+ name: package
+ path: target/*.jar
+ if-no-files-found: ignore
+ retention-days: 7
diff --git a/.gitignore b/.gitignore
index f4ffc6f5f..e3c93ad6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,4 +36,7 @@ build/
.vscode/
### Mac OS ###
-.DS_Store
\ No newline at end of file
+.DS_Store
+
+### Java ###
+target/
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..5c387551c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# FitnessTracker_LM-SS
+
+Lukasz Malinowski 81518
+
+Sebastian Skowron 81477
diff --git a/pom.xml b/pom.xml
index e707444aa..11efbcd6e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
pl.wsb
CapWSB-FitnessTracker
- 1.2.0-SNAPSHOT
+ 1.2.0-81518-81477-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
@@ -101,6 +101,18 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.32
+
+
+
\ No newline at end of file
diff --git a/src/main/java/pl/wsb/fitnesstracker/achievement/Achievement.java b/src/main/java/pl/wsb/fitnesstracker/achievement/Achievement.java
new file mode 100644
index 000000000..2fa31bd87
--- /dev/null
+++ b/src/main/java/pl/wsb/fitnesstracker/achievement/Achievement.java
@@ -0,0 +1,48 @@
+package pl.wsb.fitnesstracker.achievement;
+
+import jakarta.persistence.*;
+import pl.wsb.fitnesstracker.user.api.User;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "achievement")
+public class Achievement {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ private String name;
+
+ @Column(name = "earned_at")
+ private LocalDateTime earnedAt;
+
+ @ManyToOne
+ @JoinColumn(name = "user_id", nullable = false)
+ private User user;
+
+ protected Achievement() {
+ }
+
+ public Achievement(String name, LocalDateTime earnedAt, User user) {
+ this.name = name;
+ this.earnedAt = earnedAt;
+ this.user = user;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public LocalDateTime getEarnedAt() {
+ return earnedAt;
+ }
+
+ public User getUser() {
+ return user;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/pl/wsb/fitnesstracker/event/Event.java b/src/main/java/pl/wsb/fitnesstracker/event/Event.java
index 5d1dc4feb..7320fb2c2 100644
--- a/src/main/java/pl/wsb/fitnesstracker/event/Event.java
+++ b/src/main/java/pl/wsb/fitnesstracker/event/Event.java
@@ -1,5 +1,56 @@
package pl.wsb.fitnesstracker.event;
-// TODO: Define the Event entity with appropriate fields and annotations
+import jakarta.annotation.Nullable;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "event")
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@ToString
public class Event {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Nullable
+ private Long id;
+
+ @Column(nullable = false)
+ private String name;
+
+ @Column
+ private String description;
+
+ @Column(name = "start_time", nullable = false)
+ private LocalDateTime startTime;
+
+ @Column(name = "end_time")
+ private LocalDateTime endTime;
+
+ @Column
+ private String country;
+
+ @Column
+ private String city;
+
+ public Event(
+ final String name,
+ final String description,
+ final LocalDateTime startTime,
+ final LocalDateTime endTime,
+ final String country,
+ final String city) {
+ this.name = name;
+ this.description = description;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ this.country = country;
+ this.city = city;
+ }
}
diff --git a/src/main/java/pl/wsb/fitnesstracker/event/EventRepository.java b/src/main/java/pl/wsb/fitnesstracker/event/EventRepository.java
new file mode 100644
index 000000000..d616396f6
--- /dev/null
+++ b/src/main/java/pl/wsb/fitnesstracker/event/EventRepository.java
@@ -0,0 +1,21 @@
+package pl.wsb.fitnesstracker.event;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+public interface EventRepository extends JpaRepository {
+
+ @Query("SELECT e FROM Event e WHERE e.startTime > :now ORDER BY e.startTime")
+ List findUpcoming(@Param("now") LocalDateTime now);
+
+ @Query(
+ value = "SELECT e.name, COUNT(ue.id) FROM event e LEFT JOIN user_event ue ON e.id = ue.event_id GROUP BY e.id, e.name",
+ nativeQuery = true
+ )
+
+ List