Fix several bugs and race conditions.
This commit is contained in:
parent
eb9b29d301
commit
c66772fd67
@ -828,11 +828,11 @@
|
|||||||
if (idea.start_time && idea.end_time) {
|
if (idea.start_time && idea.end_time) {
|
||||||
const s = new Date(idea.start_time).toLocaleDateString('nb-NO', {
|
const s = new Date(idea.start_time).toLocaleDateString('nb-NO', {
|
||||||
hour: '2-digit', minute: '2-digit', hour12: false
|
hour: '2-digit', minute: '2-digit', hour12: false
|
||||||
});
|
}).replace(/ /g, ' ');
|
||||||
const e = new Date(idea.end_time).toLocaleDateString('nb-NO', {
|
const e = new Date(idea.end_time).toLocaleDateString('nb-NO', {
|
||||||
hour: '2-digit', minute: '2-digit', hour12: false
|
hour: '2-digit', minute: '2-digit', hour12: false
|
||||||
});
|
}).replace(/ /g, ' ');
|
||||||
timeCell = `<td>${s} → ${e}</td>`;
|
timeCell = `<td>${s}<br/>→ ${e}</td>`;
|
||||||
} else if (idea.start_time) {
|
} else if (idea.start_time) {
|
||||||
const s = new Date(idea.start_time).toLocaleDateString('nb-NO', {
|
const s = new Date(idea.start_time).toLocaleDateString('nb-NO', {
|
||||||
hour: '2-digit', minute: '2-digit', hour12: false
|
hour: '2-digit', minute: '2-digit', hour12: false
|
||||||
@ -848,7 +848,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
html += `<tr>`
|
html += `<tr>`
|
||||||
+ `<td><strong>${idea.name}</strong><br><small>${idea.description}</small></td>`
|
+ `<td><strong>${idea.name}</strong><br><small>${linkify(idea.description)}</small></td>`
|
||||||
+ timeCell;
|
+ timeCell;
|
||||||
allVoters.forEach(voter => {
|
allVoters.forEach(voter => {
|
||||||
html += `<td class="vote-cell">${idea.voters.includes(voter) ? '✓' : ''}</td>`;
|
html += `<td class="vote-cell">${idea.voters.includes(voter) ? '✓' : ''}</td>`;
|
||||||
|
|||||||
15
server.py
15
server.py
@ -5,6 +5,7 @@ from typing import Optional
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import FastAPI, HTTPException, Path
|
from fastapi import FastAPI, HTTPException, Path
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
from filelock import FileLock
|
||||||
import argparse
|
import argparse
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
@ -49,7 +50,11 @@ class Vote(BaseModel):
|
|||||||
DATA_DIR = "" # will be overridden via command line
|
DATA_DIR = "" # will be overridden via command line
|
||||||
|
|
||||||
def get_tour_filepath(tour_id: str) -> str:
|
def get_tour_filepath(tour_id: str) -> str:
|
||||||
return os.path.join(DATA_DIR, f"{tour_id}.json")
|
fname = f"{tour_id}.json"
|
||||||
|
full = os.path.abspath(os.path.join(DATA_DIR, fname))
|
||||||
|
if not full.startswith(os.path.abspath(DATA_DIR) + os.sep):
|
||||||
|
raise HTTPException(status_code=400, detail="Invalid tour ID")
|
||||||
|
return full
|
||||||
|
|
||||||
# ─── ENDPOINT: CREATE TOUR ─────────────────────────────────────────────────────
|
# ─── ENDPOINT: CREATE TOUR ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
@ -74,7 +79,7 @@ def create_tour(tour: TourCreate):
|
|||||||
filepath = get_tour_filepath(tour_id)
|
filepath = get_tour_filepath(tour_id)
|
||||||
with open(filepath, "w") as f:
|
with open(filepath, "w") as f:
|
||||||
# Using default=str so that datetime objects become ISO strings
|
# Using default=str so that datetime objects become ISO strings
|
||||||
json.dump(new_tour.dict(), f, default=str)
|
json.dump(new_tour.model_dump(), f, default=str)
|
||||||
|
|
||||||
return new_tour
|
return new_tour
|
||||||
|
|
||||||
@ -117,6 +122,8 @@ def add_idea(tour_id: str, idea: IdeaCreate):
|
|||||||
if not os.path.exists(filepath):
|
if not os.path.exists(filepath):
|
||||||
raise HTTPException(status_code=404, detail="Tour not found")
|
raise HTTPException(status_code=404, detail="Tour not found")
|
||||||
|
|
||||||
|
lock = FileLock(filepath + ".lock")
|
||||||
|
with lock:
|
||||||
with open(filepath) as f:
|
with open(filepath) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
|
|
||||||
@ -130,7 +137,7 @@ def add_idea(tour_id: str, idea: IdeaCreate):
|
|||||||
end_time=idea.end_time,
|
end_time=idea.end_time,
|
||||||
)
|
)
|
||||||
|
|
||||||
data["ideas"].append(new_idea.dict())
|
data["ideas"].append(new_idea.model_dump())
|
||||||
with open(filepath, "w") as f:
|
with open(filepath, "w") as f:
|
||||||
json.dump(data, f, default=str)
|
json.dump(data, f, default=str)
|
||||||
|
|
||||||
@ -147,6 +154,8 @@ def vote_idea(tour_id: str, idea_id: str, vote: Vote):
|
|||||||
if not os.path.exists(filepath):
|
if not os.path.exists(filepath):
|
||||||
raise HTTPException(status_code=404, detail="Tour not found")
|
raise HTTPException(status_code=404, detail="Tour not found")
|
||||||
|
|
||||||
|
lock = FileLock(filepath + ".lock")
|
||||||
|
with lock:
|
||||||
with open(filepath) as f:
|
with open(filepath) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user