Browse Source

Feature: ToDo dropdown

master
parent
commit
192c48eaa6
  1. 52
      pages/category.html
  2. 17
      src/db/group.go
  3. 33
      src/server/endpoints.go

52
pages/category.html

@ -16,13 +16,13 @@
<div class="list-group list-group-flush border-bottom scrollarea">
{{ range .Groups }}
<a href="/group/{{.ID}}" class="list-group-item list-group-item-action py-3 lh-sm {{if eq .ID $.CurrentGroupId}} active {{end}}" aria-current="true">
<div class="d-flex w-100 align-items-center justify-content-between">
<strong class="mb-1">{{ .Name }}</strong>
<small>{{ .TimeCreated }}</small>
<a id="group-{{.ID}}" href="/group/{{.ID}}" class="list-group-item list-group-item-action py-3 lh-sm {{if eq .ID $.CurrentGroupId}} active {{end}}" aria-current="true" ondragover="allowDrop(event);" ondrop="drop(event);">
<div id="group-{{.ID}}" class="d-flex w-100 align-items-center justify-content-between">
<strong id="group-{{.ID}}" class="mb-1">{{ .Name }}</strong>
<small id="group-{{.ID}}">{{ .TimeCreated }}</small>
</div>
{{ if not .Removable }}
<div class="col-10 mb-1 small">Not removable</div>
<div id="group-{{.ID}}" class="col-10 mb-1 small">Not removable</div>
{{ end }}
</a>
{{ end }}
@ -61,10 +61,11 @@
<tbody class="text-break">
{{ range .Todos }}
{{ if not .IsDone }}
<tr>
<td>{{ .Text }}</td>
<td>{{ .TimeCreated }}</td>
<td>{{ .Due }}</td>
<tr draggable="true" id="todo-{{.ID}}" ondragstart="dragStart(event);">
<td class="todo-text">{{ .Text }}</td>
<td class="todo-created">{{ .TimeCreated }}</td>
<td class="todo-due">{{ .Due }}</td>
<td class="todo-due-unix" style="display: none;">{{ .DueUnix }}</td>
<td>
<button class="btn btn-success" onclick="markAsDoneRefresh({{.ID}});"><img src='/static/images/check.svg'></button>
<button class="btn btn-danger" onclick="deleteTodoRefresh({{.ID}});"><img src='/static/images/trash3-fill.svg'></button>
@ -121,6 +122,39 @@ async function showDone() {
dueTodos.style.display = "none";
}
function allowDrop(event) {
event.preventDefault();
}
function dragStart(event) {
event.dataTransfer.setData("text", event.target.id);
event.dataTransfer.effectAllowed = "move";
}
async function drop(event) {
event.preventDefault();
var todoPageId = event.dataTransfer.getData("text");
let draggedTodo = document.getElementById(todoPageId);
let todoId = todoPageId.split("-")[1];
let targetGroupId = event.target.id.split("-")[1];
if (targetGroupId == document.getElementById("categoryId").innerText) {
// Do nothing
return;
}
console.log("passed");
// Add a copy of this ToDo in the corresponding group
let result = await postNewTodo({
text: draggedTodo.getElementsByClassName("todo-text")[0].innerText,
groupId: Number(targetGroupId),
dueUnix: Number(draggedTodo.getElementsByClassName("todo-due-unix")[0].innerText),
});
// Delete this ToDo in this group
await deleteTodoRefresh(todoId);
}
document.addEventListener('DOMContentLoaded', async function() {
document.getElementById("new-todo-text").focus();

17
src/db/group.go

@ -150,6 +150,23 @@ func (db *DB) DeleteTodoGroup(id uint64) error {
return err
}
// Deletes all ToDos associated with this group and then the group itself
func (db *DB) DeleteTodoGroupClean(groupId uint64) error {
_, err := db.Exec("DELETE FROM todos WHERE group_id=?",
groupId,
)
if err != nil {
return err
}
_, err = db.Exec(
"DELETE FROM todo_groups WHERE id=?",
groupId,
)
return err
}
// Updates TODO group's name
func (db *DB) UpdateTodoGroup(groupID uint64, updatedGroup TodoGroup) error {
_, err := db.Exec(

33
src/server/endpoints.go

@ -407,6 +407,11 @@ func (s *Server) EndpointTodoDelete(w http.ResponseWriter, req *http.Request) {
func (s *Server) EndpointTodoCreate(w http.ResponseWriter, req *http.Request) {
// Create a new TODO
defer req.Body.Close()
if req.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Read body
body, err := io.ReadAll(req.Body)
if err != nil {
@ -431,6 +436,16 @@ func (s *Server) EndpointTodoCreate(w http.ResponseWriter, req *http.Request) {
}
// Add TODO to the database
if newTodo.GroupID == 0 {
http.Error(w, "No group ID was provided", http.StatusBadRequest)
return
}
if !s.db.DoesUserOwnGroup(newTodo.GroupID, GetLoginFromReq(req)) {
http.Error(w, "You do not own this group", http.StatusForbidden)
return
}
newTodo.OwnerLogin = GetLoginFromReq(req)
newTodo.TimeCreatedUnix = uint64(time.Now().Unix())
err = s.db.CreateTodo(newTodo)
@ -485,6 +500,11 @@ func (s *Server) EndpointTodoGroupDelete(w http.ResponseWriter, req *http.Reques
// Delete an existing group
defer req.Body.Close()
if req.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Check if given user actually owns this group
if !IsUserAuthorizedReq(req, s.db) {
http.Error(w, "Invalid user auth data", http.StatusForbidden)
@ -516,8 +536,8 @@ func (s *Server) EndpointTodoGroupDelete(w http.ResponseWriter, req *http.Reques
return
}
// Delete
err = s.db.DeleteTodoGroup(groupId)
// Delete all ToDos associated with this group and then delete the group itself
err = s.db.DeleteTodoGroupClean(groupId)
if err != nil {
logger.Error("[Server][EndpointGroupDelete] Failed to delete %s's TODO group: %s", GetLoginFromReq(req), err)
http.Error(w, "Failed to delete TODO group", http.StatusInternalServerError)
@ -525,13 +545,19 @@ func (s *Server) EndpointTodoGroupDelete(w http.ResponseWriter, req *http.Reques
}
// Success!
logger.Info("[Server][EndpointGroupDelete] Deleted group ID: %d for %s", groupId, GetLoginFromReq(req))
logger.Info("[Server][EndpointGroupDelete] Cleanly deleted group ID: %d for %s", groupId, GetLoginFromReq(req))
w.WriteHeader(http.StatusOK)
}
func (s *Server) EndpointTodoGroupCreate(w http.ResponseWriter, req *http.Request) {
// Create a new TODO group
defer req.Body.Close()
if req.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Read body
body, err := io.ReadAll(req.Body)
if err != nil {
@ -568,7 +594,6 @@ func (s *Server) EndpointTodoGroupCreate(w http.ResponseWriter, req *http.Reques
// Success!
w.WriteHeader(http.StatusOK)
logger.Info("[Server] Created a new TODO group for %s", newGroup.OwnerLogin)
}
func (s *Server) EndpointTodoGroupGet(w http.ResponseWriter, req *http.Request) {

Loading…
Cancel
Save