Skip to content

Commit

Permalink
Streamline delete process for all deletable items
Browse files Browse the repository at this point in the history
  • Loading branch information
svera authored Mar 31, 2024
1 parent aec21c4 commit eaa86c4
Show file tree
Hide file tree
Showing 12 changed files with 49 additions and 98 deletions.
4 changes: 2 additions & 2 deletions internal/webserver/controller/document/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import (
)

func (d *Controller) Delete(c *fiber.Ctx) error {
if c.FormValue("slug") == "" {
if c.FormValue("id") == "" {
return fiber.ErrBadRequest
}

document, err := d.idx.Document(c.FormValue("slug"))
document, err := d.idx.Document(c.FormValue("id"))
if err != nil {
fmt.Println(err)
return fiber.ErrBadRequest
Expand Down
4 changes: 2 additions & 2 deletions internal/webserver/controller/user/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

// Delete removes a user from the database
func (u *Controller) Delete(c *fiber.Ctx) error {
user, err := u.repository.FindByUuid(c.FormValue("uuid"))
user, err := u.repository.FindByUuid(c.FormValue("id"))
if err != nil {
return fiber.ErrInternalServerError
}
Expand All @@ -20,7 +20,7 @@ func (u *Controller) Delete(c *fiber.Ctx) error {
return fiber.ErrForbidden
}

if err = u.repository.Delete(c.FormValue("uuid")); err != nil {
if err = u.repository.Delete(c.FormValue("id")); err != nil {
return fiber.ErrInternalServerError
}

Expand Down
35 changes: 22 additions & 13 deletions internal/webserver/embedded/js/delete.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,50 @@
const deleteModal = document.getElementById('deleteModal');
"use strict"

// We use several conventions to be able to use the same code to delete different resources.
// The link that initiates the action needs to have an attribute called data-id which must contain an unique identifier
// for the resource to delete.
// This identifier well be sent to the backend controller specified in the form's action attribute
// under the name "id".
// This code is designed to be used alongside partials/delete-modal.html

const deleteModal = document.getElementById('delete-modal');
const deleteForm = document.getElementById('delete-form');

deleteModal.addEventListener('show.bs.modal', event => {
const link = event.relatedTarget;
const slug = link.getAttribute('data-bs-slug');
const modalInputSlug = deleteModal.querySelector('.slug');
const link = event.relatedTarget
const id = link.getAttribute('data-id')
const modalInput = deleteModal.querySelector('.id')

modalInputSlug.value = slug;
modalInput.value = id;
})

deleteModal.addEventListener('hidden.bs.modal', event => {
let message = document.getElementById('delete-document-message');
let message = document.getElementById('error-message-container');
message.classList.add("visually-hidden");
})

function remove(errorMessage) {
deleteForm.addEventListener('submit', event => {
event.preventDefault();
form = document.getElementById("delete-form");
fetch('/document', {
fetch(deleteForm.getAttribute("action"), {
method: "DELETE",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'slug': form.elements['slug'].value,
'id': deleteForm.elements['id'].value,
})
})
.then((response) => {
if (response.ok) {
location.reload();
} else {
message = document.getElementById("delete-document-message")
message = document.getElementById("error-message-container")
message.classList.remove("visually-hidden");
message.innerHTML = errorMessage;
message.innerHTML = deleteForm.getAttribute("data-error-message");
}
})
.catch(function (error) {
// Catch errors
console.log(error);
});
}
})
3 changes: 0 additions & 3 deletions internal/webserver/embedded/views/highlights.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,3 @@ <h1 class="text-center">{{t .Lang "%s highlights" .Session.Name}}</h1>
{{ $length := len .Paginator.Pages }} {{ if gt $length 1 }}
{{template "partials/pagination" .}}
{{end}}

{{template "partials/delete-modal" .}}

4 changes: 2 additions & 2 deletions internal/webserver/embedded/views/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ <h2>{{t .Lang "Your highlights" }}</h2>
{{t $lang "Actions"}}
</button>
{{ template "partials/actions" dict "Lang" $lang "Document" $doc "EmailSendingConfigured"
$emailSendingConfigured "Index" $i "Session" $session "EmailFrom" $emailFrom "OnDehighlight" "remove"}}
$emailSendingConfigured "Session" $session "EmailFrom" $emailFrom "OnDehighlight" "remove"}}
</div>
</div>
</div>
{{end}}
</div>
{{template "partials/delete-modal" .}}
{{template "partials/delete-modal" dict "Lang" .Lang "Action" "/document" "ModalHeader" "Delete document" "ModalBody" "Are you sure you want to delete this document?" "ModalErrorMessage" "There was an error deleting the document"}}

<script type="text/javascript" src="/js/delete.js"></script>
<script type="text/javascript" src="/js/actions.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion internal/webserver/embedded/views/partials/actions.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
{{end}}
{{if and .Session (eq .Session.Role 2)}}
<div class="dropdown-divider"></div>
<li><a href="#" data-bs-toggle="modal" data-bs-target="#deleteModal" data-bs-slug="{{.Document.Slug}}" data-bs-index="{{.Index}}" class="dropdown-item">
<li><a href="#" data-bs-toggle="modal" data-bs-target="#delete-modal" data-id="{{.Document.Slug}}" class="dropdown-item">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash3-fill" viewBox="0 0 16 16">
<path d="M11 1.5v1h3.5a.5.5 0 0 1 0 1h-.538l-.853 10.66A2 2 0 0 1 11.115 16h-6.23a2 2 0 0 1-1.994-1.84L2.038 3.5H1.5a.5.5 0 0 1 0-1H5v-1A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5Zm-5 0v1h4v-1a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5ZM4.5 5.029l.5 8.5a.5.5 0 1 0 .998-.06l-.5-8.5a.5.5 0 1 0-.998.06Zm6.53-.528a.5.5 0 0 0-.528.47l-.5 8.5a.5.5 0 0 0 .998.058l.5-8.5a.5.5 0 0 0-.47-.528ZM8 4.5a.5.5 0 0 0-.5.5v8.5a.5.5 0 0 0 1 0V5a.5.5 0 0 0-.5-.5Z"/>
</svg>
Expand Down
12 changes: 6 additions & 6 deletions internal/webserver/embedded/views/partials/delete-modal.html
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModal" aria-hidden="true">
<div class="modal fade" id="delete-modal" tabindex="-1" aria-labelledby="delete-modal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form method="post" action="/delete" onsubmit='remove({{t .Lang "There was an error deleting the document"}})' id="delete-form">
<form action="{{.Action}}" data-error-message='{{t .Lang .ModalErrorMessage}}' id="delete-form">
<div class="modal-header">
<h1 class="modal-title fs-5" id="deleteModalLabel">{{t .Lang "Delete document"}}</h1>
<h1 class="modal-title fs-5" id="delete-modal-label">{{t .Lang .ModalHeader}}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="alert alert-danger visually-hidden" role="alert" id="delete-document-message">
<div class="alert alert-danger visually-hidden" role="alert" id="error-message-container">
</div>
<p>{{ t .Lang "Are you sure you want to delete this document?"}}</p>
<p>{{ t .Lang .ModalBody}}</p>
<p>{{ t .Lang "This action cannot be undone"}}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{t .Lang
"Cancel"}}</button>
<button type="submit" class="btn btn-primary">{{t .Lang "Delete"}}</button>
</div>
<input type="hidden" name="slug" value="" class="slug">
<input type="hidden" name="id" value="" class="id">
</form>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions internal/webserver/embedded/views/partials/docs-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ <h4 class="text-start">
{{t $lang "Actions"}}
</button>
{{ template "partials/actions" dict "Lang" $lang "Document" $document "EmailSendingConfigured"
$emailSendingConfigured "Index" $i "Session" $session "EmailFrom" $emailFrom "OnDehighlight" "remove"}}
$emailSendingConfigured "Session" $session "EmailFrom" $emailFrom "OnDehighlight" "remove"}}
</div>
</div>
</div>
Expand Down Expand Up @@ -91,7 +91,7 @@ <h5>{{t $lang "Unknown author"}}</h5>
{{end}} {{end}}
</div>

