feat: add JSON serialization, urgency field, and snake_case API contract
Fix latent API bug where multi-word fields (RecurrenceDuration, ParentUUID, CreatedAt) serialized as PascalCase, breaking the frontend. Add explicit snake_case json tags and custom MarshalJSON/UnmarshalJSON on Task, Status, and APIKey to emit unix timestamps and string status codes. Add Urgency float64 as a derived field on Task, populated via PopulateUrgency helper in all handlers before serialization. The report engine's sortByUrgency now also retains the computed score. Frontend updated with urgency type, color-coded badge in TaskItem, and mock data values. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ package engine
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -11,12 +12,69 @@ import (
|
||||
|
||||
// APIKey represents an API key in the database
|
||||
type APIKey struct {
|
||||
ID int
|
||||
Name string
|
||||
UserID int
|
||||
CreatedAt time.Time
|
||||
LastUsed *time.Time
|
||||
Revoked bool
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UserID int `json:"user_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
LastUsed *time.Time `json:"last_used,omitempty"`
|
||||
Revoked bool `json:"revoked"`
|
||||
}
|
||||
|
||||
// MarshalJSON emits APIKey with unix timestamps.
|
||||
func (k APIKey) MarshalJSON() ([]byte, error) {
|
||||
type keyJSON struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UserID int `json:"user_id"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
LastUsed *int64 `json:"last_used,omitempty"`
|
||||
Revoked bool `json:"revoked"`
|
||||
}
|
||||
|
||||
var lastUsed *int64
|
||||
if k.LastUsed != nil {
|
||||
v := k.LastUsed.Unix()
|
||||
lastUsed = &v
|
||||
}
|
||||
|
||||
return json.Marshal(keyJSON{
|
||||
ID: k.ID,
|
||||
Name: k.Name,
|
||||
UserID: k.UserID,
|
||||
CreatedAt: k.CreatedAt.Unix(),
|
||||
LastUsed: lastUsed,
|
||||
Revoked: k.Revoked,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses APIKey from JSON with unix timestamps.
|
||||
func (k *APIKey) UnmarshalJSON(data []byte) error {
|
||||
type keyJSON struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UserID int `json:"user_id"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
LastUsed *int64 `json:"last_used,omitempty"`
|
||||
Revoked bool `json:"revoked"`
|
||||
}
|
||||
|
||||
var raw keyJSON
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.ID = raw.ID
|
||||
k.Name = raw.Name
|
||||
k.UserID = raw.UserID
|
||||
k.CreatedAt = time.Unix(raw.CreatedAt, 0)
|
||||
k.Revoked = raw.Revoked
|
||||
|
||||
if raw.LastUsed != nil {
|
||||
t := time.Unix(*raw.LastUsed, 0)
|
||||
k.LastUsed = &t
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateAPIKey creates a new API key for the given name
|
||||
|
||||
Reference in New Issue
Block a user