| 24 |
24 |
|
tags TEXT, |
| 25 |
25 |
|
content TEXT NOT NULL, |
| 26 |
26 |
|
status TEXT NOT NULL DEFAULT 'draft', |
| 27 |
|
- |
created_at TEXT NOT NULL DEFAULT (datetime('now')), |
| 28 |
|
- |
updated_at TEXT NOT NULL DEFAULT (datetime('now')) |
|
27 |
+ |
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')), |
|
28 |
+ |
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')) |
| 29 |
29 |
|
); |
| 30 |
30 |
|
|
| 31 |
31 |
|
CREATE TABLE IF NOT EXISTS pages ( |
|
| 36 |
36 |
|
content TEXT NOT NULL, |
| 37 |
37 |
|
is_published INTEGER NOT NULL DEFAULT 0, |
| 38 |
38 |
|
nav_order INTEGER NOT NULL DEFAULT 0, |
| 39 |
|
- |
created_at TEXT NOT NULL DEFAULT (datetime('now')), |
| 40 |
|
- |
updated_at TEXT NOT NULL DEFAULT (datetime('now')) |
|
39 |
+ |
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')), |
|
40 |
+ |
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')) |
| 41 |
41 |
|
); |
| 42 |
42 |
|
|
| 43 |
43 |
|
CREATE TABLE IF NOT EXISTS settings ( |
|
| 52 |
52 |
|
original_name TEXT NOT NULL, |
| 53 |
53 |
|
content_type TEXT NOT NULL DEFAULT 'application/octet-stream', |
| 54 |
54 |
|
size INTEGER NOT NULL, |
| 55 |
|
- |
created_at TEXT NOT NULL DEFAULT (datetime('now')), |
|
55 |
+ |
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')), |
| 56 |
56 |
|
storage_backend TEXT NOT NULL DEFAULT 'local' |
| 57 |
57 |
|
); |
| 58 |
58 |
|
` |
|
| 148 |
148 |
|
if err != nil { |
| 149 |
149 |
|
return nil, err |
| 150 |
150 |
|
} |
|
151 |
+ |
in.PublishedDate = normalizePubDatePtr(in.PublishedDate) |
| 151 |
152 |
|
res, err := db.Exec( |
| 152 |
153 |
|
`INSERT INTO posts (short_id, title, slug, content, status, alias, canonical_url, published_date, meta_description, meta_image, lang, tags) |
| 153 |
154 |
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, |
|
| 209 |
210 |
|
} |
| 210 |
211 |
|
|
| 211 |
212 |
|
func updatePost(db *sql.DB, shortID string, in PostInput) (*Post, error) { |
|
213 |
+ |
in.PublishedDate = normalizePubDatePtr(in.PublishedDate) |
| 212 |
214 |
|
res, err := db.Exec( |
| 213 |
215 |
|
`UPDATE posts SET title = ?, slug = ?, content = ?, status = ?, alias = ?, canonical_url = ?, |
| 214 |
|
- |
published_date = CASE WHEN ? = 'published' THEN COALESCE(?, published_date, datetime('now')) ELSE ? END, |
|
216 |
+ |
published_date = CASE WHEN ? = 'published' THEN COALESCE(?, published_date, strftime('%Y-%m-%dT%H:%M:%SZ','now')) ELSE ? END, |
| 215 |
217 |
|
meta_description = ?, meta_image = ?, lang = ?, tags = ?, |
| 216 |
|
- |
updated_at = datetime('now') WHERE short_id = ?`, |
|
218 |
+ |
updated_at = strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE short_id = ?`, |
| 217 |
219 |
|
nullable(in.Title), in.Slug, in.Content, in.Status, nullable(in.Alias), nullable(in.CanonicalURL), |
| 218 |
220 |
|
in.Status, nullable(in.PublishedDate), nullable(in.PublishedDate), |
| 219 |
221 |
|
nullable(in.MetaDescription), nullable(in.MetaImage), in.Lang, nullable(in.Tags), shortID, |
|
| 251 |
253 |
|
} |
| 252 |
254 |
|
if newStatus == "published" { |
| 253 |
255 |
|
_, err = db.Exec( |
| 254 |
|
- |
`UPDATE posts SET status = ?, published_date = COALESCE(published_date, datetime('now')), updated_at = datetime('now') WHERE short_id = ?`, |
|
256 |
+ |
`UPDATE posts SET status = ?, published_date = COALESCE(published_date, strftime('%Y-%m-%dT%H:%M:%SZ','now')), updated_at = strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE short_id = ?`, |
| 255 |
257 |
|
newStatus, shortID) |
| 256 |
258 |
|
} else { |
| 257 |
|
- |
_, err = db.Exec(`UPDATE posts SET status = ?, updated_at = datetime('now') WHERE short_id = ?`, |
|
259 |
+ |
_, err = db.Exec(`UPDATE posts SET status = ?, updated_at = strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE short_id = ?`, |
| 258 |
260 |
|
newStatus, shortID) |
| 259 |
261 |
|
} |
| 260 |
262 |
|
return newStatus, err |
|
| 338 |
340 |
|
pub = 1 |
| 339 |
341 |
|
} |
| 340 |
342 |
|
res, err := db.Exec( |
| 341 |
|
- |
`UPDATE pages SET title = ?, slug = ?, content = ?, is_published = ?, nav_order = ?, updated_at = datetime('now') WHERE short_id = ?`, |
|
343 |
+ |
`UPDATE pages SET title = ?, slug = ?, content = ?, is_published = ?, nav_order = ?, updated_at = strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE short_id = ?`, |
| 342 |
344 |
|
title, slug, content, pub, navOrder, shortID) |
| 343 |
345 |
|
if err != nil { |
| 344 |
346 |
|
return nil, err |
|
| 437 |
439 |
|
} |
| 438 |
440 |
|
|
| 439 |
441 |
|
func nowDatetime() string { |
| 440 |
|
- |
return time.Now().UTC().Format("2006-01-02 15:04:05") |
|
442 |
+ |
return time.Now().UTC().Format(time.RFC3339) |
|
443 |
+ |
} |
|
444 |
+ |
|
|
445 |
+ |
// migrateTimestamps rewrites legacy "YYYY-MM-DD HH:MM:SS" and date-only values |
|
446 |
+ |
// to RFC3339 UTC. Idempotent: skips values already in RFC3339 form. |
|
447 |
+ |
func migrateTimestamps(db *sql.DB) error { |
|
448 |
+ |
stmts := []string{ |
|
449 |
+ |
`UPDATE posts SET published_date = REPLACE(published_date, ' ', 'T') || 'Z' |
|
450 |
+ |
WHERE published_date IS NOT NULL AND length(published_date) = 19 |
|
451 |
+ |
AND published_date LIKE '____-__-__ __:__:__'`, |
|
452 |
+ |
`UPDATE posts SET published_date = published_date || 'T00:00:00Z' |
|
453 |
+ |
WHERE published_date IS NOT NULL AND length(published_date) = 10 |
|
454 |
+ |
AND published_date LIKE '____-__-__'`, |
|
455 |
+ |
`UPDATE posts SET created_at = REPLACE(created_at, ' ', 'T') || 'Z' |
|
456 |
+ |
WHERE length(created_at) = 19 AND created_at LIKE '____-__-__ __:__:__'`, |
|
457 |
+ |
`UPDATE posts SET updated_at = REPLACE(updated_at, ' ', 'T') || 'Z' |
|
458 |
+ |
WHERE length(updated_at) = 19 AND updated_at LIKE '____-__-__ __:__:__'`, |
|
459 |
+ |
`UPDATE pages SET created_at = REPLACE(created_at, ' ', 'T') || 'Z' |
|
460 |
+ |
WHERE length(created_at) = 19 AND created_at LIKE '____-__-__ __:__:__'`, |
|
461 |
+ |
`UPDATE pages SET updated_at = REPLACE(updated_at, ' ', 'T') || 'Z' |
|
462 |
+ |
WHERE length(updated_at) = 19 AND updated_at LIKE '____-__-__ __:__:__'`, |
|
463 |
+ |
`UPDATE files SET created_at = REPLACE(created_at, ' ', 'T') || 'Z' |
|
464 |
+ |
WHERE length(created_at) = 19 AND created_at LIKE '____-__-__ __:__:__'`, |
|
465 |
+ |
} |
|
466 |
+ |
for _, s := range stmts { |
|
467 |
+ |
if _, err := db.Exec(s); err != nil { |
|
468 |
+ |
return err |
|
469 |
+ |
} |
|
470 |
+ |
} |
|
471 |
+ |
return nil |
|
472 |
+ |
} |
|
473 |
+ |
|
|
474 |
+ |
func normalizePubDatePtr(p *string) *string { |
|
475 |
+ |
if p == nil { |
|
476 |
+ |
return nil |
|
477 |
+ |
} |
|
478 |
+ |
if v, ok := parsePubDate(*p); ok { |
|
479 |
+ |
return &v |
|
480 |
+ |
} |
|
481 |
+ |
return p |
| 441 |
482 |
|
} |
| 442 |
483 |
|
|
| 443 |
484 |
|
func _useStrings() { |