package main import "log" import "fmt" import "sync" import "strconv" import "encoding/json" var permupdate_mutex sync.Mutex var BlankPerms Perms var BlankForumPerms ForumPerms var GuestPerms Perms var ReadForumPerms ForumPerms var ReadReplyForumPerms ForumPerms var ReadWriteForumPerms ForumPerms var AllPerms Perms var AllForumPerms ForumPerms var AllPluginPerms map[string]bool = make(map[string]bool) var LocalPermList []string = []string{ "ViewTopic", "LikeItem", "CreateTopic", "EditTopic", "DeleteTopic", "CreateReply", "EditReply", "DeleteReply", "PinTopic", "CloseTopic", } var GlobalPermList []string = []string{ "BanUsers", "ActivateUsers", "EditUser", "EditUserEmail", "EditUserPassword", "EditUserGroup", "EditUserGroupSuperMod", "EditUserGroupAdmin", "EditGroup", "EditGroupLocalPerms", "EditGroupGlobalPerms", "EditGroupSuperMod", "EditGroupAdmin", "ManageForums", "EditSettings", "ManageThemes", "ManagePlugins", "ViewAdminLogs", "ViewIPs", } // Permission Structure: ActionComponent[Subcomponent]Flag type Perms struct { // Global Permissions BanUsers bool ActivateUsers bool EditUser bool EditUserEmail bool EditUserPassword bool EditUserGroup bool EditUserGroupSuperMod bool EditUserGroupAdmin bool EditGroup bool EditGroupLocalPerms bool EditGroupGlobalPerms bool EditGroupSuperMod bool EditGroupAdmin bool ManageForums bool // This could be local, albeit limited for per-forum managers? EditSettings bool ManageThemes bool ManagePlugins bool ViewAdminLogs bool ViewIPs bool // Forum permissions ViewTopic bool LikeItem bool CreateTopic bool EditTopic bool DeleteTopic bool CreateReply bool //CreateReplyToOwn bool EditReply bool //EditOwnReply bool DeleteReply bool PinTopic bool CloseTopic bool //CloseOwnTopic bool //ExtData map[string]bool } /* Inherit from group permissions for ones we don't have */ type ForumPerms struct { ViewTopic bool LikeItem bool CreateTopic bool EditTopic bool DeleteTopic bool CreateReply bool //CreateReplyToOwn bool EditReply bool //EditOwnReply bool DeleteReply bool PinTopic bool CloseTopic bool //CloseOwnTopic bool Overrides bool ExtData map[string]bool } func init() { BlankPerms = Perms{ //ExtData: make(map[string]bool), } BlankForumPerms = ForumPerms{ ExtData: make(map[string]bool), } GuestPerms = Perms{ ViewTopic: true, //ExtData: make(map[string]bool), } AllPerms = Perms{ BanUsers: true, ActivateUsers: true, EditUser: true, EditUserEmail: true, EditUserPassword: true, EditUserGroup: true, EditUserGroupSuperMod: true, EditUserGroupAdmin: true, EditGroup: true, EditGroupLocalPerms: true, EditGroupGlobalPerms: true, EditGroupSuperMod: true, EditGroupAdmin: true, ManageForums: true, EditSettings: true, ManageThemes: true, ManagePlugins: true, ViewAdminLogs: true, ViewIPs: true, ViewTopic: true, LikeItem: true, CreateTopic: true, EditTopic: true, DeleteTopic: true, CreateReply: true, EditReply: true, DeleteReply: true, PinTopic: true, CloseTopic: true, //ExtData: make(map[string]bool), } AllForumPerms = ForumPerms{ ViewTopic: true, LikeItem: true, CreateTopic: true, EditTopic: true, DeleteTopic: true, CreateReply: true, EditReply: true, DeleteReply: true, PinTopic: true, CloseTopic: true, Overrides: true, ExtData: make(map[string]bool), } ReadWriteForumPerms = ForumPerms{ ViewTopic: true, LikeItem: true, CreateTopic: true, CreateReply: true, Overrides: true, ExtData: make(map[string]bool), } ReadReplyForumPerms = ForumPerms{ ViewTopic: true, LikeItem: true, CreateReply: true, Overrides: true, ExtData: make(map[string]bool), } ReadForumPerms = ForumPerms{ ViewTopic: true, Overrides: true, ExtData: make(map[string]bool), } guest_user.Perms = GuestPerms if dev.DebugMode { fmt.Printf("Guest Perms: ") fmt.Printf("%+v\n", GuestPerms) fmt.Printf("All Perms: ") fmt.Printf("%+v\n", AllPerms) } } func preset_to_permmap(preset string) (out map[string]ForumPerms) { out = make(map[string]ForumPerms) switch(preset) { case "all": out["guests"] = ReadForumPerms out["members"] = ReadWriteForumPerms out["staff"] = AllForumPerms out["admins"] = AllForumPerms case "announce": out["guests"] = ReadForumPerms out["members"] = ReadReplyForumPerms out["staff"] = AllForumPerms out["admins"] = AllForumPerms case "members": out["guests"] = BlankForumPerms out["members"] = ReadWriteForumPerms out["staff"] = AllForumPerms out["admins"] = AllForumPerms case "staff": out["guests"] = BlankForumPerms out["members"] = BlankForumPerms out["staff"] = ReadWriteForumPerms out["admins"] = AllForumPerms case "admins": out["guests"] = BlankForumPerms out["members"] = BlankForumPerms out["staff"] = BlankForumPerms out["admins"] = AllForumPerms case "archive": out["guests"] = ReadForumPerms out["members"] = ReadForumPerms out["staff"] = ReadForumPerms out["admins"] = ReadForumPerms //CurateForumPerms. Delete / Edit but no create? default: out["guests"] = BlankForumPerms out["members"] = BlankForumPerms out["staff"] = BlankForumPerms out["admins"] = BlankForumPerms } return out } func permmap_to_query(permmap map[string]ForumPerms, fid int) error { permupdate_mutex.Lock() defer permupdate_mutex.Unlock() _, err := delete_forum_perms_by_forum_stmt.Exec(fid) if err != nil { return err } perms, err := json.Marshal(permmap["admins"]) if err != nil { return err } _, err = add_forum_perms_to_forum_admins_stmt.Exec(fid,"",perms) if err != nil { return err } perms, err = json.Marshal(permmap["staff"]) if err != nil { return err } _, err = add_forum_perms_to_forum_staff_stmt.Exec(fid,"",perms) if err != nil { return err } perms, err = json.Marshal(permmap["members"]) if err != nil { return err } _, err = add_forum_perms_to_forum_members_stmt.Exec(fid,"",perms) if err != nil { return err } perms, err = json.Marshal(permmap["guests"]) if err != nil { return err } _, err = add_forum_perms_to_group_stmt.Exec(6,fid,"",perms) if err != nil { return err } return rebuild_forum_permissions(fid) } func rebuild_forum_permissions(fid int) error { if dev.DebugMode { log.Print("Loading the forum permissions") } forums, err := fstore.GetAll() if err != nil { return err } rows, err := db.Query("select gid, permissions from forums_permissions where fid = ? order by gid asc", fid) if err != nil { return err } defer rows.Close() if dev.DebugMode { log.Print("Updating the forum permissions") } for rows.Next() { var gid int var perms []byte var pperms ForumPerms err := rows.Scan(&gid, &perms) if err != nil { return err } err = json.Unmarshal(perms, &pperms) if err != nil { return err } pperms.ExtData = make(map[string]bool) pperms.Overrides = true _, ok := forum_perms[gid] if !ok { forum_perms[gid] = make(map[int]ForumPerms) } forum_perms[gid][fid] = pperms } for gid, _ := range groups { if dev.DebugMode { log.Print("Updating the forum permissions for Group #" + strconv.Itoa(gid)) } var blank_list []ForumPerms var blank_int_list []int groups[gid].Forums = blank_list groups[gid].CanSee = blank_int_list for ffid, _ := range forums { forum_perm, ok := forum_perms[gid][ffid] if ok { //log.Print("Overriding permissions for forum #" + strconv.Itoa(fid)) groups[gid].Forums = append(groups[gid].Forums,forum_perm) } else { //log.Print("Inheriting from default for forum #" + strconv.Itoa(fid)) forum_perm = BlankForumPerms groups[gid].Forums = append(groups[gid].Forums,forum_perm) } if forum_perm.Overrides { if forum_perm.ViewTopic { groups[gid].CanSee = append(groups[gid].CanSee, ffid) } } else if groups[gid].Perms.ViewTopic { groups[gid].CanSee = append(groups[gid].CanSee, ffid) } } if dev.SuperDebug { fmt.Printf("groups[gid].CanSee %+v\n", groups[gid].CanSee) fmt.Printf("groups[gid].Forums %+v\n", groups[gid].Forums) fmt.Println("len(groups[gid].Forums)",len(groups[gid].Forums)) } } return nil } func build_forum_permissions() error { forums, err := fstore.GetAll() if err != nil { return err } rows, err := get_forums_permissions_stmt.Query() if err != nil { return err } defer rows.Close() if dev.DebugMode { log.Print("Adding the forum permissions") } // Temporarily store the forum perms in a map before transferring it to a much faster and thread-safe slice forum_perms = make(map[int]map[int]ForumPerms) for rows.Next() { var gid, fid int var perms []byte var pperms ForumPerms err = rows.Scan(&gid, &fid, &perms) if err != nil { return err } err = json.Unmarshal(perms, &pperms) if err != nil { return err } pperms.ExtData = make(map[string]bool) pperms.Overrides = true _, ok := forum_perms[gid] if !ok { forum_perms[gid] = make(map[int]ForumPerms) } forum_perms[gid][fid] = pperms } for gid, _ := range groups { if dev.DebugMode { log.Print("Adding the forum permissions for Group #" + strconv.Itoa(gid) + " - " + groups[gid].Name) } //groups[gid].Forums = append(groups[gid].Forums,BlankForumPerms) // GID 0. No longer needed now that Uncategorised occupies that slot for fid, _ := range forums { forum_perm, ok := forum_perms[gid][fid] if ok { // Override group perms //log.Print("Overriding permissions for forum #" + strconv.Itoa(fid)) groups[gid].Forums = append(groups[gid].Forums,forum_perm) } else { // Inherit from Group //log.Print("Inheriting from default for forum #" + strconv.Itoa(fid)) forum_perm = BlankForumPerms groups[gid].Forums = append(groups[gid].Forums,forum_perm) } if forum_perm.Overrides { if forum_perm.ViewTopic { groups[gid].CanSee = append(groups[gid].CanSee, fid) } } else if groups[gid].Perms.ViewTopic { groups[gid].CanSee = append(groups[gid].CanSee, fid) } } if dev.SuperDebug { //fmt.Printf("groups[gid].CanSee %+v\n", groups[gid].CanSee) //fmt.Printf("groups[gid].Forums %+v\n", groups[gid].Forums) //fmt.Println("len(groups[gid].CanSee)",len(groups[gid].CanSee)) //fmt.Println("len(groups[gid].Forums)",len(groups[gid].Forums)) } } return nil } func forum_perms_to_group_forum_preset(fperms ForumPerms) string { if !fperms.Overrides { return "default" } if !fperms.ViewTopic { return "no_access" } var can_post bool = (fperms.LikeItem && fperms.CreateTopic && fperms.CreateReply) var can_moderate bool = (can_post && fperms.EditTopic && fperms.DeleteTopic && fperms.EditReply && fperms.DeleteReply && fperms.PinTopic && fperms.CloseTopic) if can_moderate { return "can_moderate" } if (fperms.EditTopic || fperms.DeleteTopic || fperms.EditReply || fperms.DeleteReply || fperms.PinTopic || fperms.CloseTopic) { if !can_post { return "custom" } return "quasi_mod" } if can_post { return "can_post" } if fperms.ViewTopic && !fperms.LikeItem && !fperms.CreateTopic && !fperms.CreateReply { return "read_only" } return "custom" } func group_forum_preset_to_forum_perms(preset string) (fperms ForumPerms, changed bool) { switch(preset) { case "read_only": return ReadForumPerms, true case "can_post": return ReadWriteForumPerms, true case "can_moderate": return AllForumPerms, true case "no_access": return ForumPerms{Overrides: true,ExtData: make(map[string]bool)}, true case "default": return BlankForumPerms, true //case "custom": return fperms, false } return fperms, false } func strip_invalid_group_forum_preset(preset string) string { switch(preset) { case "read_only","can_post","can_moderate","no_access","default","custom": return preset } return "" } func strip_invalid_preset(preset string) string { switch(preset) { case "all","announce","members","staff","admins","archive","custom": break default: return "" } return preset } func preset_to_lang(preset string) string { switch(preset) { case "all": return "Public" case "announce": return "Announcements" case "members": return "Member Only" case "staff": return "Staff Only" case "admins": return "Admin Only" case "archive": return "Archive" case "custom": return "Custom" } return "" } func rebuild_group_permissions(gid int) error { var permstr []byte log.Print("Reloading a group") err := db.QueryRow("select permissions from users_groups where gid = ?",gid).Scan(&permstr) if err != nil { return err } tmp_perms := Perms{ //ExtData: make(map[string]bool), } err = json.Unmarshal(permstr, &tmp_perms) if err != nil { return err } groups[gid].Perms = tmp_perms return nil } func override_perms(perms *Perms, status bool) { if status { *perms = AllPerms } else { *perms = BlankPerms } } // TO-DO: We need a better way of overriding forum perms rather than setting them one by one func override_forum_perms(perms *Perms, status bool) { perms.ViewTopic = status perms.LikeItem = status perms.CreateTopic = status perms.EditTopic = status perms.DeleteTopic = status perms.CreateReply = status perms.EditReply = status perms.DeleteReply = status perms.PinTopic = status perms.CloseTopic = status } func register_plugin_perm(name string) { AllPluginPerms[name] = true } func deregister_plugin_perm(name string) { delete(AllPluginPerms,name) }