Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ build
database.mv.db
database.trace.db
db/
!src/main/resources/db/
!src/main/resources/db/migration/
!src/main/resources/db/migration/**
.DS_Store
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-flyway")
implementation("org.flywaydb:flyway-database-postgresql")
implementation("org.springframework.boot:spring-boot-starter-security")
runtimeOnly("com.h2database:h2") // for local
runtimeOnly("org.postgresql:postgresql") // for prod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import io.papermc.patchroulette.util.TimeUtil;
import jakarta.persistence.EntityNotFoundException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
Expand Down Expand Up @@ -50,7 +50,7 @@ public ResponseEntity<List<String>> getAvailablePatches(@RequestParam final Stri
);
}

public record PatchDetails(String path, String status, String responsibleUser, LocalDateTime lastUpdated, Duration duration) {}
public record PatchDetails(String path, String status, String responsibleUser, Instant lastUpdated, Duration duration) {}

@PreAuthorize("hasRole('PATCH')")
@GetMapping(
Expand All @@ -60,7 +60,13 @@ public record PatchDetails(String path, String status, String responsibleUser, L
public ResponseEntity<List<PatchDetails>> getAllPatches(@RequestParam final String minecraftVersion) {
return ResponseEntity.ok(
this.patchService.getAllPatches(minecraftVersion).stream()
.map(patch -> new PatchDetails(patch.getPath(), patch.getStatus().name(), patch.getResponsibleUser(), patch.getLastUpdated(), patch.getDuration()))
.map(patch -> new PatchDetails(
patch.getPath(),
patch.getStatus().name(),
patch.getResponsibleUser(),
patch.getLastUpdated(),
patch.getDuration()
))
.toList()
);
}
Expand Down Expand Up @@ -232,8 +238,8 @@ public ResponseEntity<Stats> stats(@RequestParam final String minecraftVersion)

// Track the time interval for this patch if it has duration
if (patch.getDuration() != null && patch.getLastUpdated() != null) {
LocalDateTime endTime = patch.getLastUpdated();
LocalDateTime startTime = endTime.minus(patch.getDuration());
Instant endTime = patch.getLastUpdated();
Instant startTime = endTime.minus(patch.getDuration());

userIntervals.computeIfAbsent(patch.getResponsibleUser(), k -> new ArrayList<>())
.add(new TimeUtil.TimeInterval(startTime, endTime));
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/io/papermc/patchroulette/model/Patch.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import jakarta.persistence.IdClass;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Instant;

@Entity
@IdClass(PatchId.class)
Expand All @@ -25,7 +25,7 @@ public class Patch {
private Status status;

private String responsibleUser;
private LocalDateTime lastUpdated;
private Instant lastUpdated;
private Duration duration;

public Patch() {
Expand Down Expand Up @@ -63,11 +63,11 @@ public void setResponsibleUser(final String responsibleUser) {
this.responsibleUser = responsibleUser;
}

public LocalDateTime getLastUpdated() {
public Instant getLastUpdated() {
return lastUpdated;
}

public void setLastUpdated(LocalDateTime lastUpdated) {
public void setLastUpdated(Instant lastUpdated) {
this.lastUpdated = lastUpdated;
}

Expand All @@ -81,7 +81,7 @@ public void setDuration(Duration duration) {

public void updateDuration() {
if (this.lastUpdated != null) {
final Duration duration = Duration.between(this.lastUpdated, LocalDateTime.now());
final Duration duration = Duration.between(this.lastUpdated, Instant.now());
if (this.duration == null) {
this.duration = duration;
} else {
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/io/papermc/patchroulette/service/PatchService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import io.papermc.patchroulette.model.Status;
import io.papermc.patchroulette.repository.PatchRepository;

import java.time.LocalDateTime;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -29,7 +29,7 @@ public void setPatches(final String minecraftVersion, final List<String> paths)
patch.setPath(path);
patch.setStatus(Status.AVAILABLE);
patch.setMinecraftVersion(minecraftVersion);
patch.setLastUpdated(LocalDateTime.now());
patch.setLastUpdated(Instant.now());
return patch;
}).toList();

Expand Down Expand Up @@ -58,7 +58,7 @@ public List<String> startWorkOnPatches(final String minecraftVersion, final List
}
patch.setStatus(Status.WIP);
patch.setResponsibleUser(user);
patch.setLastUpdated(LocalDateTime.now());
patch.setLastUpdated(Instant.now());
this.patchRepository.save(patch);
startedPatches.add(path);
}
Expand All @@ -74,7 +74,7 @@ public void cancelWorkOnPatch(final PatchId patchId) {
patch.setStatus(Status.AVAILABLE);
patch.setResponsibleUser(null);
patch.setDuration(null);
patch.setLastUpdated(LocalDateTime.now());
patch.setLastUpdated(Instant.now());
this.patchRepository.save(patch);
}

Expand All @@ -89,7 +89,7 @@ public void finishWorkOnPatch(final PatchId patchId, final String user) {
}
patch.setStatus(Status.DONE);
patch.updateDuration();
patch.setLastUpdated(LocalDateTime.now());
patch.setLastUpdated(Instant.now());
this.patchRepository.save(patch);
}

Expand All @@ -101,7 +101,7 @@ public void undoPatch(final PatchId patchId, final String user) {
}
patch.setStatus(Status.WIP);
patch.setResponsibleUser(user);
patch.setLastUpdated(LocalDateTime.now());
patch.setLastUpdated(Instant.now());
this.patchRepository.save(patch);
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/io/papermc/patchroulette/util/TimeUtil.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package io.papermc.patchroulette.util;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

public final class TimeUtil {
private TimeUtil() {
}

public record TimeInterval(LocalDateTime start, LocalDateTime end) {}
public record TimeInterval(Instant start, Instant end) {}

public static List<TimeInterval> mergeOverlappingIntervals(List<TimeInterval> intervals) {
if (intervals.isEmpty()) {
Expand Down
9 changes: 8 additions & 1 deletion src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ spring:
username: admin
password: password
driver-class-name: org.h2.Driver
flyway:
baseline-on-migrate: true
baseline-version: 1
locations: classpath:db/migration/{vendor}
placeholders:
# Timezone used by the old LocalDateTime values during legacy migration.
legacy_timezone: UTC
jpa:
hibernate:
ddl-auto: update
ddl-auto: validate
9 changes: 9 additions & 0 deletions src/main/resources/db/migration/h2/V1__create_patch_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS patch (
minecraft_version VARCHAR(255) NOT NULL,
path VARCHAR(1024) NOT NULL,
status TINYINT,
responsible_user VARCHAR(255),
last_updated TIMESTAMP(6),
duration NUMERIC(21),
PRIMARY KEY (minecraft_version, path)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Legacy LocalDateTime values are interpreted using the deployment timezone.
ALTER TABLE patch
ALTER COLUMN last_updated TIMESTAMP(6) WITH TIME ZONE
USING CAST(FORMATDATETIME(last_updated, 'yyyy-MM-dd HH:mm:ss.SSSSSS') || ' ${legacy_timezone}' AS TIMESTAMP(6) WITH TIME ZONE);
Comment thread
jpenilla marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS patch (
minecraft_version VARCHAR(255) NOT NULL,
path VARCHAR(1024) NOT NULL,
status SMALLINT,
responsible_user VARCHAR(255),
last_updated TIMESTAMP(6),
duration NUMERIC(21),
PRIMARY KEY (minecraft_version, path)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Legacy LocalDateTime values are interpreted using the deployment timezone.
ALTER TABLE patch
ALTER COLUMN last_updated TYPE TIMESTAMP(6) WITH TIME ZONE
USING last_updated AT TIME ZONE '${legacy_timezone}';
4 changes: 3 additions & 1 deletion web/src/lib/components/PatchesTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@
filter: true,
floatingFilter: true,
valueFormatter: (params) =>
params.data?.lastUpdated ? DateTime.fromISO(params.data.lastUpdated).toLocal().toLocaleString(DateTime.DATETIME_SHORT) : "",
params.data?.lastUpdated
? DateTime.fromISO(params.data.lastUpdated, { zone: "utc" }).toLocal().toLocaleString(DateTime.DATETIME_SHORT)
: "",
},
],
getRowId: (params) => params.data.path,
Expand Down
2 changes: 1 addition & 1 deletion web/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type PatchDetails = {
path: string;
status: PatchStatus;
responsibleUser: string;
lastUpdated: string;
lastUpdated: string; // ISO 8601 UTC datetime
duration: string;
};

Expand Down
Loading