login

<     >

2023-08-05 12:48:49 (UTC-03:00)

Marcel Rodrigues <marcelgmr@gmail.com>

db: add invited_by to User and hard-code states

diff --git a/data.lua b/data.lua
index cfaa737..77a8faa 100644
--- a/data.lua
+++ b/data.lua
@@ -14,7 +14,8 @@ CREATE TABLE IF NOT EXISTS User (
     nick TEXT NOT NULL UNIQUE,
     name TEXT NOT NULL,
     salt TEXT,
-    hash TEXT
+    hash TEXT,
+    invited_by INTEGER REFERENCES User(id)
 );
 CREATE TABLE IF NOT EXISTS Invite (
     uuid TEXT PRIMARY KEY,
@@ -36,15 +37,11 @@ CREATE TABLE IF NOT EXISTS Membership (
     user_id INTEGER REFERENCES User(id),
     PRIMARY KEY(proj_id, user_id)
 );
-CREATE TABLE IF NOT EXISTS State (
-    id INTEGER PRIMARY KEY AUTOINCREMENT,
-    name TEXT NOT NULL UNIQUE
-);
 CREATE TABLE IF NOT EXISTS Ticket (
     id INTEGER PRIMARY KEY AUTOINCREMENT,
     proj_id INTEGER NOT NULL REFERENCES Project(id),
     user_id INTEGER NOT NULL REFERENCES User(id),
-    state_id INTEGER NOT NULL REFERENCES State(id),
+    state_id INTEGER NOT NULL,
     time INTEGER NOT NULL,
     code INTEGER NOT NULL,
     title TEXT NOT NULL,
@@ -60,8 +57,8 @@ CREATE TABLE IF NOT EXISTS Block (
 CREATE TABLE IF NOT EXISTS Shift (
     id INTEGER PRIMARY KEY AUTOINCREMENT,
     ticket_id INTEGER NOT NULL REFERENCES Ticket(id),
-    old_stt_id INTEGER NOT NULL REFERENCES State(id),
-    new_stt_id INTEGER NOT NULL REFERENCES State(id),
+    old_stt_id INTEGER NOT NULL,
+    new_stt_id INTEGER NOT NULL,
     user_id INTEGER NOT NULL REFERENCES User(id),
     time INTEGER NOT NULL
 );
@@ -81,33 +78,22 @@ function Model:create_tables()
     self.db:execute_many(schema)
 end
 
-function Model:create_states()
-    self.db:execute[[
-        INSERT INTO State(name) VALUES
-        ("backlog"), ("design"), ("progress"), ("review"), ("done");
-    ]]
-end
-
-function Model:get_states()
-    return self.db:execute("SELECT * FROM State;")
-end
-
-function Model:get_indexed_states()
-    local query = "SELECT id, name FROM State;"
-    local states = {}
-    for _, state in ipairs(self.db:execute(query)) do
-        states[state.id] = state.name
-    end
-    return states
-end
-
-function Model:create_user(nick, name, password)
+function Model:create_user(nick, name, password, uuid)
+    self:expire_invites()
+    local inv = self.db:execute("SELECT * FROM Invite WHERE uuid = ?;", uuid)[1]
+    if inv == nil then return false end
     local salt = auth.get_salt()
     local hash = auth.hash_pass(password, salt)
     salt = auth.b64_enc(salt)
     hash = auth.b64_enc(hash)
-    local query = "INSERT INTO User(nick, name, salt, hash) VALUES (?, ?, ?, ?);"
-    self.db:execute(query, nick, name, salt, hash)
+    local query = "INSERT INTO User(nick, name, salt, hash, invited_by) VALUES (?, ?, ?, ?, ?);"
+    self.db:execute(query, nick, name, salt, hash, inv.user_id)
+    self.db:execute("DELETE FROM Invite WHERE uuid = ?;", uuid)
+    return true
+end
+
+function Model:get_user_count()
+    return self.db:execute("SELECT COUNT(*) as count FROM User;")[1].count
 end
 
 function Model:get_user(nick)
@@ -139,15 +125,6 @@ function Model:expire_invites()
     self.db:execute("DELETE FROM Invite WHERE expire < unixepoch();")
 end
 
-function Model:use_invite(uuid)
-    self:expire_invites()
-    local inv = self.db:execute("SELECT * FROM Invite WHERE uuid = ?;", uuid)[1]
-    if inv ~= nil then
-        self.db:execute("DELETE FROM Invite WHERE uuid = ?;", uuid)
-    end
-    return inv ~= nil
-end
-
 function Model:del_invite(user_id, uuid)
     self.db:execute("DELETE FROM Invite WHERE user_id = ? AND uuid = ?;", user_id, uuid)
 end
@@ -224,7 +201,6 @@ function Model:get_ticket(proj_id, code)
 end
 
 function Model:get_tickets(proj_id, state_id)
-    -- TODO: limit "done" tickets by age
     local query = "SELECT * FROM Ticket WHERE proj_id = ? AND state_id = ?;"
     return self.db:execute(query, proj_id, state_id)
 end
@@ -292,6 +268,7 @@ end
 local function open(path)
     local self = setmetatable({path=path}, Model)
     self.db = lud.sqlite.open(path)
+    self.states = {"backlog", "design", "progress", "review", "done"}
     return self
 end
 

diff --git a/skopos.lua b/skopos.lua
index a2893c7..343f33f 100644
--- a/skopos.lua
+++ b/skopos.lua
@@ -10,12 +10,13 @@ App.__index = App
 
 function App:init()
     self.model:create_tables()
-    if #self.model:get_states() == 0 then
-        self.model:create_states()
+    local user_count = self.model:get_user_count()
+    if user_count == 0 then
         local uuid = self.model:create_invite()
         self:log(LOG_INFO, "root invite: "..uuid)
     else
         self.model:expire_invites()
+        self:log(LOG_INFO, "user count: "..user_count)
     end
 end
 
@@ -70,11 +71,10 @@ function App:routes()
         if self.model:get_user(nick) ~= nil then  -- user already exists
             return fail_path, 303
         end
-        if not self.model:use_invite(uuid) then -- invalid/expired invite
+        if not self.model:create_user(nick, name, pass, uuid) then
             self:log(LOG_WARN, "attempt to use invalid invite: "..uuid)
             return fail_path, 303
         end
-        self.model:create_user(nick, name, pass)
         self:log(LOG_INFO, "new user joined: "..nick)
         return "/login", 303
     end},
@@ -222,12 +222,11 @@ function App:routes()
         local tick = self.model:get_ticket(proj.id, tonumber(code))
         if tick == nil then return "not found", 404 end
         local users = self.model:get_indexed_users()
-        local states = self.model:get_indexed_states()
         -- TODO: load comments
         local comments = {}
         local env = {
             title=self.title, user=user, proj=proj, tick=tick,
-            users=users, states=states, comments=comments
+            users=users, states=self.model.states, comments=comments
         }
         return lud.template.render_file("view/ticket.html", env)
     end},