2018-06-17 07:28:18 +00:00
|
|
|
package panel
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
2021-01-18 22:11:30 +00:00
|
|
|
"html/template"
|
2018-06-17 07:28:18 +00:00
|
|
|
"net/http"
|
2021-01-18 22:11:30 +00:00
|
|
|
"net/url"
|
2018-06-17 07:28:18 +00:00
|
|
|
"strconv"
|
|
|
|
|
2019-04-19 08:20:10 +00:00
|
|
|
c "github.com/Azareal/Gosora/common"
|
2018-06-17 07:28:18 +00:00
|
|
|
)
|
|
|
|
|
2020-06-08 11:31:45 +00:00
|
|
|
func Users(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
|
|
|
basePage, ferr := buildBasePage(w, r, u, "users", "users")
|
2018-06-17 07:28:18 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
2021-01-18 22:11:30 +00:00
|
|
|
|
|
|
|
name := r.FormValue("s-name")
|
|
|
|
email := r.FormValue("s-email")
|
2021-01-19 02:48:49 +00:00
|
|
|
if !u.Perms.EditUserEmail && email != "" {
|
2021-01-19 02:51:24 +00:00
|
|
|
return c.LocalError("Only users with the EditUserEmail permission can search by email.", w, r, u)
|
2021-01-19 02:48:49 +00:00
|
|
|
}
|
2021-01-18 22:11:30 +00:00
|
|
|
hasParam := name != "" || email != ""
|
|
|
|
|
2018-06-17 07:28:18 +00:00
|
|
|
page, _ := strconv.Atoi(r.FormValue("page"))
|
2018-12-06 11:09:10 +00:00
|
|
|
perPage := 15
|
2021-01-18 22:11:30 +00:00
|
|
|
userCount := basePage.Stats.Users
|
|
|
|
if hasParam {
|
|
|
|
userCount = c.Users.CountSearch(name, email)
|
|
|
|
}
|
|
|
|
offset, page, lastPage := c.PageOffset(userCount, page, perPage)
|
2018-06-17 07:28:18 +00:00
|
|
|
|
2021-01-18 22:11:30 +00:00
|
|
|
var users []*c.User
|
|
|
|
var e error
|
|
|
|
if hasParam {
|
|
|
|
users, e = c.Users.SearchOffset(name, email, offset, perPage)
|
|
|
|
} else {
|
|
|
|
users, e = c.Users.GetOffset(offset, perPage)
|
|
|
|
}
|
|
|
|
if e != nil {
|
|
|
|
return c.InternalError(e, w, r)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 22:11:30 +00:00
|
|
|
name = url.QueryEscape(name)
|
|
|
|
email = url.QueryEscape(email)
|
|
|
|
search := c.PanelUserPageSearch{name, email}
|
|
|
|
|
|
|
|
var params string
|
|
|
|
if hasParam {
|
|
|
|
if name != "" {
|
|
|
|
params += "s-name=" + name + "&"
|
|
|
|
}
|
|
|
|
if email != "" {
|
|
|
|
params += "s-email=" + email + "&"
|
|
|
|
}
|
|
|
|
}
|
2019-06-04 05:48:12 +00:00
|
|
|
pageList := c.Paginate(page, lastPage, 5)
|
2021-01-18 22:11:30 +00:00
|
|
|
pi := c.PanelUserPage{basePage, users, search, c.PaginatorMod{template.URL(params), pageList, page, lastPage}}
|
2019-11-04 23:32:25 +00:00
|
|
|
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_users", &pi})
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-08 11:31:45 +00:00
|
|
|
func UsersEdit(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError {
|
|
|
|
basePage, ferr := buildBasePage(w, r, u, "edit_user", "users")
|
2018-06-17 07:28:18 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
2020-06-08 11:31:45 +00:00
|
|
|
if !u.Perms.EditUser {
|
|
|
|
return c.NoPermissions(w, r, u)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uid, err := strconv.Atoi(suid)
|
|
|
|
if err != nil {
|
2020-06-08 11:31:45 +00:00
|
|
|
return c.LocalError("The provided UserID is not a valid number.", w, r, u)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
2019-04-19 08:20:10 +00:00
|
|
|
targetUser, err := c.Users.Get(uid)
|
2018-06-17 07:28:18 +00:00
|
|
|
if err == sql.ErrNoRows {
|
2020-06-08 11:31:45 +00:00
|
|
|
return c.LocalError("The user you're trying to edit doesn't exist.", w, r, u)
|
2018-06-17 07:28:18 +00:00
|
|
|
} else if err != nil {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
2020-06-08 11:31:45 +00:00
|
|
|
if targetUser.IsAdmin && !u.IsAdmin {
|
|
|
|
return c.LocalError("Only administrators can edit the account of an administrator.", w, r, u)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ? - Should we stop admins from deleting all the groups? Maybe, protect the group they're currently using?
|
2019-04-19 08:20:10 +00:00
|
|
|
groups, err := c.Groups.GetRange(1, 0) // ? - 0 = Go to the end
|
2018-06-17 07:28:18 +00:00
|
|
|
if err != nil {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2019-11-04 23:32:25 +00:00
|
|
|
var groupList []*c.Group
|
2018-06-17 07:28:18 +00:00
|
|
|
for _, group := range groups {
|
2020-06-08 11:31:45 +00:00
|
|
|
if !u.Perms.EditUserGroupAdmin && group.IsAdmin {
|
2018-06-17 07:28:18 +00:00
|
|
|
continue
|
|
|
|
}
|
2020-06-08 11:31:45 +00:00
|
|
|
if !u.Perms.EditUserGroupSuperMod && group.IsMod {
|
2018-06-17 07:28:18 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
groupList = append(groupList, group)
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.FormValue("updated") == "1" {
|
|
|
|
basePage.AddNotice("panel_user_updated")
|
|
|
|
}
|
2019-11-04 23:32:25 +00:00
|
|
|
showEmail := r.FormValue("show-email") == "1"
|
2018-06-17 07:28:18 +00:00
|
|
|
|
2019-11-04 23:32:25 +00:00
|
|
|
pi := c.PanelUserEditPage{basePage, groupList, targetUser, showEmail}
|
|
|
|
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_user_edit", &pi})
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:21:34 +00:00
|
|
|
func UsersEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, suid string) c.RouteError {
|
|
|
|
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
|
|
|
if !user.Perms.EditUser {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.NoPermissions(w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uid, err := strconv.Atoi(suid)
|
|
|
|
if err != nil {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("The provided UserID is not a valid number.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
2019-04-19 08:20:10 +00:00
|
|
|
targetUser, err := c.Users.Get(uid)
|
2018-06-17 07:28:18 +00:00
|
|
|
if err == sql.ErrNoRows {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("The user you're trying to edit doesn't exist.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
} else if err != nil {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
if targetUser.IsAdmin && !user.IsAdmin {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("Only administrators can edit the account of other administrators.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2020-02-09 10:00:08 +00:00
|
|
|
newName := c.SanitiseSingleLine(r.PostFormValue("name"))
|
|
|
|
if newName == "" {
|
2019-11-04 23:32:25 +00:00
|
|
|
return c.LocalError("You didn't put in a name.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: How should activation factor into admin set emails?
|
|
|
|
// TODO: How should we handle secondary emails? Do we even have secondary emails implemented?
|
2020-02-09 10:00:08 +00:00
|
|
|
newEmail := c.SanitiseSingleLine(r.PostFormValue("email"))
|
|
|
|
if newEmail == "" && targetUser.Email != "" {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("You didn't put in an email address.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
2020-02-09 10:00:08 +00:00
|
|
|
if newEmail == "-1" {
|
|
|
|
newEmail = targetUser.Email
|
2019-11-04 23:32:25 +00:00
|
|
|
}
|
2020-02-09 10:00:08 +00:00
|
|
|
if (newEmail != targetUser.Email) && !user.Perms.EditUserEmail {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("You need the EditUserEmail permission to edit the email address of a user.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2020-02-09 10:00:08 +00:00
|
|
|
newPassword := r.PostFormValue("password")
|
|
|
|
if newPassword != "" && !user.Perms.EditUserPassword {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("You need the EditUserPassword permission to edit the password of a user.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2020-02-09 10:00:08 +00:00
|
|
|
newGroup, err := strconv.Atoi(r.PostFormValue("group"))
|
2018-06-17 07:28:18 +00:00
|
|
|
if err != nil {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("You need to provide a whole number for the group ID", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
2020-02-09 10:00:08 +00:00
|
|
|
group, err := c.Groups.Get(newGroup)
|
2018-06-17 07:28:18 +00:00
|
|
|
if err == sql.ErrNoRows {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("The group you're trying to place this user in doesn't exist.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
} else if err != nil {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
if !user.Perms.EditUserGroupAdmin && group.IsAdmin {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("You need the EditUserGroupAdmin permission to assign someone to an administrator group.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
if !user.Perms.EditUserGroupSuperMod && group.IsMod {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.LocalError("You need the EditUserGroupSuperMod permission to assign someone to a super mod group.", w, r, user)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 02:07:21 +00:00
|
|
|
err = targetUser.Update(newName, c.CanonEmail(newEmail), newGroup)
|
2018-06-17 07:28:18 +00:00
|
|
|
if err != nil {
|
2019-04-19 08:20:10 +00:00
|
|
|
return c.InternalError(err, w, r)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
|
2019-11-04 23:32:25 +00:00
|
|
|
red := false
|
2020-02-09 10:00:08 +00:00
|
|
|
if newPassword != "" {
|
|
|
|
c.SetPassword(targetUser.ID, newPassword)
|
2018-06-17 07:28:18 +00:00
|
|
|
// Log the user out as a safety precaution
|
2019-04-19 08:20:10 +00:00
|
|
|
c.Auth.ForceLogout(targetUser.ID)
|
2019-11-04 23:32:25 +00:00
|
|
|
red = true
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
targetUser.CacheRemove()
|
|
|
|
|
2020-02-09 10:00:08 +00:00
|
|
|
targetUser, err = c.Users.Get(uid)
|
|
|
|
if err == sql.ErrNoRows {
|
|
|
|
return c.LocalError("The user you're trying to edit doesn't exist.", w, r, user)
|
|
|
|
} else if err != nil {
|
|
|
|
return c.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
err = c.GroupPromotions.PromoteIfEligible(targetUser, targetUser.Level, targetUser.Posts, targetUser.CreatedAt)
|
|
|
|
if err != nil {
|
|
|
|
return c.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
targetUser.CacheRemove()
|
|
|
|
|
2019-12-31 21:57:54 +00:00
|
|
|
err = c.AdminLogs.Create("edit", targetUser.ID, "user", user.GetIP(), user.ID)
|
2019-11-06 02:00:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return c.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
|
2018-06-17 07:28:18 +00:00
|
|
|
// If we're changing our own password, redirect to the index rather than to a noperms error due to the force logout
|
2019-11-04 23:32:25 +00:00
|
|
|
if targetUser.ID == user.ID && red {
|
2018-06-17 07:28:18 +00:00
|
|
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
|
|
|
} else {
|
2019-11-04 23:32:25 +00:00
|
|
|
var se string
|
|
|
|
if r.PostFormValue("show-email") == "1" {
|
|
|
|
se = "&show-email=1"
|
|
|
|
}
|
|
|
|
http.Redirect(w, r, "/panel/users/edit/"+strconv.Itoa(targetUser.ID)+"?updated=1"+se, http.StatusSeeOther)
|
2018-06-17 07:28:18 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2019-06-10 22:00:57 +00:00
|
|
|
|
2020-06-08 11:31:45 +00:00
|
|
|
func UsersAvatarSubmit(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError {
|
|
|
|
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
2019-06-11 04:36:03 +00:00
|
|
|
// TODO: Check the UploadAvatars permission too?
|
2020-06-08 11:31:45 +00:00
|
|
|
if !u.Perms.EditUser {
|
|
|
|
return c.NoPermissions(w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uid, err := strconv.Atoi(suid)
|
|
|
|
if err != nil {
|
2020-06-08 11:31:45 +00:00
|
|
|
return c.LocalError("The provided UserID is not a valid number.", w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
}
|
|
|
|
targetUser, err := c.Users.Get(uid)
|
|
|
|
if err == sql.ErrNoRows {
|
2020-06-08 11:31:45 +00:00
|
|
|
return c.LocalError("The user you're trying to edit doesn't exist.", w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
} else if err != nil {
|
|
|
|
return c.InternalError(err, w, r)
|
|
|
|
}
|
2020-06-08 11:31:45 +00:00
|
|
|
if targetUser.IsAdmin && !u.IsAdmin {
|
|
|
|
return c.LocalError("Only administrators can edit the account of other administrators.", w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
}
|
|
|
|
|
2020-06-08 11:31:45 +00:00
|
|
|
ext, ferr := c.UploadAvatar(w, r, u, targetUser.ID)
|
2019-06-10 22:00:57 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
2020-03-18 09:21:34 +00:00
|
|
|
ferr = c.ChangeAvatar("."+ext, w, r, targetUser)
|
2019-06-10 22:00:57 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
|
|
|
// TODO: Only schedule a resize if the avatar isn't tiny
|
|
|
|
err = targetUser.ScheduleAvatarResize()
|
|
|
|
if err != nil {
|
|
|
|
return c.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
|
2020-06-08 11:31:45 +00:00
|
|
|
err = c.AdminLogs.Create("edit", targetUser.ID, "user", u.GetIP(), u.ID)
|
2019-11-08 07:52:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return c.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
|
2019-11-04 23:32:25 +00:00
|
|
|
var se string
|
|
|
|
if r.PostFormValue("show-email") == "1" {
|
|
|
|
se = "&show-email=1"
|
|
|
|
}
|
|
|
|
http.Redirect(w, r, "/panel/users/edit/"+strconv.Itoa(targetUser.ID)+"?updated=1"+se, http.StatusSeeOther)
|
2019-06-10 22:00:57 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-08 11:31:45 +00:00
|
|
|
func UsersAvatarRemoveSubmit(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError {
|
|
|
|
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
2020-06-08 11:31:45 +00:00
|
|
|
if !u.Perms.EditUser {
|
|
|
|
return c.NoPermissions(w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uid, err := strconv.Atoi(suid)
|
|
|
|
if err != nil {
|
2020-06-08 11:31:45 +00:00
|
|
|
return c.LocalError("The provided UserID is not a valid number.", w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
}
|
|
|
|
targetUser, err := c.Users.Get(uid)
|
|
|
|
if err == sql.ErrNoRows {
|
2020-06-08 11:31:45 +00:00
|
|
|
return c.LocalError("The user you're trying to edit doesn't exist.", w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
} else if err != nil {
|
|
|
|
return c.InternalError(err, w, r)
|
|
|
|
}
|
2020-06-08 11:31:45 +00:00
|
|
|
if targetUser.IsAdmin && !u.IsAdmin {
|
|
|
|
return c.LocalError("Only administrators can edit the account of other administrators.", w, r, u)
|
2019-06-10 22:00:57 +00:00
|
|
|
}
|
2020-03-18 09:21:34 +00:00
|
|
|
ferr = c.ChangeAvatar("", w, r, targetUser)
|
2019-06-10 22:00:57 +00:00
|
|
|
if ferr != nil {
|
|
|
|
return ferr
|
|
|
|
}
|
|
|
|
|
2020-06-08 11:31:45 +00:00
|
|
|
err = c.AdminLogs.Create("edit", targetUser.ID, "user", u.GetIP(), u.ID)
|
2019-11-08 07:52:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return c.InternalError(err, w, r)
|
|
|
|
}
|
|
|
|
|
2019-11-04 23:32:25 +00:00
|
|
|
var se string
|
|
|
|
if r.PostFormValue("show-email") == "1" {
|
|
|
|
se = "&show-email=1"
|
|
|
|
}
|
|
|
|
http.Redirect(w, r, "/panel/users/edit/"+strconv.Itoa(targetUser.ID)+"?updated=1"+se, http.StatusSeeOther)
|
2019-06-10 22:00:57 +00:00
|
|
|
return nil
|
2019-11-04 23:32:25 +00:00
|
|
|
}
|