{{template "partials/delete-modal" .}}
{{template "partials/delete-modal" dict "Lang" $lang "Action" "/document" "ModalHeader" "Delete document" "ModalBody" "Are you sure you want to delete this document?" "ModalErrorMessage" "There was an error deleting the document"}}

<script type="text/javascript" src="/js/delete.js"></script>
<script type="text/javascript" src="/js/actions.js"></script>
Expand Down
65 changes: 3 additions & 62 deletions internal/webserver/embedded/views/users/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ <h2>{{t $lang "Users"}}</h2>
{{end}}
</div>
{{ if not (and (eq $admins 1) (eq $user.Role 2)) }}
<a href="#" data-bs-toggle="modal" data-bs-target="#deleteModal" data-bs-uuid="{{$user.Uuid}}">
<a href="#" data-bs-toggle="modal" data-bs-target="#delete-modal" data-id="{{$user.Uuid}}">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash3-fill" viewBox="0 0 16 16">
<path d="M11 1.5v1h3.5a.5.5 0 0 1 0 1h-.538l-.853 10.66A2 2 0 0 1 11.115 16h-6.23a2 2 0 0 1-1.994-1.84L2.038 3.5H1.5a.5.5 0 0 1 0-1H5v-1A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5Zm-5 0v1h4v-1a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5ZM4.5 5.029l.5 8.5a.5.5 0 1 0 .998-.06l-.5-8.5a.5.5 0 1 0-.998.06Zm6.53-.528a.5.5 0 0 0-.528.47l-.5 8.5a.5.5 0 0 0 .998.058l.5-8.5a.5.5 0 0 0-.47-.528ZM8 4.5a.5.5 0 0 0-.5.5v8.5a.5.5 0 0 0 1 0V5a.5.5 0 0 0-.5-.5Z"/>
</svg>
Expand All @@ -40,65 +40,6 @@ <h2>{{t $lang "Users"}}</h2>
{{template "partials/pagination" .}}
{{end}}

