login

<     >

2023-08-09 11:58:34 (UTC-03:00)

Marcel Rodrigues <marcelgmr@gmail.com>

add basic comment CRUD

diff --git a/data.lua b/data.lua
index b172d45..5753297 100644
--- a/data.lua
+++ b/data.lua
@@ -67,6 +67,7 @@ CREATE TABLE IF NOT EXISTS Comment (
     ticket_id INTEGER NOT NULL REFERENCES Ticket(id),
     user_id INTEGER NOT NULL REFERENCES User(id),
     time INTEGER NOT NULL,
+    code INTEGER NOT NULL,
     text TEXT NOT NULL
 );
 ]]
@@ -173,21 +174,24 @@ function Model:del_project(proj_id)
     self.db:execute("DELETE FROM Project WHERE id = ?;", proj_id)
 end
 
--- generate new ticket code for a given project
-function Model:get_next_code(proj_id)
-    local query = "SELECT code FROM Ticket WHERE proj_id = ? ORDER BY code DESC LIMIT 1;"
-    local last_ticket = self.db:execute(query, proj_id)[1]
+-- generate new code for a child object
+-- ticket_code = get_next_ticket_code("Ticket", "proj_id", proj_id)
+-- comment_code = get_next_ticket_code("Comment", "ticket_id", ticket_id)
+function Model:get_next_code(class, parent_row, parent_id)
+    local query = "SELECT code FROM %s WHERE %s = ? ORDER BY code DESC LIMIT 1;"
+    query = query:format(class, parent_row)
+    local last_child = self.db:execute(query, parent_id)[1]
     local last_code
-    if last_ticket == nil then
+    if last_child == nil then
         last_code = 0
     else
-        last_code = last_ticket.code
+        last_code = last_child.code
     end
     return last_code + 1
 end
 
 function Model:create_ticket(user_id, proj_id, title, desc, priority)
-    local code = self:get_next_code(proj_id)
+    local code = self:get_next_code("Ticket", "proj_id", proj_id)
     self.db:execute([[
         INSERT INTO Ticket(proj_id, user_id, state_id, time, code, title, desc, priority, is_active)
         VALUES (?, ?, 1, unixepoch(), ?, ?, ?, ?, 1);
@@ -245,14 +249,39 @@ function Model:del_ticket(tick_id)
 end
 
 function Model:add_comment(user_id, ticket_id, text)
+    local code = self:get_next_code("Comment", "ticket_id", ticket_id)
     self.db:execute([[
-        INSERT INTO Comment(ticket_id, user_id, time, text)
-        VALUES (?, ?, unixepoch(), ?);
-    ]], ticket_id, user_id, text)
+        INSERT INTO Comment(ticket_id, user_id, time, code, text)
+        VALUES (?, ?, unixepoch(), ?, ?);
+    ]], ticket_id, user_id, code, text)
+    return code
+end
+
+function Model:get_comment(ticket_id, code, full)
+    local query
+    if full then
+        query = [[
+            SELECT Comment.*, User.nick AS author_nick, User.name AS author_name
+            FROM Comment JOIN User ON Comment.user_id = User.id
+            WHERE Comment.ticket_id = ? AND Comment.code = ?;
+        ]]
+    else
+        query = "SELECT * FROM Comment WHERE ticket_id = ? AND code = ?;"
+    end
+    return self.db:execute(query, ticket_id, code)[1]
 end
 
 function Model:get_comments(ticket_id)
-    return self.db:execute("SELECT * FROM Comment WHERE ticket_id = ?;", ticket_id)
+    local query = "SELECT * FROM Comment WHERE ticket_id = ? ORDER BY code ASC;"
+    return self.db:execute(query, ticket_id)
+end
+
+function Model:update_comment(comm_id, text)
+    self.db:execute("UPDATE Comment SET text = ? WHERE id = ?;", text, comm_id)
+end
+
+function Model:del_comment(comm_id)
+    self.db:execute("DELETE FROM Comment WHERE id = ?;", comm_id)
 end
 
 -- return a list of columns ordered by state ID

diff --git a/skopos.lua b/skopos.lua
index fe1bcaa..35c22e5 100644
--- a/skopos.lua
+++ b/skopos.lua
@@ -227,8 +227,7 @@ function App:routes()
         if proj == nil then return "not found", 404 end
         local tick = self.model:get_ticket(proj.id, code, true)
         if tick == nil then return "not found", 404 end
-        -- TODO: load comments
-        local comments = {}
+        local comments = self.model:get_comments(tick.id)
         local env = {
             title=self.title, user=user, proj=proj, tick=tick,
             states=self.model.states, comments=comments
@@ -304,6 +303,74 @@ function App:routes()
         end
         return "/p/"..name, 303
     end},
