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>