You can now create forums with a specific permission preset. The ability to change the preset of a forum and more granular control over it's permissions is coming soon.

Fixed a bug in the /forums/ route over which forums were visible.
This commit is contained in:
Azareal 2017-02-04 06:19:55 +00:00
parent f5c6f6b552
commit f8e657ee39
13 changed files with 408 additions and 172 deletions

View File

@ -59,6 +59,7 @@ CREATE TABLE `forums`(
CREATE TABLE `forums_permissions`(
`fid` int not null,
`gid` int not null,
`preset` varchar(100) DEFAULT '' not null,
`permissions` text not null
);

View File

@ -47,8 +47,9 @@ func create_forum(forum_name string, active bool) (int, error) {
if err != nil {
return 0, err
}
fid = int(fid64)
forums = append(forums, Forum{int(fid64),forum_name,active,0,"",0,"",0,""})
forums = append(forums, Forum{fid,forum_name,active,0,"",0,"",0,""})
return fid, nil
}

111
group.go
View File

@ -1,10 +1,4 @@
package main
import "fmt"
var BlankPerms Perms
var BlankForumPerms ForumPerms
var GuestPerms Perms
var AllPerms Perms
type Group struct
{
@ -19,108 +13,3 @@ type Group struct
Forums []ForumPerms
CanSee []int // The IDs of the forums this group can see
}
// 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
ManageForums bool // This could be local, albeit limited for per-forum managers
EditSettings bool
ManageThemes bool
ManagePlugins bool
ViewIPs bool
// Forum permissions
ViewTopic bool
CreateTopic bool
EditTopic bool
DeleteTopic bool
CreateReply bool
//CreateReplyToOwn bool
EditReply bool
//EditOwnReply bool
DeleteReply bool
PinTopic bool
CloseTopic bool
//CloseOwnTopic bool
ExtData interface{}
}
/* Inherit from group permissions for ones we don't have */
type ForumPerms struct
{
ViewTopic 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,
ManageForums: true,
EditSettings: true,
ManageThemes: true,
ManagePlugins: true,
ViewIPs: true,
ViewTopic: true,
CreateTopic: true,
EditTopic: true,
DeleteTopic: true,
CreateReply: true,
EditReply: true,
DeleteReply: true,
PinTopic: true,
CloseTopic: true,
ExtData: make(map[string]bool),
}
if debug {
fmt.Printf("Guest Perms: ")
fmt.Printf("%+v\n", GuestPerms)
fmt.Printf("All Perms: ")
fmt.Printf("%+v\n", AllPerms)
}
}

View File

@ -31,7 +31,7 @@ var settings map[string]interface{} = make(map[string]interface{})
var external_sites map[string]string = make(map[string]string)
var groups []Group
var forums []Forum // The IDs for a forum tend to be low and sequential for the most part, so we can get more performance out of using a slice instead of a map AND it has better concurrency
var forum_perms [][]ForumPerms // [gid][fid]Perms
var forum_perms map[int]map[int]ForumPerms // [gid][fid]Perms
var groupCapCount int
var forumCapCount int
var static_files map[string]SFile = make(map[string]SFile)

View File

@ -729,6 +729,7 @@ func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
var active bool
fname := r.PostFormValue("forum-name")
fpreset := r.PostFormValue("forum-preset")
factive := r.PostFormValue("forum-name")
if factive == "on" || factive == "1" {
active = true
@ -736,11 +737,13 @@ func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
active = false
}
_, err = create_forum(fname, active)
fid, err := create_forum(fname,active)
if err != nil {
InternalError(err,w,r,user)
return
}
permmap_to_query(preset_to_permmap(fpreset),fid)
http.Redirect(w,r,"/panel/forums/",http.StatusSeeOther)
}
@ -1246,7 +1249,6 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){
} else {
puser.Tag = ""
}
userList = append(userList,puser)
}
err = rows.Err()

View File