+    -- Comments
+    {"GET", "/p/([-_%w]+)/t/(%d+)/c/new",
+    function (req, name, tcode)
+        local user = self:get_user(req)
+        if user == nil then return "/login?after="..req.path, 303 end
+        local proj = self.model:get_user_project(user.id, name)
+        if proj == nil then return "not found", 404 end
+        local tick = self.model:get_ticket(proj.id, tcode)
+        if tick == nil then return "not found", 404 end
+        local env = {title=self.title, user=user, proj=proj, tick=tick}
+        return lud.template.render_file("view/comment_form.html", env)
+    end},
+    {"POST", "/p/([-_%w]+)/t/(%d+)/c",
+    function (req, name, tcode)
+        local user = self:get_user(req)
+        if user == nil then return "/login", 303 end
+        local proj = self.model:get_user_project(user.id, name)
+        if proj == nil then return "not found", 404 end
+        local tick = self.model:get_ticket(proj.id, tcode)
+        if tick == nil then return "not found", 404 end
+        local text = req.form.text
+        local code = self.model:add_comment(user.id, tick.id, text)
+        self:log(LOG_INFO, "user "..user.nick.." commented on ticket "..name.."#"..tcode)
+        return "/p/"..name.."/t/"..tcode, 303
+    end},
+    {"GET", "/p/([-_%w]+)/t/(%d+)/c/(%d+)/edit",
+    function (req, name, tcode, ccode)
+        local user = self:get_user(req)
+        if user == nil then return "/login?after="..req.path, 303 end
+        local proj = self.model:get_user_project(user.id, name)
+        if proj == nil then return "not found", 404 end
+        local tick = self.model:get_ticket(proj.id, tcode)
+        if tick == nil then return "not found", 404 end
+        local comm = self.model:get_comment(tick.id, ccode)
+        if comm == nil then return "not found", 404 end
+        local env = {title=self.title, user=user, proj=proj, tick=tick, comm=comm}
+        return lud.template.render_file("view/comment_form.html", env)
+    end},
+    {"POST", "/p/([-_%w]+)/t/(%d+)/c/(%d+)/put",
+    function (req, name, tcode, ccode)
+        local user = self:get_user(req)
+        if user == nil then return "/login", 303 end
+        local proj = self.model:get_user_project(user.id, name)
+        if proj == nil then return "not found", 404 end
+        local tick = self.model:get_ticket(proj.id, tcode)
+        if tick == nil then return "not found", 404 end
+        local comm = self.model:get_comment(tick.id, ccode)
+        if comm == nil then return "not found", 404 end
+        local text = req.form.text
+        self.model:update_comment(comm.id, text)
+        self:log(LOG_INFO, "user "..user.nick.." edited comment "..name.."#"..tcode.."#"..ccode)
+        return "/p/"..name.."/t/"..tcode, 303
+    end},
+    {"POST", "/p/([-_%w]+)/t/(%d+)/c/(%d+)/del",
+    function (req, name, tcode, ccode)
+        local user = self:get_user(req)
+        if user == nil then return "/login", 303 end
+        local proj = self.model:get_user_project(user.id, name)
+        if proj == nil then return "not found", 404 end
+        local tick = self.model:get_ticket(proj.id, tcode)
+        if tick == nil then return "not found", 404 end
+        local comm = self.model:get_comment(tick.id, ccode)
+        if comm ~= nil then
+            self.model:del_comment(comm.id)
+            self:log(LOG_INFO, "user "..user.nick.." deleted comment "..name.."#"..tcode.."#"..ccode)
+        end
+        return "/p/"..name.."/t/"..tcode, 303
+    end},
 } end
 
 local function new_app(db_path, port, title, log_level)

diff --git a/view/comment_form.html b/view/comment_form.html
new file mode 100644
index 0000000..05b714c
--- /dev/null
+++ b/view/comment_form.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>{{$title}}</title>
+  <style>
+    .centered { text-align: center; }
+    % include view/form.css
+  </style>
+</head>
+<body>
+  <h1 class="centered">Comment</h1>
+  % set action = "/p/" .. $proj.name .. "/t/" .. $tick.code .. "/c"
+  % if $comm == nil then
+  %   set action = $action
+  %   set comm = {text=""}
+  %   set submit_value = "Create"
+  % else
+  %   set action = $action .. "/" .. $comm.code .. "/put"
+  %   set submit_value = "Save"
+  % end
+  <form action="{{$action}}" method="post">
+    <table class="field-list">
+      <tbody>
+        <tr>
+          <td>
+            <label for="desc">Text:</label>
+          </td>
+          <td>
+            <textarea
+              class="flat-field" id="text" name="text"
+              cols="50" rows="5">{{$comm.text}}</textarea>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+    <br>
+    <input type="submit" class="flat-button" value="{{$submit_value}}">
+  </form>
+</body>
+</html>

diff --git a/view/ticket.html b/view/ticket.html
index 05006bd..30257ff 100644
--- a/view/ticket.html
+++ b/view/ticket.html
@@ -34,16 +34,24 @@
   </div>
   <div class="comments-section">
     <h2>Comments</h2>
-    % for comment in $comments do
+    % for comm in $comments do
     <div class="comment">
       <div class="header-details">
-        <p class="date"><strong>Date:</strong> {{os.date("%Y-%m-%d", $comment.time)}}</p>
+        <p class="date"><strong>Date:</strong> {{os.date("%Y-%m-%d", $comm.time)}}</p>
         <p class="author">
           <strong>Author:</strong>
-          <a href="/u/{{$comment.author_nick}}">{{$comment.author_name}}</a>
+          <a href="/u/{{$comm.author_nick}}">{{$comm.author_name}}</a>
         </p>
       </div>
-      <pre>{{$comment.text}}</pre>
+      <pre>{{$comm.text}}</pre>
+      <div class="footer-details">
+        <div class="menu">
+          <a href="/p/{{$proj.name}}/t/{{$tick.code}}/c/{{$comm.code}}/edit">edit</a>
+          <form action="/p/{{$proj.name}}/t/{{$tick.code}}/c/{{$comm.code}}/del" method="post">
+            <button type="submit">delete</button>
+          </form>
+        </div>
+      </div>
     </div>
     % end
   </div>