Add Web Push, guided start screen, SVG icons, chunked uploads, rename
- Web Push (VAPID + RFC 8291, pure Rust): permission/question/finished notifications while no app window is visible; settings with test button - Guided new-session flow: task, craft target (website/app/game/old software/fresh), clean room or deep, description, model, folder (new, existing or cloned git repository); originals upload to original/ - Craft phase bar (craft_phase tool) for study/specify/build/check/ready - Chunked uploads (8 MB) up to server.max_upload_mb (default 500 MB) - All UI glyphs and emojis replaced by themeable SVG icons - Rename dialog with manual name or model-generated suggestion Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
013695722a
commit
a0d0e707f2
48 files changed
+2724
-228
No files matched your search
@@ -97,6 +97,13 @@ impl Store {
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS queue_session ON queue(session_id, created_at);
|
||||
CREATE TABLE IF NOT EXISTS push_subs (
|
||||
endpoint TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
p256dh TEXT NOT NULL,
|
||||
auth TEXT NOT NULL,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS audit (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ts INTEGER NOT NULL,
|
||||
@@ -874,6 +881,30 @@ impl Store {
|
||||
// --- audit log & backup ----------------------------------------------------------
|
||||
|
||||
impl Store {
|
||||
// --- web push ---------------------------------------------------------
|
||||
|
||||
pub fn push_add(&self, user_id: &str, endpoint: &str, p256dh: &str, auth: &str) -> Result<()> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO push_subs (endpoint, user_id, p256dh, auth, created_at) VALUES (?1, ?2, ?3, ?4, ?5)
|
||||
ON CONFLICT(endpoint) DO UPDATE SET user_id = ?2, p256dh = ?3, auth = ?4",
|
||||
rusqlite::params![endpoint, user_id, p256dh, auth, now_ms()],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_remove(&self, endpoint: &str) -> Result<()> {
|
||||
self.conn.lock().unwrap().execute("DELETE FROM push_subs WHERE endpoint = ?1", [endpoint])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_subscriptions(&self, user_id: &str) -> Result<Vec<PushSub>> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let mut stmt = conn.prepare("SELECT endpoint, p256dh, auth FROM push_subs WHERE user_id = ?1")?;
|
||||
let rows = stmt.query_map([user_id], |r| Ok(PushSub { endpoint: r.get(0)?, p256dh: r.get(1)?, auth: r.get(2)? }))?;
|
||||
Ok(rows.collect::<std::result::Result<_, _>>()?)
|
||||
}
|
||||
|
||||
pub fn audit(&self, user_id: Option<&str>, username: &str, action: &str, detail: &str, ip: &str) {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let _ = conn.execute(
|
||||
@@ -946,3 +977,9 @@ impl Store {
|
||||
Ok(data.and_then(|d| serde_json::from_str::<Value>(&d).ok()).and_then(|v| v["created_at"].as_i64()))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PushSub {
|
||||
pub endpoint: String,
|
||||
pub p256dh: String,
|
||||
pub auth: String,
|
||||
}
|
||||
Reference in new issue
Block a user