datestuff
This commit is contained in:
parent
1a6d7291c4
commit
e11dd4ed1f
5 changed files with 326 additions and 27 deletions
114
main.go
114
main.go
|
@ -37,6 +37,8 @@ type ChecklistItem struct {
|
|||
LockUntil *time.Time `json:"lock_until,omitempty"`
|
||||
Checklist string `json:"checklist_uuid"`
|
||||
Dependencies []int `json:"dependencies,omitempty"`
|
||||
NotBefore *time.Time `json:"not_before,omitempty"`
|
||||
NotAfter *time.Time `json:"not_after,omitempty"`
|
||||
}
|
||||
|
||||
type ItemLock struct {
|
||||
|
@ -78,6 +80,8 @@ func getChecklistDB(uuid string) (*sql.DB, error) {
|
|||
content TEXT NOT NULL,
|
||||
checked INTEGER NOT NULL,
|
||||
parent_id INTEGER,
|
||||
not_before TEXT,
|
||||
not_after TEXT,
|
||||
FOREIGN KEY(parent_id) REFERENCES items(id)
|
||||
);`,
|
||||
`CREATE TABLE IF NOT EXISTS dependencies (
|
||||
|
@ -173,7 +177,7 @@ func loadChecklistItems(uuid string) ([]ChecklistItem, error) {
|
|||
}
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query(`SELECT id, content, checked, parent_id FROM items`)
|
||||
rows, err := db.Query(`SELECT id, content, checked, parent_id, not_before, not_after FROM items`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -183,7 +187,9 @@ func loadChecklistItems(uuid string) ([]ChecklistItem, error) {
|
|||
var it ChecklistItem
|
||||
var checked int
|
||||
var parentID sql.NullInt64
|
||||
err = rows.Scan(&it.ID, &it.Content, &checked, &parentID)
|
||||
var notBefore sql.NullString
|
||||
var notAfter sql.NullString
|
||||
err = rows.Scan(&it.ID, &it.Content, &checked, &parentID, ¬Before, ¬After)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -192,6 +198,16 @@ func loadChecklistItems(uuid string) ([]ChecklistItem, error) {
|
|||
v := int(parentID.Int64)
|
||||
it.ParentID = &v
|
||||
}
|
||||
if notBefore.Valid {
|
||||
if t, err := time.Parse(time.RFC3339, notBefore.String); err == nil {
|
||||
it.NotBefore = &t
|
||||
}
|
||||
}
|
||||
if notAfter.Valid {
|
||||
if t, err := time.Parse(time.RFC3339, notAfter.String); err == nil {
|
||||
it.NotAfter = &t
|
||||
}
|
||||
}
|
||||
it.Checklist = uuid
|
||||
|
||||
// Load dependencies for this item
|
||||
|
@ -227,15 +243,25 @@ func addChecklist(name string) (string, error) {
|
|||
return uuidStr, err
|
||||
}
|
||||
|
||||
func addItem(uuid, content string, parentID *int) (ChecklistItem, error) {
|
||||
func addItem(uuid, content string, parentID *int, notBefore *time.Time, notAfter *time.Time) (ChecklistItem, error) {
|
||||
db, err := getChecklistDB(uuid)
|
||||
if err != nil {
|
||||
return ChecklistItem{}, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
res, err := db.Exec(`INSERT INTO items (content, checked, parent_id) VALUES (?, 0, ?)`,
|
||||
content, parentID)
|
||||
var notBeforeStr, notAfterStr *string
|
||||
if notBefore != nil {
|
||||
s := notBefore.Format(time.RFC3339)
|
||||
notBeforeStr = &s
|
||||
}
|
||||
if notAfter != nil {
|
||||
s := notAfter.Format(time.RFC3339)
|
||||
notAfterStr = &s
|
||||
}
|
||||
|
||||
res, err := db.Exec(`INSERT INTO items (content, checked, parent_id, not_before, not_after) VALUES (?, 0, ?, ?, ?)`,
|
||||
content, parentID, notBeforeStr, notAfterStr)
|
||||
if err != nil {
|
||||
return ChecklistItem{}, err
|
||||
}
|
||||
|
@ -245,11 +271,13 @@ func addItem(uuid, content string, parentID *int) (ChecklistItem, error) {
|
|||
Content: content,
|
||||
Checked: false,
|
||||
ParentID: parentID,
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
Checklist: uuid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func updateItem(uuid string, id int, content *string, checked *bool, parentID *int, dependencies *[]int) (ChecklistItem, error) {
|
||||
func updateItem(uuid string, id int, content *string, checked *bool, parentID *int, dependencies *[]int, notBefore *time.Time, notAfter *time.Time) (ChecklistItem, error) {
|
||||
log.Printf("updateItem called with uuid: %s, id: %d", uuid, id)
|
||||
log.Printf("Parameters: content=%v, checked=%v, parentID=%v, dependencies=%v", content, checked, parentID, dependencies)
|
||||
|
||||
|
@ -262,7 +290,7 @@ func updateItem(uuid string, id int, content *string, checked *bool, parentID *i
|
|||
|
||||
log.Printf("Database connection successful for uuid: %s", uuid)
|
||||
|
||||
// If trying to check an item, validate dependencies first
|
||||
// If trying to check an item, validate dependencies and date constraints first
|
||||
if checked != nil && *checked {
|
||||
log.Printf("Validating dependencies for item %d", id)
|
||||
deps, err := loadItemDependencies(db, id)
|
||||
|
@ -283,8 +311,32 @@ func updateItem(uuid string, id int, content *string, checked *bool, parentID *i
|
|||
return ChecklistItem{}, fmt.Errorf("cannot complete item: dependency %d is not completed", depID)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate date constraints
|
||||
now := time.Now()
|
||||
var notBeforeStr, notAfterStr sql.NullString
|
||||
err = db.QueryRow(`SELECT not_before, not_after FROM items WHERE id = ?`, id).Scan(¬BeforeStr, ¬AfterStr)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get date constraints: %v", err)
|
||||
return ChecklistItem{}, err
|
||||
}
|
||||
|
||||
if notBeforeStr.Valid {
|
||||
if notBefore, err := time.Parse(time.RFC3339, notBeforeStr.String); err == nil {
|
||||
if now.Before(notBefore) {
|
||||
return ChecklistItem{}, fmt.Errorf("cannot complete item: not before %s", notBefore.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
}
|
||||
}
|
||||
if notAfterStr.Valid {
|
||||
if notAfter, err := time.Parse(time.RFC3339, notAfterStr.String); err == nil {
|
||||
if now.After(notAfter) {
|
||||
return ChecklistItem{}, fmt.Errorf("cannot complete item: not after %s", notAfter.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Printf("Skipping dependency validation - checked is %v", checked)
|
||||
log.Printf("Skipping dependency and date validation - checked is %v", checked)
|
||||
}
|
||||
|
||||
log.Printf("About to check dependencies parameter")
|
||||
|
@ -331,6 +383,14 @@ func updateItem(uuid string, id int, content *string, checked *bool, parentID *i
|
|||
set = append(set, "parent_id = ?")
|
||||
args = append(args, *parentID)
|
||||
}
|
||||
if notBefore != nil {
|
||||
set = append(set, "not_before = ?")
|
||||
args = append(args, notBefore.Format(time.RFC3339))
|
||||
}
|
||||
if notAfter != nil {
|
||||
set = append(set, "not_after = ?")
|
||||
args = append(args, notAfter.Format(time.RFC3339))
|
||||
}
|
||||
if len(set) > 0 {
|
||||
q := "UPDATE items SET " + strings.Join(set, ", ") + " WHERE id = ?"
|
||||
args = append(args, id)
|
||||
|
@ -347,7 +407,7 @@ func updateItem(uuid string, id int, content *string, checked *bool, parentID *i
|
|||
|
||||
// Return updated item
|
||||
log.Printf("Querying updated item %d", id)
|
||||
rows, err := db.Query(`SELECT id, content, checked, parent_id FROM items WHERE id = ?`, id)
|
||||
rows, err := db.Query(`SELECT id, content, checked, parent_id, not_before, not_after FROM items WHERE id = ?`, id)
|
||||
if err != nil {
|
||||
log.Printf("Failed to query updated item: %v", err)
|
||||
return ChecklistItem{}, err
|
||||
|
@ -358,7 +418,9 @@ func updateItem(uuid string, id int, content *string, checked *bool, parentID *i
|
|||
var it ChecklistItem
|
||||
var checkedInt int
|
||||
var parentID sql.NullInt64
|
||||
err = rows.Scan(&it.ID, &it.Content, &checkedInt, &parentID)
|
||||
var notBefore sql.NullString
|
||||
var notAfter sql.NullString
|
||||
err = rows.Scan(&it.ID, &it.Content, &checkedInt, &parentID, ¬Before, ¬After)
|
||||
if err != nil {
|
||||
log.Printf("Failed to scan updated item: %v", err)
|
||||
return ChecklistItem{}, err
|
||||
|
@ -368,6 +430,16 @@ func updateItem(uuid string, id int, content *string, checked *bool, parentID *i
|
|||
v := int(parentID.Int64)
|
||||
it.ParentID = &v
|
||||
}
|
||||
if notBefore.Valid {
|
||||
if t, err := time.Parse(time.RFC3339, notBefore.String); err == nil {
|
||||
it.NotBefore = &t
|
||||
}
|
||||
}
|
||||
if notAfter.Valid {
|
||||
if t, err := time.Parse(time.RFC3339, notAfter.String); err == nil {
|
||||
it.NotAfter = &t
|
||||
}
|
||||
}
|
||||
it.Checklist = uuid
|
||||
|
||||
// Load dependencies
|
||||
|
@ -477,15 +549,17 @@ func handleAddItem(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
type Req struct {
|
||||
Content string `json:"content"`
|
||||
ParentID *int `json:"parent_id"`
|
||||
Content string `json:"content"`
|
||||
ParentID *int `json:"parent_id"`
|
||||
NotBefore *time.Time `json:"not_before"`
|
||||
NotAfter *time.Time `json:"not_after"`
|
||||
}
|
||||
var req Req
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || strings.TrimSpace(req.Content) == "" {
|
||||
http.Error(w, "Missing content", 400)
|
||||
return
|
||||
}
|
||||
item, err := addItem(uuid, req.Content, req.ParentID)
|
||||
item, err := addItem(uuid, req.Content, req.ParentID, req.NotBefore, req.NotAfter)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to add item", 500)
|
||||
return
|
||||
|
@ -521,19 +595,21 @@ func handleUpdateItem(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
type Req struct {
|
||||
Content *string `json:"content"`
|
||||
Checked *bool `json:"checked"`
|
||||
ParentID *int `json:"parent_id"`
|
||||
Dependencies *[]int `json:"dependencies"`
|
||||
Content *string `json:"content"`
|
||||
Checked *bool `json:"checked"`
|
||||
ParentID *int `json:"parent_id"`
|
||||
Dependencies *[]int `json:"dependencies"`
|
||||
NotBefore *time.Time `json:"not_before"`
|
||||
NotAfter *time.Time `json:"not_after"`
|
||||
}
|
||||
var req Req
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Bad body", 400)
|
||||
return
|
||||
}
|
||||
item, err := updateItem(uuid, id, req.Content, req.Checked, req.ParentID, req.Dependencies)
|
||||
item, err := updateItem(uuid, id, req.Content, req.Checked, req.ParentID, req.Dependencies, req.NotBefore, req.NotAfter)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "cannot complete item: dependency") {
|
||||
if strings.Contains(err.Error(), "cannot complete item:") {
|
||||
http.Error(w, err.Error(), 400)
|
||||
} else {
|
||||
http.Error(w, "Not found", 404)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue