From 3593d84fe6b32bb6ce76b2747c36d833da438c40 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Sun, 15 Jan 2023 15:50:23 -0500 Subject: [PATCH] Migrate profile/account deletion --- src/JobsJobsJobs/App/src/router/index.ts | 13 ---- .../App/src/views/so-long/DeletionOptions.vue | 61 ------------------- .../App/src/views/so-long/DeletionSuccess.vue | 9 --- src/JobsJobsJobs/Server/Handlers.fs | 40 +++++++----- src/JobsJobsJobs/Server/Views/Citizen.fs | 44 ++++++++++++- src/JobsJobsJobs/Server/Views/Profile.fs | 2 +- 6 files changed, 67 insertions(+), 102 deletions(-) delete mode 100644 src/JobsJobsJobs/App/src/views/so-long/DeletionOptions.vue delete mode 100644 src/JobsJobsJobs/App/src/views/so-long/DeletionSuccess.vue diff --git a/src/JobsJobsJobs/App/src/router/index.ts b/src/JobsJobsJobs/App/src/router/index.ts index 9fe6b8b..85cc3a4 100644 --- a/src/JobsJobsJobs/App/src/router/index.ts +++ b/src/JobsJobsJobs/App/src/router/index.ts @@ -74,19 +74,6 @@ const routes: Array = [ component: () => import(/* webpackChunkName: "joblist" */ "../views/listing/MyListings.vue"), meta: { auth: true, title: "My Job Listings" } }, - // "So Long" URLs - { - path: "/so-long/options", - name: "DeletionOptions", - component: () => import(/* webpackChunkName: "so-long" */ "../views/so-long/DeletionOptions.vue"), - meta: { auth: true, title: "Account Deletion Options" } - }, - { - path: "/so-long/success", - name: "DeletionSuccess", - component: () => import(/* webpackChunkName: "so-long" */ "../views/so-long/DeletionSuccess.vue"), - meta: { auth: false, title: "Account Deletion Success" } - }, // Success Story URLs { path: "/success-story/list", diff --git a/src/JobsJobsJobs/App/src/views/so-long/DeletionOptions.vue b/src/JobsJobsJobs/App/src/views/so-long/DeletionOptions.vue deleted file mode 100644 index e498d2a..0000000 --- a/src/JobsJobsJobs/App/src/views/so-long/DeletionOptions.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - diff --git a/src/JobsJobsJobs/App/src/views/so-long/DeletionSuccess.vue b/src/JobsJobsJobs/App/src/views/so-long/DeletionSuccess.vue deleted file mode 100644 index 04d5d17..0000000 --- a/src/JobsJobsJobs/App/src/views/so-long/DeletionSuccess.vue +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/src/JobsJobsJobs/Server/Handlers.fs b/src/JobsJobsJobs/Server/Handlers.fs index 11a6a9b..79f0939 100644 --- a/src/JobsJobsJobs/Server/Handlers.fs +++ b/src/JobsJobsJobs/Server/Handlers.fs @@ -289,6 +289,13 @@ module Citizen = return! Citizen.dashboard citizen.Value profile prfCount |> render "Dashboard" next ctx } + // POST: /citizen/delete + let delete : HttpHandler = requireUser >=> validateCsrf >=> fun next ctx -> task { + do! Citizens.deleteById (currentCitizenId ctx) + do! ctx.SignOutAsync () + return! render "Account Deleted Successfully" next ctx Citizen.deleted + } + // GET: /citizen/deny/[token] let deny token next ctx = task { let! wasDeleted = Citizens.denyAccount token @@ -402,6 +409,10 @@ module Citizen = return! refreshPage () next ctx } + // GET: /citizen/so-long + let soLong : HttpHandler = requireUser >=> fun next ctx -> + Citizen.deletionOptions (csrf ctx) |> render "Account Deletion Options" next ctx + /// Handlers for /api/citizen routes [] @@ -442,12 +453,6 @@ module CitizenApi = | None -> return! Error.notFound next ctx } - // DELETE: /api/citizen - let delete : HttpHandler = authorize >=> fun next ctx -> task { - do! Citizens.deleteById (currentCitizenId ctx) - return! ok next ctx - } - /// Handlers for /api/continent routes [] @@ -590,6 +595,13 @@ module Listing = [] module Profile = + // POST: /profile/delete + let delete : HttpHandler = requireUser >=> validateCsrf >=> fun next ctx -> task { + do! Profiles.deleteById (currentCitizenId ctx) + do! addSuccess "Profile deleted successfully" ctx + return! redirectToGet "/citizen/dashboard" next ctx + } + // GET: /profile/edit let edit : HttpHandler = requireUser >=> fun next ctx -> task { let citizenId = currentCitizenId ctx @@ -743,12 +755,6 @@ module ProfileApi = | None -> return! Error.notFound next ctx } - // DELETE: /api/profile - let delete : HttpHandler = authorize >=> fun next ctx -> task { - do! Profiles.deleteById (currentCitizenId ctx) - return! ok next ctx - } - /// Handlers for /api/success routes [] @@ -811,8 +817,10 @@ let allEndpoints = [ route "/log-off" Citizen.logOff route "/log-on" Citizen.logOn route "/register" Citizen.register + route "/so-long" Citizen.soLong ] POST [ + route "/delete" Citizen.delete route "/log-on" Citizen.doLogOn route "/register" Citizen.doRegistration ] @@ -826,7 +834,10 @@ let allEndpoints = [ route "/search" Profile.search route "/seeking" Profile.seeking ] - POST [ route "/save" Profile.save ] + POST [ + route "/delete" Profile.delete + route "/save" Profile.save + ] ] GET_HEAD [ route "/terms-of-service" Home.termsOfService ] @@ -836,9 +847,6 @@ let allEndpoints = [ PATCH [ route "/account" CitizenApi.account ] - DELETE [ - route "" CitizenApi.delete - ] ] GET_HEAD [ route "/continents" Continent.all ] subRoute "/listing" [ diff --git a/src/JobsJobsJobs/Server/Views/Citizen.fs b/src/JobsJobsJobs/Server/Views/Citizen.fs index ef1a8f7..22fdb4c 100644 --- a/src/JobsJobsJobs/Server/Views/Citizen.fs +++ b/src/JobsJobsJobs/Server/Views/Citizen.fs @@ -94,6 +94,46 @@ let dashboard (citizen : Citizen) (profile : Profile option) profileCount = ] +/// The account deletion success page +let deleted = + article [] [ + h3 [ _class "pb-3" ] [ rawText "Account Deletion Success" ] + p [] [ rawText " " ] + p [] [ rawText "Your account has been successfully deleted." ] + p [] [ rawText " " ] + p [] [ rawText "Thank you for participating, and thank you for your courage. #GitmoNation" ] + ] + + +/// The profile or account deletion page +let deletionOptions csrf = + article [] [ + h3 [ _class "pb-3" ] [ rawText "Account Deletion Options" ] + h4 [ _class "pb-3" ] [ rawText "Option 1 – Delete Your Profile" ] + p [] [ + rawText "Utilizing this option will remove your current employment profile and skills. This will preserve " + rawText "any job listings you may have posted, or any success stories you may have written, and preserves " + rawText "this application’s knowledge of you. This is what you want to use if you want to clear out " + rawText "your profile and start again (and remove the current one from others’ view)." + ] + form [ _class "text-center"; _method "POST"; _action "/profile/delete" ] [ + antiForgery csrf + button [ _type "submit"; _class "btn btn-danger" ] [ rawText "Delete Your Profile" ] + ] + hr [] + h4 [ _class "pb-3" ] [ rawText "Option 2 – Delete Your Account" ] + p [] [ + rawText "This option will make it like you never visited this site. It will delete your profile, skills, " + rawText "job listings, success stories, and account. This is what you want to use if you want to disappear " + rawText "from this application." + ] + form [ _class "text-center"; _method "POST"; _action "/citizen/delete" ] [ + antiForgery csrf + button [ _type "submit"; _class "btn btn-danger" ] [ rawText "Delete Your Entire Account" ] + ] + ] + + /// The account denial page let denyAccount wasDeleted = article [] [ @@ -179,11 +219,11 @@ let register q1 q2 (m : RegisterViewModel) csrf = ] ] div [ _class "col-12 col-xl-6" ] [ - textBox [ _type "text"; _maxlength "30" ] (nameof m.Question1Answer) m.Question1Answer "Question 1" true + textBox [ _type "text"; _maxlength "30" ] (nameof m.Question1Answer) m.Question1Answer q1 true input [ _type "hidden"; _name (nameof m.Question1Index); _value (string m.Question1Index ) ] ] div [ _class "col-12 col-xl-6" ] [ - textBox [ _type "text"; _maxlength "30" ] (nameof m.Question2Answer) m.Question2Answer "Question 2" true + textBox [ _type "text"; _maxlength "30" ] (nameof m.Question2Answer) m.Question2Answer q2 true input [ _type "hidden"; _name (nameof m.Question2Index); _value (string m.Question2Index ) ] ] div [ _class "col-12" ] [ diff --git a/src/JobsJobsJobs/Server/Views/Profile.fs b/src/JobsJobsJobs/Server/Views/Profile.fs index 2508095..5a5b78b 100644 --- a/src/JobsJobsJobs/Server/Views/Profile.fs +++ b/src/JobsJobsJobs/Server/Views/Profile.fs @@ -117,7 +117,7 @@ let edit (m : EditProfileViewModel) continents isNew citizenId csrf = hr [] p [ _class "text-muted fst-italic" ] [ rawText "(If you want to delete your profile, or your entire account, " - a [ _href "/so-long/options" ] [ rawText "see your deletion options here" ]; rawText ".)" + a [ _href "/citizen/so-long" ] [ rawText "see your deletion options here" ]; rawText ".)" ] script [] [ rawText """addEventListener("DOMContentLoaded", function () {"""