Added the Group Editor.

Revamped the dual column layout CSS.

Improved the Control Panel Group List.
Fixed the email verification system.
Fixed some visual glitches in the Cosmo Conflux and Cosmo themes.

Added the EditGroup, EditGroupLocalPerms, EditGroupGlobalPerms, EditGroupSuperMod and EditGroup Admin permissions.
Added the group_exists function.
Added the EditGroupPage struct.
Swapped some log.Fatal calls out for InternalError calls to avoid whitescreens.
This commit is contained in:
Azareal 2017-03-18 07:23:02 +00:00
parent 27df532617
commit c14a1e2100
32 changed files with 823 additions and 347 deletions

View File

@ -189,6 +189,11 @@ EditUserPassword
EditUserGroup
EditUserGroupSuperMod
EditUserGroupAdmin
EditGroup
EditGroupLocalPerms
EditGroupGlobalPerms
EditGroupSuperMod
EditGroupAdmin
ManageForums
EditSettings
ManageThemes
@ -207,8 +212,8 @@ PinTopic
CloseTopic
*/
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,1,"Admin");
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":true,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManageThemes":false,"ManagePlugins":false,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,"Mod");
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,1,"Admin");
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,"Mod");
INSERT INTO users_groups(`name`,`permissions`) VALUES ('Member','{"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}');
INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Banned','{"ViewTopic":true}',1);
INSERT INTO users_groups(`name`,`permissions`) VALUES ('Awaiting Activation','{"ViewTopic":true}');

View File

@ -1,5 +1,19 @@
package main
import "sync"
var group_update_mutex sync.Mutex
type GroupAdmin struct
{
ID int
Name string
Rank string
RankEmoji string
CanEdit bool
CanDelete bool
}
type Group struct
{
ID int
@ -13,3 +27,10 @@ type Group struct
Forums []ForumPerms
CanSee []int // The IDs of the forums this group can see
}
func group_exists(gid int) bool {
//fmt.Println(gid <= groupCapCount)
//fmt.Println(gid > 0)
//fmt.Println(groups[gid].Name!="")
return (gid <= groupCapCount) && (gid > 0) && groups[gid].Name!=""
}

