Shorten more things.

This commit is contained in:
Azareal 2019-09-01 08:59:00 +10:00
parent f1bebb7326
commit 218e177a29
15 changed files with 227 additions and 222 deletions

View File

@ -74,23 +74,23 @@ func forumUserCheck(header *Header, w http.ResponseWriter, r *http.Request, user
}
// TODO: Put this on the user instance? Do we really want forum specific logic in there? Maybe, a method which spits a new pointer with the same contents as user?
func cascadeForumPerms(fperms *ForumPerms, user *User) {
if fperms.Overrides && !user.IsSuperAdmin {
user.Perms.ViewTopic = fperms.ViewTopic
user.Perms.LikeItem = fperms.LikeItem
user.Perms.CreateTopic = fperms.CreateTopic
user.Perms.EditTopic = fperms.EditTopic
user.Perms.DeleteTopic = fperms.DeleteTopic
user.Perms.CreateReply = fperms.CreateReply
user.Perms.EditReply = fperms.EditReply
user.Perms.DeleteReply = fperms.DeleteReply
user.Perms.PinTopic = fperms.PinTopic
user.Perms.CloseTopic = fperms.CloseTopic
user.Perms.MoveTopic = fperms.MoveTopic
func cascadeForumPerms(fp *ForumPerms, u *User) {
if fp.Overrides && !u.IsSuperAdmin {
u.Perms.ViewTopic = fp.ViewTopic
u.Perms.LikeItem = fp.LikeItem
u.Perms.CreateTopic = fp.CreateTopic
u.Perms.EditTopic = fp.EditTopic
u.Perms.DeleteTopic = fp.DeleteTopic
u.Perms.CreateReply = fp.CreateReply
u.Perms.EditReply = fp.EditReply
u.Perms.DeleteReply = fp.DeleteReply
u.Perms.PinTopic = fp.PinTopic
u.Perms.CloseTopic = fp.CloseTopic
u.Perms.MoveTopic = fp.MoveTopic
if len(fperms.ExtData) != 0 {
for name, perm := range fperms.ExtData {
user.PluginPerms[name] = perm
if len(fp.ExtData) != 0 {
for name, perm := range fp.ExtData {
u.PluginPerms[name] = perm
}
}
}
@ -151,7 +151,8 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header
stats.Themes = len(Themes)
stats.Reports = 0 // TODO: Do the report count. Only show open threads?
var addPreScript = func(name string) {
addPreScript := func(name string) {
// TODO: Optimise this by removing a superfluous string alloc
var tname string
if theme.OverridenMap != nil {
_, ok := theme.OverridenMap[name]
@ -212,6 +213,7 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head
Writer: w,
IsoCode: phrases.GetLangPack().IsoCode,
}
// TODO: Optimise this by avoiding accessing a map string index
header.GoogSiteVerify = header.Settings["google_site_verify"].(string)
if user.IsBanned {
@ -256,7 +258,8 @@ func PrepResources(user *User, header *Header, theme *Theme) {
}
}
var addPreScript = func(name string) {
addPreScript := func(name string) {
// TODO: Optimise this by removing a superfluous string alloc
var tname string
if theme.OverridenMap != nil {
//fmt.Printf("name %+v\n", name)
@ -471,6 +474,7 @@ func NoSessionMismatch(w http.ResponseWriter, r *http.Request, user User) RouteE
if err != nil {
return LocalError("Bad Form", w, r, user)
}
// TODO: Try to eliminate some of these allocations
sess := []byte(user.Session)
if len(sess) == 0 {
return SecurityError(w, r, user)
@ -501,6 +505,7 @@ func HandleUploadRoute(w http.ResponseWriter, r *http.Request, user User, maxFil
}
func NoUploadSessionMismatch(w http.ResponseWriter, r *http.Request, user User) RouteError {
// TODO: Try to eliminate some of these allocations
sess := []byte(user.Session)
if len(sess) == 0 {
return SecurityError(w, r, user)

View File

@ -57,13 +57,13 @@ type User struct {
TempGroup int
}
func (user *User) WebSockets() *WsJSONUser {
var groupID = user.Group
if user.TempGroup != 0 {
groupID = user.TempGroup
func (u *User) WebSockets() *WsJSONUser {
groupID := u.Group
if u.TempGroup != 0 {
groupID = u.TempGroup
}
// TODO: Do we want to leak the user's permissions? Users will probably be able to see their status from the group tags, but still
return &WsJSONUser{user.ID, user.Link, user.Name, groupID, user.IsMod, user.Avatar, user.MicroAvatar, user.Level, user.Score, user.Liked}
return &WsJSONUser{u.ID, u.Link, u.Name, groupID, u.IsMod, u.Avatar, u.MicroAvatar, u.Level, u.Score, u.Liked}
}
// Use struct tags to avoid having to define this? It really depends on the circumstances, sometimes we want the whole thing, sometimes... not.
@ -80,12 +80,12 @@ type WsJSONUser struct {
Liked int
}
func (user *User) Me() *MeUser {
var groupID = user.Group
if user.TempGroup != 0 {
groupID = user.TempGroup
func (u *User) Me() *MeUser {
groupID := u.Group
if u.TempGroup != 0 {
groupID = u.TempGroup
}
return &MeUser{user.ID, user.Link, user.Name, groupID, user.Active, user.IsMod, user.IsSuperMod, user.IsAdmin, user.IsBanned, user.Session, user.Avatar, user.MicroAvatar, user.Tag, user.Level, user.Score, user.Liked}
return &MeUser{u.ID, u.Link, u.Name, groupID, u.Active, u.IsMod, u.IsSuperMod, u.IsAdmin, u.IsBanned, u.Session, u.Avatar, u.MicroAvatar, u.Tag, u.Level, u.Score, u.Liked}
}
// For when users need to see their own data, I've omitted some redundancies and less useful items, so we don't wind up sending them on every request
@ -104,7 +104,7 @@ type MeUser struct {
//Perms Perms
//PluginPerms map[string]bool
Session string
S string // Session
Avatar string
MicroAvatar string
Tag string
@ -170,53 +170,53 @@ func init() {
})
}
func (user *User) Init() {
user.Avatar, user.MicroAvatar = BuildAvatar(user.ID, user.RawAvatar)
user.Link = BuildProfileURL(NameToSlug(user.Name), user.ID)
user.Tag = Groups.DirtyGet(user.Group).Tag
user.InitPerms()
func (u *User) Init() {
u.Avatar, u.MicroAvatar = BuildAvatar(u.ID, u.RawAvatar)
u.Link = BuildProfileURL(NameToSlug(u.Name), u.ID)
u.Tag = Groups.DirtyGet(u.Group).Tag
u.InitPerms()
}
// TODO: Refactor this idiom into something shorter, maybe with a NullUserCache when one isn't set?
func (user *User) CacheRemove() {
func (u *User) CacheRemove() {
ucache := Users.GetCache()
if ucache != nil {
ucache.Remove(user.ID)
ucache.Remove(u.ID)
}
TopicListThaw.Thaw()
}
func (user *User) Ban(duration time.Duration, issuedBy int) error {
return user.ScheduleGroupUpdate(BanGroup, issuedBy, duration)
func (u *User) Ban(duration time.Duration, issuedBy int) error {
return u.ScheduleGroupUpdate(BanGroup, issuedBy, duration)
}
func (user *User) Unban() error {
return user.RevertGroupUpdate()
func (u *User) Unban() error {
return u.RevertGroupUpdate()
}
func (user *User) deleteScheduleGroupTx(tx *sql.Tx) error {
func (u *User) deleteScheduleGroupTx(tx *sql.Tx) error {
deleteScheduleGroupStmt, err := qgen.Builder.SimpleDeleteTx(tx, "users_groups_scheduler", "uid = ?")
if err != nil {
return err
}
_, err = deleteScheduleGroupStmt.Exec(user.ID)
_, err = deleteScheduleGroupStmt.Exec(u.ID)
return err
}
func (user *User) setTempGroupTx(tx *sql.Tx, tempGroup int) error {
func (u *User) setTempGroupTx(tx *sql.Tx, tempGroup int) error {
setTempGroupStmt, err := qgen.Builder.SimpleUpdateTx(tx, "users", "temp_group = ?", "uid = ?")
if err != nil {
return err
}
_, err = setTempGroupStmt.Exec(tempGroup, user.ID)
_, err = setTempGroupStmt.Exec(tempGroup, u.ID)
return err
}
// Make this more stateless?
func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Duration) error {
var temporary bool
func (u *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Duration) error {
var temp bool
if duration.Nanoseconds() != 0 {
temporary = true
temp = true
}
revertAt := time.Now().Add(duration)
@ -226,94 +226,94 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat
}
defer tx.Rollback()
err = user.deleteScheduleGroupTx(tx)
err = u.deleteScheduleGroupTx(tx)
if err != nil {
return err
}
createScheduleGroupTx, err := qgen.Builder.SimpleInsertTx(tx, "users_groups_scheduler", "uid, set_group, issued_by, issued_at, revert_at, temporary", "?,?,?,UTC_TIMESTAMP(),?,?")
createScheduleGroupTx, err := qgen.Builder.SimpleInsertTx(tx, "users_groups_scheduler", "uid,set_group,issued_by,issued_at,revert_at,temporary", "?,?,?,UTC_TIMESTAMP(),?,?")
if err != nil {
return err
}
_, err = createScheduleGroupTx.Exec(user.ID, gid, issuedBy, revertAt, temporary)
_, err = createScheduleGroupTx.Exec(u.ID, gid, issuedBy, revertAt, temp)
if err != nil {
return err
}
err = user.setTempGroupTx(tx, gid)
err = u.setTempGroupTx(tx, gid)
if err != nil {
return err
}
err = tx.Commit()
user.CacheRemove()
u.CacheRemove()
return err
}
func (user *User) RevertGroupUpdate() error {
func (u *User) RevertGroupUpdate() error {
tx, err := qgen.Builder.Begin()
if err != nil {
return err
}
defer tx.Rollback()
err = user.deleteScheduleGroupTx(tx)
err = u.deleteScheduleGroupTx(tx)
if err != nil {
return err
}
err = user.setTempGroupTx(tx, 0)
err = u.setTempGroupTx(tx, 0)
if err != nil {
return err
}
err = tx.Commit()
user.CacheRemove()
u.CacheRemove()
return err
}
// TODO: Use a transaction here
// ? - Add a Deactivate method? Not really needed, if someone's been bad you could do a ban, I guess it might be useful, if someone says that email x isn't actually owned by the user in question?
func (user *User) Activate() (err error) {
_, err = userStmts.activate.Exec(user.ID)
func (u *User) Activate() (err error) {
_, err = userStmts.activate.Exec(u.ID)
if err != nil {
return err
}
_, err = userStmts.changeGroup.Exec(Config.DefaultGroup, user.ID)
user.CacheRemove()
_, err = userStmts.changeGroup.Exec(Config.DefaultGroup, u.ID)
u.CacheRemove()
return err
}
// TODO: Write tests for this
// TODO: Delete this user's content too?
// TODO: Expose this to the admin?
func (user *User) Delete() error {
_, err := userStmts.delete.Exec(user.ID)
func (u *User) Delete() error {
_, err := userStmts.delete.Exec(u.ID)
if err != nil {
return err
}
user.CacheRemove()
return err
u.CacheRemove()
return nil
}
func (user *User) bindStmt(stmt *sql.Stmt, params ...interface{}) (err error) {
params = append(params, user.ID)
func (u *User) bindStmt(stmt *sql.Stmt, params ...interface{}) (err error) {
params = append(params, u.ID)
_, err = stmt.Exec(params...)
user.CacheRemove()
u.CacheRemove()
return err
}
func (user *User) ChangeName(username string) (err error) {
return user.bindStmt(userStmts.setUsername, username)
func (u *User) ChangeName(name string) (err error) {
return u.bindStmt(userStmts.setUsername, name)
}
func (user *User) ChangeAvatar(avatar string) (err error) {
return user.bindStmt(userStmts.setAvatar, avatar)
func (u *User) ChangeAvatar(avatar string) (err error) {
return u.bindStmt(userStmts.setAvatar, avatar)
}
// TODO: Abstract this with an interface so we can scale this with an actual dedicated queue in a real cluster
func (user *User) ScheduleAvatarResize() (err error) {
_, err = userStmts.scheduleAvatarResize.Exec(user.ID)
func (u *User) ScheduleAvatarResize() (err error) {
_, err = userStmts.scheduleAvatarResize.Exec(u.ID)
if err != nil {
// TODO: Do a more generic check so that we're not as tied to MySQL
me, ok := err.(*mysql.MySQLError)
@ -328,29 +328,29 @@ func (user *User) ScheduleAvatarResize() (err error) {
return nil
}
func (user *User) ChangeGroup(group int) (err error) {
return user.bindStmt(userStmts.changeGroup, group)
func (u *User) ChangeGroup(group int) (err error) {
return u.bindStmt(userStmts.changeGroup, group)
}
// ! Only updates the database not the *User for safety reasons
func (user *User) UpdateIP(host string) error {
_, err := userStmts.updateLastIP.Exec(host, user.ID)
func (u *User) UpdateIP(host string) error {
_, err := userStmts.updateLastIP.Exec(host, u.ID)
ucache := Users.GetCache()
if ucache != nil {
ucache.Remove(user.ID)
ucache.Remove(u.ID)
}
return err
}
func (user *User) Update(newname string, newemail string, newgroup int) (err error) {
return user.bindStmt(userStmts.update, newname, newemail, newgroup)
func (u *User) Update(newname string, newemail string, newgroup int) (err error) {
return u.bindStmt(userStmts.update, newname, newemail, newgroup)
}
func (user *User) IncreasePostStats(wcount int, topic bool) (err error) {
func (u *User) IncreasePostStats(wcount int, topic bool) (err error) {
var mod int
baseScore := 1
if topic {
_, err = userStmts.incrementTopics.Exec(1, user.ID)
_, err = userStmts.incrementTopics.Exec(1, u.ID)
if err != nil {
return err
}
@ -359,34 +359,34 @@ func (user *User) IncreasePostStats(wcount int, topic bool) (err error) {
settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) {
_, err = userStmts.incrementMegaposts.Exec(1, 1, 1, user.ID)
_, err = userStmts.incrementMegaposts.Exec(1, 1, 1, u.ID)
mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) {
_, err = userStmts.incrementBigposts.Exec(1, 1, user.ID)
_, err = userStmts.incrementBigposts.Exec(1, 1, u.ID)
mod = 1
} else {
_, err = userStmts.incrementPosts.Exec(1, user.ID)
_, err = userStmts.incrementPosts.Exec(1, u.ID)
}
if err != nil {
return err
}
_, err = userStmts.incrementScore.Exec(baseScore+mod, user.ID)
_, err = userStmts.incrementScore.Exec(baseScore+mod, u.ID)
if err != nil {
return err
}
//log.Print(user.Score + base_score + mod)
//log.Print(getLevel(user.Score + base_score + mod))
//log.Print(u.Score + baseScore + mod)
//log.Print(getLevel(u.Score + baseScore + mod))
// TODO: Use a transaction to prevent level desyncs?
_, err = userStmts.updateLevel.Exec(GetLevel(user.Score+baseScore+mod), user.ID)
_, err = userStmts.updateLevel.Exec(GetLevel(u.Score+baseScore+mod), u.ID)
return err
}
func (user *User) DecreasePostStats(wcount int, topic bool) (err error) {
func (u *User) DecreasePostStats(wcount int, topic bool) (err error) {
var mod int
baseScore := -1
if topic {
_, err = userStmts.incrementTopics.Exec(-1, user.ID)
_, err = userStmts.incrementTopics.Exec(-1, u.ID)
if err != nil {
return err
}
@ -395,56 +395,56 @@ func (user *User) DecreasePostStats(wcount int, topic bool) (err error) {
settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) {
_, err = userStmts.incrementMegaposts.Exec(-1, -1, -1, user.ID)
_, err = userStmts.incrementMegaposts.Exec(-1, -1, -1, u.ID)
mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) {
_, err = userStmts.incrementBigposts.Exec(-1, -1, user.ID)
_, err = userStmts.incrementBigposts.Exec(-1, -1, u.ID)
mod = 1
} else {
_, err = userStmts.incrementPosts.Exec(-1, user.ID)
_, err = userStmts.incrementPosts.Exec(-1, u.ID)
}
if err != nil {
return err
}
_, err = userStmts.incrementScore.Exec(baseScore-mod, user.ID)
_, err = userStmts.incrementScore.Exec(baseScore-mod, u.ID)
if err != nil {
return err
}
// TODO: Use a transaction to prevent level desyncs?
_, err = userStmts.updateLevel.Exec(GetLevel(user.Score-baseScore-mod), user.ID)
_, err = userStmts.updateLevel.Exec(GetLevel(u.Score-baseScore-mod), u.ID)
return err
}
// Copy gives you a non-pointer concurrency safe copy of the user
func (user *User) Copy() User {
return *user
func (u *User) Copy() User {
return *u
}
// TODO: Write unit tests for this
func (user *User) InitPerms() {
if user.TempGroup != 0 {
user.Group = user.TempGroup
func (u *User) InitPerms() {
if u.TempGroup != 0 {
u.Group = u.TempGroup
}
group := Groups.DirtyGet(user.Group)
if user.IsSuperAdmin {
user.Perms = AllPerms
user.PluginPerms = AllPluginPerms
group := Groups.DirtyGet(u.Group)
if u.IsSuperAdmin {
u.Perms = AllPerms
u.PluginPerms = AllPluginPerms
} else {
user.Perms = group.Perms
user.PluginPerms = group.PluginPerms
u.Perms = group.Perms
u.PluginPerms = group.PluginPerms
}
/*if len(group.CanSee) == 0 {
panic("should not be zero")
}*/
user.IsAdmin = user.IsSuperAdmin || group.IsAdmin
user.IsSuperMod = user.IsAdmin || group.IsMod
user.IsMod = user.IsSuperMod
user.IsBanned = group.IsBanned
if user.IsBanned && user.IsSuperMod {
user.IsBanned = false
u.IsAdmin = u.IsSuperAdmin || group.IsAdmin
u.IsSuperMod = u.IsAdmin || group.IsMod
u.IsMod = u.IsSuperMod
u.IsBanned = group.IsBanned
if u.IsBanned && u.IsSuperMod {
u.IsBanned = false
}
}

View File

@ -725,7 +725,7 @@ function mainInit(){
let formAction = $(this).closest('a').attr("href");
$.ajax({
url: formAction + "?session=" + me.User.Session,
url: formAction + "?s=" + me.User.S,
type: "POST",
dataType: "json",
error: ajaxError,
@ -793,7 +793,7 @@ function mainInit(){
var formAction = $(this).closest('a').attr("href");
//console.log("Form Action:", formAction);
//console.log(outData);
$.ajax({ url: formAction + "?session=" + me.User.Session, type:"POST", dataType:"json", data: outData, error: ajaxError });
$.ajax({ url: formAction + "?s=" + me.User.S, type:"POST", dataType:"json", data: outData, error: ajaxError });
blockParent.find('.hide_on_edit').removeClass("edit_opened");
blockParent.find('.show_on_edit').removeClass("edit_opened");
});
@ -853,7 +853,7 @@ function mainInit(){
$("#themeSelectorSelect").change(function(){
console.log("Changing the theme to " + this.options[this.selectedIndex].getAttribute("val"));
$.ajax({
url: this.form.getAttribute("action") + "?session=" + me.User.Session,
url: this.form.getAttribute("action") + "?s=" + me.User.S,
type: "POST",
dataType: "json",
data: { "newTheme": this.options[this.selectedIndex].getAttribute("val"), isJs: "1" },

View File

@ -251,7 +251,7 @@ function fetchPhrases(plist) {
runInitHook("pre_init");
});
} else {
me = {User:{ID:0,Session:""},Site:{"MaxRequestSize":0}};
me = {User:{ID:0,S:""},Site:{"MaxRequestSize":0}};
runInitHook("pre_init");
}
})();

View File

@ -68,7 +68,7 @@
console.log("hash",hash);
let formData = new FormData();
formData.append("session",me.User.Session);
formData.append("s",me.User.S);
for(let i = 0; i < this.files.length; i++) formData.append("upload_files",this.files[i]);
bindAttachManager();
@ -183,7 +183,7 @@
$(".attach_item_delete").click(function(){
let formData = new URLSearchParams();
formData.append("session",me.User.Session);
formData.append("s",me.User.S);
let post = this.closest(".post_item");
let aidList = "";
@ -233,7 +233,7 @@
});
let bulkActionSender = function(action, selectedTopics, fragBit) {
let url = "/topic/"+action+"/submit/"+fragBit+"?session=" + me.User.Session;
let url = "/topic/"+action+"/submit/"+fragBit+"?s=" + me.User.S;
$.ajax({
url: url,
type: "POST",

View File

@ -47,7 +47,7 @@ document.getElementById("panel_forums_order_button").addEventListener("click", (
console.trace();
}
// ? - Is encodeURIComponent the right function for this?
req.open("POST","/panel/forums/order/edit/submit/?session=" + encodeURIComponent(me.User.Session));
req.open("POST","/panel/forums/order/edit/submit/?s=" + encodeURIComponent(me.User.S));
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
let items = "";
for(let i = 0; item = forums[i];i++) items += item+",";

View File

@ -44,7 +44,7 @@ document.getElementById("panel_menu_items_order_button").addEventListener("click
}
// ? - Is encodeURIComponent the right function for this?
let spl = document.location.pathname.split("/");
req.open("POST","/panel/themes/menus/item/order/edit/submit/"+parseInt(spl[spl.length-1],10)+"?session=" + encodeURIComponent(me.User.Session));
req.open("POST","/panel/themes/menus/item/order/edit/submit/"+parseInt(spl[spl.length-1],10)+"?s=" + encodeURIComponent(me.User.S));
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
let items = "";
for(let i = 0; item = menuItems[i];i++) items += item+",";

View File

@ -19,7 +19,7 @@ $(document).ready(() => {
event.preventDefault();
eparent.remove();
let formData = new URLSearchParams();
formData.append("session",me.User.Session);
formData.append("s",me.User.S);
let req = new XMLHttpRequest();
let target = this.closest("a").getAttribute("href");
req.open("POST",target,true);
@ -58,7 +58,7 @@ $(document).ready(() => {
let pform = this.closest("form");
let data = new URLSearchParams();
for (const pair of new FormData(pform)) data.append(pair[0], pair[1]);
data.append("session",me.User.Session);
data.append("s",me.User.S);
var req = new XMLHttpRequest();
req.open("POST", pform.getAttribute("action"));
req.send(data);

View File

@ -7,7 +7,7 @@
{{range .Header.PreScriptsAsync}}
<script async type="text/javascript" src="/s/{{.}}"></script>{{end}}
<meta property="x-loggedin" content="{{.CurrentUser.Loggedin}}" />
<script type="text/javascript" src="/s/init.js?i=9"></script>
<script type="text/javascript" src="/s/init.js?i=10"></script>
{{range .Header.ScriptsAsync}}
<script async type="text/javascript" src="/s/{{.}}"></script>{{end}}
<script type="text/javascript" src="/s/jquery-3.1.1.min.js"></script>

View File

@ -7,7 +7,7 @@
<div class="rowitem"><h1>{{.Name}}{{lang "panel_group_head_suffix"}}</h1></div>
</div>
<div id="panel_group" class="colstack_item the_form">
<form action="/panel/groups/edit/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
<form action="/panel/groups/edit/submit/{{.ID}}?s={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_group_name"}}</a></div>
<div class="formitem"><input name="group-name" type="text" value="{{.Name}}" placeholder="{{lang "panel_group_name_placeholder"}}" /></div>

View File

@ -6,7 +6,7 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{.Name}}{{lang "panel_group_head_suffix"}}</h1></div>
</div>
<form action="/panel/groups/edit/perms/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
<form action="/panel/groups/edit/perms/submit/{{.ID}}?s={{.CurrentUser.Session}}" method="post">
{{if .CurrentUser.Perms.EditGroupLocalPerms}}
<div class="colstack_item rowlist formlist the_form panel_group_perms">
{{range .LocalPerms}}

View File

@ -7,7 +7,7 @@
<a href="/panel/pages/edit/{{.ID}}" class="panel_upshift">{{.Title}}</a>&nbsp;<a href="/pages/{{.Name}}">[{{.Name}}]</a>
<span class="panel_buttons">
<a href="/panel/pages/edit/{{.ID}}" class="panel_tag panel_right_button edit_button" aria-label="{{lang "panel_pages_edit_button_aria"}}"></a>
<a href="/panel/pages/delete/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="panel_tag panel_right_button delete_button" aria-label="{{lang "panel_pages_delete_button_aria"}}"></a>
<a href="/panel/pages/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="panel_tag panel_right_button delete_button" aria-label="{{lang "panel_pages_delete_button_aria"}}"></a>
</span>
</div>
{{else}}
@ -21,7 +21,7 @@
<div class="rowitem"><h1>{{lang "panel_pages_create_head"}}</h1></div>
</div>
<div class="colstack_item the_form">
<form action="/panel/pages/create/submit/?session={{.CurrentUser.Session}}" method="post">
<form action="/panel/pages/create/submit/?s={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_pages_create_name"}}</a></div>
<div class="formitem"><input name="name" type="text" placeholder="{{lang "panel_pages_create_name_placeholder"}}" /></div>

View File

@ -1,23 +1,23 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_pages_edit_head"}}</h1></div>
</div>
<form action="/panel/pages/edit/submit/{{.Page.ID}}?session={{.CurrentUser.Session}}" method="post">
<div id="panel_page_edit_item" class="colstack_item the_form">
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_pages_name"}}</a></div>
<div class="formitem"><input name="name" type="text" value="{{.Page.Name}}" /></div>
</div>
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_pages_title"}}</a></div>
<div class="formitem"><input name="title" type="text" value="{{.Page.Title}}" /></div>
</div>
<div class="formrow">
<div class="formitem">
<textarea name="body">{{.Page.Body}}</textarea>
</div>
</div>
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton">{{lang "panel_pages_edit_update_button"}}</button></div>
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_pages_edit_head"}}</h1></div>
</div>
<form action="/panel/pages/edit/submit/{{.Page.ID}}?s={{.CurrentUser.Session}}" method="post">
<div id="panel_page_edit_item" class="colstack_item the_form">
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_pages_name"}}</a></div>
<div class="formitem"><input name="name" type="text" value="{{.Page.Name}}" /></div>
</div>
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_pages_title"}}</a></div>
<div class="formitem"><input name="title" type="text" value="{{.Page.Title}}" /></div>
</div>
<div class="formrow">
<div class="formitem">
<textarea name="body">{{.Page.Body}}</textarea>
</div>
</div>
</form>
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton">{{lang "panel_pages_edit_update_button"}}</button></div>
</div>
</div>
</form>

View File

@ -1,37 +1,37 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{.Setting.FriendlyName}}</h1></div>
</div>
<div id="panel_setting" class="colstack_item the_form">
<form action="/panel/settings/edit/submit/{{.Setting.Name}}?session={{.CurrentUser.Session}}" method="post">
{{if eq .Setting.Type "list"}}
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_setting_value"}}</a></div>
<div class="formitem">
<select name="setting-value">
{{range .ItemList}}<option{{if .Selected}} selected{{end}} value="{{.Value}}">{{.Label}}</option>{{end}}
</select>
</div>
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{.Setting.FriendlyName}}</h1></div>
</div>
<div id="panel_setting" class="colstack_item the_form">
<form action="/panel/settings/edit/submit/{{.Setting.Name}}?s={{.CurrentUser.Session}}" method="post">
{{if eq .Setting.Type "list"}}
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_setting_value"}}</a></div>
<div class="formitem">
<select name="setting-value">
{{range .ItemList}}<option{{if .Selected}} selected{{end}} value="{{.Value}}">{{.Label}}</option>{{end}}
</select>
</div>
{{else if eq .Setting.Type "bool"}}
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_setting_value"}}</a></div>
<div class="formitem">
<select name="setting-value">
<option{{if eq .Setting.Content "1"}} selected{{end}} value="1">{{lang "option_yes"}}</option>
<option{{if eq .Setting.Content "0"}} selected{{end}} value="0">{{lang "option_no"}}</option>
</select>
</div>
</div>
{{else if eq .Setting.Type "bool"}}
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_setting_value"}}</a></div>
<div class="formitem">
<select name="setting-value">
<option{{if eq .Setting.Content "1"}} selected{{end}} value="1">{{lang "option_yes"}}</option>
<option{{if eq .Setting.Content "0"}} selected{{end}} value="0">{{lang "option_no"}}</option>
</select>
</div>
{{else if eq .Setting.Type "textarea"}}
<div class="formrow">
<div class="formitem"><textarea name="setting-value">{{.Setting.Content}}</textarea></div>
</div>
{{else}}<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_setting_value"}}</a></div>
<div class="formitem"><input name="setting-value" type="text" value="{{.Setting.Content}}" /></div>
</div>{{end}}
<div class="formrow form_button_row">
<div class="formitem"><button name="panel-button" class="formbutton">{{lang "panel_setting_update_button"}}</button></div>
</div>
</form>
</div>
</div>
{{else if eq .Setting.Type "textarea"}}
<div class="formrow">
<div class="formitem"><textarea name="setting-value">{{.Setting.Content}}</textarea></div>
</div>
{{else}}<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_setting_value"}}</a></div>
<div class="formitem"><input name="setting-value" type="text" value="{{.Setting.Content}}" /></div>
</div>{{end}}
<div class="formrow form_button_row">
<div class="formitem"><button name="panel-button" class="formbutton">{{lang "panel_setting_update_button"}}</button></div>
</div>
</form>
</div>

View File

@ -1,40 +1,40 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_word_filters_head"}}</h1></div>
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_word_filters_head"}}</h1></div>
</div>
<div id="panel_word_filters" class="colstack_item rowlist micro_grid">
{{range .Something}}
<div class="rowitem panel_compactrow editable_parent">
<a data-field="find" data-type="text" href="/panel/settings/word-filters/edit/{{.ID}}" class="editable_block panel_upshift edit_fields filter_find">{{.Find}}</a>
<span class="itemSeparator"></span>
<a data-field="replacement" data-type="text" class="editable_block panel_compacttext filter_replace">{{.Replacement}}</a>
<span class="panel_buttons">
<a class="panel_tag edit_fields hide_on_edit panel_right_button edit_button" aria-label="{{lang "panel_word_filters_edit_button_aria"}}"></a>
<a class="panel_right_button show_on_edit" href="/panel/settings/word-filters/edit/submit/{{.ID}}"><button class='panel_tag submit_edit' type='submit'>{{lang "panel_word_filters_update_button"}}</button></a>
<a href="/panel/settings/word-filters/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="panel_tag panel_right_button hide_on_edit delete_button" aria-label="{{lang "panel_word_filters_delete_button_aria"}}"></a>
</span>
</div>
<div id="panel_word_filters" class="colstack_item rowlist micro_grid">
{{range .Something}}
<div class="rowitem panel_compactrow editable_parent">
<a data-field="find" data-type="text" href="/panel/settings/word-filters/edit/{{.ID}}" class="editable_block panel_upshift edit_fields filter_find">{{.Find}}</a>
<span class="itemSeparator"></span>
<a data-field="replacement" data-type="text" class="editable_block panel_compacttext filter_replace">{{.Replacement}}</a>
<span class="panel_buttons">
<a class="panel_tag edit_fields hide_on_edit panel_right_button edit_button" aria-label="{{lang "panel_word_filters_edit_button_aria"}}"></a>
<a class="panel_right_button show_on_edit" href="/panel/settings/word-filters/edit/submit/{{.ID}}"><button class='panel_tag submit_edit' type='submit'>{{lang "panel_word_filters_update_button"}}</button></a>
<a href="/panel/settings/word-filters/delete/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="panel_tag panel_right_button hide_on_edit delete_button" aria-label="{{lang "panel_word_filters_delete_button_aria"}}"></a>
</span>
</div>
{{else}}
<div class="rowitem rowmsg">
<a>{{lang "panel_word_filters_no_filters"}}</a>
</div>
{{end}}
{{else}}
<div class="rowitem rowmsg">
<a>{{lang "panel_word_filters_no_filters"}}</a>
</div>
{{end}}
</div>
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_word_filters_create_head"}}</h1></div>
</div>
<div class="colstack_item the_form">
<form action="/panel/settings/word-filters/create/?session={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_word_filters_create_find"}}</a></div>
<div class="formitem"><input name="find" type="text" placeholder="{{lang "panel_word_filters_create_find_placeholder"}}" /></div>
</div>
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_word_filters_create_replacement"}}</a></div>
<div class="formitem"><input name="replacement" type="text" placeholder="{{lang "panel_word_filters_create_replacement_placeholder"}}" /></div>
</div>
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">{{lang "panel_word_filters_create_create_word_filter_button"}}</button></div>
</div>
</form>
</div>
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{lang "panel_word_filters_create_head"}}</h1></div>
</div>
<div class="colstack_item the_form">
<form action="/panel/settings/word-filters/create/?s={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_word_filters_create_find"}}</a></div>
<div class="formitem"><input name="find" type="text" placeholder="{{lang "panel_word_filters_create_find_placeholder"}}" /></div>
</div>
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_word_filters_create_replacement"}}</a></div>
<div class="formitem"><input name="replacement" type="text" placeholder="{{lang "panel_word_filters_create_replacement_placeholder"}}" /></div>
</div>
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">{{lang "panel_word_filters_create_create_word_filter_button"}}</button></div>
</div>
</form>
</div>