@ -59,6 +59,12 @@ var create_forum_stmt *sql.Stmt
var delete_forum_stmt *sql.Stmt
var update_forum_stmt *sql.Stmt
var forum_entry_exists_stmt *sql.Stmt
var delete_forum_perms_by_forum_stmt *sql.Stmt
var add_forum_perms_to_forum_stmt *sql.Stmt
var add_forum_perms_to_forum_admins_stmt *sql.Stmt
var add_forum_perms_to_forum_staff_stmt *sql.Stmt
var add_forum_perms_to_forum_members_stmt *sql.Stmt
var add_forum_perms_to_forum_guests_stmt *sql.Stmt
var update_setting_stmt *sql.Stmt
var add_plugin_stmt *sql.Stmt
var update_plugin_stmt *sql.Stmt
@ -379,6 +385,42 @@ func init_database(err error) {
log.Fatal(err)
}
log.Print("Preparing delete_forum_perms_by_forum statement.")
delete_forum_perms_by_forum_stmt, err = db.Prepare("DELETE FROM forums_permissions WHERE fid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing add_forum_perms_to_forum statement.")
add_forum_perms_to_forum_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) VALUES(?,?,?,?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing add_forum_perms_to_forum_admins statement.")
add_forum_perms_to_forum_admins_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) SELECT `gid`,? AS fid,? AS preset, ? AS permissions FROM users_groups WHERE is_admin = 1")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing add_forum_perms_to_forum_staff statement.")
add_forum_perms_to_forum_staff_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) SELECT `gid`,? AS fid,? AS preset, ? AS permissions FROM users_groups WHERE is_admin = 0 AND is_mod = 1")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing add_forum_perms_to_forum_members statement.")
add_forum_perms_to_forum_members_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) SELECT `gid`,? AS fid,? AS preset, ? AS permissions FROM users_groups WHERE is_admin = 0 AND is_mod = 0 AND is_banned = 0")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing add_forum_perms_to_forum_guests statement.")
add_forum_perms_to_forum_guests_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) VALUES(6,?,?,?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_setting statement.")
update_setting_stmt, err = db.Prepare("UPDATE settings SET content = ? WHERE name = ?")
if err != nil {
@ -404,7 +446,7 @@ func init_database(err error) {
}
log.Print("Preparing update_theme statement.")
update_theme_stmt, err = db.Prepare("UPDATE `themes` SET `default` = ? WHERE `uname` = ?")
update_theme_stmt, err = db.Prepare("update `themes` set `default` = ? where `uname` = ?")
if err != nil {
log.Fatal(err)
}
@ -514,8 +556,8 @@ func init_database(err error) {
// Temporarily store the forum perms in a map before transferring it to a much faster slice
log.Print("Adding the forum permissions")
forum_perms := make(map[int]map[int]ForumPerms)
for ;rows.Next();i++ {
forum_perms = make(map[int]map[int]ForumPerms)
for rows.Next() {
var gid int
var fid int
var perms []byte
@ -537,7 +579,7 @@ func init_database(err error) {
forum_perms[gid][fid] = pperms
}
for gid, _ := range groups {
log.Print("Adding the forum permissions for Group #" + strconv.Itoa(gid))
log.Print("Adding the forum permissions for Group #" + strconv.Itoa(gid) + " - " + groups[gid].Name)
//groups[gid].Forums = append(groups[gid].Forums,BlankForumPerms) // GID 0. I sometimes wish MySQL's AUTO_INCREMENT would start at zero
for fid, _ := range forums {
forum_perm, ok := forum_perms[gid][fid]
@ -562,6 +604,7 @@ func init_database(err error) {
}
//fmt.Printf("%+v\n", groups[gid].CanSee)
//fmt.Printf("%+v\n", groups[gid].Forums)
//fmt.Println(len(groups[gid].CanSee))
//fmt.Println(len(groups[gid].Forums))
}

301
permissions.go Normal file
View File

@ -0,0 +1,301 @@
package main
import "log"
import "fmt"
import "sync"
import "strconv"
import "encoding/json"
var BlankPerms Perms
var BlankForumPerms ForumPerms
var GuestPerms Perms
var ReadForumPerms ForumPerms
var ReadReplyForumPerms ForumPerms
var ReadWriteForumPerms ForumPerms
var AllPerms Perms
var AllForumPerms ForumPerms
// 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
ManageForums bool // This could be local, albeit limited for per-forum managers
EditSettings bool
ManageThemes bool
ManagePlugins bool
ViewIPs bool
// Forum permissions
ViewTopic bool
CreateTopic bool
EditTopic bool
DeleteTopic bool
CreateReply bool
//CreateReplyToOwn bool
EditReply bool
//EditOwnReply bool
DeleteReply bool
PinTopic bool
CloseTopic bool
//CloseOwnTopic bool
ExtData interface{}
}
/* Inherit from group permissions for ones we don't have */
type ForumPerms struct
{
ViewTopic 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,
ManageForums: true,
EditSettings: true,
ManageThemes: true,
ManagePlugins: true,
ViewIPs: true,
ViewTopic: 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,
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,
CreateTopic: true,
CreateReply: true,
Overrides: true,
ExtData: make(map[string]bool),
}
ReadReplyForumPerms = ForumPerms{
ViewTopic: true,
CreateReply: true,
Overrides: true,
ExtData: make(map[string]bool),
}
ReadForumPerms = ForumPerms{
ViewTopic: true,
Overrides: true,
ExtData: make(map[string]bool),
}
if debug {
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
}
var permupdate_mutex sync.Mutex
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"])
_, err = add_forum_perms_to_forum_admins_stmt.Exec(fid,"",perms)
if err != nil {
return err
}
perms, err = json.Marshal(permmap["staff"])
_, err = add_forum_perms_to_forum_staff_stmt.Exec(fid,"",perms)
if err != nil {
return err
}
perms, err = json.Marshal(permmap["members"])
_, err = add_forum_perms_to_forum_members_stmt.Exec(fid,"",perms)
if err != nil {
return err
}
perms, err = json.Marshal(permmap["guests"])
_, err = add_forum_perms_to_forum_guests_stmt.Exec(fid,"",perms)
if err != nil {
return err
}
return rebuild_forum_permissions(fid)
}
func rebuild_forum_permissions(fid int) error {
log.Print("Loading the forum permissions")
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()
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 {
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)
}
}
//fmt.Printf("%+v\n", groups[gid].CanSee)
//fmt.Printf("%+v\n", groups[gid].Forums)
//fmt.Println(len(groups[gid].Forums))
}
return nil
}
func build_forum_permissions() error {
return nil
}

View File

@ -80,8 +80,8 @@ func route_custom_page(w http.ResponseWriter, r *http.Request){
NotFound(w,r,user)
return
}
pi := Page{"Page",user,noticeList,tList,nil}
err := templates.ExecuteTemplate(w,"page_" + name,pi)
err := templates.ExecuteTemplate(w,"page_" + name,Page{"Page",user,noticeList,tList,nil})
if err != nil {
InternalError(err,w,r,user)
}
@ -233,7 +233,9 @@ func route_forums(w http.ResponseWriter, r *http.Request){
var forumList []Forum
group := groups[user.Group]
for fid, _ := range group.CanSee {
//fmt.Println(group.CanSee)
for _, fid := range group.CanSee {
//fmt.Println(forums[fid])
if forums[fid].Active && forums[fid].Name != "" {
forumList = append(forumList, forums[fid])
}
@ -1309,8 +1311,7 @@ func route_register(w http.ResponseWriter, r *http.Request) {
LocalError("You're already logged in.",w,r,user)
return
}
pi := Page{"Registration",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"register.html", pi)
templates.ExecuteTemplate(w,"register.html",Page{"Registration",user,noticeList,tList,nil})
}
func route_register_submit(w http.ResponseWriter, r *http.Request) {
@ -1397,7 +1398,6 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r,user)
return
}
lastId, err := res.LastInsertId()
if err != nil {
InternalError(err,w,r,user)

View File

@ -1,7 +1,7 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main
import "strconv"
import "io"
import "strconv"
func init() {
template_forum_handle = template_forum

View File

@ -1,8 +1,8 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main
import "io"
import "strconv"
import "html/template"
import "io"
func init() {
template_topic_handle = template_topic

View File

@ -1,8 +1,8 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main
import "io"
import "strconv"
import "html/template"
import "io"
func init() {
template_topic_alt_handle = template_topic_alt

View File

@ -33,7 +33,7 @@
<option value="0">No</option>
</select></div>
</div>
<!--<div class="formrow">
<div class="formrow">
<div class="formitem"><a>Preset</a></div>
<div class="formitem"><select name="forum-preset">
<option selected value="all">Everyone</option>
@ -42,8 +42,9 @@
<option value="staff">Staff Only</option>
<option value="admins">Admin Only</option>
<option value="archive">Archive</option>
<option value="custom">Custom</option>
</select></div>
</div>-->
</div>
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton">Add Forum</button></div>
</div>

View File

@ -98,7 +98,6 @@ func write_file(name string, content string) {
if err != nil {
log.Fatal(err)
}
_, err = f.WriteString(content)
if err != nil {
log.Fatal(err)
@ -138,9 +137,8 @@ func getLevel(score int) (level int) {
prev = current
if float64(score) < current {
break
} else {
level++
}
level++
}
return level
}