BIN
images/group_editor_wip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
images/group_list_wip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -228,7 +228,7 @@ func main(){
router.HandleFunc("/user/edit/username/", route_account_own_edit_username)
router.HandleFunc("/user/edit/username/submit/", route_account_own_edit_username_submit)
router.HandleFunc("/user/edit/email/", route_account_own_edit_email)
router.HandleFunc("/user/edit/email/token/", route_account_own_edit_email_token_submit)
router.HandleFunc("/user/edit/token/", route_account_own_edit_email_token_submit)
router.HandleFunc("/user/", route_profile)
router.HandleFunc("/profile/reply/create/", route_profile_reply_create)
router.HandleFunc("/profile/reply/edit/submit/", route_profile_reply_edit_submit)
@ -259,6 +259,8 @@ func main(){
router.HandleFunc("/panel/users/edit/", route_panel_users_edit)
router.HandleFunc("/panel/users/edit/submit/", route_panel_users_edit_submit)
router.HandleFunc("/panel/groups/", route_panel_groups)
router.HandleFunc("/panel/groups/edit/", route_panel_groups_edit)
router.HandleFunc("/panel/groups/edit/submit/", route_panel_groups_edit_submit)
router.HandleFunc("/api/", route_api)
//router.HandleFunc("/exit/", route_exit)

View File

@ -1393,13 +1393,231 @@ func route_panel_groups(w http.ResponseWriter, r *http.Request){
var groupList []interface{}
for _, group := range groups[1:] {
groupList = append(groupList, group)
var rank string
var rank_emoji string
var can_edit bool
var can_delete bool = false
if group.Is_Admin {
rank = "Admin"
rank_emoji = "👑"
} else if group.Is_Mod {
rank = "Mod"
rank_emoji = "👮"
} else if group.Is_Banned {
rank = "Banned"
rank_emoji = "⛓️"
} else if group.ID == 6 {
rank = "Guest"
rank_emoji = "👽"
} else {
rank = "Member"
rank_emoji = "👪"
}
if user.Perms.EditGroup && (!group.Is_Admin || user.Perms.EditGroupAdmin) && (!group.Is_Mod || user.Perms.EditGroupSuperMod) {
can_edit = true
} else {
can_edit = false
}
groupList = append(groupList, GroupAdmin{group.ID,group.Name,rank,rank_emoji,can_edit,can_delete})
}
//fmt.Printf("%+v\n", groupList)
pi := Page{"Group Manager",user,noticeList,groupList,nil}
templates.ExecuteTemplate(w,"panel-groups.html",pi)
}
func route_panel_groups_edit(w http.ResponseWriter, r *http.Request){
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Super_Mod || !user.Perms.EditGroup {
NoPermissions(w,r,user)
return
}
gid, err := strconv.Atoi(r.URL.Path[len("/panel/groups/edit/"):])
if err != nil {
LocalError("The Group ID is not a valid integer.",w,r,user)
return
}
if !group_exists(gid) {
//fmt.Println("aaaaa monsters")
NotFound(w,r)
return
}
group := groups[gid]
if group.Is_Admin && !user.Perms.EditGroupAdmin {
LocalError("You need the EditGroupAdmin permission to edit an admin group.",w,r,user)
return
}
if group.Is_Mod && !user.Perms.EditGroupSuperMod {
LocalError("You need the EditGroupSuperMod permission to edit an super-mod group.",w,r,user)
return
}
var rank string
if group.Is_Admin {
rank = "Admin"
} else if group.Is_Mod {
rank = "Mod"
} else if group.Is_Banned {
rank = "Banned"
} else if group.ID == 6 {
rank = "Guest"
} else {
rank = "Member"
}
var disable_rank bool
if !user.Perms.EditGroupGlobalPerms || (group.ID == 6) {
disable_rank = true
}
pi := EditGroupPage{"Group Editor",user,noticeList,group.ID,group.Name,group.Tag,rank,disable_rank,nil}
err = templates.ExecuteTemplate(w,"panel-group-edit.html",pi)
if err != nil {
InternalError(err,w,r)
}
}
func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request){
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Super_Mod || !user.Perms.EditGroup {
NoPermissions(w,r,user)
return
}
if r.FormValue("session") != user.Session {
SecurityError(w,r,user)
return
}
gid, err := strconv.Atoi(r.URL.Path[len("/panel/groups/edit/submit/"):])
if err != nil {
LocalError("The Group ID is not a valid integer.",w,r,user)
return
}
if !group_exists(gid) {
//fmt.Println("aaaaa monsters")
NotFound(w,r)
return
}
group := groups[gid]
if group.Is_Admin && !user.Perms.EditGroupAdmin {
LocalError("You need the EditGroupAdmin permission to edit an admin group.",w,r,user)
return
}
if group.Is_Mod && !user.Perms.EditGroupSuperMod {
LocalError("You need the EditGroupSuperMod permission to edit an super-mod group.",w,r,user)
return
}
gname := r.FormValue("group-name")
if gname == "" {
LocalError("The group name can't be left blank.",w,r,user)
return
}
gtag := r.FormValue("group-tag")
rank := r.FormValue("group-type")
var original_rank string
if group.Is_Admin {
original_rank = "Admin"
} else if group.Is_Mod {
original_rank = "Mod"
} else if group.Is_Banned {
original_rank = "Banned"
} else if group.ID == 6 {
original_rank = "Guest"
} else {
original_rank = "Member"
}
group_update_mutex.Lock()
defer group_update_mutex.Unlock()
if rank != original_rank {
if !user.Perms.EditGroupGlobalPerms {
LocalError("You need the EditGroupGlobalPerms permission to change the group type.",w,r,user)
return
}
switch(rank) {
case "Admin":
if !user.Perms.EditGroupAdmin {
LocalError("You need the EditGroupAdmin permission to designate this group as an admin group.",w,r,user)
return
}
_, err = update_group_rank_stmt.Exec(1,1,0,gid)
if err != nil {
InternalError(err,w,r)
return
}
groups[gid].Is_Admin = true
groups[gid].Is_Mod = true
groups[gid].Is_Banned = false
case "Mod":
if !user.Perms.EditGroupSuperMod {
LocalError("You need the EditGroupSuperMod permission to designate this group as an admin group.",w,r,user)
return
}
_, err = update_group_rank_stmt.Exec(0,1,0,gid)
if err != nil {
InternalError(err,w,r)
return
}
groups[gid].Is_Admin = false
groups[gid].Is_Mod = true
groups[gid].Is_Banned = false
case "Banned":
_, err = update_group_rank_stmt.Exec(0,0,1,gid)
if err != nil {
InternalError(err,w,r)
return
}
groups[gid].Is_Admin = false
groups[gid].Is_Mod = false
groups[gid].Is_Banned = true
case "Guest":
LocalError("You can't designate a group as a guest group.",w,r,user)
return
case "Member":
_, err = update_group_rank_stmt.Exec(0,0,0,gid)
if err != nil {
InternalError(err,w,r)
return
}
groups[gid].Is_Admin = false
groups[gid].Is_Mod = false
groups[gid].Is_Banned = false
default:
LocalError("Invalid group type.",w,r,user)
return
}
}
_, err = update_group_stmt.Exec(gname,gtag,gid)
if err != nil {
InternalError(err,w,r)
return
}
groups[gid].Name = gname
groups[gid].Tag = gtag
http.Redirect(w,r,"/panel/groups/edit/" + strconv.Itoa(gid),http.StatusSeeOther)
}
func route_panel_themes(w http.ResponseWriter, r *http.Request){
user, noticeList, ok := SessionCheck(w,r)
if !ok {

View File

@ -83,6 +83,8 @@ var update_setting_stmt *sql.Stmt
var add_plugin_stmt *sql.Stmt
var update_plugin_stmt *sql.Stmt
var update_user_stmt *sql.Stmt
var update_group_rank_stmt *sql.Stmt
var update_group_stmt *sql.Stmt
var add_theme_stmt *sql.Stmt
var update_theme_stmt *sql.Stmt
@ -552,6 +554,18 @@ func init_database(err error) {
log.Fatal(err)
}
log.Print("Preparing update_group_rank statement.")
update_group_rank_stmt, err = db.Prepare("update `users_groups` set `is_admin` = ?, `is_mod` = ?, `is_banned` = ? where `gid` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_group statement.")
update_group_stmt, err = db.Prepare("update `users_groups` set `name` = ?, `tag` = ? where `gid` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Loading the usergroups.")
groups = append(groups, Group{ID:0,Name:"System"})
@ -591,6 +605,7 @@ func init_database(err error) {
if err != nil {
log.Fatal(err)
}
groupCapCount = i
log.Print("Binding the Not Loggedin Group")
GuestPerms = groups[6].Perms

View File

@ -86,6 +86,19 @@ type ThemesPage struct
ExtData interface{}
}
type EditGroupPage struct
{
Title string
CurrentUser User
NoticeList []string
ID int
Name string
Tag string
Rank string
DisableRank bool
ExtData interface{}
}
type PageSimple struct
{
Title string

View File

@ -26,6 +26,11 @@ type Perms struct
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
@ -94,6 +99,11 @@ func init() {
EditUserGroup: true,
EditUserGroupSuperMod: true,
EditUserGroupAdmin: true,
EditGroup: true,
EditGroupLocalPerms: true,
EditGroupGlobalPerms: true,
EditGroupSuperMod: true,
EditGroupAdmin: true,
ManageForums: true,
EditSettings: true,
ManageThemes: true,

View File

@ -1403,21 +1403,23 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
LocalError("You need to login to edit your account.",w,r,user)
return
}
token := r.URL.Path[len("/user/edit/email/token/"):]
token := r.URL.Path[len("/user/edit/token/"):]
email := Email{UserID: user.ID}
targetEmail := Email{UserID: user.ID}
var emailList []interface{}
rows, err := db.Query("select email, validated, token from emails where uid = ?", user.ID)
if err != nil {
log.Fatal(err)
InternalError(err,w,r)
return
}
defer rows.Close()
for rows.Next() {
err := rows.Scan(&email.Email, &email.Validated, &email.Token)
if err != nil {
log.Fatal(err)
InternalError(err,w,r)
return
}
if email.Email == user.Email {
@ -1430,7 +1432,8 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
}
err = rows.Err()
if err != nil {
log.Fatal(err)
InternalError(err,w,r)
return
}
if len(emailList) == 0 {

View File

@ -1,5 +1,8 @@
<div class="colblock_left">
<div class="colstack_left">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>My Account</a></div>
</div>
<div class="colstack_item">
<div class="rowitem passive"><a href="/user/edit/avatar/">Change Avatar</a></div>
<div class="rowitem passive"><a href="/user/edit/username/">Change Username</a></div>
<div class="rowitem passive"><a href="/user/edit/critical/">Change Password</a></div>
@ -8,3 +11,4 @@
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
</div>
</div>

View File

@ -1,14 +1,15 @@
{{template "header.html" . }}
{{template "account-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Edit Avatar</a></div>
</div>
{{if .CurrentUser.Avatar}}
<div class="colblock_right">
<div class="colstack_item">
<div class="rowitem"><img src="{{.CurrentUser.Avatar}}" height="128px" max-width="128px" /></div>
</div>
{{end}}
<div class="colblock_right">
<div class="colstack_item">
<form action="/user/edit/avatar/submit/" method="post" enctype="multipart/form-data">
<div class="formrow">
<div class="formitem"><a>Upload Avatar</a></div>
@ -19,4 +20,5 @@
</div>
</form>
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,9 +1,10 @@
{{template "header.html" . }}
{{template "account-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Emails</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
{{range .ItemList}}
<div class="rowitem" style="font-weight: normal;">
<a style="text-transform: none;">{{.Email}}</a>
@ -14,4 +15,5 @@
</div>
{{end}}
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,9 +1,10 @@
{{template "header.html" . }}
{{template "account-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Edit Username</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
<form action="/user/edit/username/submit/" method="post">
<div class="formrow">
<div class="formitem"><a>Current Username</a></div>
@ -18,4 +19,5 @@
</div>
</form>
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,9 +1,10 @@
{{template "header.html" . }}
{{template "account-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Edit Password</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
<form action="/user/edit/critical/submit/" method="post">
<div class="formrow">
<div class="formitem"><a>Current Password</a></div>
@ -22,4 +23,5 @@
</div>
</form>
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,9 +1,11 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Dashboard</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
<div class="rowitem passive">Coming Soon...</div>
</div>
</div>
{{template "footer.html" . }}

View File

@ -4,28 +4,31 @@
'forum-active': ['Hide','Show'],
'forum-preset': ['all','announce','members','staff','admins','archive','custom']};
</script>
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Forums</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
{{range .ItemList}}
<div class="rowitem editable_parent" style="font-weight: normal;{{if eq .ID 1}}border-bottom-style:solid;{{end}}">
<a data-field="forum-name" data-type="text" class="editable_block" style="font-size: 20px;position:relative;top: -2px;text-transform: none;{{if not .Active}}color:#707070;{{end}}">{{.Name}}</a>
<span style="float: right;">
<span data-field="forum-active" data-type="list" class="username editable_block hide_on_zero" title="Hidden" style="color: black;{{if .Active}}display:none;" data-value="1"{{else}}" data-value="0"{{end}}>🕵️</span>
{{if .PresetEmoji}}<span data-field="forum-preset" data-type="list" data-value="{{.Preset}}" class="username editable_block" title="{{.PresetLang}}">{{.PresetEmoji}}</span>
{{else if .PresetLang}}<span data-field="forum-preset" data-type="list" data-value="{{.Preset}}" class="username editable_block">{{.PresetLang}}</span>{{else}}<span data-field="forum-preset" data-type="list" data-value="{{.Preset}}" class="username editable_block" style="display:none;">{{.PresetLang}}</span>{{end}}
{{if gt .ID 0}}<a class="username edit_fields hide_on_edit">Edit</a>
<a href="/panel/forums/edit/submit/{{.ID}}"><button class='username submit_edit show_on_edit' type='submit'>Update</button></a>{{end}}
{{if gt .ID 1}}<a href="/panel/forums/delete/{{.ID}}?session={{$.CurrentUser.Session}}" class="username">Delete</a>{{end}}
</span>
</div>
{{end}}
</div><br />
<div class="colblock_right">
</div>
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Add Forum</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
<form action="/panel/forums/create/?session={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem"><a>Forum Name</a></div>
@ -55,4 +58,5 @@
</div>
</form>
</div>
</div>
{{template "footer.html" . }}

View File

@ -0,0 +1,46 @@
{{template "header.html" . }}
<div class="colstack_left">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a href="/panel/groups/edit/{{.ID}}">Group Editor</a></div>
</div>
<div class="colstack_item">
<div class="rowitem passive"><a href="/panel/groups/edit/{{.ID}}">General</a></div>
<div class="rowitem passive"><a>Promotions</a></div>
<div class="rowitem passive"><a>Permissions</a></div>
</div>
{{template "panel-inner-menu.html" . }}
</div>
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>{{.Name}} Group</a></div>
</div>
<div class="colstack_item">
<form action="/panel/groups/edit/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem"><a>Name</a></div>
<div class="formitem"><input name="group-name" type="text" value="{{.Name}}" placeholder="General Forum" /></div>
</div>
{{if .CurrentUser.Perms.EditUserGroup}}
<div class="formrow">
<div class="formitem"><a>Type</a></div>
<div class="formitem">
<select name="group-type"{{if .DisableRank}} disabled{{end}}>
<option{{if eq .Rank "Guest"}} selected{{end}} disabled>Guest</option>
<option{{if eq .Rank "Member"}} selected{{end}}>Member</option>
<option{{if eq .Rank "Mod"}} selected{{end}}{{if not .CurrentUser.Perms.EditGroupSuperMod}} disabled{{end}}>Mod</option>
<option{{if eq .Rank "Admin"}} selected{{end}}{{if not .CurrentUser.Perms.EditGroupAdmin}} disabled{{end}}>Admin</option>
<option{{if eq .Rank "Banned"}} selected{{end}}>Banned</option>
</select>
</div>
</div>{{end}}
<div class="formrow">
<div class="formitem"><a>Tag</a></div>
<div class="formitem"><input name="group-tag" type="text" value="{{.Tag}}" placeholder="VIP" /></div>
</div>
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton">Update Group</button></div>
</div>
</form>
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,13 +1,21 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Groups</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
{{range .ItemList}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;">
<a class="editable_block" style="font-size: 20px;">{{.Name}}</a>
<a href="/panel/groups/edit/{{.ID}}" style="font-size: 20px;position:relative;top: -2px;text-transform: none;">{{.Name}}</a>
<span style="float: right;">
{{if .RankEmoji}}<a class="username" title="{{.Rank}}">{{.RankEmoji}}</a>
{{else}}<span class="username">{{.Rank}}</span>{{end}}
{{if .CanEdit}}<a href="/panel/groups/edit/{{.ID}}" class="username">Edit</a>{{end}}
</span>
</div>
{{end}}
</div>
</div>
{{template "footer.html" . }}

View File

@ -0,0 +1,12 @@
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a href="/panel/">Control Panel</a></div>
</div>
<div class="colstack_item">
<div class="rowitem passive"><a href="/panel/users/">Users</a></div>
<div class="rowitem passive"><a href="/panel/groups/">Groups</a></div>
{{if .CurrentUser.Perms.ManageForums}}<div class="rowitem passive"><a href="/panel/forums/">Forums</a></div>{{end}}
{{if .CurrentUser.Perms.EditSettings}}<div class="rowitem passive"><a href="/panel/settings/">Settings</a></div>{{end}}
{{if .CurrentUser.Perms.ManageThemes}}<div class="rowitem passive"><a href="/panel/themes/">Themes</a></div>{{end}}
{{if .CurrentUser.Perms.ManagePlugins}}<div class="rowitem passive"><a href="/panel/plugins/">Plugins</a></div>{{end}}
<div class="rowitem passive"><a href="/forum/1">Reports</a></div>
</div>

View File

@ -1,10 +1 @@
<div class="colblock_left">
<div class="rowitem rowhead" style="border-bottom-width:2px;border-bottom-style:solid;"><a href="/panel/">Control Panel</a></div>
<div class="rowitem passive"><a href="/panel/users/">Users</a></div>
<div class="rowitem passive"><a href="/panel/groups/">Groups</a></div>
{{if .CurrentUser.Perms.ManageForums}}<div class="rowitem passive"><a href="/panel/forums/">Forums</a></div>{{end}}
{{if .CurrentUser.Perms.EditSettings}}<div class="rowitem passive"><a href="/panel/settings/">Settings</a></div>{{end}}
{{if .CurrentUser.Perms.ManageThemes}}<div class="rowitem passive"><a href="/panel/themes/">Themes</a></div>{{end}}
{{if .CurrentUser.Perms.ManagePlugins}}<div class="rowitem passive"><a href="/panel/plugins/">Plugins</a></div>{{end}}
<div class="rowitem passive"><a href="/forum/1">Reports</a></div>
</div>
<div class="colstack_left">{{template "panel-inner-menu.html" . }}</div>

View File

@ -1,9 +1,10 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Plugins</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
{{range .ItemList}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;">
<a {{if .URL}}href="{{.URL}}" {{end}}class="editable_block" style="font-size: 20px;position:relative;top: -2px;">{{.Name}}</a><br />
@ -16,4 +17,5 @@
</div>
{{end}}
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,9 +1,10 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Edit Setting</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
<form action="/panel/settings/edit/submit/{{.Something.Name}}?session={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem"><a>Setting Name</a></div>
@ -28,8 +29,9 @@
<div class="formitem"><input name="setting-value" type="text" value="{{.Something.Content}}" /></div>
</div>{{end}}
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton">Update Setting</div></div>
<div class="formitem"><button name="panel-button" class="formbutton">Update Setting</button></div>
</div>
</form>
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,9 +1,10 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Settings</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
{{range $key, $value := .Something}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;">
<a href="/panel/settings/edit/{{$key}}" class="editable_block" style="font-size: 20px;position:relative;top: -2px;">{{$key}}</a>
@ -11,4 +12,5 @@
</div>
{{end}}
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,10 +1,11 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<style type="text/css">.rowitem::after {content:"";display:block;clear:both;}</style>
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Primary Themes</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
{{range .PrimaryThemes}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;{{if .FullImage}}background-image: url('/static/{{.FullImage}}');background-position: center;background-size: 50%;background-repeat: no-repeat;{{end}}">
<span style="float: left;">
@ -19,10 +20,10 @@
</div>
{{end}}
</div>
<div class="colblock_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Variant Themes</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
{{range .VariantThemes}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;{{if .FullImage}}background-image: url('/static/{{.FullImage}}');background-position: center;background-size: 50%;background-repeat: no-repeat;{{end}}">
<span style="float: left;">
@ -37,4 +38,5 @@
</div>
{{end}}
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,9 +1,10 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>User Editor</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
<form action="/panel/users/edit/submit/{{.Something.ID}}?session={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem"><a>Name</a></div>
@ -27,8 +28,9 @@
</div>
</div>{{end}}
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton">Update User</div></div>
<div class="formitem"><button name="panel-button" class="formbutton">Update User</button></div>
</div>
</form>
</div>
</div>
{{template "footer.html" . }}

View File

@ -1,9 +1,10 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<div class="colblock_right">
<div class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem rowhead"><a>Users</a></div>
</div>
<div class="colblock_right">
<div class="colstack_item">
{{range .ItemList}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;">
<a {{if $.CurrentUser.Perms.EditUser}}href="/panel/users/edit/{{.ID}}?session={{$.CurrentUser.Session}} "{{end}}class="editable_block" style="font-size: 20px;position:relative;top: -2px;">{{.Name}}</a>
@ -16,4 +17,5 @@
</div>
{{end}}
</div>
</div>
{{template "footer.html" . }}

View File

@ -191,7 +191,7 @@ hr { color: silver; border: 1px solid silver; }
-o-transition: color 1s;
}
.rowblock, .colblock_left, .colblock_right {
.rowblock, .colblock_left, .colblock_right, .colstack_item {
background: rgba(240,240,240,1);
border-spacing: 0;
border-collapse: collapse;
@ -208,13 +208,8 @@ hr { color: silver; border: 1px solid silver; }
border-left: 1px solid black;
border-right: 1px solid black;
}
.rowitem:not(:last-child)
{
border-bottom: 1px dotted #ccc;
}
.rowblock:first-of-type {
margin-top: 8px;
}
.rowitem:not(:last-child) { border-bottom: 1px dotted #ccc; }
.rowblock:first-of-type { margin-top: 8px; }
.rowhead, .colhead {
background: #ce2424;
@ -261,20 +256,39 @@ hr { color: silver; border: 1px solid silver; }
overflow: hidden;
word-wrap: break-word;
}
.colblock_left:empty
.colblock_left:empty { display: none; }
.colblock_right:empty { display: none; }
.colblock_left:first-of-type { margin-top: 8px; }
.colblock_right:first-of-type { margin-top: 8px; }
/* The new method of doing columns layouts, colblock is now deprecated */
.colstack_left
{
display: none;
float: left;
width: 30%;
margin-right: 8px;
margin-top: 12px;
}
.colblock_right:empty
.colstack_right
{
display: none;
float: left;
width: 65%;
width: calc(70% - 15px);
margin-top: 12px;
}
.colblock_left:first-of-type {
margin-top: 8px;
}
.colblock_right:first-of-type {
margin-top: 8px;
.colstack_item
{
padding: 0px;
padding-top: 0px;
width: 100%;
margin-bottom: 8px;
overflow: hidden;
word-wrap: break-word;
}
.colstack_head { margin-bottom: 0px; }
.colstack_left:empty { display: none; }
.colstack_right:empty { display: none; }
.colitem
{
padding-left: 8px;
@ -294,10 +308,7 @@ hr { color: silver; border: 1px solid silver; }
text-decoration: none;
color: black;
}
.colitem a:hover
{
color: silver;
}
.colitem a:hover { color: silver; }
.col_left
{
width: 30%;
@ -320,13 +331,8 @@ hr { color: silver; border: 1px solid silver; }
content: " ";
display: table;
}
.formrow:after {
clear: both;
}
.formrow:not(:last-child)
{
border-bottom: 1px dotted #ccc;
}
.formrow:after { clear: both; }
.formrow:not(:last-child) { border-bottom: 1px dotted #ccc; }
.formitem
{
@ -337,18 +343,9 @@ hr { color: silver; border: 1px solid silver; }
padding-bottom: 8px;
font-weight: bold;
}
.formitem:first-child
{
font-weight: bold;
}
.formitem:not(:last-child)
{
border-right: 1px dotted #ccc;
}
.formitem.invisible_border
{
border: none;
}
.formitem:first-child { font-weight: bold; }
.formitem:not(:last-child) { border-right: 1px dotted #ccc; }
.formitem.invisible_border { border: none; }
/* Mostly for textareas */
.formitem:only-child { width: 100%; }
@ -583,6 +580,22 @@ blockquote p
height: 20px;
}
.tag-mini
{
text-transform: none;
margin-left: 0px;
padding-left: 3px;
padding-right: 3px;
padding-top: 1.5px;
padding-bottom: 0px;
color: #505050; /* 80,80,80 */
background-color: #FFFFFF;
border-style: dotted;
border-color: #505050; /* 232,232,232. All three RGB colours being the same seems to create a shade of gray */
border-width: 1px;
font-size: 10px;
}
.action_button {
display: block;
float: left;

View File

@ -180,7 +180,7 @@ hr { color: silver; border: 1px solid silver; }
-o-transition: color 1s;
}
.rowblock, .colblock_left, .colblock_right {
.rowblock, .colblock_left, .colblock_right, .colstack_item {
background: rgba(240,240,240,1);
border-spacing: 0;
border-collapse: collapse;
@ -249,20 +249,40 @@ hr { color: silver; border: 1px solid silver; }
overflow: hidden;
word-wrap: break-word;
}
.colblock_left:empty
{
display: none;
}
.colblock_left:empty { display: none; }
.colblock_right:empty
{ display: none; }
.colblock_left:first-of-type { margin-top: 8px; }
.colblock_right:first-of-type { margin-top: 8px; }
/* The new method of doing columns layouts, colblock is now deprecated */
.colstack_left
{
display: none;
float: left;
width: 30%;
margin-right: 8px;
margin-top: 12px;
}
.colblock_left:first-of-type {
margin-top: 8px;
.colstack_right
{
float: left;
width: 65%;
width: calc(70% - 15px);
margin-top: 12px;
}
.colblock_right:first-of-type {
margin-top: 8px;
.colstack_item
{
padding: 0px;
padding-top: 0px;
width: 100%;
margin-bottom: 8px;
overflow: hidden;
word-wrap: break-word;
}
.colstack_head { margin-bottom: 0px; }
.colstack_left:empty { display: none; }
.colstack_right:empty { display: none; }
.colitem
{
padding-left: 8px;

View File

@ -155,10 +155,7 @@ li a
padding: 0px;
padding-top: 0px;
}
.rowblock:empty
{
display: none;
}
.rowblock:empty { display: none; }
.colblock_left
{
@ -178,14 +175,35 @@ li a
overflow: hidden;
word-wrap: break-word;
}
.colblock_left:empty
.colblock_left:empty { display: none; }
.colblock_right:empty { display: none; }
/* The new method of doing columns layouts, colblock is now deprecated */
.colstack_left
{
display: none;
float: left;
width: 30%;
margin-right: 8px;
}
.colblock_right:empty
.colstack_right
{
display: none;
float: left;
width: 65%;
width: calc(70% - 15px);
}
.colstack_item
{
border: 1px solid #ccc;
padding: 0px;
padding-top: 0px;
width: 100%;
margin-bottom: 8px;
overflow: hidden;
word-wrap: break-word;
}
.colstack_head { margin-bottom: 0px; }
.colstack_left:empty { display: none; }
.colstack_right:empty { display: none; }
.rowitem
{
@ -244,10 +262,7 @@ li a
text-decoration: none;
color: black;
}
.colitem a:hover
{
color: silver;
}
.colitem a:hover { color: silver; }
.formrow
{

View File

@ -167,6 +167,33 @@ li a
.colblock_left:empty { display: none; }
.colblock_right:empty { display: none; }
/* The new method of doing columns layouts, colblock is now deprecated */
.colstack_left
{
float: left;
width: 30%;
margin-right: 8px;
}
.colstack_right
{
float: left;
width: 65%;
width: calc(70% - 15px);
}
.colstack_item
{
border: 1px solid #ccc;
padding: 0px;
padding-top: 0px;
width: 100%;
margin-bottom: 8px;
overflow: hidden;
word-wrap: break-word;
}
.colstack_head { margin-bottom: 0px; }
.colstack_left:empty { display: none; }
.colstack_right:empty { display: none; }
.rowhead { font-family: cursive; }
.rowitem
{

View File

@ -167,6 +167,33 @@ li a
.colblock_left:empty { display: none; }
.colblock_right:empty { display: none; }
/* The new method of doing columns layouts, colblock is now deprecated */
.colstack_left
{
float: left;
width: 30%;
margin-right: 8px;
}
.colstack_right
{
float: left;
width: 65%;
width: calc(70% - 15px);
}
.colstack_item
{
border: 1px solid #ccc;
padding: 0px;
padding-top: 0px;
width: 100%;
margin-bottom: 8px;
overflow: hidden;
word-wrap: break-word;
}
.colstack_head { margin-bottom: 0px; }
.colstack_left:empty { display: none; }
.colstack_right:empty { display: none; }
.rowitem
{
width: 100%;