gosora/routes/panel/groups.go
Azareal 5705252029 Add UseConvos permission.
Use UseConvos permission instead of ban flags in convo perm checks.
Stop users without the UseConvos permission from editing convo replies, although they can still delete them for privacy reasons.

Shorten some things and reduce the amount of boilerplate.
Add a few misc parser test cases.
Fix footer and tweak indentation.
2019-10-06 10:34:09 +10:00

521 lines
15 KiB
Go

package panel
import (
"database/sql"
"net/http"
"strconv"
"strings"
c "github.com/Azareal/Gosora/common"
p "github.com/Azareal/Gosora/common/phrases"
)
func Groups(w http.ResponseWriter, r *http.Request, u c.User) c.RouteError {
bPage, ferr := buildBasePage(w, r, &u, "groups", "groups")
if ferr != nil {
return ferr
}
page, _ := strconv.Atoi(r.FormValue("page"))
perPage := 15
offset, page, lastPage := c.PageOffset(bPage.Stats.Groups, page, perPage)
// Skip the 'Unknown' group
offset++
var count int
var groupList []c.GroupAdmin
groups, _ := c.Groups.GetRange(offset, 0)
for _, g := range groups {
if count == perPage {
break
}
var rank string
var rankClass string
var canDelete = false
// TODO: Localise this
switch {
case g.IsAdmin:
rank = "Admin"
rankClass = "admin"
case g.IsMod:
rank = "Mod"
rankClass = "mod"
case g.IsBanned:
rank = "Banned"
rankClass = "banned"
case g.ID == 6:
rank = "Guest"
rankClass = "guest"
default:
rank = "Member"
rankClass = "member"
}
canEdit := u.Perms.EditGroup && (!g.IsAdmin || u.Perms.EditGroupAdmin) && (!g.IsMod || u.Perms.EditGroupSuperMod)
groupList = append(groupList, c.GroupAdmin{g.ID, g.Name, rank, rankClass, canEdit, canDelete})
count++
}
pageList := c.Paginate(page, lastPage, 5)
pi := c.PanelGroupPage{bPage, groupList, c.Paginator{pageList, page, lastPage}}
return renderTemplate("panel", w, r, bPage.Header, c.Panel{bPage, "", "", "panel_groups", &pi})
}
func GroupsEdit(w http.ResponseWriter, r *http.Request, user c.User, sgid string) c.RouteError {
basePage, ferr := buildBasePage(w, r, &user, "edit_group", "groups")
if ferr != nil {
return ferr
}
if !user.Perms.EditGroup {
return c.NoPermissions(w, r, user)
}
gid, err := strconv.Atoi(sgid)
if err != nil {
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
}
g, err := c.Groups.Get(gid)
if err == sql.ErrNoRows {
//log.Print("aaaaa monsters")
return c.NotFound(w, r, basePage.Header)
}
ferr = groupCheck(w, r, user, g, err)
if ferr != nil {
return ferr
}
var rank string
switch {
case g.IsAdmin:
rank = "Admin"
case g.IsMod:
rank = "Mod"
case g.IsBanned:
rank = "Banned"
case g.ID == 6:
rank = "Guest"
default:
rank = "Member"
}
disableRank := !user.Perms.EditGroupGlobalPerms || (g.ID == 6)
pi := c.PanelEditGroupPage{basePage, g.ID, g.Name, g.Tag, rank, disableRank}
return renderTemplate("panel_group_edit", w, r, basePage.Header, pi)
}
func GroupsEditPromotions(w http.ResponseWriter, r *http.Request, user c.User, sgid string) c.RouteError {
basePage, ferr := buildBasePage(w, r, &user, "edit_group", "groups")
if ferr != nil {
return ferr
}
if !user.Perms.EditGroup {
return c.NoPermissions(w, r, user)
}
gid, err := strconv.Atoi(sgid)
if err != nil {
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
}
g, err := c.Groups.Get(gid)
if err == sql.ErrNoRows {
//log.Print("aaaaa monsters")
return c.NotFound(w, r, basePage.Header)
}
ferr = groupCheck(w, r, user, g, err)
if ferr != nil {
return ferr
}
promotions, err := c.GroupPromotions.GetByGroup(g.ID)
if err != sql.ErrNoRows && err != nil {
return c.InternalError(err, w, r)
}
promoteExt := make([]*c.GroupPromotionExtend, len(promotions))
for i, promote := range promotions {
fg, err := c.Groups.Get(promote.From)
if err == sql.ErrNoRows {
fg = &c.Group{Name: "Deleted Group"}
} else if err != nil {
return c.InternalError(err, w, r)
}
tg, err := c.Groups.Get(promote.To)
if err == sql.ErrNoRows {
tg = &c.Group{Name: "Deleted Group"}
} else if err != nil {
return c.InternalError(err, w, r)
}
promoteExt[i] = &c.GroupPromotionExtend{promote, fg, tg}
}
// ? - Should we stop admins from deleting all the groups? Maybe, protect the group they're currently using?
groups, err := c.Groups.GetRange(1, 0) // ? - 0 = Go to the end
if err != nil {
return c.InternalError(err, w, r)
}
var groupList []*c.Group
for _, group := range groups {
if !user.Perms.EditUserGroupAdmin && group.IsAdmin {
continue
}
if !user.Perms.EditUserGroupSuperMod && group.IsMod {
continue
}
groupList = append(groupList, group)
}
pi := c.PanelEditGroupPromotionsPage{basePage, g.ID, g.Name, promoteExt, groupList}
return renderTemplate("panel_group_edit_promotions", w, r, basePage.Header, pi)
}
func groupCheck(w http.ResponseWriter, r *http.Request, user c.User, g *c.Group, err error) c.RouteError {
if err == sql.ErrNoRows {
return c.LocalError("No such group.", w, r, user)
} else if err != nil {
return c.InternalError(err, w, r)
}
if g.IsAdmin && !user.Perms.EditGroupAdmin {
return c.LocalError(p.GetErrorPhrase("panel_groups_cannot_edit_admin"), w, r, user)
}
if g.IsMod && !user.Perms.EditGroupSuperMod {
return c.LocalError(p.GetErrorPhrase("panel_groups_cannot_edit_supermod"), w, r, user)
}
return nil
}
func GroupsPromotionsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User, sgid string) c.RouteError {
if !user.Perms.EditGroup {
return c.NoPermissions(w, r, user)
}
gid, err := strconv.Atoi(sgid)
if err != nil {
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
}
from, err := strconv.Atoi(r.FormValue("from"))
if err != nil {
return c.LocalError("from must be integer", w, r, user)
}
to, err := strconv.Atoi(r.FormValue("to"))
if err != nil {
return c.LocalError("to must be integer", w, r, user)
}
twoWay := r.FormValue("two-way") == "1"
level, err := strconv.Atoi(r.FormValue("level"))
if err != nil {
return c.LocalError("level must be integer", w, r, user)
}
g, err := c.Groups.Get(from)
ferr := groupCheck(w, r, user, g, err)
if err != nil {
return ferr
}
g, err = c.Groups.Get(to)
ferr = groupCheck(w, r, user, g, err)
if err != nil {
return ferr
}
_, err = c.GroupPromotions.Create(from, to, twoWay, level)
if err != nil {
return c.InternalError(err, w, r)
}
http.Redirect(w, r, "/panel/groups/edit/promotions/"+strconv.Itoa(gid), http.StatusSeeOther)
return nil
}
func GroupsPromotionsDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, sspl string) c.RouteError {
if !user.Perms.EditGroup {
return c.NoPermissions(w, r, user)
}
spl := strings.Split(sspl, "-")
if len(spl) < 2 {
return c.LocalError("need two params", w, r, user)
}
gid, err := strconv.Atoi(spl[0])
if err != nil {
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
}
pid, err := strconv.Atoi(spl[1])
if err != nil {
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
}
pro, err := c.GroupPromotions.Get(pid)
if err == sql.ErrNoRows {
return c.LocalError("That group promotion doesn't exist", w, r, user)
} else if err != nil {
return c.InternalError(err, w, r)
}
g, err := c.Groups.Get(pro.From)
ferr := groupCheck(w, r, user, g, err)
if err != nil {
return ferr
}
g, err = c.Groups.Get(pro.To)
ferr = groupCheck(w, r, user, g, err)
if err != nil {
return ferr
}
err = c.GroupPromotions.Delete(pid)
if err != nil {
return c.InternalError(err, w, r)
}
http.Redirect(w, r, "/panel/groups/edit/promotions/"+strconv.Itoa(gid), http.StatusSeeOther)
return nil
}
func GroupsEditPerms(w http.ResponseWriter, r *http.Request, user c.User, sgid string) c.RouteError {
basePage, ferr := buildBasePage(w, r, &user, "edit_group", "groups")
if ferr != nil {
return ferr
}
if !user.Perms.EditGroup {
return c.NoPermissions(w, r, user)
}
gid, err := strconv.Atoi(sgid)
if err != nil {
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
}
g, err := c.Groups.Get(gid)
if err == sql.ErrNoRows {
//log.Print("aaaaa monsters")
return c.NotFound(w, r, basePage.Header)
} else if err != nil {
return c.InternalError(err, w, r)
}
if g.IsAdmin && !user.Perms.EditGroupAdmin {
return c.LocalError(p.GetErrorPhrase("panel_groups_cannot_edit_admin"), w, r, user)
}
if g.IsMod && !user.Perms.EditGroupSuperMod {
return c.LocalError(p.GetErrorPhrase("panel_groups_cannot_edit_supermod"), w, r, user)
}
// TODO: Load the phrases in bulk for efficiency?
var localPerms []c.NameLangToggle
addLocalPerm := func(permStr string, perm bool) {
localPerms = append(localPerms, c.NameLangToggle{permStr, p.GetLocalPermPhrase(permStr), perm})
}
addLocalPerm("ViewTopic", g.Perms.ViewTopic)
addLocalPerm("LikeItem", g.Perms.LikeItem)
addLocalPerm("CreateTopic", g.Perms.CreateTopic)
//<--
addLocalPerm("EditTopic", g.Perms.EditTopic)
addLocalPerm("DeleteTopic", g.Perms.DeleteTopic)
addLocalPerm("CreateReply", g.Perms.CreateReply)
addLocalPerm("EditReply", g.Perms.EditReply)
addLocalPerm("DeleteReply", g.Perms.DeleteReply)
addLocalPerm("PinTopic", g.Perms.PinTopic)
addLocalPerm("CloseTopic", g.Perms.CloseTopic)
addLocalPerm("MoveTopic", g.Perms.MoveTopic)
var globalPerms []c.NameLangToggle
addGlobalPerm := func(permStr string, perm bool) {
globalPerms = append(globalPerms, c.NameLangToggle{permStr, p.GetGlobalPermPhrase(permStr), perm})
}
addGlobalPerm("BanUsers", g.Perms.BanUsers)
addGlobalPerm("ActivateUsers", g.Perms.ActivateUsers)
addGlobalPerm("EditUser", g.Perms.EditUser)
addGlobalPerm("EditUserEmail", g.Perms.EditUserEmail)
addGlobalPerm("EditUserPassword", g.Perms.EditUserPassword)
addGlobalPerm("EditUserGroup", g.Perms.EditUserGroup)
addGlobalPerm("EditUserGroupSuperMod", g.Perms.EditUserGroupSuperMod)
addGlobalPerm("EditUserGroupAdmin", g.Perms.EditUserGroupAdmin)
addGlobalPerm("EditGroup", g.Perms.EditGroup)
addGlobalPerm("EditGroupLocalPerms", g.Perms.EditGroupLocalPerms)
addGlobalPerm("EditGroupGlobalPerms", g.Perms.EditGroupGlobalPerms)
addGlobalPerm("EditGroupSuperMod", g.Perms.EditGroupSuperMod)
addGlobalPerm("EditGroupAdmin", g.Perms.EditGroupAdmin)
addGlobalPerm("ManageForums", g.Perms.ManageForums)
addGlobalPerm("EditSettings", g.Perms.EditSettings)
addGlobalPerm("ManageThemes", g.Perms.ManageThemes)
addGlobalPerm("ManagePlugins", g.Perms.ManagePlugins)
addGlobalPerm("ViewAdminLogs", g.Perms.ViewAdminLogs)
addGlobalPerm("ViewIPs", g.Perms.ViewIPs)
addGlobalPerm("UploadFiles", g.Perms.UploadFiles)
addGlobalPerm("UploadAvatars", g.Perms.UploadAvatars)
addGlobalPerm("UseConvos", g.Perms.UseConvos)
pi := c.PanelEditGroupPermsPage{basePage, g.ID, g.Name, localPerms, globalPerms}
return renderTemplate("panel_group_edit_perms", w, r, basePage.Header, pi)
}
func GroupsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sgid string) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
}
if !user.Perms.EditGroup {
return c.NoPermissions(w, r, user)
}
gid, err := strconv.Atoi(sgid)
if err != nil {
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
}
group, err := c.Groups.Get(gid)
if err == sql.ErrNoRows {
//log.Print("aaaaa monsters")
return c.NotFound(w, r, nil)
}
ferr = groupCheck(w, r, user, group, err)
if ferr != nil {
return ferr
}
gname := r.FormValue("group-name")
if gname == "" {
return c.LocalError(p.GetErrorPhrase("panel_groups_need_name"), w, r, user)
}
gtag := r.FormValue("group-tag")
rank := r.FormValue("group-type")
var originalRank string
// TODO: Use a switch for this
if group.IsAdmin {
originalRank = "Admin"
} else if group.IsMod {
originalRank = "Mod"
} else if group.IsBanned {
originalRank = "Banned"
} else if group.ID == 6 {
originalRank = "Guest"
} else {
originalRank = "Member"
}
if rank != originalRank && originalRank != "Guest" {
if !user.Perms.EditGroupGlobalPerms {
return c.LocalError(p.GetErrorPhrase("panel_groups_cannot_edit_group_type"), w, r, user)
}
switch rank {
case "Admin":
if !user.Perms.EditGroupAdmin {
return c.LocalError(p.GetErrorPhrase("panel_groups_edit_cannot_designate_admin"), w, r, user)
}
err = group.ChangeRank(true, true, false)
case "Mod":
if !user.Perms.EditGroupSuperMod {
return c.LocalError(p.GetErrorPhrase("panel_groups_edit_cannot_designate_supermod"), w, r, user)
}
err = group.ChangeRank(false, true, false)
case "Banned":
err = group.ChangeRank(false, false, true)
case "Guest":
return c.LocalError(p.GetErrorPhrase("panel_groups_cannot_be_guest"), w, r, user)
case "Member":
err = group.ChangeRank(false, false, false)
default:
return c.LocalError(p.GetErrorPhrase("panel_groups_invalid_group_type"), w, r, user)
}
if err != nil {
return c.InternalError(err, w, r)
}
}
err = group.Update(gname, gtag)
if err != nil {
return c.InternalError(err, w, r)
}
http.Redirect(w, r, "/panel/groups/edit/"+strconv.Itoa(gid), http.StatusSeeOther)
return nil
}
func GroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user c.User, sgid string) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
}
if !user.Perms.EditGroup {
return c.NoPermissions(w, r, user)
}
gid, err := strconv.Atoi(sgid)
if err != nil {
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
}
group, err := c.Groups.Get(gid)
if err == sql.ErrNoRows {
//log.Print("aaaaa monsters o.o")
return c.NotFound(w, r, nil)
}
ferr = groupCheck(w, r, user, group, err)
if ferr != nil {
return ferr
}
// TODO: Don't unset perms we don't have permission to set?
pmap := make(map[string]bool)
pCheck := func(hasPerm bool, perms []string) {
if hasPerm {
for _, perm := range perms {
pvalue := r.PostFormValue("group-perm-" + perm)
pmap[perm] = (pvalue == "1")
}
}
}
pCheck(user.Perms.EditGroupLocalPerms, c.LocalPermList)
pCheck(user.Perms.EditGroupGlobalPerms, c.GlobalPermList)
err = group.UpdatePerms(pmap)
if err != nil {
return c.InternalError(err, w, r)
}
http.Redirect(w, r, "/panel/groups/edit/perms/"+strconv.Itoa(gid), http.StatusSeeOther)
return nil
}
func GroupsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
}
if !user.Perms.EditGroup {
return c.NoPermissions(w, r, user)
}
groupName := r.PostFormValue("group-name")
if groupName == "" {
return c.LocalError(p.GetErrorPhrase("panel_groups_need_name"), w, r, user)
}
groupTag := r.PostFormValue("group-tag")
var isAdmin, isMod, isBanned bool
if user.Perms.EditGroupGlobalPerms {
switch r.PostFormValue("group-type") {
case "Admin":
if !user.Perms.EditGroupAdmin {
return c.LocalError(p.GetErrorPhrase("panel_groups_create_cannot_designate_admin"), w, r, user)
}
isAdmin = true
isMod = true
case "Mod":
if !user.Perms.EditGroupSuperMod {
return c.LocalError(p.GetErrorPhrase("panel_groups_create_cannot_designate_supermod"), w, r, user)
}
isMod = true
case "Banned":
isBanned = true
}
}
gid, err := c.Groups.Create(groupName, groupTag, isAdmin, isMod, isBanned)
if err != nil {
return c.InternalError(err, w, r)
}
http.Redirect(w, r, "/panel/groups/edit/"+strconv.Itoa(gid), http.StatusSeeOther)
return nil
}