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  }