<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form method="post" action="/users/delete" onsubmit='remove({{t .Lang "There was an error deleting the user, please try again later"}})' id="delete-form">
<div class="modal-header">
<h1 class="modal-title fs-5" id="deleteModalLabel">{{t $lang "Delete user"}}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="alert alert-danger visually-hidden" role="alert" id="delete-user-message">
</div>
{{t $lang "Are you sure you want to delete this user?"}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{t $lang
"Cancel"}}</button>
<button type="submit" class="btn btn-primary">{{t $lang "Delete"}}</button>
</div>
<input type="hidden" name="uuid" value="" class="uuid">
</form>
</div>
</div>
</div>


<script type="text/javascript">
const deleteModal = document.getElementById('deleteModal')
deleteModal.addEventListener('show.bs.modal', event => {
const link = event.relatedTarget
const uuid = link.getAttribute('data-bs-uuid')
const modalInput = deleteModal.querySelector('.uuid')

modalInput.value = uuid;
})
{{template "partials/delete-modal" dict "Lang" $lang "Action" "/users" "ModalHeader" "Delete user" "ModalBody" "Are you sure you want to delete this user?" "ModalErrorMessage" "There was an error deleting the user, try again later"}}

function remove(errorMessage) {
event.preventDefault();
form = document.getElementById("delete-form");
fetch('/users', {
method: "DELETE",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'uuid': form.elements['uuid'].value,
})
})
.then((response) => {
if (response.ok) {
location.reload();
} else {
message = document.getElementById("delete-user-message")
message.classList.remove("visually-hidden");
message.innerHTML = errorMessage;
}
})
.catch(function (error) {
// Catch errors
console.log(error);
});
}
</script>
<script type="text/javascript" src="/js/delete.js"></script>
6 changes: 5 additions & 1 deletion internal/webserver/highlights_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ func TestHighlights(t *testing.T) {
t.Fatalf("Unexpected error: %v", err.Error())
}

data = url.Values{
"id": {"john-doe-test-epub"},
}

_, err = deleteRequest(data, adminCookie, app, "/document")
if err != nil {
t.Fatalf("Unexpected error: %v", err.Error())
Expand Down Expand Up @@ -148,7 +152,7 @@ func TestHighlights(t *testing.T) {
}

data := url.Values{
"uuid": {regularUser.Uuid},
"id": {regularUser.Uuid},
}

_, err = deleteRequest(data, adminCookie, app, "/users")
Expand Down
2 changes: 1 addition & 1 deletion internal/webserver/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func TestRemoveDocument(t *testing.T) {
)

data := url.Values{
"slug": {tcase.slug},
"id": {tcase.slug},
}

cookie, err := login(app, tcase.email, tcase.password)
Expand Down
6 changes: 3 additions & 3 deletions internal/webserver/user_management_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func TestUserManagement(t *testing.T) {
})

data = url.Values{
"uuid": {testUser.Uuid},
"id": {testUser.Uuid},
}

t.Run("Try to delete a user without an active session", func(t *testing.T) {
Expand Down Expand Up @@ -264,7 +264,7 @@ func TestUserManagement(t *testing.T) {

t.Run("Try to delete the only existing admin user", func(t *testing.T) {
data = url.Values{
"uuid": {adminUser.Uuid},
"id": {adminUser.Uuid},
}
response, err := deleteRequest(data, adminCookie, app, "/users")
if response == nil {
Expand All @@ -276,7 +276,7 @@ func TestUserManagement(t *testing.T) {

t.Run("Try to delete a non existing user with an admin session", func(t *testing.T) {
data = url.Values{
"uuid": {"abcde"},
"id": {"abcde"},
}

response, err := deleteRequest(data, adminCookie, app, "/users")
Expand Down

0 comments on commit eaa86c4

Please sign in to comment.