website/pkg/controller/admin/user_actions.go
2023-12-04 19:57:14 -08:00

172 lines
4.7 KiB
Go

package admin
import (
"net/http"
"strconv"
"code.nonshy.com/nonshy/website/pkg/config"
"code.nonshy.com/nonshy/website/pkg/models"
"code.nonshy.com/nonshy/website/pkg/models/deletion"
"code.nonshy.com/nonshy/website/pkg/session"
"code.nonshy.com/nonshy/website/pkg/templates"
)
// Admin actions against a user account.
func UserActions() http.HandlerFunc {
tmpl := templates.Must("admin/user_actions.html")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var (
intent = r.FormValue("intent")
confirm = r.Method == http.MethodPost
reason = r.FormValue("reason") // for impersonation
userId uint64
)
// Get current user.
currentUser, err := session.CurrentUser(r)
if err != nil {
session.FlashError(w, r, "Failed to get current user: %s", err)
templates.Redirect(w, "/")
return
}
if idInt, err := strconv.Atoi(r.FormValue("user_id")); err == nil {
userId = uint64(idInt)
} else {
session.FlashError(w, r, "Invalid or missing user_id parameter: %s", err)
templates.Redirect(w, "/admin")
return
}
// Get this user.
user, err := models.GetUser(userId)
if err != nil {
session.FlashError(w, r, "Didn't find user ID in database: %s", err)
templates.Redirect(w, "/admin")
return
}
// Template variables.
var vars = map[string]interface{}{
"Intent": intent,
"User": user,
}
switch intent {
case "insights":
// Admin insights (peek at block lists, etc.)
if !currentUser.HasAdminScope(config.ScopeUserInsight) {
session.FlashError(w, r, "Missing admin scope: %s", config.ScopeUserInsight)
templates.Redirect(w, "/admin")
return
}
insights, err := models.GetBlocklistInsights(user)
if err != nil {
session.FlashError(w, r, "Error getting blocklist insights: %s", err)
}
vars["BlocklistInsights"] = insights
case "impersonate":
// Scope check.
if !currentUser.HasAdminScope(config.ScopeUserImpersonate) {
session.FlashError(w, r, "Missing admin scope: %s", config.ScopeUserImpersonate)
templates.Redirect(w, "/admin")
return
}
if confirm {
if err := session.ImpersonateUser(w, r, user, currentUser, reason); err != nil {
session.FlashError(w, r, "Failed to impersonate user: %s", err)
} else {
session.Flash(w, r, "You are now impersonating %s", user.Username)
templates.Redirect(w, "/me")
return
}
}
case "ban":
// Scope check.
if !currentUser.HasAdminScope(config.ScopeUserBan) {
session.FlashError(w, r, "Missing admin scope: %s", config.ScopeUserBan)
templates.Redirect(w, "/admin")
return
}
if confirm {
status := r.PostFormValue("status")
if status == "active" {
user.Status = models.UserStatusActive
} else if status == "banned" {
user.Status = models.UserStatusBanned
}
user.Save()
session.Flash(w, r, "User ban status updated!")
templates.Redirect(w, "/u/"+user.Username)
return
}
case "promote":
// Scope check.
if !currentUser.HasAdminScope(config.ScopeUserPromote) {
session.FlashError(w, r, "Missing admin scope: %s", config.ScopeUserPromote)
templates.Redirect(w, "/admin")
return
}
if confirm {
action := r.PostFormValue("action")
user.IsAdmin = action == "promote"
user.Save()
session.Flash(w, r, "User admin status updated!")
templates.Redirect(w, "/u/"+user.Username)
return
}
case "delete":
// Scope check.
if !currentUser.HasAdminScope(config.ScopeUserDelete) {
session.FlashError(w, r, "Missing admin scope: %s", config.ScopeUserDelete)
templates.Redirect(w, "/admin")
return
}
if confirm {
if err := deletion.DeleteUser(user); err != nil {
session.FlashError(w, r, "Failed when deleting the user: %s", err)
} else {
session.Flash(w, r, "User has been deleted!")
}
templates.Redirect(w, "/admin")
return
}
default:
session.FlashError(w, r, "Unsupported admin user intent: %s", intent)
templates.Redirect(w, "/admin")
return
}
if err := tmpl.Execute(w, r, vars); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
}
// Un-impersonate a user account.
func Unimpersonate() http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sess := session.Get(r)
if sess.Impersonator > 0 {
user, err := models.GetUser(sess.Impersonator)
if err != nil {
session.FlashError(w, r, "Couldn't unimpersonate: impersonator (%d) is not an admin!", user.ID)
templates.Redirect(w, "/")
return
}
session.LoginUser(w, r, user)
session.Flash(w, r, "No longer impersonating.")
templates.Redirect(w, "/")
}
templates.Redirect(w, "/")
})
}