diff --git a/api/auth.go b/api/auth.go
index 03c9ba2..1e14048 100644
--- a/api/auth.go
+++ b/api/auth.go
@@ -720,6 +720,67 @@ func routeAuthLogout(w http.ResponseWriter, r *http.Request, p httprouter.Params
writeJSON(w, http.StatusOK, statusResponse{"ok"})
}
+func routeAuthRequestAccountDelete(w http.ResponseWriter, r *http.Request, p httprouter.Params, c RouteContext) {
+ if r.FormValue("clientType") == "" || r.FormValue("password") == "" {
+ writeJSON(w, http.StatusBadRequest, errorResponse{"error", "missing_params"})
+ return
+ }
+
+ clientType := r.FormValue("clientType")
+ password := r.FormValue("password")
+
+ if c.User.PasswordHash == "" {
+ errorlog.LogError("user request account deletion", errors.New("user is missing password hash"))
+ writeJSON(w, http.StatusInternalServerError, errorResponse{"error", "internal_server_error"})
+ return
+ }
+
+ err := bcrypt.CompareHashAndPassword([]byte(c.User.PasswordHash), []byte(password))
+ if err == bcrypt.ErrMismatchedHashAndPassword {
+ // bye
+ writeJSON(w, http.StatusUnauthorized, errorResponse{"error", "password_incorrect"})
+ return
+ } else if err != nil {
+ errorlog.LogError("user request account deletion", err)
+ writeJSON(w, http.StatusInternalServerError, errorResponse{"error", "internal_server_error"})
+ return
+ }
+
+ deviceText := map[string]string{
+ "web": "our website",
+ "ios": "an iOS device",
+ "android": "an Android device",
+ }[clientType]
+ ipAddress := getRequestRemoteAddr(r)
+
+ // if we got here, no error -> password correct
+
+ // send the deletion emails
+
+ err = email.Send("", c.User, "accountDeletionRequest", map[string]interface{}{
+ "DeviceText": deviceText,
+ "IPAddress": ipAddress,
+ })
+ if err != nil {
+ errorlog.LogError("user request account deletion", err)
+ writeJSON(w, http.StatusInternalServerError, errorResponse{"error", "internal_server_error"})
+ return
+ }
+
+ adminEmail := "astuder@myhomework.space"
+ err = email.Send(adminEmail, c.User, "accountDeletionRequest", map[string]interface{}{
+ "DeviceText": deviceText,
+ "IPAddress": ipAddress,
+ })
+ if err != nil {
+ errorlog.LogError("user request account deletion", err)
+ writeJSON(w, http.StatusInternalServerError, errorResponse{"error", "internal_server_error"})
+ return
+ }
+
+ writeJSON(w, http.StatusOK, statusResponse{"ok"})
+}
+
func routeAuthResendVerificationEmail(w http.ResponseWriter, r *http.Request, p httprouter.Params, c RouteContext) {
if c.User.EmailVerified {
writeJSON(w, http.StatusBadRequest, errorResponse{"error", "already_verified"})
diff --git a/api/main.go b/api/main.go
index 00198e4..3ae653d 100644
--- a/api/main.go
+++ b/api/main.go
@@ -287,6 +287,7 @@ func Init(router *httprouter.Router) {
router.POST("/auth/login", route(routeAuthLogin, authLevelNone))
router.GET("/auth/me", route(routeAuthMe, authLevelLoggedIn))
router.GET("/auth/logout", route(routeAuthLogout, authLevelLoggedIn))
+ router.POST("/auth/requestAccountDelete", route(routeAuthRequestAccountDelete, authLevelLoggedIn))
router.POST("/auth/resetPassword", route(routeAuthResetPassword, authLevelNone))
router.POST("/auth/resendVerificationEmail", route(routeAuthResendVerificationEmail, authLevelNone))
router.GET("/auth/session", route(routeAuthSession, authLevelNone))
diff --git a/templates/accountDeletionRequest/subject.txt b/templates/accountDeletionRequest/subject.txt
new file mode 100644
index 0000000..97f14aa
--- /dev/null
+++ b/templates/accountDeletionRequest/subject.txt
@@ -0,0 +1 @@
+Your account has been scheduled for deletion
\ No newline at end of file
diff --git a/templates/accountDeletionRequest/template.html b/templates/accountDeletionRequest/template.html
new file mode 100644
index 0000000..fef1d87
--- /dev/null
+++ b/templates/accountDeletionRequest/template.html
@@ -0,0 +1,15 @@
+{{template "header"}}
+Hi {{.User.Name | fname}},
+
+You requested deletion of your MyHomeworkSpace account with email {{.User.Email}}. It will be deleted within 48 hours. This includes all homework, classes, and calendar events on your account.
+
+If you did not make this request, email hello@myhomework.space immediately to cancel it.
+
+Note that some of your data might remain on our systems even after your account is deleted - for example, your account might still be present in our automated database backups.
+
+The request was made on {{.Data.DeviceText}} from IP address {{.Data.IPAddress}}.
+
+We thank you for using our service. If you have any feedback to share, please email hello@myhomework.space.
+
+MyHomeworkSpace
+{{template "footer"}}
\ No newline at end of file
diff --git a/templates/accountDeletionRequest/template.txt b/templates/accountDeletionRequest/template.txt
new file mode 100644
index 0000000..71b38fc
--- /dev/null
+++ b/templates/accountDeletionRequest/template.txt
@@ -0,0 +1,13 @@
+Hi {{.User.Name | fname}},
+
+You requested deletion of your MyHomeworkSpace account with email {{.User.Email}}. It will be deleted within 48 hours. This includes all homework, classes, and calendar events on your account.
+
+If you did not make this request, email hello@myhomework.space immediately to cancel it.
+
+Note that some of your data might remain on our systems even after your account is deleted - for example, your account might still be present in our automated database backups.
+
+The request was made on {{.Data.DeviceText}} from IP address {{.Data.IPAddress}}.
+
+We thank you for using our service. If you have any feedback to share, please email hello@myhomework.space.
+
+MyHomeworkSpace
\ No newline at end of file