Accounts can now be deleted
This commit is contained in:
@@ -6,10 +6,12 @@ import be.simplenotes.app.extensions.redirect
|
||||
import be.simplenotes.app.views.UserView
|
||||
import be.simplenotes.domain.security.JwtPayload
|
||||
import be.simplenotes.domain.usecases.UserService
|
||||
import be.simplenotes.domain.usecases.login.*
|
||||
import be.simplenotes.domain.usecases.register.InvalidRegisterForm
|
||||
import be.simplenotes.domain.usecases.register.RegisterForm
|
||||
import be.simplenotes.domain.usecases.register.UserExists
|
||||
import be.simplenotes.domain.usecases.users.delete.DeleteError
|
||||
import be.simplenotes.domain.usecases.users.delete.DeleteForm
|
||||
import be.simplenotes.domain.usecases.users.login.*
|
||||
import be.simplenotes.domain.usecases.users.register.InvalidRegisterForm
|
||||
import be.simplenotes.domain.usecases.users.register.RegisterForm
|
||||
import be.simplenotes.domain.usecases.users.register.UserExists
|
||||
import be.simplenotes.shared.config.JwtConfig
|
||||
import org.http4k.core.Method.GET
|
||||
import org.http4k.core.Request
|
||||
@@ -110,4 +112,38 @@ class UserController(
|
||||
|
||||
fun logout(@Suppress("UNUSED_PARAMETER") request: Request) = Response.redirect("/")
|
||||
.invalidateCookie("Authorization")
|
||||
|
||||
private fun Request.deleteForm(jwtPayload: JwtPayload) =
|
||||
DeleteForm(jwtPayload.username, form("password"), form("checked") != null)
|
||||
|
||||
fun settings(request: Request, jwtPayload: JwtPayload): Response {
|
||||
if (request.method == GET)
|
||||
return Response(OK).html(userView.settings(jwtPayload))
|
||||
|
||||
val deleteForm = request.deleteForm(jwtPayload)
|
||||
val result = userService.delete(deleteForm)
|
||||
|
||||
return result.fold(
|
||||
{
|
||||
when (it) {
|
||||
DeleteError.Unregistered -> Response.redirect("/").invalidateCookie("Authorization")
|
||||
DeleteError.WrongPassword -> Response(OK).html(
|
||||
userView.settings(
|
||||
jwtPayload,
|
||||
error = "Wrong password"
|
||||
)
|
||||
)
|
||||
is DeleteError.InvalidForm -> Response(OK).html(
|
||||
userView.settings(
|
||||
jwtPayload,
|
||||
validationErrors = it.validationErrors
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
Response.redirect("/").invalidateCookie("Authorization")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ class Router(
|
||||
)
|
||||
|
||||
val protectedRoutes = routes(
|
||||
"/account" bind GET to { TODO() },
|
||||
"/settings" bind GET to { protected(it, userController::settings) },
|
||||
"/settings" bind POST to { protected(it, userController::settings) },
|
||||
"/export" bind POST to { TODO() },
|
||||
"/notes" bind GET to { protected(it, noteController::list) },
|
||||
"/notes/new" bind GET to { protected(it, noteController::new) },
|
||||
|
||||
@@ -8,6 +8,7 @@ import be.simplenotes.app.views.components.submitButton
|
||||
import be.simplenotes.domain.security.JwtPayload
|
||||
import io.konform.validation.ValidationError
|
||||
import kotlinx.html.*
|
||||
import kotlinx.html.ButtonType.submit
|
||||
|
||||
class UserView(staticFileResolver: StaticFileResolver) : View(staticFileResolver) {
|
||||
fun register(
|
||||
@@ -70,4 +71,74 @@ class UserView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun settings(
|
||||
jwtPayload: JwtPayload,
|
||||
error: String? = null,
|
||||
validationErrors: List<ValidationError> = emptyList(),
|
||||
) = renderPage("Settings", jwtPayload = jwtPayload) {
|
||||
div("container mx-auto p-8") {
|
||||
|
||||
section("m-4 p-4 bg-gray-800 rounded") {
|
||||
h1("text-xl") {
|
||||
+"Welcome "
|
||||
span("text-teal-200 font-semibold") { +jwtPayload.username }
|
||||
}
|
||||
}
|
||||
|
||||
section("m-4 p-4 bg-gray-800 rounded") {
|
||||
p(classes = "mb-4") {
|
||||
+"Export all my data in a zip file"
|
||||
}
|
||||
|
||||
form {
|
||||
button(classes = "btn btn-teal block") { +"Export my data" }
|
||||
}
|
||||
}
|
||||
|
||||
section(classes = "m-4 p-4 bg-gray-800 rounded") {
|
||||
h2(classes = "mb-4 text-red-600 text-lg font-semibold") {
|
||||
+"Delete my account"
|
||||
}
|
||||
|
||||
error?.let { alert(Alert.Warning, error) }
|
||||
|
||||
details {
|
||||
summary {
|
||||
span(classes = "mb-4 font-semibold underline") {
|
||||
+"Are you sure? "
|
||||
+"You are about to delete this user, and this process is irreversible !"
|
||||
}
|
||||
}
|
||||
|
||||
form(classes = "mt-4", method = FormMethod.post) {
|
||||
input(
|
||||
id = "password",
|
||||
placeholder = "Password",
|
||||
autoComplete = "off",
|
||||
type = InputType.password,
|
||||
error = validationErrors.find { it.dataPath == ".password" }?.message
|
||||
)
|
||||
checkBoxInput(name = "checked") {
|
||||
attributes["required"] = ""
|
||||
+" Do you want to proceed ?"
|
||||
}
|
||||
button(type = submit, classes = "block mt-4 btn btn-red", name = "delete") { +"I'm sure" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SUMMARY(consumer: TagConsumer<*>) :
|
||||
HTMLTag(
|
||||
"summary", consumer, emptyMap(),
|
||||
inlineTag = true,
|
||||
emptyTag = false
|
||||
),
|
||||
HtmlInlineTag
|
||||
|
||||
fun DETAILS.summary(block: SUMMARY.() -> Unit = {}) {
|
||||
SUMMARY(consumer).visit(block)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user