github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/routes/panel/users.go (about) 1 package panel 2 3 import ( 4 "database/sql" 5 "html/template" 6 "net/http" 7 "net/url" 8 "strconv" 9 10 c "github.com/Azareal/Gosora/common" 11 ) 12 13 func Users(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError { 14 basePage, ferr := buildBasePage(w, r, u, "users", "users") 15 if ferr != nil { 16 return ferr 17 } 18 19 name := r.FormValue("s-name") 20 email := r.FormValue("s-email") 21 if !u.Perms.EditUserEmail && email != "" { 22 return c.LocalError("Only users with the EditUserEmail permission can search by email.", w, r, u) 23 } 24 group := r.FormValue("s-group") 25 f := func(l ...string) bool { 26 for _, ll := range l { 27 if ll != "" { 28 return true 29 } 30 } 31 return false 32 } 33 hasParam := f(name, email, group) 34 gid, _ := strconv.Atoi(group) 35 /*if group == "" { 36 gid = -1 37 }*/ 38 hasParam = hasParam || gid > 0 39 40 page, _ := strconv.Atoi(r.FormValue("page")) 41 perPage := 15 42 userCount := basePage.Stats.Users 43 if hasParam { 44 userCount = c.Users.CountSearch(name, email, gid) 45 } 46 offset, page, lastPage := c.PageOffset(userCount, page, perPage) 47 48 allGroups, e := c.Groups.GetAll() 49 if e != nil { 50 return c.InternalError(e, w, r) 51 } 52 53 var users []*c.User 54 if hasParam { 55 users, e = c.Users.SearchOffset(name, email, gid, offset, perPage) 56 } else { 57 users, e = c.Users.GetOffset(offset, perPage) 58 } 59 if e != nil { 60 return c.InternalError(e, w, r) 61 } 62 63 name = url.QueryEscape(name) 64 email = url.QueryEscape(email) 65 search := c.PanelUserPageSearch{name, email, gid, hasParam} 66 67 var params string 68 if hasParam { 69 if name != "" { 70 params += "s-name=" + name + "&" 71 } 72 if email != "" { 73 params += "s-email=" + email + "&" 74 } 75 if gid > 0 { 76 params += "s-group=" + strconv.Itoa(gid) + "&" 77 } 78 } 79 pageList := c.Paginate(page, lastPage, 5) 80 pi := c.PanelUserPage{basePage, users, allGroups, search, c.PaginatorMod{template.URL(params), pageList, page, lastPage}} 81 return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_users", &pi}) 82 } 83 84 func UsersEdit(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError { 85 basePage, ferr := buildBasePage(w, r, u, "edit_user", "users") 86 if ferr != nil { 87 return ferr 88 } 89 if !u.Perms.EditUser { 90 return c.NoPermissions(w, r, u) 91 } 92 93 uid, err := strconv.Atoi(suid) 94 if err != nil { 95 return c.LocalError("The provided UserID is not a valid number.", w, r, u) 96 } 97 targetUser, err := c.Users.Get(uid) 98 if err == sql.ErrNoRows { 99 return c.LocalError("The user you're trying to edit doesn't exist.", w, r, u) 100 } else if err != nil { 101 return c.InternalError(err, w, r) 102 } 103 if targetUser.IsAdmin && !u.IsAdmin { 104 return c.LocalError("Only administrators can edit the account of an administrator.", w, r, u) 105 } 106 107 // ? - Should we stop admins from deleting all the groups? Maybe, protect the group they're currently using? 108 groups, err := c.Groups.GetRange(1, 0) // ? - 0 = Go to the end 109 if err != nil { 110 return c.InternalError(err, w, r) 111 } 112 113 var groupList []*c.Group 114 for _, group := range groups { 115 if !u.Perms.EditUserGroupAdmin && group.IsAdmin { 116 continue 117 } 118 if !u.Perms.EditUserGroupSuperMod && group.IsMod { 119 continue 120 } 121 groupList = append(groupList, group) 122 } 123 124 if r.FormValue("updated") == "1" { 125 basePage.AddNotice("panel_user_updated") 126 } 127 showEmail := r.FormValue("show-email") == "1" 128 129 pi := c.PanelUserEditPage{basePage, groupList, targetUser, showEmail} 130 return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_user_edit", &pi}) 131 } 132 133 func UsersEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, suid string) c.RouteError { 134 _, ferr := c.SimplePanelUserCheck(w, r, user) 135 if ferr != nil { 136 return ferr 137 } 138 if !user.Perms.EditUser { 139 return c.NoPermissions(w, r, user) 140 } 141 142 uid, err := strconv.Atoi(suid) 143 if err != nil { 144 return c.LocalError("The provided UserID is not a valid number.", w, r, user) 145 } 146 targetUser, err := c.Users.Get(uid) 147 if err == sql.ErrNoRows { 148 return c.LocalError("The user you're trying to edit doesn't exist.", w, r, user) 149 } else if err != nil { 150 return c.InternalError(err, w, r) 151 } 152 if targetUser.IsAdmin && !user.IsAdmin { 153 return c.LocalError("Only administrators can edit the account of other administrators.", w, r, user) 154 } 155 156 newName := c.SanitiseSingleLine(r.PostFormValue("name")) 157 if newName == "" { 158 return c.LocalError("You didn't put in a name.", w, r, user) 159 } 160 161 // TODO: How should activation factor into admin set emails? 162 // TODO: How should we handle secondary emails? Do we even have secondary emails implemented? 163 newEmail := c.SanitiseSingleLine(r.PostFormValue("email")) 164 if newEmail == "" && targetUser.Email != "" { 165 return c.LocalError("You didn't put in an email address.", w, r, user) 166 } 167 if newEmail == "-1" { 168 newEmail = targetUser.Email 169 } 170 if (newEmail != targetUser.Email) && !user.Perms.EditUserEmail { 171 return c.LocalError("You need the EditUserEmail permission to edit the email address of a user.", w, r, user) 172 } 173 174 newPassword := r.PostFormValue("password") 175 if newPassword != "" && !user.Perms.EditUserPassword { 176 return c.LocalError("You need the EditUserPassword permission to edit the password of a user.", w, r, user) 177 } 178 179 newGroup, err := strconv.Atoi(r.PostFormValue("group")) 180 if err != nil { 181 return c.LocalError("You need to provide a whole number for the group ID", w, r, user) 182 } 183 group, err := c.Groups.Get(newGroup) 184 if err == sql.ErrNoRows { 185 return c.LocalError("The group you're trying to place this user in doesn't exist.", w, r, user) 186 } else if err != nil { 187 return c.InternalError(err, w, r) 188 } 189 if !user.Perms.EditUserGroupAdmin && group.IsAdmin { 190 return c.LocalError("You need the EditUserGroupAdmin permission to assign someone to an administrator group.", w, r, user) 191 } 192 if !user.Perms.EditUserGroupSuperMod && group.IsMod { 193 return c.LocalError("You need the EditUserGroupSuperMod permission to assign someone to a super mod group.", w, r, user) 194 } 195 196 err = targetUser.Update(newName, c.CanonEmail(newEmail), newGroup) 197 if err != nil { 198 return c.InternalError(err, w, r) 199 } 200 201 red := false 202 if newPassword != "" { 203 c.SetPassword(targetUser.ID, newPassword) 204 // Log the user out as a safety precaution 205 c.Auth.ForceLogout(targetUser.ID) 206 red = true 207 } 208 targetUser.CacheRemove() 209 210 targetUser, err = c.Users.Get(uid) 211 if err == sql.ErrNoRows { 212 return c.LocalError("The user you're trying to edit doesn't exist.", w, r, user) 213 } else if err != nil { 214 return c.InternalError(err, w, r) 215 } 216 err = c.GroupPromotions.PromoteIfEligible(targetUser, targetUser.Level, targetUser.Posts, targetUser.CreatedAt) 217 if err != nil { 218 return c.InternalError(err, w, r) 219 } 220 targetUser.CacheRemove() 221 222 err = c.AdminLogs.Create("edit", targetUser.ID, "user", user.GetIP(), user.ID) 223 if err != nil { 224 return c.InternalError(err, w, r) 225 } 226 227 // If we're changing our own password, redirect to the index rather than to a noperms error due to the force logout 228 if targetUser.ID == user.ID && red { 229 http.Redirect(w, r, "/", http.StatusSeeOther) 230 } else { 231 var se string 232 if r.PostFormValue("show-email") == "1" { 233 se = "&show-email=1" 234 } 235 http.Redirect(w, r, "/panel/users/edit/"+strconv.Itoa(targetUser.ID)+"?updated=1"+se, http.StatusSeeOther) 236 } 237 return nil 238 } 239 240 func UsersAvatarSubmit(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError { 241 _, ferr := c.SimplePanelUserCheck(w, r, u) 242 if ferr != nil { 243 return ferr 244 } 245 // TODO: Check the UploadAvatars permission too? 246 if !u.Perms.EditUser { 247 return c.NoPermissions(w, r, u) 248 } 249 250 uid, err := strconv.Atoi(suid) 251 if err != nil { 252 return c.LocalError("The provided UserID is not a valid number.", w, r, u) 253 } 254 targetUser, err := c.Users.Get(uid) 255 if err == sql.ErrNoRows { 256 return c.LocalError("The user you're trying to edit doesn't exist.", w, r, u) 257 } else if err != nil { 258 return c.InternalError(err, w, r) 259 } 260 if targetUser.IsAdmin && !u.IsAdmin { 261 return c.LocalError("Only administrators can edit the account of other administrators.", w, r, u) 262 } 263 264 ext, ferr := c.UploadAvatar(w, r, u, targetUser.ID) 265 if ferr != nil { 266 return ferr 267 } 268 ferr = c.ChangeAvatar("."+ext, w, r, targetUser) 269 if ferr != nil { 270 return ferr 271 } 272 // TODO: Only schedule a resize if the avatar isn't tiny 273 err = targetUser.ScheduleAvatarResize() 274 if err != nil { 275 return c.InternalError(err, w, r) 276 } 277 278 err = c.AdminLogs.Create("edit", targetUser.ID, "user", u.GetIP(), u.ID) 279 if err != nil { 280 return c.InternalError(err, w, r) 281 } 282 283 var se string 284 if r.PostFormValue("show-email") == "1" { 285 se = "&show-email=1" 286 } 287 http.Redirect(w, r, "/panel/users/edit/"+strconv.Itoa(targetUser.ID)+"?updated=1"+se, http.StatusSeeOther) 288 return nil 289 } 290 291 func UsersAvatarRemoveSubmit(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError { 292 _, ferr := c.SimplePanelUserCheck(w, r, u) 293 if ferr != nil { 294 return ferr 295 } 296 if !u.Perms.EditUser { 297 return c.NoPermissions(w, r, u) 298 } 299 300 uid, err := strconv.Atoi(suid) 301 if err != nil { 302 return c.LocalError("The provided UserID is not a valid number.", w, r, u) 303 } 304 targetUser, err := c.Users.Get(uid) 305 if err == sql.ErrNoRows { 306 return c.LocalError("The user you're trying to edit doesn't exist.", w, r, u) 307 } else if err != nil { 308 return c.InternalError(err, w, r) 309 } 310 if targetUser.IsAdmin && !u.IsAdmin { 311 return c.LocalError("Only administrators can edit the account of other administrators.", w, r, u) 312 } 313 ferr = c.ChangeAvatar("", w, r, targetUser) 314 if ferr != nil { 315 return ferr 316 } 317 318 err = c.AdminLogs.Create("edit", targetUser.ID, "user", u.GetIP(), u.ID) 319 if err != nil { 320 return c.InternalError(err, w, r) 321 } 322 323 var se string 324 if r.PostFormValue("show-email") == "1" { 325 se = "&show-email=1" 326 } 327 http.Redirect(w, r, "/panel/users/edit/"+strconv.Itoa(targetUser.ID)+"?updated=1"+se, http.StatusSeeOther) 328 return nil 329 }