Add per-user profile comment visibility settings.
Honor user blocks in ProfileReplyEditSubmit. Reduce boilerplate. Update account_privacy_profile_comments phrase. Add account_privacy_profile_comments_public phrase. Add account_privacy_profile_comments_registered phrase. Add account_privacy_profile_comments_self phrase. Add account_privacy_enable_embeds phrase. Add profile_comments column to users table. Add who_can_convo column to users table. You will need to run the updater / patcher for this commit.
This commit is contained in:
parent
4bdc528744
commit
b1af963916
|
@ -5,12 +5,16 @@ import qgen "github.com/Azareal/Gosora/query_gen"
|
|||
var mysqlPre = "utf8mb4"
|
||||
var mysqlCol = "utf8mb4_general_ci"
|
||||
|
||||
var tables []string
|
||||
|
||||
type tblColumn = qgen.DBTableColumn
|
||||
type tC = tblColumn
|
||||
type tblKey = qgen.DBTableKey
|
||||
|
||||
func createTables(a qgen.Adapter) error {
|
||||
tables = nil
|
||||
f := func(table, charset, collation string, cols []tC, keys []tblKey) error {
|
||||
tables = append(tables, table)
|
||||
return qgen.Install.CreateTable(table, charset, collation, cols, keys)
|
||||
}
|
||||
return createTables2(a, f)
|
||||
|
@ -23,30 +27,65 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
}
|
||||
err = f(table, charset, collation, cols, keys)
|
||||
}
|
||||
bcol := func(col string, val bool) qgen.DBTableColumn {
|
||||
if val {
|
||||
return tC{col, "boolean", 0, false, false, "1"}
|
||||
}
|
||||
return tC{col, "boolean", 0, false, false, "0"}
|
||||
}
|
||||
ccol := func(col string, size int, sdefault string) qgen.DBTableColumn {
|
||||
return tC{col, "varchar", size, false, false, sdefault}
|
||||
}
|
||||
text := func(params ...string) qgen.DBTableColumn {
|
||||
if len(params) == 0 {
|
||||
return tC{"", "text", 0, false, false, ""}
|
||||
}
|
||||
col, sdefault := params[0], ""
|
||||
if len(params) > 1 {
|
||||
sdefault = params[1]
|
||||
if sdefault == "" {
|
||||
sdefault = "''"
|
||||
}
|
||||
}
|
||||
return tC{col, "text", 0, false, false, sdefault}
|
||||
}
|
||||
createdAt := func(coll ...string) qgen.DBTableColumn {
|
||||
var col string
|
||||
if len(coll) > 0 {
|
||||
col = coll[0]
|
||||
}
|
||||
if col == "" {
|
||||
col = "createdAt"
|
||||
}
|
||||
return tC{col, "createdAt", 0, false, false, ""}
|
||||
}
|
||||
|
||||
createTable("users", mysqlPre, mysqlCol,
|
||||
[]tC{
|
||||
tC{"uid", "int", 0, false, true, ""},
|
||||
tC{"name", "varchar", 100, false, false, ""},
|
||||
tC{"password", "varchar", 100, false, false, ""},
|
||||
ccol("name", 100, ""),
|
||||
ccol("password", 100, ""),
|
||||
|
||||
tC{"salt", "varchar", 80, false, false, "''"},
|
||||
ccol("salt", 80, "''"),
|
||||
tC{"group", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"active", "boolean", 0, false, false, "0"},
|
||||
tC{"is_super_admin", "boolean", 0, false, false, "0"},
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
bcol("active", false),
|
||||
bcol("is_super_admin", false),
|
||||
createdAt(),
|
||||
tC{"lastActiveAt", "datetime", 0, false, false, ""},
|
||||
tC{"session", "varchar", 200, false, false, "''"},
|
||||
//tC{"authToken", "varchar", 200, false, false, "''"},
|
||||
tC{"last_ip", "varchar", 200, false, false, "''"},
|
||||
ccol("session", 200, "''"),
|
||||
//ccol("authToken", 200, "''"),
|
||||
ccol("last_ip", 200, "''"),
|
||||
tC{"profile_comments", "int", 0, false, false, "0"},
|
||||
tC{"who_can_convo", "int", 0, false, false, "0"},
|
||||
tC{"enable_embeds", "int", 0, false, false, "-1"},
|
||||
tC{"email", "varchar", 200, false, false, "''"},
|
||||
tC{"avatar", "varchar", 100, false, false, "''"},
|
||||
tC{"message", "text", 0, false, false, "''"},
|
||||
ccol("email", 200, "''"),
|
||||
ccol("avatar", 100, "''"),
|
||||
text("message"),
|
||||
|
||||
// TODO: Drop these columns?
|
||||
tC{"url_prefix", "varchar", 20, false, false, "''"},
|
||||
tC{"url_name", "varchar", 100, false, false, "''"},
|
||||
//tC{"pub_key", "text", 0, false, false, "''"},
|
||||
ccol("url_prefix", 20, "''"),
|
||||
ccol("url_name", 100, "''"),
|
||||
//text("pub_key"),
|
||||
|
||||
tC{"level", "smallint", 0, false, false, "0"},
|
||||
tC{"score", "int", 0, false, false, "0"},
|
||||
|
@ -63,27 +102,27 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
//tC{"penalty_count","int",0,false,false,"0"},
|
||||
tC{"temp_group", "int", 0, false, false, "0"}, // For temporary groups, set this to zero when a temporary group isn't in effect
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"uid", "primary", "", false},
|
||||
tblKey{"name", "unique", "", false},
|
||||
[]tK{
|
||||
tK{"uid", "primary", "", false},
|
||||
tK{"name", "unique", "", false},
|
||||
},
|
||||
)
|
||||
|
||||
createTable("users_groups", mysqlPre, mysqlCol,
|
||||
[]tC{
|
||||
tC{"gid", "int", 0, false, true, ""},
|
||||
tC{"name", "varchar", 100, false, false, ""},
|
||||
tC{"permissions", "text", 0, false, false, ""},
|
||||
tC{"plugin_perms", "text", 0, false, false, ""},
|
||||
tC{"is_mod", "boolean", 0, false, false, "0"},
|
||||
tC{"is_admin", "boolean", 0, false, false, "0"},
|
||||
tC{"is_banned", "boolean", 0, false, false, "0"},
|
||||
ccol("name", 100, ""),
|
||||
text("permissions"),
|
||||
text("plugin_perms"),
|
||||
bcol("is_mod", false),
|
||||
bcol("is_admin", false),
|
||||
bcol("is_banned", false),
|
||||
tC{"user_count", "int", 0, false, false, "0"}, // TODO: Implement this
|
||||
|
||||
tC{"tag", "varchar", 50, false, false, "''"},
|
||||
ccol("tag", 50, "''"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"gid", "primary", "", false},
|
||||
[]tK{
|
||||
tK{"gid", "primary", "", false},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -92,7 +131,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
tC{"pid", "int", 0, false, true, ""},
|
||||
tC{"from_gid", "int", 0, false, false, ""},
|
||||
tC{"to_gid", "int", 0, false, false, ""},
|
||||
tC{"two_way", "boolean", 0, false, false, "0"}, // If a user no longer meets the requirements for this promotion then they will be demoted if this flag is set
|
||||
bcol("two_way", false), // If a user no longer meets the requirements for this promotion then they will be demoted if this flag is set
|
||||
|
||||
// Requirements
|
||||
tC{"level", "int", 0, false, false, ""},
|
||||
|
@ -100,8 +139,8 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
tC{"minTime", "int", 0, false, false, ""}, // How long someone needs to have been in their current group before being promoted
|
||||
tC{"registeredFor", "int", 0, false, false, "0"}, // minutes
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"pid", "primary", "", false},
|
||||
[]tK{
|
||||
tK{"pid", "primary", "", false},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -122,15 +161,15 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
createTable("users_2fa_keys", mysqlPre, mysqlCol,
|
||||
[]tC{
|
||||
tC{"uid", "int", 0, false, false, ""},
|
||||
tC{"secret", "varchar", 100, false, false, ""},
|
||||
tC{"scratch1", "varchar", 50, false, false, ""},
|
||||
tC{"scratch2", "varchar", 50, false, false, ""},
|
||||
tC{"scratch3", "varchar", 50, false, false, ""},
|
||||
tC{"scratch4", "varchar", 50, false, false, ""},
|
||||
tC{"scratch5", "varchar", 50, false, false, ""},
|
||||
tC{"scratch6", "varchar", 50, false, false, ""},
|
||||
tC{"scratch7", "varchar", 50, false, false, ""},
|
||||
tC{"scratch8", "varchar", 50, false, false, ""},
|
||||
ccol("secret", 100, ""),
|
||||
ccol("scratch1", 50, ""),
|
||||
ccol("scratch2", 50, ""),
|
||||
ccol("scratch3", 50, ""),
|
||||
ccol("scratch4", 50, ""),
|
||||
ccol("scratch5", 50, ""),
|
||||
ccol("scratch6", 50, ""),
|
||||
ccol("scratch7", 50, ""),
|
||||
ccol("scratch8", 50, ""),
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
},
|
||||
[]tblKey{
|
||||
|
@ -148,12 +187,12 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"uid","int",0,false,false,""},
|
||||
tC{"element_id","int",0,false,false,""},
|
||||
tC{"element_type","varchar",50,false,false,""}, //forum, profile?, and social_group. Leave blank for global.
|
||||
tC{"overrides","text",0,false,false,"{}"},
|
||||
ccol("element_type",50,""), //forum, profile?, and social_group. Leave blank for global.
|
||||
text("overrides","{}"),
|
||||
|
||||
tC{"mod_queue","boolean",0,false,false,"0"},
|
||||
tC{"shadow_ban","boolean",0,false,false,"0"},
|
||||
tC{"no_avatar","boolean",0,false,false,"0"}, // Coming Soon. Should this be a perm override instead?
|
||||
bcol("mod_queue",false),
|
||||
bcol("shadow_ban",false),
|
||||
bcol("no_avatar",false), // Coming Soon. Should this be a perm override instead?
|
||||
|
||||
// Do we *really* need rate-limit penalty types? Are we going to be allowing bots or something?
|
||||
//tC{"posts_per_hour","int",0,false,false,"0"},
|
||||
|
@ -163,7 +202,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
//tC{"last_hour","int",0,false,false,"0"}, // UNIX Time, as we don't need to do anything too fancy here. When an hour has elapsed since that time, reset the hourly penalty counters.
|
||||
|
||||
tC{"issued_by","int",0,false,false,""},
|
||||
tC{"issued_at","createdAt",0,false,false,""},
|
||||
createdAt("issued_at"),
|
||||
tC{"expires_at","datetime",0,false,false,""},
|
||||
}, nil,
|
||||
)*/
|
||||
|
@ -174,7 +213,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
tC{"set_group", "int", 0, false, false, ""},
|
||||
|
||||
tC{"issued_by", "int", 0, false, false, ""},
|
||||
tC{"issued_at", "createdAt", 0, false, false, ""},
|
||||
createdAt("issued_at"),
|
||||
tC{"revert_at", "datetime", 0, false, false, ""},
|
||||
tC{"temporary", "boolean", 0, false, false, ""}, // special case for permanent bans to do the necessary bookkeeping, might be removed in the future
|
||||
},
|
||||
|
@ -197,10 +236,10 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
// TODO: Add an autoincrement key?
|
||||
createTable("emails", "", "",
|
||||
[]tC{
|
||||
tC{"email", "varchar", 200, false, false, ""},
|
||||
ccol("email", 200, ""),
|
||||
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"validated", "boolean", 0, false, false, "0"},
|
||||
tC{"token", "varchar", 200, false, false, "''"},
|
||||
bcol("validated", false),
|
||||
ccol("token", 200, "''"),
|
||||
}, nil,
|
||||
)
|
||||
|
||||
|
@ -208,11 +247,11 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
/*
|
||||
createTable("email_domain_blacklist", "", "",
|
||||
[]tC{
|
||||
tC{"domain", "varchar", 200, false, false, ""},
|
||||
tC{"gtld", "boolean", 0, false, false, "0"},
|
||||
ccol("domain", 200, ""),
|
||||
bcol("gtld", false),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"domain", "primary"},
|
||||
[]tK{
|
||||
tK{"domain", "primary"},
|
||||
},
|
||||
)
|
||||
*/
|
||||
|
@ -220,26 +259,26 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
// TODO: Implement password resets
|
||||
createTable("password_resets", "", "",
|
||||
[]tC{
|
||||
tC{"email", "varchar", 200, false, false, ""},
|
||||
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"validated", "varchar", 200, false, false, ""}, // Token given once the one-use token is consumed, used to prevent multiple people consuming the same one-use token
|
||||
tC{"token", "varchar", 200, false, false, ""},
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
ccol("email", 200, ""),
|
||||
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
ccol("validated", 200, ""), // Token given once the one-use token is consumed, used to prevent multiple people consuming the same one-use token
|
||||
ccol("token", 200, ""),
|
||||
createdAt(),
|
||||
}, nil,
|
||||
)
|
||||
|
||||
createTable("forums", mysqlPre, mysqlCol,
|
||||
[]tC{
|
||||
tC{"fid", "int", 0, false, true, ""},
|
||||
tC{"name", "varchar", 100, false, false, ""},
|
||||
tC{"desc", "varchar", 200, false, false, ""},
|
||||
tC{"tmpl", "varchar", 200, false, false, "''"},
|
||||
tC{"active", "boolean", 0, false, false, "1"},
|
||||
ccol("name", 100, ""),
|
||||
ccol("desc", 200, ""),
|
||||
ccol("tmpl", 200, "''"),
|
||||
bcol("active", true),
|
||||
tC{"order", "int", 0, false, false, "0"},
|
||||
tC{"topicCount", "int", 0, false, false, "0"},
|
||||
tC{"preset", "varchar", 100, false, false, "''"},
|
||||
ccol("preset", 100, "''"),
|
||||
tC{"parentID", "int", 0, false, false, "0"},
|
||||
tC{"parentType", "varchar", 50, false, false, "''"},
|
||||
ccol("parentType", 50, "''"),
|
||||
tC{"lastTopicID", "int", 0, false, false, "0"},
|
||||
tC{"lastReplyerID", "int", 0, false, false, "0"},
|
||||
},
|
||||
|
@ -252,8 +291,8 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"fid", "int", 0, false, false, ""},
|
||||
tC{"gid", "int", 0, false, false, ""},
|
||||
tC{"preset", "varchar", 100, false, false, "''"},
|
||||
tC{"permissions", "text", 0, false, false, ""},
|
||||
ccol("preset", 100, "''"),
|
||||
text("permissions", "{}"),
|
||||
},
|
||||
[]tblKey{
|
||||
// TODO: Test to see that the compound primary key works
|
||||
|
@ -264,19 +303,19 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
createTable("topics", mysqlPre, mysqlCol,
|
||||
[]tC{
|
||||
tC{"tid", "int", 0, false, true, ""},
|
||||
tC{"title", "varchar", 100, false, false, ""}, // TODO: Increase the max length to 200?
|
||||
tC{"content", "text", 0, false, false, ""},
|
||||
tC{"parsed_content", "text", 0, false, false, ""},
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
ccol("title", 100, ""), // TODO: Increase the max length to 200?
|
||||
text("content"),
|
||||
text("parsed_content"),
|
||||
createdAt(),
|
||||
tC{"lastReplyAt", "datetime", 0, false, false, ""},
|
||||
tC{"lastReplyBy", "int", 0, false, false, ""},
|
||||
tC{"lastReplyID", "int", 0, false, false, "0"},
|
||||
tC{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"is_closed", "boolean", 0, false, false, "0"},
|
||||
tC{"sticky", "boolean", 0, false, false, "0"},
|
||||
bcol("is_closed", false),
|
||||
bcol("sticky", false),
|
||||
// TODO: Add an index for this
|
||||
tC{"parentID", "int", 0, false, false, "2"},
|
||||
tC{"ip", "varchar", 200, false, false, "''"},
|
||||
ccol("ip", 200, "''"),
|
||||
tC{"postCount", "int", 0, false, false, "1"},
|
||||
tC{"likeCount", "int", 0, false, false, "0"},
|
||||
tC{"attachCount", "int", 0, false, false, "0"},
|
||||
|
@ -288,14 +327,14 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
// ? - A little hacky, maybe we could do something less likely to bite us with huge numbers of topics?
|
||||
// TODO: Add an index for this?
|
||||
//tC{"lastMonth", "datetime", 0, false, false, ""},
|
||||
tC{"css_class", "varchar", 100, false, false, "''"},
|
||||
ccol("css_class", 100, "''"),
|
||||
tC{"poll", "int", 0, false, false, "0"},
|
||||
tC{"data", "varchar", 200, false, false, "''"},
|
||||
ccol("data", 200, "''"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"tid", "primary", "", false},
|
||||
tblKey{"title", "fulltext", "", false},
|
||||
tblKey{"content", "fulltext", "", false},
|
||||
[]tK{
|
||||
tK{"tid", "primary", "", false},
|
||||
tK{"title", "fulltext", "", false},
|
||||
tK{"content", "fulltext", "", false},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -303,23 +342,23 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"rid", "int", 0, false, true, ""}, // TODO: Rename to replyID?
|
||||
tC{"tid", "int", 0, false, false, ""}, // TODO: Rename to topicID?
|
||||
tC{"content", "text", 0, false, false, ""},
|
||||
tC{"parsed_content", "text", 0, false, false, ""},
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
text("content"),
|
||||
text("parsed_content"),
|
||||
createdAt(),
|
||||
tC{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"lastEdit", "int", 0, false, false, "0"},
|
||||
tC{"lastEditBy", "int", 0, false, false, "0"},
|
||||
tC{"lastUpdated", "datetime", 0, false, false, ""},
|
||||
tC{"ip", "varchar", 200, false, false, "''"},
|
||||
ccol("ip", 200, "''"),
|
||||
tC{"likeCount", "int", 0, false, false, "0"},
|
||||
tC{"attachCount", "int", 0, false, false, "0"},
|
||||
tC{"words", "int", 0, false, false, "1"}, // ? - replies has a default of 1 and topics has 0? why?
|
||||
tC{"actionType", "varchar", 20, false, false, "''"},
|
||||
ccol("actionType", 20, "''"),
|
||||
tC{"poll", "int", 0, false, false, "0"},
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"rid", "primary", "", false},
|
||||
tblKey{"content", "fulltext", "", false},
|
||||
[]tK{
|
||||
tK{"rid", "primary", "", false},
|
||||
tK{"content", "fulltext", "", false},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -327,12 +366,12 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"attachID", "int", 0, false, true, ""},
|
||||
tC{"sectionID", "int", 0, false, false, "0"},
|
||||
tC{"sectionTable", "varchar", 200, false, false, "forums"},
|
||||
ccol("sectionTable", 200, "forums"),
|
||||
tC{"originID", "int", 0, false, false, ""},
|
||||
tC{"originTable", "varchar", 200, false, false, "replies"},
|
||||
ccol("originTable", 200, "replies"),
|
||||
tC{"uploadedBy", "int", 0, false, false, ""}, // TODO; Make this a foreign key
|
||||
tC{"path", "varchar", 200, false, false, ""},
|
||||
tC{"extra", "varchar", 200, false, false, ""},
|
||||
ccol("path", 200, ""),
|
||||
ccol("extra", 200, ""),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"attachID", "primary", "", false},
|
||||
|
@ -342,10 +381,10 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
createTable("revisions", mysqlPre, mysqlCol,
|
||||
[]tC{
|
||||
tC{"reviseID", "int", 0, false, true, ""},
|
||||
tC{"content", "text", 0, false, false, ""},
|
||||
text("content"),
|
||||
tC{"contentID", "int", 0, false, false, ""},
|
||||
tC{"contentType", "varchar", 100, false, false, "replies"},
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
ccol("contentType", 100, "replies"),
|
||||
createdAt(),
|
||||
// TODO: Add a createdBy column?
|
||||
},
|
||||
[]tblKey{
|
||||
|
@ -357,7 +396,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"pollID", "int", 0, false, true, ""},
|
||||
tC{"parentID", "int", 0, false, false, "0"},
|
||||
tC{"parentTable", "varchar", 100, false, false, "topics"}, // topics, replies
|
||||
ccol("parentTable", 100, "topics"), // topics, replies
|
||||
tC{"type", "int", 0, false, false, "0"},
|
||||
tC{"options", "json", 0, false, false, ""},
|
||||
tC{"votes", "int", 0, false, false, "0"},
|
||||
|
@ -380,8 +419,8 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
tC{"pollID", "int", 0, false, false, ""},
|
||||
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"option", "int", 0, false, false, "0"},
|
||||
tC{"castAt", "createdAt", 0, false, false, ""},
|
||||
tC{"ip", "varchar", 200, false, false, "''"},
|
||||
createdAt("castAt"),
|
||||
ccol("ip", 200, "''"),
|
||||
}, nil,
|
||||
)
|
||||
|
||||
|
@ -389,13 +428,13 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"rid", "int", 0, false, true, ""},
|
||||
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"content", "text", 0, false, false, ""},
|
||||
tC{"parsed_content", "text", 0, false, false, ""},
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
text("content"),
|
||||
text("parsed_content"),
|
||||
createdAt(),
|
||||
tC{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"lastEdit", "int", 0, false, false, "0"},
|
||||
tC{"lastEditBy", "int", 0, false, false, "0"},
|
||||
tC{"ip", "varchar", 200, false, false, "''"},
|
||||
ccol("ip", 200, "''"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"rid", "primary", "", false},
|
||||
|
@ -406,9 +445,9 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"weight", "tinyint", 0, false, false, "1"},
|
||||
tC{"targetItem", "int", 0, false, false, ""},
|
||||
tC{"targetType", "varchar", 50, false, false, "replies"},
|
||||
ccol("targetType", 50, "replies"),
|
||||
tC{"sentBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
createdAt(),
|
||||
tC{"recalc", "tinyint", 0, false, false, "0"},
|
||||
}, nil,
|
||||
)
|
||||
|
@ -418,7 +457,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"cid", "int", 0, false, true, ""},
|
||||
tC{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
createdAt(),
|
||||
tC{"lastReplyAt", "datetime", 0, false, false, ""},
|
||||
tC{"lastReplyBy", "int", 0, false, false, ""},
|
||||
},
|
||||
|
@ -432,8 +471,8 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
tC{"pid", "int", 0, false, true, ""},
|
||||
tC{"cid", "int", 0, false, false, ""},
|
||||
tC{"createdBy", "int", 0, false, false, ""},
|
||||
tC{"body", "varchar", 50, false, false, ""},
|
||||
tC{"post", "varchar", 50, false, false, "''"},
|
||||
ccol("body", 50, ""),
|
||||
ccol("post", 50, "''"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"pid", "primary", "", false},
|
||||
|
@ -482,35 +521,39 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
createTable("activity_stream", "", "",
|
||||
[]tC{
|
||||
tC{"asid", "int", 0, false, true, ""},
|
||||
tC{"actor", "int", 0, false, false, ""}, /* the one doing the act */ // TODO: Make this a foreign key
|
||||
tC{"targetUser", "int", 0, false, false, ""}, /* the user who created the item the actor is acting on, some items like forums may lack a targetUser field */
|
||||
tC{"event", "varchar", 50, false, false, ""}, /* mention, like, reply (as in the act of replying to an item, not the reply item type, you can "reply" to a forum by making a topic in it), friend_invite */
|
||||
tC{"elementType", "varchar", 50, false, false, ""}, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
|
||||
tC{"elementID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
tC{"extra", "varchar", 200, false, false, "''"},
|
||||
tC{"actor", "int", 0, false, false, ""}, /* the one doing the act */ // TODO: Make this a foreign key
|
||||
tC{"targetUser", "int", 0, false, false, ""}, /* the user who created the item the actor is acting on, some items like forums may lack a targetUser field */
|
||||
ccol("event", 50, ""), /* mention, like, reply (as in the act of replying to an item, not the reply item type, you can "reply" to a forum by making a topic in it), friend_invite */
|
||||
ccol("elementType", 50, ""), /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
|
||||
|
||||
// replacement for elementType
|
||||
tC{"elementTable", "int", 0, false, false, "0"},
|
||||
|
||||
tC{"elementID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
|
||||
createdAt(),
|
||||
ccol("extra", 200, "''"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"asid", "primary", "", false},
|
||||
[]tK{
|
||||
tK{"asid", "primary", "", false},
|
||||
},
|
||||
)
|
||||
|
||||
createTable("activity_subscriptions", "", "",
|
||||
[]tC{
|
||||
tC{"user", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"targetID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
|
||||
tC{"targetType", "varchar", 50, false, false, ""}, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
|
||||
tC{"level", "int", 0, false, false, "0"}, /* 0: Mentions (aka the global default for any post), 1: Replies To You, 2: All Replies*/
|
||||
tC{"user", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"targetID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
|
||||
ccol("targetType", 50, ""), /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
|
||||
tC{"level", "int", 0, false, false, "0"}, /* 0: Mentions (aka the global default for any post), 1: Replies To You, 2: All Replies*/
|
||||
}, nil,
|
||||
)
|
||||
|
||||
/* Due to MySQL's design, we have to drop the unique keys for table settings, plugins, and themes down from 200 to 180 or it will error */
|
||||
createTable("settings", "", "",
|
||||
[]tC{
|
||||
tC{"name", "varchar", 180, false, false, ""},
|
||||
tC{"content", "varchar", 250, false, false, ""},
|
||||
tC{"type", "varchar", 50, false, false, ""},
|
||||
tC{"constraints", "varchar", 200, false, false, "''"},
|
||||
ccol("name", 180, ""),
|
||||
ccol("content", 250, ""),
|
||||
ccol("type", 50, ""),
|
||||
ccol("constraints", 200, "''"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"name", "unique", "", false},
|
||||
|
@ -520,8 +563,8 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
createTable("word_filters", "", "",
|
||||
[]tC{
|
||||
tC{"wfid", "int", 0, false, true, ""},
|
||||
tC{"find", "varchar", 200, false, false, ""},
|
||||
tC{"replacement", "varchar", 200, false, false, ""},
|
||||
ccol("find", 200, ""),
|
||||
ccol("replacement", 200, ""),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"wfid", "primary", "", false},
|
||||
|
@ -530,9 +573,9 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
|
||||
createTable("plugins", "", "",
|
||||
[]tC{
|
||||
tC{"uname", "varchar", 180, false, false, ""},
|
||||
tC{"active", "boolean", 0, false, false, "0"},
|
||||
tC{"installed", "boolean", 0, false, false, "0"},
|
||||
ccol("uname", 180, ""),
|
||||
bcol("active", false),
|
||||
bcol("installed", false),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"uname", "unique", "", false},
|
||||
|
@ -541,9 +584,9 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
|
||||
createTable("themes", "", "",
|
||||
[]tC{
|
||||
tC{"uname", "varchar", 180, false, false, ""},
|
||||
tC{"default", "boolean", 0, false, false, "0"},
|
||||
//tC{"profileUserVars", "text", 0, false, false, "''"},
|
||||
ccol("uname", 180, ""),
|
||||
bcol("default", false),
|
||||
//text("profileUserVars"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"uname", "unique", "", false},
|
||||
|
@ -554,11 +597,11 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"wid", "int", 0, false, true, ""},
|
||||
tC{"position", "int", 0, false, false, ""},
|
||||
tC{"side", "varchar", 100, false, false, ""},
|
||||
tC{"type", "varchar", 100, false, false, ""},
|
||||
tC{"active", "boolean", 0, false, false, "0"},
|
||||
tC{"location", "varchar", 100, false, false, ""},
|
||||
tC{"data", "text", 0, false, false, "''"},
|
||||
ccol("side", 100, ""),
|
||||
ccol("type", 100, ""),
|
||||
bcol("active", false),
|
||||
ccol("location", 100, ""),
|
||||
text("data"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"wid", "primary", "", false},
|
||||
|
@ -578,51 +621,51 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"miid", "int", 0, false, true, ""},
|
||||
tC{"mid", "int", 0, false, false, ""},
|
||||
tC{"name", "varchar", 200, false, false, "''"},
|
||||
tC{"htmlID", "varchar", 200, false, false, "''"},
|
||||
tC{"cssClass", "varchar", 200, false, false, "''"},
|
||||
tC{"position", "varchar", 100, false, false, ""},
|
||||
tC{"path", "varchar", 200, false, false, "''"},
|
||||
tC{"aria", "varchar", 200, false, false, "''"},
|
||||
tC{"tooltip", "varchar", 200, false, false, "''"},
|
||||
tC{"tmplName", "varchar", 200, false, false, "''"},
|
||||
ccol("name", 200, "''"),
|
||||
ccol("htmlID", 200, "''"),
|
||||
ccol("cssClass", 200, "''"),
|
||||
ccol("position", 100, ""),
|
||||
ccol("path", 200, "''"),
|
||||
ccol("aria", 200, "''"),
|
||||
ccol("tooltip", 200, "''"),
|
||||
ccol("tmplName", 200, "''"),
|
||||
tC{"order", "int", 0, false, false, "0"},
|
||||
|
||||
tC{"guestOnly", "boolean", 0, false, false, "0"},
|
||||
tC{"memberOnly", "boolean", 0, false, false, "0"},
|
||||
tC{"staffOnly", "boolean", 0, false, false, "0"},
|
||||
tC{"adminOnly", "boolean", 0, false, false, "0"},
|
||||
bcol("guestOnly", false),
|
||||
bcol("memberOnly", false),
|
||||
bcol("staffOnly", false),
|
||||
bcol("adminOnly", false),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"miid", "primary", "", false},
|
||||
[]tK{
|
||||
tK{"miid", "primary", "", false},
|
||||
},
|
||||
)
|
||||
|
||||
createTable("pages", mysqlPre, mysqlCol,
|
||||
[]tC{
|
||||
tC{"pid", "int", 0, false, true, ""},
|
||||
//tC{"path", "varchar", 200, false, false, ""},
|
||||
tC{"name", "varchar", 200, false, false, ""},
|
||||
tC{"title", "varchar", 200, false, false, ""},
|
||||
tC{"body", "text", 0, false, false, ""},
|
||||
//ccol("path", 200, ""),
|
||||
ccol("name", 200, ""),
|
||||
ccol("title", 200, ""),
|
||||
text("body"),
|
||||
// TODO: Make this a table?
|
||||
tC{"allowedGroups", "text", 0, false, false, ""},
|
||||
text("allowedGroups"),
|
||||
tC{"menuID", "int", 0, false, false, "-1"}, // simple sidebar menu
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"pid", "primary", "", false},
|
||||
[]tK{
|
||||
tK{"pid", "primary", "", false},
|
||||
},
|
||||
)
|
||||
|
||||
createTable("registration_logs", "", "",
|
||||
[]tC{
|
||||
tC{"rlid", "int", 0, false, true, ""},
|
||||
tC{"username", "varchar", 100, false, false, ""},
|
||||
ccol("username", 100, ""),
|
||||
tC{"email", "varchar", 100, false, false, ""},
|
||||
tC{"failureReason", "varchar", 100, false, false, ""},
|
||||
tC{"success", "bool", 0, false, false, "0"}, // Did this attempt succeed?
|
||||
tC{"ipaddress", "varchar", 200, false, false, ""},
|
||||
tC{"doneAt", "createdAt", 0, false, false, ""},
|
||||
ccol("failureReason", 100, ""),
|
||||
bcol("success", false), // Did this attempt succeed?
|
||||
ccol("ipaddress", 200, ""),
|
||||
createdAt("doneAt"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"rlid", "primary", "", false},
|
||||
|
@ -633,9 +676,9 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"lid", "int", 0, false, true, ""},
|
||||
tC{"uid", "int", 0, false, false, ""},
|
||||
tC{"success", "bool", 0, false, false, "0"}, // Did this attempt succeed?
|
||||
tC{"ipaddress", "varchar", 200, false, false, ""},
|
||||
tC{"doneAt", "createdAt", 0, false, false, ""},
|
||||
bcol("success", false), // Did this attempt succeed?
|
||||
ccol("ipaddress", 200, ""),
|
||||
createdAt("doneAt"),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"lid", "primary", "", false},
|
||||
|
@ -644,25 +687,25 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
|
||||
createTable("moderation_logs", "", "",
|
||||
[]tC{
|
||||
tC{"action", "varchar", 100, false, false, ""},
|
||||
ccol("action", 100, ""),
|
||||
tC{"elementID", "int", 0, false, false, ""},
|
||||
tC{"elementType", "varchar", 100, false, false, ""},
|
||||
tC{"ipaddress", "varchar", 200, false, false, ""},
|
||||
ccol("elementType", 100, ""),
|
||||
ccol("ipaddress", 200, ""),
|
||||
tC{"actorID", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"doneAt", "datetime", 0, false, false, ""},
|
||||
tC{"extra", "text", 0, false, false, ""},
|
||||
text("extra"),
|
||||
}, nil,
|
||||
)
|
||||
|
||||
createTable("administration_logs", "", "",
|
||||
[]tC{
|
||||
tC{"action", "varchar", 100, false, false, ""},
|
||||
ccol("action", 100, ""),
|
||||
tC{"elementID", "int", 0, false, false, ""},
|
||||
tC{"elementType", "varchar", 100, false, false, ""},
|
||||
tC{"ipaddress", "varchar", 200, false, false, ""},
|
||||
ccol("elementType", 100, ""),
|
||||
ccol("ipaddress", 200, ""),
|
||||
tC{"actorID", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"doneAt", "datetime", 0, false, false, ""},
|
||||
tC{"extra", "text", 0, false, false, ""},
|
||||
text("extra"),
|
||||
}, nil,
|
||||
)
|
||||
|
||||
|
@ -671,7 +714,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
tC{"count", "int", 0, false, false, "0"},
|
||||
tC{"avg", "int", 0, false, false, "0"},
|
||||
tC{"createdAt", "datetime", 0, false, false, ""},
|
||||
tC{"route", "varchar", 200, false, false, ""}, // todo: set a default empty here
|
||||
ccol("route", 200, ""), // TODO: set a default empty here
|
||||
}, nil,
|
||||
)
|
||||
|
||||
|
@ -679,8 +722,8 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"count", "int", 0, false, false, "0"},
|
||||
tC{"createdAt", "datetime", 0, false, false, ""},
|
||||
tC{"browser", "varchar", 200, false, false, ""}, // googlebot, firefox, opera, etc.
|
||||
//tC{"version","varchar",0,false,false,""}, // the version of the browser or bot
|
||||
ccol("browser", 200, ""), // googlebot, firefox, opera, etc.
|
||||
//ccol("version",0,""), // the version of the browser or bot
|
||||
}, nil,
|
||||
)
|
||||
|
||||
|
@ -688,7 +731,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"count", "int", 0, false, false, "0"},
|
||||
tC{"createdAt", "datetime", 0, false, false, ""},
|
||||
tC{"system", "varchar", 200, false, false, ""}, // windows, android, unknown, etc.
|
||||
ccol("system", 200, ""), // windows, android, unknown, etc.
|
||||
}, nil,
|
||||
)
|
||||
|
||||
|
@ -696,7 +739,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"count", "int", 0, false, false, "0"},
|
||||
tC{"createdAt", "datetime", 0, false, false, ""},
|
||||
tC{"lang", "varchar", 200, false, false, ""}, // en, ru, etc.
|
||||
ccol("lang", 200, ""), // en, ru, etc.
|
||||
}, nil,
|
||||
)
|
||||
|
||||
|
@ -704,7 +747,7 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
[]tC{
|
||||
tC{"count", "int", 0, false, false, "0"},
|
||||
tC{"createdAt", "datetime", 0, false, false, ""},
|
||||
tC{"domain", "varchar", 200, false, false, ""},
|
||||
ccol("domain", 200, ""),
|
||||
}, nil,
|
||||
)
|
||||
|
||||
|
@ -764,18 +807,19 @@ func createTables2(a qgen.Adapter, f func(table, charset, collation string, colu
|
|||
|
||||
createTable("meta", "", "",
|
||||
[]tC{
|
||||
tC{"name", "varchar", 200, false, false, ""},
|
||||
tC{"value", "varchar", 200, false, false, ""},
|
||||
ccol("name", 200, ""),
|
||||
ccol("value", 200, ""),
|
||||
}, nil,
|
||||
)
|
||||
|
||||
/*createTable("tables", mysqlPre, mysqlCol,
|
||||
/*createTable("tables", "", "",
|
||||
[]tC{
|
||||
tC{"id", "int", 0, false, true, ""},
|
||||
tC{"name", "varchar", 200, false, false, ""},
|
||||
ccol("name", 200, ""),
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"id", "primary", "", false},
|
||||
[]tK{
|
||||
tK{"id", "primary", "", false},
|
||||
tK{"name", "unique", "", false},
|
||||
},
|
||||
)*/
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ func NewDefaultAuth() (*DefaultAuth, error) {
|
|||
// Authenticate checks if a specific username and password is valid and returns the UID for the corresponding user, if so. Otherwise, a user safe error.
|
||||
// IF MFA is enabled, then pass it back a flag telling the caller that authentication isn't complete yet
|
||||
// TODO: Find a better way of handling errors we don't want to reach the user
|
||||
func (auth *DefaultAuth) Authenticate(name string, password string) (uid int, err error, requiresExtraAuth bool) {
|
||||
func (auth *DefaultAuth) Authenticate(name, password string) (uid int, err error, requiresExtraAuth bool) {
|
||||
var realPassword, salt string
|
||||
err = auth.login.QueryRow(name).Scan(&uid, &realPassword, &salt)
|
||||
if err == ErrNoRows {
|
||||
|
@ -211,7 +211,7 @@ func (auth *DefaultAuth) SetCookies(w http.ResponseWriter, uid int, session stri
|
|||
|
||||
// TODO: Set the cookie domain
|
||||
// SetProvisionalCookies sets the two cookies required for guests to be recognised as having passed the initial login but not having passed the additional checks (e.g. multi-factor authentication)
|
||||
func (auth *DefaultAuth) SetProvisionalCookies(w http.ResponseWriter, uid int, provSession string, signedSession string) {
|
||||
func (auth *DefaultAuth) SetProvisionalCookies(w http.ResponseWriter, uid int, provSession, signedSession string) {
|
||||
cookie := http.Cookie{Name: "uid", Value: strconv.Itoa(uid), Path: "/", MaxAge: int(Year)}
|
||||
setCookie(w, &cookie, "lax")
|
||||
cookie = http.Cookie{Name: "provSession", Value: provSession, Path: "/", MaxAge: int(Year)}
|
||||
|
@ -282,7 +282,7 @@ func (auth *DefaultAuth) CreateSession(uid int) (session string, err error) {
|
|||
return session, nil
|
||||
}
|
||||
|
||||
func (auth *DefaultAuth) CreateProvisionalSession(uid int) (provSession string, signedSession string, err error) {
|
||||
func (auth *DefaultAuth) CreateProvisionalSession(uid int) (provSession, signedSession string, err error) {
|
||||
provSession, err = GenerateSafeString(SessionLength)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
|
|
|
@ -232,6 +232,7 @@ type ProfilePage struct {
|
|||
Blocked bool
|
||||
CanMessage bool
|
||||
CanComment bool
|
||||
ShowComments bool
|
||||
}
|
||||
|
||||
type CreateTopicPage struct {
|
||||
|
@ -249,7 +250,7 @@ type IPSearchPage struct {
|
|||
type RegisterPage struct {
|
||||
*Header
|
||||
RequireEmail bool
|
||||
Token string
|
||||
Token string
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
|
@ -278,8 +279,8 @@ type AccountBlocksPage struct {
|
|||
|
||||
type AccountPrivacyPage struct {
|
||||
*Header
|
||||
ProfileComments bool
|
||||
ReceiveConvos bool
|
||||
ProfileComments int
|
||||
ReceiveConvos int
|
||||
EnableEmbeds bool
|
||||
}
|
||||
|
||||
|
|
|
@ -95,14 +95,14 @@ var Template_account_handle = genIntTmpl("account")
|
|||
|
||||
func tmplInitUsers() (*User, *User, *User) {
|
||||
avatar, microAvatar := BuildAvatar(62, "")
|
||||
u := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", avatar, microAvatar, "", "", 0, 0, 0, 0, StartTime, "0.0.0.0.0", 0, 0, nil}
|
||||
u := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", avatar, microAvatar, "", "", 0, 0, 0, 0, StartTime, "0.0.0.0.0", 0, 0, nil, UserPrivacy{}}
|
||||
|
||||
// TODO: Do a more accurate level calculation for this?
|
||||
avatar, microAvatar = BuildAvatar(1, "")
|
||||
u2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", 58, 1000, 0, 1000, StartTime, "127.0.0.1", 0, 0, nil}
|
||||
u2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", 58, 1000, 0, 1000, StartTime, "127.0.0.1", 0, 0, nil, UserPrivacy{}}
|
||||
|
||||
avatar, microAvatar = BuildAvatar(2, "")
|
||||
u3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", 42, 900, 0, 900, StartTime, "::1", 0, 0, nil}
|
||||
u3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", 42, 900, 0, 900, StartTime, "::1", 0, 0, nil, UserPrivacy{}}
|
||||
return &u, &u2, &u3
|
||||
}
|
||||
|
||||
|
@ -306,7 +306,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
|||
return err
|
||||
}
|
||||
|
||||
ppage := ProfilePage{htitle("User 526"), replyList, *user, 0, 0, false, false, false} // TODO: Use the score from user to generate the currentScore and nextScore
|
||||
ppage := ProfilePage{htitle("User 526"), replyList, *user, 0, 0, false, false, false, false} // TODO: Use the score from user to generate the currentScore and nextScore
|
||||
t.Add("profile", "c.ProfilePage", ppage)
|
||||
|
||||
var topicsList []*TopicsRow
|
||||
|
@ -349,7 +349,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
|||
}
|
||||
|
||||
t.AddStd("login", "c.Page", Page{htitle("Login Page"), tList, nil})
|
||||
t.AddStd("register", "c.RegisterPage", RegisterPage{htitle("Registration Page"), false,""})
|
||||
t.AddStd("register", "c.RegisterPage", RegisterPage{htitle("Registration Page"), false, ""})
|
||||
t.AddStd("error", "c.ErrorPage", ErrorPage{htitle("Error"), "A problem has occurred in the system."})
|
||||
|
||||
ipSearchPage := IPSearchPage{htitle("IP Search"), map[int]*User{1: user2}, "::1"}
|
||||
|
|
|
@ -62,6 +62,12 @@ type User struct {
|
|||
TempGroup int
|
||||
|
||||
ParseSettings *ParseSettings
|
||||
Privacy UserPrivacy
|
||||
}
|
||||
|
||||
type UserPrivacy struct {
|
||||
ShowComments int // 0 = default, 1 = public, 2 = registered, 3 = friends, 4 = mods / self
|
||||
AllowMessage int // 0 = default, 1 = registered, 2 = friends, 3 = mods / self
|
||||
}
|
||||
|
||||
func (u *User) WebSockets() *WsJSONUser {
|
||||
|
@ -191,7 +197,7 @@ func init() {
|
|||
decLiked: acc.Update(u).Set("liked=liked-?").Where(w).Prepare(),
|
||||
//recalcLastLiked: acc...
|
||||
updateLastIP: acc.SimpleUpdate(u, "last_ip=?", w),
|
||||
updatePrivacy: acc.Update(u).Set("enable_embeds=?").Where(w).Prepare(),
|
||||
updatePrivacy: acc.Update(u).Set("profile_comments=?,enable_embeds=?").Where(w).Prepare(),
|
||||
|
||||
setPassword: acc.Update(u).Set("password=?,salt=?").Where(w).Prepare(),
|
||||
|
||||
|
@ -211,6 +217,10 @@ func init() {
|
|||
}
|
||||
|
||||
func (u *User) Init() {
|
||||
// TODO: Let admins configure the minimum default?
|
||||
if u.Privacy.ShowComments < 1 {
|
||||
u.Privacy.ShowComments = 1
|
||||
}
|
||||
u.Avatar, u.MicroAvatar = BuildAvatar(u.ID, u.RawAvatar)
|
||||
u.Link = BuildProfileURL(NameToSlug(u.Name), u.ID)
|
||||
u.Tag = Groups.DirtyGet(u.Group).Tag
|
||||
|
@ -554,12 +564,27 @@ func (u *User) UpdateIP(ip string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (u *User) UpdatePrivacy(enableEmbeds int) error {
|
||||
_, err := userStmts.updatePrivacy.Exec(enableEmbeds, u.ID)
|
||||
//var ErrMalformedInteger = errors.New("malformed integer")
|
||||
var ErrProfileCommentsOutOfBounds = errors.New("profile_comments must be an integer between -1 and 4")
|
||||
var ErrEnableEmbedsOutOfBounds = errors.New("enable_embeds must be -1, 0 or 1")
|
||||
|
||||
/*func (u *User) UpdatePrivacyS(sProfileComments, sEnableEmbeds string) error {
|
||||
|
||||
return u.UpdatePrivacy(profileComments, enableEmbeds)
|
||||
}*/
|
||||
|
||||
func (u *User) UpdatePrivacy(profileComments, enableEmbeds int) error {
|
||||
if profileComments < -1 || profileComments > 4 {
|
||||
return ErrProfileCommentsOutOfBounds
|
||||
}
|
||||
if enableEmbeds < -1 || enableEmbeds > 1 {
|
||||
return ErrEnableEmbedsOutOfBounds
|
||||
}
|
||||
_, e := userStmts.updatePrivacy.Exec(profileComments, enableEmbeds, u.ID)
|
||||
if uc := Users.GetCache(); uc != nil {
|
||||
uc.Remove(u.ID)
|
||||
}
|
||||
return err
|
||||
return e
|
||||
}
|
||||
|
||||
func (u *User) Update(name, email string, group int) (err error) {
|
||||
|
@ -790,3 +815,17 @@ func BuildProfileURL(slug string, uid int) string {
|
|||
}
|
||||
return "/user/" + slug + "." + strconv.Itoa(uid)
|
||||
}
|
||||
|
||||
func BuildProfileURLSb(sb *strings.Builder, slug string, uid int) {
|
||||
if slug == "" || !Config.BuildSlugs {
|
||||
sb.Grow(6 + 1)
|
||||
sb.WriteString("/user/")
|
||||
sb.WriteString(strconv.Itoa(uid))
|
||||
return
|
||||
}
|
||||
sb.Grow(7 + 1 + len(slug))
|
||||
sb.WriteString("/user/")
|
||||
sb.WriteString(slug)
|
||||
sb.WriteRune('.')
|
||||
sb.WriteString(strconv.Itoa(uid))
|
||||
}
|
||||
|
|
|
@ -54,16 +54,16 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
|
|||
cache = NewNullUserCache()
|
||||
}
|
||||
u := "users"
|
||||
allCols := "uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds"
|
||||
allCols := "uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo"
|
||||
// TODO: Add an admin version of registerStmt with more flexibility?
|
||||
return &DefaultUserStore{
|
||||
cache: cache,
|
||||
get: acc.Select(u).Columns("name, group, active, is_super_admin, session, email, avatar, message, level, score, posts, liked, last_ip, temp_group, createdAt, enable_embeds").Where("uid=?").Prepare(),
|
||||
get: acc.Select(u).Columns("name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo").Where("uid=?").Prepare(),
|
||||
getByName: acc.Select(u).Columns(allCols).Where("name=?").Prepare(),
|
||||
getOffset: acc.Select(u).Columns(allCols).Orderby("uid ASC").Limit("?,?").Prepare(),
|
||||
getAll: acc.Select(u).Columns(allCols).Prepare(),
|
||||
exists: acc.Exists(u, "uid").Prepare(),
|
||||
register: acc.Insert(u).Columns("name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt, lastLiked, oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here
|
||||
register: acc.Insert(u).Columns("name,email,password,salt,group,is_super_admin,session,active,message,createdAt,lastActiveAt,lastLiked,oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here
|
||||
nameExists: acc.Exists(u, "name").Prepare(),
|
||||
count: acc.Count(u).Prepare(),
|
||||
}, acc.FirstError()
|
||||
|
@ -93,16 +93,7 @@ func (s *DefaultUserStore) Get(id int) (*User, error) {
|
|||
|
||||
u = &User{ID: id, Loggedin: true}
|
||||
var embeds int
|
||||
err = s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds)
|
||||
/*if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
u.ParseSettings.NoEmbed = embeds == 0
|
||||
}
|
||||
u.Init()
|
||||
s.cache.Set(u)*/
|
||||
err = s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
|
||||
if err == nil {
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
|
@ -122,7 +113,7 @@ func (s *DefaultUserStore) Getn(id int) *User {
|
|||
|
||||
u = &User{ID: id, Loggedin: true}
|
||||
var embeds int
|
||||
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds)
|
||||
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -140,7 +131,7 @@ func (s *DefaultUserStore) Getn(id int) *User {
|
|||
func (s *DefaultUserStore) GetByName(name string) (*User, error) {
|
||||
u := &User{Loggedin: true}
|
||||
var embeds int
|
||||
err := s.getByName.QueryRow(name).Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds)
|
||||
err := s.getByName.QueryRow(name).Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -165,7 +156,7 @@ func (s *DefaultUserStore) GetOffset(offset, perPage int) (users []*User, err er
|
|||
var embeds int
|
||||
for rows.Next() {
|
||||
u := &User{Loggedin: true}
|
||||
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds)
|
||||
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -180,24 +171,24 @@ func (s *DefaultUserStore) GetOffset(offset, perPage int) (users []*User, err er
|
|||
return users, rows.Err()
|
||||
}
|
||||
func (s *DefaultUserStore) Each(f func(*User) error) error {
|
||||
rows, err := s.getAll.Query()
|
||||
if err != nil {
|
||||
return err
|
||||
rows, e := s.getAll.Query()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer rows.Close()
|
||||
var embeds int
|
||||
for rows.Next() {
|
||||
u := new(User)
|
||||
if err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds); err != nil {
|
||||
return err
|
||||
if e := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage); e != nil {
|
||||
return e
|
||||
}
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
u.ParseSettings.NoEmbed = embeds == 0
|
||||
}
|
||||
u.Init()
|
||||
if err := f(u); err != nil {
|
||||
return err
|
||||
if e := f(u); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
|
@ -246,7 +237,7 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)
|
|||
}
|
||||
q = q[0 : len(q)-1]
|
||||
|
||||
rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds").Where("uid IN(" + q + ")").Query(idList...)
|
||||
rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo").Where("uid IN(" + q + ")").Query(idList...)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
@ -255,7 +246,7 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)
|
|||
var embeds int
|
||||
for rows.Next() {
|
||||
u := &User{Loggedin: true}
|
||||
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds)
|
||||
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
@ -292,7 +283,7 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)
|
|||
func (s *DefaultUserStore) BypassGet(id int) (*User, error) {
|
||||
u := &User{ID: id, Loggedin: true}
|
||||
var embeds int
|
||||
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds)
|
||||
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
|
||||
if err == nil {
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
|
|
|
@ -577,7 +577,11 @@
|
|||
"account_password_update_button":"Update",
|
||||
|
||||
"account_privacy_head":"Privacy",
|
||||
"account_privacy_profile_comments":"Enable Profile Comments",
|
||||
"account_privacy_profile_comments":"Profile Comment Visibility",
|
||||
"account_privacy_profile_comments_public":"Anyone",
|
||||
"account_privacy_profile_comments_registered":"Registered Users",
|
||||
"account_privacy_profile_comments_self":"Only Me",
|
||||
"account_privacy_enable_embeds":"Enable Embeds",
|
||||
"account_privacy_button":"Update",
|
||||
|
||||
"account_mfa_head":"Manage 2FA",
|
||||
|
|
|
@ -51,18 +51,21 @@ func init() {
|
|||
addPatch(31, patch31)
|
||||
addPatch(32, patch32)
|
||||
addPatch(33, patch33)
|
||||
addPatch(34, patch34)
|
||||
//addPatch(35, patch35)
|
||||
}
|
||||
|
||||
func bcol(col string, val bool) qgen.DBTableColumn {
|
||||
if val {
|
||||
return tC{col, "boolean", 0, false, false, "1"}
|
||||
}
|
||||
return tC{col, "boolean", 0, false, false, "0"}
|
||||
}
|
||||
func ccol(col string, size int, sdefault string) qgen.DBTableColumn {
|
||||
return tC{col, "varchar", size, false, false, sdefault}
|
||||
}
|
||||
|
||||
func patch0(scanner *bufio.Scanner) (err error) {
|
||||
err = execStmt(qgen.Builder.DropTable("menus"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.DropTable("menu_items"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = createTable("menus", "", "",
|
||||
[]tC{
|
||||
tC{"mid", "int", 0, false, true, ""},
|
||||
|
@ -79,20 +82,20 @@ func patch0(scanner *bufio.Scanner) (err error) {
|
|||
[]tC{
|
||||
tC{"miid", "int", 0, false, true, ""},
|
||||
tC{"mid", "int", 0, false, false, ""},
|
||||
tC{"name", "varchar", 200, false, false, ""},
|
||||
tC{"htmlID", "varchar", 200, false, false, "''"},
|
||||
tC{"cssClass", "varchar", 200, false, false, "''"},
|
||||
tC{"position", "varchar", 100, false, false, ""},
|
||||
tC{"path", "varchar", 200, false, false, "''"},
|
||||
tC{"aria", "varchar", 200, false, false, "''"},
|
||||
tC{"tooltip", "varchar", 200, false, false, "''"},
|
||||
tC{"tmplName", "varchar", 200, false, false, "''"},
|
||||
ccol("name", 200, ""),
|
||||
ccol("htmlID", 200, "''"),
|
||||
ccol("cssClass", 200, "''"),
|
||||
ccol("position", 100, ""),
|
||||
ccol("path", 200, "''"),
|
||||
ccol("aria", 200, "''"),
|
||||
ccol("tooltip", 200, "''"),
|
||||
ccol("tmplName", 200, "''"),
|
||||
tC{"order", "int", 0, false, false, "0"},
|
||||
|
||||
tC{"guestOnly", "boolean", 0, false, false, "0"},
|
||||
tC{"memberOnly", "boolean", 0, false, false, "0"},
|
||||
tC{"staffOnly", "boolean", 0, false, false, "0"},
|
||||
tC{"adminOnly", "boolean", 0, false, false, "0"},
|
||||
bcol("guestOnly", false),
|
||||
bcol("memberOnly", false),
|
||||
bcol("staffOnly", false),
|
||||
bcol("adminOnly", false),
|
||||
},
|
||||
[]tK{
|
||||
tK{"miid", "primary", "", false},
|
||||
|
@ -194,11 +197,11 @@ func patch3(scanner *bufio.Scanner) error {
|
|||
return createTable("registration_logs", "", "",
|
||||
[]tC{
|
||||
tC{"rlid", "int", 0, false, true, ""},
|
||||
tC{"username", "varchar", 100, false, false, ""},
|
||||
tC{"email", "varchar", 100, false, false, ""},
|
||||
tC{"failureReason", "varchar", 100, false, false, ""},
|
||||
tC{"success", "bool", 0, false, false, "0"}, // Did this attempt succeed?
|
||||
tC{"ipaddress", "varchar", 200, false, false, ""},
|
||||
ccol("username", 100, ""),
|
||||
ccol("email", 100, ""),
|
||||
ccol("failureReason", 100, ""),
|
||||
bcol("success", false), // Did this attempt succeed?
|
||||
ccol("ipaddress", 200, ""),
|
||||
tC{"doneAt", "createdAt", 0, false, false, ""},
|
||||
},
|
||||
[]tK{
|
||||
|
@ -258,8 +261,8 @@ func patch4(scanner *bufio.Scanner) error {
|
|||
err = createTable("pages", "utf8mb4", "utf8mb4_general_ci",
|
||||
[]tC{
|
||||
tC{"pid", "int", 0, false, true, ""},
|
||||
tC{"name", "varchar", 200, false, false, ""},
|
||||
tC{"title", "varchar", 200, false, false, ""},
|
||||
ccol("name", 200, ""),
|
||||
ccol("title", 200, ""),
|
||||
tC{"body", "text", 0, false, false, ""},
|
||||
tC{"allowedGroups", "text", 0, false, false, ""},
|
||||
tC{"menuID", "int", 0, false, false, "-1"},
|
||||
|
@ -293,29 +296,24 @@ func patch5(scanner *bufio.Scanner) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = createTable("users_2fa_keys", "utf8mb4", "utf8mb4_general_ci",
|
||||
return createTable("users_2fa_keys", "utf8mb4", "utf8mb4_general_ci",
|
||||
[]tC{
|
||||
tC{"uid", "int", 0, false, false, ""},
|
||||
tC{"secret", "varchar", 100, false, false, ""},
|
||||
tC{"scratch1", "varchar", 50, false, false, ""},
|
||||
tC{"scratch2", "varchar", 50, false, false, ""},
|
||||
tC{"scratch3", "varchar", 50, false, false, ""},
|
||||
tC{"scratch4", "varchar", 50, false, false, ""},
|
||||
tC{"scratch5", "varchar", 50, false, false, ""},
|
||||
tC{"scratch6", "varchar", 50, false, false, ""},
|
||||
tC{"scratch7", "varchar", 50, false, false, ""},
|
||||
tC{"scratch8", "varchar", 50, false, false, ""},
|
||||
ccol("secret", 100, ""),
|
||||
ccol("scratch1", 50, ""),
|
||||
ccol("scratch2", 50, ""),
|
||||
ccol("scratch3", 50, ""),
|
||||
ccol("scratch4", 50, ""),
|
||||
ccol("scratch5", 50, ""),
|
||||
ccol("scratch6", 50, ""),
|
||||
ccol("scratch7", 50, ""),
|
||||
ccol("scratch8", 50, ""),
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
},
|
||||
[]tK{
|
||||
tK{"uid", "primary", "", false},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func patch6(scanner *bufio.Scanner) error {
|
||||
|
@ -382,10 +380,6 @@ func patch8(scanner *bufio.Scanner) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = execStmt(qgen.Builder.DropTable("updates"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return createTable("updates", "", "",
|
||||
[]tC{
|
||||
tC{"dbVersion", "int", 0, false, false, "0"},
|
||||
|
@ -404,8 +398,8 @@ func patch9(scanner *bufio.Scanner) error {
|
|||
[]tC{
|
||||
tC{"lid", "int", 0, false, true, ""},
|
||||
tC{"uid", "int", 0, false, false, ""},
|
||||
tC{"success", "bool", 0, false, false, "0"}, // Did this attempt succeed?
|
||||
tC{"ipaddress", "varchar", 200, false, false, ""},
|
||||
bcol("success", false), // Did this attempt succeed?
|
||||
ccol("ipaddress", 200, ""),
|
||||
tC{"doneAt", "createdAt", 0, false, false, ""},
|
||||
},
|
||||
[]tK{
|
||||
|
@ -463,7 +457,7 @@ func patch11(scanner *bufio.Scanner) error {
|
|||
}
|
||||
|
||||
// Attachments for replies got the topicID rather than the replyID for a while in error, so we want to separate these out
|
||||
_, err = acc().Update("attachments").Set("originTable = 'freplies'").Where("originTable = 'replies'").Exec()
|
||||
_, err = acc().Update("attachments").Set("originTable='freplies'").Where("originTable='replies'").Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -491,39 +485,26 @@ func patch11(scanner *bufio.Scanner) error {
|
|||
}
|
||||
|
||||
func patch12(scanner *bufio.Scanner) error {
|
||||
err := execStmt(qgen.Builder.AddIndex("topics", "parentID", "parentID"))
|
||||
if err != nil {
|
||||
return err
|
||||
var e error
|
||||
addIndex := func(tbl, iname, colname string) {
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
/*e = execStmt(qgen.Builder.RemoveIndex(tbl, iname))
|
||||
if e != nil {
|
||||
return
|
||||
}*/
|
||||
e = execStmt(qgen.Builder.AddIndex(tbl, iname, colname))
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddIndex("replies", "tid", "tid"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddIndex("polls", "parentID", "parentID"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddIndex("likes", "targetItem", "targetItem"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddIndex("emails", "uid", "uid"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddIndex("attachments", "originID", "originID"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddIndex("attachments", "path", "path"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddIndex("activity_stream_matches", "watcher", "watcher"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
addIndex("topics", "parentID", "parentID")
|
||||
addIndex("replies", "tid", "tid")
|
||||
addIndex("polls", "parentID", "parentID")
|
||||
addIndex("likes", "targetItem", "targetItem")
|
||||
addIndex("emails", "uid", "uid")
|
||||
addIndex("attachments", "originID", "originID")
|
||||
addIndex("attachments", "path", "path")
|
||||
addIndex("activity_stream_matches", "watcher", "watcher")
|
||||
return e
|
||||
}
|
||||
|
||||
func patch13(scanner *bufio.Scanner) error {
|
||||
|
@ -554,17 +535,17 @@ func patch15(scanner *bufio.Scanner) error {
|
|||
func patch16(scanner *bufio.Scanner) error {
|
||||
return createTable("password_resets", "", "",
|
||||
[]tC{
|
||||
tC{"email", "varchar", 200, false, false, ""},
|
||||
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
tC{"validated", "varchar", 200, false, false, ""}, // Token given once the one-use token is consumed, used to prevent multiple people consuming the same one-use token
|
||||
tC{"token", "varchar", 200, false, false, ""},
|
||||
ccol("email", 200, ""),
|
||||
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
ccol("validated", 200, ""), // Token given once the one-use token is consumed, used to prevent multiple people consuming the same one-use token
|
||||
ccol("token", 200, ""),
|
||||
tC{"createdAt", "createdAt", 0, false, false, ""},
|
||||
}, nil,
|
||||
)
|
||||
}
|
||||
|
||||
func patch17(scanner *bufio.Scanner) error {
|
||||
err := execStmt(qgen.Builder.AddColumn("attachments", tC{"extra", "varchar", 200, false, false, ""}, nil))
|
||||
err := execStmt(qgen.Builder.AddColumn("attachments", ccol("extra", 200, ""), nil))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -575,7 +556,7 @@ func patch17(scanner *bufio.Scanner) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = acc().Update("attachments").Set("sectionID=?").Where("originTable = 'topics' AND originID = ?").Exec(parentID, tid)
|
||||
_, err = acc().Update("attachments").Set("sectionID=?").Where("originTable='topics' AND originID=?").Exec(parentID, tid)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -592,7 +573,7 @@ func patch17(scanner *bufio.Scanner) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = acc().Update("attachments").Set("sectionID=?, extra=?").Where("originTable = 'replies' AND originID = ?").Exec(sectionID, tid, rid)
|
||||
_, err = acc().Update("attachments").Set("sectionID=?, extra=?").Where("originTable='replies' AND originID=?").Exec(sectionID, tid, rid)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
@ -613,16 +594,15 @@ func patch19(scanner *bufio.Scanner) error {
|
|||
func patch20(scanner *bufio.Scanner) error {
|
||||
err := acc().Select("activity_stream_matches").Cols("asid").Each(func(rows *sql.Rows) error {
|
||||
var asid int
|
||||
err := rows.Scan(&asid)
|
||||
if err != nil {
|
||||
return err
|
||||
if e := rows.Scan(&asid); e != nil {
|
||||
return e
|
||||
}
|
||||
err = acc().Select("activity_stream").Cols("asid").Where("asid = ?").QueryRow(asid).Scan(&asid)
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
e := acc().Select("activity_stream").Cols("asid").Where("asid=?").QueryRow(asid).Scan(&asid)
|
||||
if e != sql.ErrNoRows {
|
||||
return e
|
||||
}
|
||||
_, err = acc().Delete("activity_stream_matches").Where("asid = ?").Run(asid)
|
||||
return err
|
||||
_, e = acc().Delete("activity_stream_matches").Where("asid=?").Run(asid)
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -644,8 +624,8 @@ func patch21(scanner *bufio.Scanner) error {
|
|||
|
||||
err = createTable("meta", "", "",
|
||||
[]tC{
|
||||
tC{"name", "varchar", 200, false, false, ""},
|
||||
tC{"value", "varchar", 200, false, false, ""},
|
||||
ccol("name", 200, ""),
|
||||
ccol("value", 200, ""),
|
||||
}, nil,
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -656,15 +636,11 @@ func patch21(scanner *bufio.Scanner) error {
|
|||
}
|
||||
|
||||
func patch22(scanner *bufio.Scanner) error {
|
||||
return execStmt(qgen.Builder.AddColumn("forums", tC{"tmpl", "varchar", 200, false, false, "''"}, nil))
|
||||
return execStmt(qgen.Builder.AddColumn("forums", ccol("tmpl", 200, "''"), nil))
|
||||
}
|
||||
|
||||
func patch23(scanner *bufio.Scanner) error {
|
||||
err := execStmt(qgen.Builder.DropTable("conversations"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = createTable("conversations", "", "",
|
||||
err := createTable("conversations", "", "",
|
||||
[]tC{
|
||||
tC{"cid", "int", 0, false, true, ""},
|
||||
tC{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
|
@ -680,17 +656,13 @@ func patch23(scanner *bufio.Scanner) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = execStmt(qgen.Builder.DropTable("conversations_posts"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = createTable("conversations_posts", "", "",
|
||||
[]tC{
|
||||
tC{"pid", "int", 0, false, true, ""},
|
||||
tC{"cid", "int", 0, false, false, ""},
|
||||
tC{"createdBy", "int", 0, false, false, ""},
|
||||
tC{"body", "varchar", 50, false, false, ""},
|
||||
tC{"post", "varchar", 50, false, false, "''"},
|
||||
ccol("body", 50, ""),
|
||||
ccol("post", 50, "''"),
|
||||
},
|
||||
[]tK{
|
||||
tK{"pid", "primary", "", false},
|
||||
|
@ -700,10 +672,6 @@ func patch23(scanner *bufio.Scanner) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = execStmt(qgen.Builder.DropTable("conversations_participants"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return createTable("conversations_participants", "", "",
|
||||
[]tC{
|
||||
tC{"uid", "int", 0, false, false, ""},
|
||||
|
@ -713,16 +681,12 @@ func patch23(scanner *bufio.Scanner) error {
|
|||
}
|
||||
|
||||
func patch24(scanner *bufio.Scanner) error {
|
||||
err := execStmt(qgen.Builder.DropTable("users_groups_promotions"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return createTable("users_groups_promotions", "", "",
|
||||
[]tC{
|
||||
tC{"pid", "int", 0, false, true, ""},
|
||||
tC{"from_gid", "int", 0, false, false, ""},
|
||||
tC{"to_gid", "int", 0, false, false, ""},
|
||||
tC{"two_way", "boolean", 0, false, false, "0"}, // If a user no longer meets the requirements for this promotion then they will be demoted if this flag is set
|
||||
bcol("two_way", false), // If a user no longer meets the requirements for this promotion then they will be demoted if this flag is set
|
||||
|
||||
// Requirements
|
||||
tC{"level", "int", 0, false, false, ""},
|
||||
|
@ -812,28 +776,21 @@ func patch29(scanner *bufio.Scanner) error {
|
|||
return err
|
||||
}
|
||||
|
||||
fixCol := func(tbl string) error {
|
||||
//err := execStmt(qgen.Builder.RenameColumn(tbl, "ipaddress","ip"))
|
||||
err := execStmt(qgen.Builder.ChangeColumn(tbl, "ipaddress", tC{"ip", "varchar", 200, false, false, "''"}))
|
||||
if err != nil {
|
||||
return err
|
||||
fixCols := func(tbls ...string) error {
|
||||
for _, tbl := range tbls {
|
||||
//err := execStmt(qgen.Builder.RenameColumn(tbl, "ipaddress","ip"))
|
||||
err := execStmt(qgen.Builder.ChangeColumn(tbl, "ipaddress", ccol("ip", 200, "''")))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.SetDefaultColumn(tbl, "ip", "varchar", ""))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return execStmt(qgen.Builder.SetDefaultColumn(tbl, "ip", "varchar", ""))
|
||||
return nil
|
||||
}
|
||||
|
||||
err = fixCol("topics")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = fixCol("replies")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = fixCol("polls_votes")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = fixCol("users_replies")
|
||||
err = fixCols("topics", "replies", "polls_votes", "users_replies")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -867,36 +824,31 @@ func patch30(scanner *bufio.Scanner) error {
|
|||
return execStmt(qgen.Builder.SetDefaultColumn("users", "last_ip", "varchar", ""))
|
||||
}
|
||||
|
||||
func patch31(scanner *bufio.Scanner) error {
|
||||
err := execStmt(qgen.Builder.RemoveIndex("topics", "title"))
|
||||
func patch31(scanner *bufio.Scanner) (e error) {
|
||||
addKey := func(tbl, col string, tk qgen.DBTableKey) error {
|
||||
/*err := execStmt(qgen.Builder.RemoveIndex(tbl, col))
|
||||
if err != nil {
|
||||
return err
|
||||
}*/
|
||||
return execStmt(qgen.Builder.AddKey(tbl, col, tk))
|
||||
}
|
||||
err := addKey("topics", "title", tK{"title", "fulltext", "", false})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.RemoveIndex("topics", "content"))
|
||||
err = addKey("topics", "content", tK{"content", "fulltext", "", false})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.RemoveIndex("replies", "content"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddKey("topics", "title", tK{"title", "fulltext", "", false}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddKey("topics", "content", tK{"content", "fulltext", "", false}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execStmt(qgen.Builder.AddKey("replies", "content", tK{"content", "fulltext", "", false}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return addKey("replies", "content", tK{"content", "fulltext", "", false})
|
||||
}
|
||||
|
||||
func createTable(table, charset, collation string, cols []tC, keys []tK) error {
|
||||
return execStmt(qgen.Builder.CreateTable(table, charset, collation, cols, keys))
|
||||
func createTable(tbl, charset, collation string, cols []tC, keys []tK) error {
|
||||
err := execStmt(qgen.Builder.DropTable(tbl))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return execStmt(qgen.Builder.CreateTable(tbl, charset, collation, cols, keys))
|
||||
}
|
||||
|
||||
func patch32(scanner *bufio.Scanner) error {
|
||||
|
@ -913,3 +865,75 @@ func patch32(scanner *bufio.Scanner) error {
|
|||
func patch33(scanner *bufio.Scanner) error {
|
||||
return execStmt(qgen.Builder.AddColumn("viewchunks", tC{"avg", "int", 0, false, false, "0"}, nil))
|
||||
}
|
||||
|
||||
func patch34(scanner *bufio.Scanner) error {
|
||||
/*err := createTable("tables", "", "",
|
||||
[]tC{
|
||||
tC{"id", "int", 0, false, true, ""},
|
||||
ccol("name", 200, ""),
|
||||
},
|
||||
[]tK{
|
||||
tK{"id", "primary", "", false},
|
||||
tK{"name", "unique", "", false},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
insert := func(tbl, cols, fields string) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = execStmt(qgen.Builder.SimpleInsert(tbl, cols, fields))
|
||||
}
|
||||
insert("tables", "name", "forums")
|
||||
insert("tables", "name", "topics")
|
||||
insert("tables", "name", "replies")
|
||||
// ! Hold onto freplies for a while longer
|
||||
insert("tables", "name", "freplies")*/
|
||||
/*err := execStmt(qgen.Builder.AddColumn("topics", tC{"attachCount", "int", 0, false, false, "0"}, nil))
|
||||
if err != nil {
|
||||
return err
|
||||
}*/
|
||||
overwriteColumn := func(tbl, col string, tc qgen.DBTableColumn) error {
|
||||
/*e := execStmt(qgen.Builder.DropColumn(tbl, col))
|
||||
if e != nil {
|
||||
return e
|
||||
}*/
|
||||
return execStmt(qgen.Builder.AddColumn(tbl, tc, nil))
|
||||
}
|
||||
err := overwriteColumn("users", "profile_comments", tC{"profile_comments", "int", 0, false, false, "0"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = overwriteColumn("users", "who_can_convo", tC{"who_can_convo", "int", 0, false, false, "0"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
setDefault := func(tbl, col, typ, val string) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = execStmt(qgen.Builder.SetDefaultColumn(tbl, col, typ, val))
|
||||
}
|
||||
setDefault("users_groups", "permissions", "text", "{}")
|
||||
setDefault("users_groups", "plugin_perms", "text", "{}")
|
||||
setDefault("forums_permissions", "permissions", "text", "{}")
|
||||
setDefault("topics", "content", "text", "")
|
||||
setDefault("topics", "parsed_content", "text", "")
|
||||
setDefault("replies", "content", "text", "")
|
||||
setDefault("replies", "parsed_content", "text", "")
|
||||
//setDefault("revisions", "content", "text", "")
|
||||
setDefault("users_replies", "content", "text", "")
|
||||
setDefault("users_replies", "parsed_content", "text", "")
|
||||
setDefault("pages", "body", "text", "")
|
||||
setDefault("pages", "allowedGroups", "text", "")
|
||||
setDefault("moderation_logs", "extra", "text", "")
|
||||
setDefault("administration_logs", "extra", "text", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ type DBStmt struct {
|
|||
Type string // create-table, insert, update, delete
|
||||
}
|
||||
|
||||
// TODO: Add the DropTable, TableExists, AddColumn, ColumnExists, and RemoveColumn methods
|
||||
// TODO: Add the TableExists and ColumnExists methods
|
||||
type Adapter interface {
|
||||
GetName() string
|
||||
BuildConn(config map[string]string) (*sql.DB, error)
|
||||
|
|
|
@ -614,8 +614,8 @@ func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, u *c.Us
|
|||
|
||||
func AccountEditPrivacy(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
|
||||
accountEditHead("account_privacy", w, r, u, h)
|
||||
profileComments := false
|
||||
receiveConvos := false
|
||||
profileComments := u.Privacy.ShowComments
|
||||
receiveConvos := u.Privacy.AllowMessage
|
||||
enableEmbeds := !c.DefaultParseSettings.NoEmbed
|
||||
if u.ParseSettings != nil {
|
||||
enableEmbeds = !u.ParseSettings.NoEmbed
|
||||
|
@ -626,14 +626,21 @@ func AccountEditPrivacy(w http.ResponseWriter, r *http.Request, u *c.User, h *c.
|
|||
|
||||
func AccountEditPrivacySubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
//headerLite, _ := c.SimpleUserCheck(w, r, u)
|
||||
|
||||
sProfileComments := r.FormValue("profile_comments")
|
||||
sEnableEmbeds := r.FormValue("enable_embeds")
|
||||
enableEmbeds, e := strconv.Atoi(sEnableEmbeds)
|
||||
if e != nil {
|
||||
return c.LocalError("enable_embeds must be 0 or 1", w, r, u)
|
||||
}
|
||||
if sEnableEmbeds != r.FormValue("o_enable_embeds") {
|
||||
if e = u.UpdatePrivacy(enableEmbeds); e != nil {
|
||||
oProfileComments := r.FormValue("o_profile_comments")
|
||||
oEnableEmbeds := r.FormValue("o_enable_embeds")
|
||||
|
||||
if sProfileComments != oProfileComments || sEnableEmbeds != oEnableEmbeds {
|
||||
profileComments, e := strconv.Atoi(sProfileComments)
|
||||
enableEmbeds, e2 := strconv.Atoi(sEnableEmbeds)
|
||||
if e != nil || e2 != nil {
|
||||
return c.LocalError("malformed integer", w, r, u)
|
||||
}
|
||||
e = u.UpdatePrivacy(profileComments, enableEmbeds)
|
||||
if e == c.ErrProfileCommentsOutOfBounds || e == c.ErrEnableEmbedsOutOfBounds {
|
||||
return c.LocalError(e.Error(), w, r, u)
|
||||
} else if e != nil {
|
||||
return c.InternalError(e, w, r)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -399,24 +399,18 @@ func ConvosEditReplySubmit(w http.ResponseWriter, r *http.Request, user *c.User,
|
|||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
if !js {
|
||||
http.Redirect(w, r, "/user/convo/"+strconv.Itoa(post.CID), http.StatusSeeOther)
|
||||
} else {
|
||||
w.Write(successJSONBytes)
|
||||
}
|
||||
return nil
|
||||
return actionSuccess(w, r, "/user/convo/"+strconv.Itoa(post.CID), js)
|
||||
}
|
||||
|
||||
func RelationsBlockCreate(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header, spid string) c.RouteError {
|
||||
func RelationsBlockCreate(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header, spid string) c.RouteError {
|
||||
h.Title = p.GetTitlePhrase("create_block")
|
||||
pid, err := strconv.Atoi(spid)
|
||||
if err != nil {
|
||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
|
||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, u)
|
||||
}
|
||||
puser, err := c.Users.Get(pid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to block doesn't exist.", w, r, user)
|
||||
return c.LocalError("The user you're trying to block doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -425,22 +419,22 @@ func RelationsBlockCreate(w http.ResponseWriter, r *http.Request, user *c.User,
|
|||
return renderTemplate("are_you_sure", w, r, h, pi)
|
||||
}
|
||||
|
||||
func RelationsBlockCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User, spid string) c.RouteError {
|
||||
func RelationsBlockCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User, spid string) c.RouteError {
|
||||
pid, err := strconv.Atoi(spid)
|
||||
if err != nil {
|
||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
|
||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, u)
|
||||
}
|
||||
puser, err := c.Users.Get(pid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to block doesn't exist.", w, r, user)
|
||||
return c.LocalError("The user you're trying to block doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if user.ID == puser.ID {
|
||||
return c.LocalError("You can't block yourself.", w, r, user)
|
||||
if u.ID == puser.ID {
|
||||
return c.LocalError("You can't block yourself.", w, r, u)
|
||||
}
|
||||
|
||||
err = c.UserBlocks.Add(user.ID, puser.ID)
|
||||
err = c.UserBlocks.Add(u.ID, puser.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -449,15 +443,15 @@ func RelationsBlockCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.
|
|||
return nil
|
||||
}
|
||||
|
||||
func RelationsBlockRemove(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header, spid string) c.RouteError {
|
||||
func RelationsBlockRemove(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header, spid string) c.RouteError {
|
||||
h.Title = p.GetTitlePhrase("remove_block")
|
||||
pid, err := strconv.Atoi(spid)
|
||||
if err != nil {
|
||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
|
||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, u)
|
||||
}
|
||||
puser, err := c.Users.Get(pid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to block doesn't exist.", w, r, user)
|
||||
return c.LocalError("The user you're trying to block doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -466,19 +460,19 @@ func RelationsBlockRemove(w http.ResponseWriter, r *http.Request, user *c.User,
|
|||
return renderTemplate("are_you_sure", w, r, h, pi)
|
||||
}
|
||||
|
||||
func RelationsBlockRemoveSubmit(w http.ResponseWriter, r *http.Request, user *c.User, spid string) c.RouteError {
|
||||
func RelationsBlockRemoveSubmit(w http.ResponseWriter, r *http.Request, u *c.User, spid string) c.RouteError {
|
||||
pid, err := strconv.Atoi(spid)
|
||||
if err != nil {
|
||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
|
||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, u)
|
||||
}
|
||||
puser, err := c.Users.Get(pid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to unblock doesn't exist.", w, r, user)
|
||||
return c.LocalError("The user you're trying to unblock doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
err = c.UserBlocks.Remove(user.ID, puser.ID)
|
||||
err = c.UserBlocks.Remove(u.ID, puser.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
|
|
@ -35,23 +35,23 @@ func Pages(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
|||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_page_list", "", "panel_pages", &pi})
|
||||
}
|
||||
|
||||
func PagesCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func PagesCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
|
||||
name := c.SanitiseSingleLine(r.PostFormValue("name"))
|
||||
if name == "" {
|
||||
return c.LocalError("No name was provided for this page", w, r, user)
|
||||
return c.LocalError("No name was provided for this page", w, r, u)
|
||||
}
|
||||
title := c.SanitiseSingleLine(r.PostFormValue("title"))
|
||||
if title == "" {
|
||||
return c.LocalError("No title was provided for this page", w, r, user)
|
||||
return c.LocalError("No title was provided for this page", w, r, u)
|
||||
}
|
||||
body := r.PostFormValue("body")
|
||||
if body == "" {
|
||||
return c.LocalError("No body was provided for this page", w, r, user)
|
||||
return c.LocalError("No body was provided for this page", w, r, u)
|
||||
}
|
||||
|
||||
page := c.BlankCustomPage()
|
||||
|
@ -62,7 +62,7 @@ func PagesCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.R
|
|||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.AdminLogs.Create("create", pid, "page", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("create", pid, "page", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -95,27 +95,27 @@ func PagesEdit(w http.ResponseWriter, r *http.Request, u *c.User, spid string) c
|
|||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_page_edit", "", "panel_pages_edit", &pi})
|
||||
}
|
||||
|
||||
func PagesEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, spid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func PagesEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, spid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(spid)
|
||||
if err != nil {
|
||||
return c.LocalError("Page ID needs to be an integer", w, r, user)
|
||||
return c.LocalError("Page ID needs to be an integer", w, r, u)
|
||||
}
|
||||
name := c.SanitiseSingleLine(r.PostFormValue("name"))
|
||||
if name == "" {
|
||||
return c.LocalError("No name was provided for this page", w, r, user)
|
||||
return c.LocalError("No name was provided for this page", w, r, u)
|
||||
}
|
||||
title := c.SanitiseSingleLine(r.PostFormValue("title"))
|
||||
if title == "" {
|
||||
return c.LocalError("No title was provided for this page", w, r, user)
|
||||
return c.LocalError("No title was provided for this page", w, r, u)
|
||||
}
|
||||
body := r.PostFormValue("body")
|
||||
if body == "" {
|
||||
return c.LocalError("No body was provided for this page", w, r, user)
|
||||
return c.LocalError("No body was provided for this page", w, r, u)
|
||||
}
|
||||
|
||||
page, err := c.Pages.Get(pid)
|
||||
|
@ -129,7 +129,7 @@ func PagesEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, spid
|
|||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.AdminLogs.Create("edit", pid, "page", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("edit", pid, "page", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
|
|
@ -26,54 +26,54 @@ func Plugins(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
|||
}
|
||||
|
||||
// TODO: Abstract more of the plugin activation / installation / deactivation logic, so we can test all that more reliably and easily
|
||||
func PluginsActivate(w http.ResponseWriter, r *http.Request, user *c.User, uname string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func PluginsActivate(w http.ResponseWriter, r *http.Request, u *c.User, uname string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManagePlugins {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
plugin, ok := c.Plugins[uname]
|
||||
pl, ok := c.Plugins[uname]
|
||||
if !ok {
|
||||
return c.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
return c.LocalError("The plugin isn't registered in the system", w, r, u)
|
||||
}
|
||||
if plugin.Installable && !plugin.Installed {
|
||||
return c.LocalError("You can't activate this plugin without installing it first", w, r, user)
|
||||
if pl.Installable && !pl.Installed {
|
||||
return c.LocalError("You can't activate this plugin without installing it first", w, r, u)
|
||||
}
|
||||
|
||||
active, err := plugin.BypassActive()
|
||||
hasPlugin, err2 := plugin.InDatabase()
|
||||
active, err := pl.BypassActive()
|
||||
hasPlugin, err2 := pl.InDatabase()
|
||||
if err != nil || err2 != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
if plugin.Activate != nil {
|
||||
err = plugin.Activate(plugin)
|
||||
if pl.Activate != nil {
|
||||
err = pl.Activate(pl)
|
||||
if err != nil {
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
return c.LocalError(err.Error(), w, r, u)
|
||||
}
|
||||
}
|
||||
|
||||
if hasPlugin {
|
||||
if active {
|
||||
return c.LocalError("The plugin is already active", w, r, user)
|
||||
return c.LocalError("The plugin is already active", w, r, u)
|
||||
}
|
||||
err = plugin.SetActive(true)
|
||||
err = pl.SetActive(true)
|
||||
} else {
|
||||
err = plugin.AddToDatabase(true, false)
|
||||
err = pl.AddToDatabase(true, false)
|
||||
}
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
log.Printf("Activating plugin '%s'", plugin.Name)
|
||||
err = plugin.Init(plugin)
|
||||
log.Printf("Activating plugin '%s'", pl.Name)
|
||||
err = pl.Init(pl)
|
||||
if err != nil {
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
return c.LocalError(err.Error(), w, r, u)
|
||||
}
|
||||
err = c.AdminLogs.CreateExtra("activate", 0, "plugin", user.GetIP(), user.ID, c.SanitiseSingleLine(plugin.Name))
|
||||
err = c.AdminLogs.CreateExtra("activate", 0, "plugin", u.GetIP(), u.ID, c.SanitiseSingleLine(pl.Name))
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -82,36 +82,36 @@ func PluginsActivate(w http.ResponseWriter, r *http.Request, user *c.User, uname
|
|||
return nil
|
||||
}
|
||||
|
||||
func PluginsDeactivate(w http.ResponseWriter, r *http.Request, user *c.User, uname string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func PluginsDeactivate(w http.ResponseWriter, r *http.Request, u *c.User, uname string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManagePlugins {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
plugin, ok := c.Plugins[uname]
|
||||
pl, ok := c.Plugins[uname]
|
||||
if !ok {
|
||||
return c.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
return c.LocalError("The plugin isn't registered in the system", w, r, u)
|
||||
}
|
||||
log.Printf("plugin: %+v\n", plugin)
|
||||
log.Printf("plugin: %+v\n", pl)
|
||||
|
||||
active, err := plugin.BypassActive()
|
||||
active, err := pl.BypassActive()
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
} else if !active {
|
||||
return c.LocalError("The plugin you're trying to deactivate isn't active", w, r, user)
|
||||
return c.LocalError("The plugin you're trying to deactivate isn't active", w, r, u)
|
||||
}
|
||||
|
||||
err = plugin.SetActive(false)
|
||||
err = pl.SetActive(false)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if plugin.Deactivate != nil {
|
||||
plugin.Deactivate(plugin)
|
||||
if pl.Deactivate != nil {
|
||||
pl.Deactivate(pl)
|
||||
}
|
||||
err = c.AdminLogs.CreateExtra("deactivate", 0, "plugin", user.GetIP(), user.ID, c.SanitiseSingleLine(plugin.Name))
|
||||
err = c.AdminLogs.CreateExtra("deactivate", 0, "plugin", u.GetIP(), u.ID, c.SanitiseSingleLine(pl.Name))
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -120,28 +120,28 @@ func PluginsDeactivate(w http.ResponseWriter, r *http.Request, user *c.User, una
|
|||
return nil
|
||||
}
|
||||
|
||||
func PluginsInstall(w http.ResponseWriter, r *http.Request, user *c.User, uname string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func PluginsInstall(w http.ResponseWriter, r *http.Request, u *c.User, uname string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManagePlugins {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
plugin, ok := c.Plugins[uname]
|
||||
pl, ok := c.Plugins[uname]
|
||||
if !ok {
|
||||
return c.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
return c.LocalError("The plugin isn't registered in the system", w, r, u)
|
||||
}
|
||||
if !plugin.Installable {
|
||||
return c.LocalError("This plugin is not installable", w, r, user)
|
||||
if !pl.Installable {
|
||||
return c.LocalError("This plugin is not installable", w, r, u)
|
||||
}
|
||||
if plugin.Installed {
|
||||
return c.LocalError("This plugin has already been installed", w, r, user)
|
||||
if pl.Installed {
|
||||
return c.LocalError("This plugin has already been installed", w, r, u)
|
||||
}
|
||||
|
||||
active, err := plugin.BypassActive()
|
||||
hasPlugin, err2 := plugin.InDatabase()
|
||||
active, err := pl.BypassActive()
|
||||
hasPlugin, err2 := pl.InDatabase()
|
||||
if err != nil || err2 != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -149,39 +149,39 @@ func PluginsInstall(w http.ResponseWriter, r *http.Request, user *c.User, uname
|
|||
return c.InternalError(errors.New("An uninstalled plugin is still active"), w, r)
|
||||
}
|
||||
|
||||
if plugin.Install != nil {
|
||||
err = plugin.Install(plugin)
|
||||
if pl.Install != nil {
|
||||
err = pl.Install(pl)
|
||||
if err != nil {
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
return c.LocalError(err.Error(), w, r, u)
|
||||
}
|
||||
}
|
||||
|
||||
if plugin.Activate != nil {
|
||||
err = plugin.Activate(plugin)
|
||||
if pl.Activate != nil {
|
||||
err = pl.Activate(pl)
|
||||
if err != nil {
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
return c.LocalError(err.Error(), w, r, u)
|
||||
}
|
||||
}
|
||||
|
||||
if hasPlugin {
|
||||
err = plugin.SetInstalled(true)
|
||||
err = pl.SetInstalled(true)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = plugin.SetActive(true)
|
||||
err = pl.SetActive(true)
|
||||
} else {
|
||||
err = plugin.AddToDatabase(true, true)
|
||||
err = pl.AddToDatabase(true, true)
|
||||
}
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
log.Printf("Installing plugin '%s'", plugin.Name)
|
||||
err = plugin.Init(plugin)
|
||||
log.Printf("Installing plugin '%s'", pl.Name)
|
||||
err = pl.Init(pl)
|
||||
if err != nil {
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
return c.LocalError(err.Error(), w, r, u)
|
||||
}
|
||||
err = c.AdminLogs.CreateExtra("install", 0, "plugin", user.GetIP(), user.ID, c.SanitiseSingleLine(plugin.Name))
|
||||
err = c.AdminLogs.CreateExtra("install", 0, "plugin", u.GetIP(), u.ID, c.SanitiseSingleLine(pl.Name))
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ import (
|
|||
p "github.com/Azareal/Gosora/common/phrases"
|
||||
)
|
||||
|
||||
func Themes(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, user, "themes", "themes")
|
||||
func Themes(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, u, "themes", "themes")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
var pThemeList, vThemeList []*c.Theme
|
||||
|
@ -37,28 +37,28 @@ func Themes(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
|||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_themes", "", "panel_themes", &pi})
|
||||
}
|
||||
|
||||
func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user *c.User, uname string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ThemesSetDefault(w http.ResponseWriter, r *http.Request, u *c.User, uname string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
theme, ok := c.Themes[uname]
|
||||
if !ok {
|
||||
return c.LocalError("The theme isn't registered in the system", w, r, user)
|
||||
return c.LocalError("The theme isn't registered in the system", w, r, u)
|
||||
}
|
||||
if theme.Disabled {
|
||||
return c.LocalError("You must not enable this theme", w, r, user)
|
||||
return c.LocalError("You must not enable this theme", w, r, u)
|
||||
}
|
||||
|
||||
err := c.UpdateDefaultTheme(theme)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.AdminLogs.CreateExtra("set_default", 0, "theme", user.GetIP(), user.ID, c.SanitiseSingleLine(theme.Name))
|
||||
err = c.AdminLogs.CreateExtra("set_default", 0, "theme", u.GetIP(), u.ID, c.SanitiseSingleLine(theme.Name))
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -67,13 +67,13 @@ func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user *c.User, unam
|
|||
return nil
|
||||
}
|
||||
|
||||
func ThemesMenus(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, user, "themes_menus", "themes")
|
||||
func ThemesMenus(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, u, "themes_menus", "themes")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
var menuList []c.PanelMenuListItem
|
||||
|
@ -92,21 +92,21 @@ func ThemesMenus(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteEr
|
|||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_menus", &c.PanelMenuListPage{basePage, menuList}})
|
||||
}
|
||||
|
||||
func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user *c.User, smid string) c.RouteError {
|
||||
func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, u *c.User, smid string) c.RouteError {
|
||||
// TODO: Something like Menu #1 for the title?
|
||||
basePage, ferr := buildBasePage(w, r, user, "themes_menus_edit", "themes")
|
||||
basePage, ferr := buildBasePage(w, r, u, "themes_menus_edit", "themes")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
basePage.Header.AddScript("Sortable-1.4.0/Sortable.min.js")
|
||||
basePage.Header.AddScriptAsync("panel_menu_items.js")
|
||||
|
||||
mid, err := strconv.Atoi(smid)
|
||||
if err != nil {
|
||||
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
|
||||
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, u)
|
||||
}
|
||||
menuHold, err := c.Menus.Get(mid)
|
||||
if err == sql.ErrNoRows {
|
||||
|
@ -138,19 +138,19 @@ func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user *c.User, smid
|
|||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_menus_items", &c.PanelMenuPage{basePage, mid, menuList}})
|
||||
}
|
||||
|
||||
func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, user *c.User, sitemID string) c.RouteError {
|
||||
func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, u *c.User, sitemID string) c.RouteError {
|
||||
// TODO: Something like Menu #1 for the title?
|
||||
basePage, ferr := buildBasePage(w, r, user, "themes_menus_edit", "themes")
|
||||
basePage, ferr := buildBasePage(w, r, u, "themes_menus_edit", "themes")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
itemID, err := strconv.Atoi(sitemID)
|
||||
if err != nil {
|
||||
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
|
||||
return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, u)
|
||||
}
|
||||
menuItem, err := c.Menus.ItemStore().Get(itemID)
|
||||
if err == sql.ErrNoRows {
|
||||
|
@ -205,23 +205,23 @@ func themesMenuItemSetters(r *http.Request, i c.MenuItem) c.MenuItem {
|
|||
return i
|
||||
}
|
||||
|
||||
func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, sitemID string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sitemID string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
itemID, err := strconv.Atoi(sitemID)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, user, js)
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
|
||||
}
|
||||
menuItem, err := c.Menus.ItemStore().Get(itemID)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalErrorJSQ("This item doesn't exist.", w, r, user, js)
|
||||
return c.LocalErrorJSQ("This item doesn't exist.", w, r, u, js)
|
||||
} else if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user *c.Us
|
|||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
err = c.AdminLogs.Create("edit", menuItem.ID, "menu_item", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("edit", menuItem.ID, "menu_item", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -240,23 +240,23 @@ func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user *c.Us
|
|||
return successRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, js)
|
||||
}
|
||||
|
||||
func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
smenuID := r.PostFormValue("mid")
|
||||
if smenuID == "" {
|
||||
return c.LocalErrorJSQ("No menuID provided", w, r, user, js)
|
||||
return c.LocalErrorJSQ("No menuID provided", w, r, u, js)
|
||||
}
|
||||
menuID, err := strconv.Atoi(smenuID)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, user, js)
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
|
||||
}
|
||||
|
||||
menuItem := c.MenuItem{MenuID: menuID}
|
||||
|
@ -265,7 +265,7 @@ func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.
|
|||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
err = c.AdminLogs.Create("create", itemID, "menu_item", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("create", itemID, "menu_item", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -273,23 +273,23 @@ func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.
|
|||
return successRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, js)
|
||||
}
|
||||
|
||||
func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.User, sitemID string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sitemID string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
itemID, err := strconv.Atoi(sitemID)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, user, js)
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
|
||||
}
|
||||
menuItem, err := c.Menus.ItemStore().Get(itemID)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalErrorJSQ("This item doesn't exist.", w, r, user, js)
|
||||
return c.LocalErrorJSQ("This item doesn't exist.", w, r, u, js)
|
||||
} else if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.
|
|||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
err = c.AdminLogs.Create("delete", menuItem.ID, "menu_item", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("delete", menuItem.ID, "menu_item", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -307,23 +307,23 @@ func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.
|
|||
return successRedirect("/panel/themes/menus/", w, r, js)
|
||||
}
|
||||
|
||||
func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user *c.User, smid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, u *c.User, smid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
mid, err := strconv.Atoi(smid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, user, js)
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
|
||||
}
|
||||
menuHold, err := c.Menus.Get(mid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalErrorJSQ("Can't find menu", w, r, user, js)
|
||||
return c.LocalErrorJSQ("Can't find menu", w, r, u, js)
|
||||
} else if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
@ -335,13 +335,13 @@ func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user *c.U
|
|||
for index, smiid := range strings.Split(sitems, ",") {
|
||||
miid, err := strconv.Atoi(smiid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ("Invalid integer in menu item list", w, r, user, js)
|
||||
return c.LocalErrorJSQ("Invalid integer in menu item list", w, r, u, js)
|
||||
}
|
||||
updateMap[miid] = index
|
||||
}
|
||||
menuHold.UpdateOrder(updateMap)
|
||||
|
||||
err = c.AdminLogs.Create("suborder", menuHold.MenuID, "menu", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("suborder", menuHold.MenuID, "menu", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -349,13 +349,13 @@ func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user *c.U
|
|||
return successRedirect("/panel/themes/menus/edit/"+strconv.Itoa(mid), w, r, js)
|
||||
}
|
||||
|
||||
func ThemesWidgets(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, user, "themes_widgets", "themes")
|
||||
func ThemesWidgets(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, u, "themes_widgets", "themes")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
basePage.Header.AddScript("widgets.js")
|
||||
|
||||
|
@ -414,20 +414,20 @@ func widgetsParseInputs(r *http.Request, widget *c.Widget) (*c.WidgetEdit, error
|
|||
}
|
||||
|
||||
// ThemesWidgetsEditSubmit is an action which is triggered when someone sends an update request for a widget
|
||||
func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, swid string) c.RouteError {
|
||||
func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, swid string) c.RouteError {
|
||||
//fmt.Println("in ThemesWidgetsEditSubmit")
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
wid, err := strconv.Atoi(swid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, user, js)
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
|
||||
}
|
||||
widget, err := c.Widgets.Get(wid)
|
||||
if err == sql.ErrNoRows {
|
||||
|
@ -438,14 +438,14 @@ func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user *c.Use
|
|||
|
||||
ewidget, err := widgetsParseInputs(r, widget.Copy())
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(err.Error(), w, r, user, js)
|
||||
return c.LocalErrorJSQ(err.Error(), w, r, u, js)
|
||||
}
|
||||
|
||||
err = ewidget.Commit()
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
err = c.AdminLogs.Create("edit", widget.ID, "widget", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("edit", widget.ID, "widget", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -454,25 +454,25 @@ func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user *c.Use
|
|||
}
|
||||
|
||||
// ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget
|
||||
func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
js := r.PostFormValue("js") == "1"
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
ewidget, err := widgetsParseInputs(r, &c.Widget{})
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(err.Error(), w, r, user, js)
|
||||
return c.LocalErrorJSQ(err.Error(), w, r, u, js)
|
||||
}
|
||||
wid, err := ewidget.Create()
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
err = c.AdminLogs.Create("create", wid, "widget", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("create", wid, "widget", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -480,19 +480,19 @@ func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.U
|
|||
return successRedirect("/panel/themes/widgets/", w, r, js)
|
||||
}
|
||||
|
||||
func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.User, swid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, swid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
if !user.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.ManageThemes {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
wid, err := strconv.Atoi(swid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, user, js)
|
||||
return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
|
||||
}
|
||||
widget, err := c.Widgets.Get(wid)
|
||||
if err == sql.ErrNoRows {
|
||||
|
@ -504,7 +504,7 @@ func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.U
|
|||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.AdminLogs.Create("delete", widget.ID, "widget", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("delete", widget.ID, "widget", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
|
|
@ -110,9 +110,49 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Head
|
|||
return c.InternalError(err, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
canMessage := (!blockedInv && user.Perms.UseConvos) || (!blockedInv && puser.IsSuperMod && user.Perms.UseConvosOnlyWithMod) || user.IsSuperMod
|
||||
canComment := !blockedInv && user.Perms.CreateProfileReply
|
||||
showComments := profileCommentsShow(puser, user)
|
||||
if !showComments {
|
||||
canComment = false
|
||||
}
|
||||
if !profileAllowMessage(puser, user) {
|
||||
canMessage = false
|
||||
}
|
||||
|
||||
ppage := c.ProfilePage{h, reList, *puser, currentScore, nextScore, blocked, canMessage, canComment}
|
||||
ppage := c.ProfilePage{h, reList, *puser, currentScore, nextScore, blocked, canMessage, canComment, showComments}
|
||||
return renderTemplate("profile", w, r, h, ppage)
|
||||
}
|
||||
|
||||
func profileAllowMessage(pu, u *c.User) (canMsg bool) {
|
||||
switch pu.Privacy.AllowMessage {
|
||||
case 4: // Unused
|
||||
canMsg = false
|
||||
case 3: // mods / self
|
||||
canMsg = u.IsSuperMod
|
||||
//case 2: // friends
|
||||
case 1: // registered
|
||||
canMsg = true
|
||||
default: // 0
|
||||
canMsg = true
|
||||
}
|
||||
return canMsg
|
||||
}
|
||||
|
||||
func profileCommentsShow(pu, u *c.User) (showComments bool) {
|
||||
switch pu.Privacy.ShowComments {
|
||||
case 5: // Unused
|
||||
showComments = false
|
||||
case 4: // Self
|
||||
showComments = u.ID == pu.ID
|
||||
//case 3: // friends
|
||||
case 2: // registered
|
||||
showComments = u.Loggedin
|
||||
case 1: // public
|
||||
showComments = true
|
||||
default: // 0
|
||||
showComments = true
|
||||
}
|
||||
return showComments
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.Us
|
|||
if err != nil {
|
||||
return c.LocalError("Invalid UID", w, r, user)
|
||||
}
|
||||
|
||||
profileOwner, err := c.Users.Get(uid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The profile you're trying to post on doesn't exist.", w, r, user)
|
||||
|
@ -30,7 +29,7 @@ func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.Us
|
|||
return c.InternalError(err, w, r)
|
||||
}
|
||||
// Supermods can bypass blocks so they can tell people off when they do something stupid or have to convey important information
|
||||
if blocked && !user.IsSuperMod {
|
||||
if (blocked || !profileCommentsShow(profileOwner, user)) && !user.IsSuperMod {
|
||||
return c.LocalError("You don't have permission to send messages to one of these users.", w, r, user)
|
||||
}
|
||||
|
||||
|
@ -56,13 +55,12 @@ func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.Us
|
|||
return nil
|
||||
}
|
||||
|
||||
func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, srid string) c.RouteError {
|
||||
func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, srid string) c.RouteError {
|
||||
js := r.PostFormValue("js") == "1"
|
||||
rid, err := strconv.Atoi(srid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js)
|
||||
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, u, js)
|
||||
}
|
||||
|
||||
reply, err := c.Prstore.Get(rid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js)
|
||||
|
@ -74,34 +72,41 @@ func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User
|
|||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
if !user.Perms.CreateProfileReply {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.CreateProfileReply {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
// ? Does the admin understand that this group perm affects this?
|
||||
if user.ID != creator.ID && !user.Perms.EditReply {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if u.ID != creator.ID && !u.Perms.EditReply {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
// TODO: Stop blocked users from modifying profile replies?
|
||||
profileOwner, err := c.Users.Get(reply.ParentID)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The profile you're trying to edit a post on doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
blocked, err := c.UserBlocks.IsBlockedBy(profileOwner.ID, u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
// Supermods can bypass blocks so they can tell people off when they do something stupid or have to convey important information
|
||||
if (blocked || !profileCommentsShow(profileOwner, u)) && !u.IsSuperMod {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
err = reply.SetBody(r.PostFormValue("edit_item"))
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
||||
if !js {
|
||||
http.Redirect(w, r, "/user/"+strconv.Itoa(creator.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
||||
} else {
|
||||
w.Write(successJSONBytes)
|
||||
}
|
||||
return nil
|
||||
return actionSuccess(w, r, "/user/"+strconv.Itoa(creator.ID)+"#reply-"+strconv.Itoa(rid), js)
|
||||
}
|
||||
|
||||
func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.User, srid string) c.RouteError {
|
||||
func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, srid string) c.RouteError {
|
||||
js := r.PostFormValue("js") == "1"
|
||||
rid, err := strconv.Atoi(srid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js)
|
||||
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, u, js)
|
||||
}
|
||||
|
||||
reply, err := c.Prstore.Get(rid)
|
||||
|
@ -115,15 +120,15 @@ func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.Us
|
|||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
if user.ID != creator.ID && !user.Perms.DeleteReply {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if u.ID != creator.ID && !u.Perms.DeleteReply {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
|
||||
err = reply.Delete()
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
//log.Printf("The profile post '%d' was deleted by c.User #%d", reply.ID, user.ID)
|
||||
//log.Printf("The profile post '%d' was deleted by c.User #%d", reply.ID, u.ID)
|
||||
|
||||
if !js {
|
||||
//http.Redirect(w,r, "/user/" + strconv.Itoa(creator.ID), http.StatusSeeOther)
|
||||
|
@ -131,7 +136,7 @@ func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.Us
|
|||
w.Write(successJSONBytes)
|
||||
}
|
||||
|
||||
err = c.ModLogs.Create("delete", reply.ParentID, "profile-reply", user.GetIP(), user.ID)
|
||||
err = c.ModLogs.Create("delete", reply.ParentID, "profile-reply", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
|
|
@ -9,46 +9,46 @@ import (
|
|||
c "github.com/Azareal/Gosora/common"
|
||||
)
|
||||
|
||||
func BanUserSubmit(w http.ResponseWriter, r *http.Request, user *c.User, suid string) c.RouteError {
|
||||
if !user.Perms.BanUsers {
|
||||
return c.NoPermissions(w, r, user)
|
||||
func BanUserSubmit(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError {
|
||||
if !u.Perms.BanUsers {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
uid, err := strconv.Atoi(suid)
|
||||
if err != nil {
|
||||
return c.LocalError("The provided UserID is not a valid number.", w, r, user)
|
||||
return c.LocalError("The provided UserID is not a valid number.", w, r, u)
|
||||
}
|
||||
if uid == -2 {
|
||||
return c.LocalError("Why don't you like Merlin?", w, r, user)
|
||||
return c.LocalError("Why don't you like Merlin?", w, r, u)
|
||||
}
|
||||
|
||||
targetUser, err := c.Users.Get(uid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to ban no longer exists.", w, r, user)
|
||||
return c.LocalError("The user you're trying to ban no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
// TODO: Is there a difference between IsMod and IsSuperMod? Should we delete the redundant one?
|
||||
if targetUser.IsMod {
|
||||
return c.LocalError("You may not ban another staff member.", w, r, user)
|
||||
return c.LocalError("You may not ban another staff member.", w, r, u)
|
||||
}
|
||||
if uid == user.ID {
|
||||
return c.LocalError("Why are you trying to ban yourself? Stop that.", w, r, user)
|
||||
if uid == u.ID {
|
||||
return c.LocalError("Why are you trying to ban yourself? Stop that.", w, r, u)
|
||||
}
|
||||
if targetUser.IsBanned {
|
||||
return c.LocalError("The user you're trying to unban is already banned.", w, r, user)
|
||||
return c.LocalError("The user you're trying to unban is already banned.", w, r, u)
|
||||
}
|
||||
|
||||
durDays, err := strconv.Atoi(r.FormValue("dur-days"))
|
||||
if err != nil {
|
||||
return c.LocalError("You can only use whole numbers for the number of days", w, r, user)
|
||||
return c.LocalError("You can only use whole numbers for the number of days", w, r, u)
|
||||
}
|
||||
durWeeks, err := strconv.Atoi(r.FormValue("dur-weeks"))
|
||||
if err != nil {
|
||||
return c.LocalError("You can only use whole numbers for the number of weeks", w, r, user)
|
||||
return c.LocalError("You can only use whole numbers for the number of weeks", w, r, u)
|
||||
}
|
||||
durMonths, err := strconv.Atoi(r.FormValue("dur-months"))
|
||||
if err != nil {
|
||||
return c.LocalError("You can only use whole numbers for the number of months", w, r, user)
|
||||
return c.LocalError("You can only use whole numbers for the number of months", w, r, u)
|
||||
}
|
||||
deletePosts := false
|
||||
switch r.FormValue("delete-posts") {
|
||||
|
@ -67,13 +67,13 @@ func BanUserSubmit(w http.ResponseWriter, r *http.Request, user *c.User, suid st
|
|||
dur, _ = time.ParseDuration(strconv.Itoa(secs) + "s")
|
||||
}
|
||||
|
||||
err = targetUser.Ban(dur, user.ID)
|
||||
err = targetUser.Ban(dur, u.ID)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to ban no longer exists.", w, r, user)
|
||||
return c.LocalError("The user you're trying to ban no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.ModLogs.Create("ban", uid, "user", user.GetIP(), user.ID)
|
||||
err = c.ModLogs.Create("ban", uid, "user", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -81,11 +81,11 @@ func BanUserSubmit(w http.ResponseWriter, r *http.Request, user *c.User, suid st
|
|||
if deletePosts {
|
||||
err = targetUser.DeletePosts()
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to ban no longer exists.", w, r, user)
|
||||
return c.LocalError("The user you're trying to ban no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.ModLogs.Create("delete-posts", uid, "user", user.GetIP(), user.ID)
|
||||
err = c.ModLogs.Create("delete-posts", uid, "user", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func BanUserSubmit(w http.ResponseWriter, r *http.Request, user *c.User, suid st
|
|||
|
||||
// TODO: Trickle the hookTable down from the router
|
||||
hTbl := c.GetHookTable()
|
||||
skip, rerr := hTbl.VhookSkippable("action_end_ban_user", targetUser.ID, user)
|
||||
skip, rerr := hTbl.VhookSkippable("action_end_ban_user", targetUser.ID, u)
|
||||
if skip || rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
|
@ -102,42 +102,42 @@ func BanUserSubmit(w http.ResponseWriter, r *http.Request, user *c.User, suid st
|
|||
return nil
|
||||
}
|
||||
|
||||
func UnbanUser(w http.ResponseWriter, r *http.Request, user *c.User, suid string) c.RouteError {
|
||||
if !user.Perms.BanUsers {
|
||||
return c.NoPermissions(w, r, user)
|
||||
func UnbanUser(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError {
|
||||
if !u.Perms.BanUsers {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
uid, err := strconv.Atoi(suid)
|
||||
if err != nil {
|
||||
return c.LocalError("The provided UserID is not a valid number.", w, r, user)
|
||||
return c.LocalError("The provided UserID is not a valid number.", w, r, u)
|
||||
}
|
||||
|
||||
targetUser, err := c.Users.Get(uid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to unban no longer exists.", w, r, user)
|
||||
return c.LocalError("The user you're trying to unban no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if !targetUser.IsBanned {
|
||||
return c.LocalError("The user you're trying to unban isn't banned.", w, r, user)
|
||||
return c.LocalError("The user you're trying to unban isn't banned.", w, r, u)
|
||||
}
|
||||
|
||||
err = targetUser.Unban()
|
||||
if err == c.ErrNoTempGroup {
|
||||
return c.LocalError("The user you're trying to unban is not banned", w, r, user)
|
||||
return c.LocalError("The user you're trying to unban is not banned", w, r, u)
|
||||
} else if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to unban no longer exists.", w, r, user)
|
||||
return c.LocalError("The user you're trying to unban no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
err = c.ModLogs.Create("unban", uid, "user", user.GetIP(), user.ID)
|
||||
err = c.ModLogs.Create("unban", uid, "user", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
// TODO: Trickle the hookTable down from the router
|
||||
hTbl := c.GetHookTable()
|
||||
skip, rerr := hTbl.VhookSkippable("action_end_unban_user", targetUser.ID, user)
|
||||
skip, rerr := hTbl.VhookSkippable("action_end_unban_user", targetUser.ID, u)
|
||||
if skip || rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
|
@ -146,23 +146,23 @@ func UnbanUser(w http.ResponseWriter, r *http.Request, user *c.User, suid string
|
|||
return nil
|
||||
}
|
||||
|
||||
func ActivateUser(w http.ResponseWriter, r *http.Request, user *c.User, suid string) c.RouteError {
|
||||
if !user.Perms.ActivateUsers {
|
||||
return c.NoPermissions(w, r, user)
|
||||
func ActivateUser(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError {
|
||||
if !u.Perms.ActivateUsers {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
uid, err := strconv.Atoi(suid)
|
||||
if err != nil {
|
||||
return c.LocalError("The provided UserID is not a valid number.", w, r, user)
|
||||
return c.LocalError("The provided UserID is not a valid number.", w, r, u)
|
||||
}
|
||||
|
||||
targetUser, err := c.Users.Get(uid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The account you're trying to activate no longer exists.", w, r, user)
|
||||
return c.LocalError("The account you're trying to activate no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if targetUser.Active {
|
||||
return c.LocalError("The account you're trying to activate has already been activated.", w, r, user)
|
||||
return c.LocalError("The account you're trying to activate has already been activated.", w, r, u)
|
||||
}
|
||||
err = targetUser.Activate()
|
||||
if err != nil {
|
||||
|
@ -171,7 +171,7 @@ func ActivateUser(w http.ResponseWriter, r *http.Request, user *c.User, suid str
|
|||
|
||||
targetUser, err = c.Users.Get(uid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The account you're trying to activate no longer exists.", w, r, user)
|
||||
return c.LocalError("The account you're trying to activate no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -181,14 +181,14 @@ func ActivateUser(w http.ResponseWriter, r *http.Request, user *c.User, suid str
|
|||
}
|
||||
targetUser.CacheRemove()
|
||||
|
||||
err = c.ModLogs.Create("activate", targetUser.ID, "user", user.GetIP(), user.ID)
|
||||
err = c.ModLogs.Create("activate", targetUser.ID, "user", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
// TODO: Trickle the hookTable down from the router
|
||||
hTbl := c.GetHookTable()
|
||||
skip, rerr := hTbl.VhookSkippable("action_end_activate_user", targetUser.ID, user)
|
||||
skip, rerr := hTbl.VhookSkippable("action_end_activate_user", targetUser.ID, u)
|
||||
if skip || rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
|
@ -197,40 +197,40 @@ func ActivateUser(w http.ResponseWriter, r *http.Request, user *c.User, suid str
|
|||
return nil
|
||||
}
|
||||
|
||||
func DeletePostsSubmit(w http.ResponseWriter, r *http.Request, user *c.User, suid string) c.RouteError {
|
||||
if !user.Perms.BanUsers {
|
||||
return c.NoPermissions(w, r, user)
|
||||
func DeletePostsSubmit(w http.ResponseWriter, r *http.Request, u *c.User, suid string) c.RouteError {
|
||||
if !u.Perms.BanUsers {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
uid, err := strconv.Atoi(suid)
|
||||
if err != nil {
|
||||
return c.LocalError("The provided UserID is not a valid number.", w, r, user)
|
||||
return c.LocalError("The provided UserID is not a valid number.", w, r, u)
|
||||
}
|
||||
|
||||
targetUser, err := c.Users.Get(uid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to purge posts of no longer exists.", w, r, user)
|
||||
return c.LocalError("The user you're trying to purge posts of no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
// TODO: Is there a difference between IsMod and IsSuperMod? Should we delete the redundant one?
|
||||
if targetUser.IsMod {
|
||||
return c.LocalError("You may not purge the posts of another staff member.", w, r, user)
|
||||
return c.LocalError("You may not purge the posts of another staff member.", w, r, u)
|
||||
}
|
||||
|
||||
err = targetUser.DeletePosts()
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The user you're trying to purge posts of no longer exists.", w, r, user)
|
||||
return c.LocalError("The user you're trying to purge posts of no longer exists.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.ModLogs.Create("delete-posts", uid, "user", user.GetIP(), user.ID)
|
||||
err = c.ModLogs.Create("delete-posts", uid, "user", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
// TODO: Trickle the hookTable down from the router
|
||||
hTbl := c.GetHookTable()
|
||||
skip, rerr := hTbl.VhookSkippable("action_end_delete_posts", targetUser.ID, user)
|
||||
skip, rerr := hTbl.VhookSkippable("action_end_delete_posts", targetUser.ID, u)
|
||||
if skip || rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
CREATE TABLE `login_logs` (
|
||||
`lid` int not null AUTO_INCREMENT,
|
||||
`uid` int not null,
|
||||
`success` bool DEFAULT 0 not null,
|
||||
`success` boolean DEFAULT 0 not null,
|
||||
`ipaddress` varchar(200) not null,
|
||||
`doneAt` datetime not null,
|
||||
primary key(`lid`)
|
||||
|
|
|
@ -3,7 +3,7 @@ CREATE TABLE `registration_logs` (
|
|||
`username` varchar(100) not null,
|
||||
`email` varchar(100) not null,
|
||||
`failureReason` varchar(100) not null,
|
||||
`success` bool DEFAULT 0 not null,
|
||||
`success` boolean DEFAULT 0 not null,
|
||||
`ipaddress` varchar(200) not null,
|
||||
`doneAt` datetime not null,
|
||||
primary key(`rlid`)
|
||||
|
|
|
@ -10,6 +10,8 @@ CREATE TABLE `users` (
|
|||
`lastActiveAt` datetime not null,
|
||||
`session` varchar(200) DEFAULT '' not null,
|
||||
`last_ip` varchar(200) DEFAULT '' not null,
|
||||
`profile_comments` int DEFAULT 0 not null,
|
||||
`who_can_convo` int DEFAULT 0 not null,
|
||||
`enable_embeds` int DEFAULT -1 not null,
|
||||
`email` varchar(200) DEFAULT '' not null,
|
||||
`avatar` varchar(100) DEFAULT '' not null,
|
||||
|
|
|
@ -2,6 +2,6 @@ CREATE TABLE "forums_permissions" (
|
|||
`fid` int not null,
|
||||
`gid` int not null,
|
||||
`preset` varchar (100) DEFAULT '' not null,
|
||||
`permissions` text not null,
|
||||
`permissions` text DEFAULT '{}' not null,
|
||||
primary key(`fid`,`gid`)
|
||||
);
|
|
@ -1,7 +1,7 @@
|
|||
CREATE TABLE "login_logs" (
|
||||
`lid` serial not null,
|
||||
`uid` int not null,
|
||||
`success` bool DEFAULT 0 not null,
|
||||
`success` boolean DEFAULT 0 not null,
|
||||
`ipaddress` varchar (200) not null,
|
||||
`doneAt` timestamp not null,
|
||||
primary key(`lid`)
|
||||
|
|
|
@ -3,7 +3,7 @@ CREATE TABLE "registration_logs" (
|
|||
`username` varchar (100) not null,
|
||||
`email` varchar (100) not null,
|
||||
`failureReason` varchar (100) not null,
|
||||
`success` bool DEFAULT 0 not null,
|
||||
`success` boolean DEFAULT 0 not null,
|
||||
`ipaddress` varchar (200) not null,
|
||||
`doneAt` timestamp not null,
|
||||
primary key(`rlid`)
|
||||
|
|
|
@ -3,17 +3,18 @@
|
|||
</div>
|
||||
<div class="colstack_item the_form">
|
||||
<form action="/user/edit/privacy/submit/?s={{.CurrentUser.Session}}" method="post">
|
||||
<!--<input name="o_profile_comments" value="{{if .ProfileComments}}1{{else}}0{{end}}" type="hidden">
|
||||
<input name="o_receive_convos" value="{{if .ReceiveConvos}}1{{else}}0{{end}}" type="hidden">-->
|
||||
<input name="o_profile_comments" value="{{.ProfileComments}}" type="hidden">
|
||||
<!--<input name="o_receive_convos" value="{{if .ReceiveConvos}}1{{else}}0{{end}}" type="hidden">-->
|
||||
<input name="o_enable_embeds" value="{{if .EnableEmbeds}}1{{else}}0{{end}}" type="hidden">
|
||||
<!--<div class="formrow real_first_child">
|
||||
<div class="formrow real_first_child">
|
||||
<div class="formitem formlabel">{{lang "account_privacy_profile_comments"}}</div>
|
||||
<div class="formitem"><select name="profile_comments">
|
||||
<option{{if .ProfileComments}} selected{{end}} value=1>{{lang "option_yes"}}</option>
|
||||
<option{{if not .ProfileComments}} selected{{end}} value=0>{{lang "option_no"}}</option>
|
||||
<option{{if eq .ProfileComments 1}} selected{{end}} value=1>{{lang "account_privacy_profile_comments_public"}}</option>
|
||||
<option{{if eq .ProfileComments 2}} selected{{end}} value=2>{{lang "account_privacy_profile_comments_registered"}}</option>
|
||||
<option{{if eq .ProfileComments 4}} selected{{end}} value=4>{{lang "account_privacy_profile_comments_self"}}</option>
|
||||
</select></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<!--<div class="formrow">
|
||||
<div class="formitem formlabel"><a>Receive Conversations</a></div>
|
||||
<div class="formitem"><select name="receive_convos">
|
||||
<option{{if .ReceiveConvos}} selected{{end}} value=1>{{lang "option_yes"}}</option>
|
||||
|
@ -21,7 +22,7 @@
|
|||
</select></div>
|
||||
</div>-->
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>Enable Embeds</a></div>
|
||||
<div class="formitem formlabel"><a>{{lang "account_privacy_enable_embeds"}}</a></div>
|
||||
<div class="formitem"><select name="enable_embeds">
|
||||
<option{{if .EnableEmbeds}} selected{{end}} value=1>{{lang "option_yes"}}</option>
|
||||
<option{{if not .EnableEmbeds}} selected{{end}} value=0>{{lang "option_no"}}</option>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{template "header.html" . }}
|
||||
<main id="forumItemList" itemscope itemtype="http://schema.org/ItemList">
|
||||
<link rel="canonical" href="//{{.Site.URL}}{{.Forum.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}"/>
|
||||
<main id="forumItemList"itemscope itemtype="http://schema.org/ItemList">
|
||||
<link rel="canonical"href="//{{.Site.URL}}{{.Forum.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}">
|
||||
|
||||
<div id="forum_head_block" class="rowblock rowhead topic_list_title_block{{if .CurrentUser.Loggedin}} has_opt{{end}}">
|
||||
<div id="forum_head_block"class="rowblock rowhead topic_list_title_block{{if .CurrentUser.Loggedin}} has_opt{{end}}">
|
||||
<div class="rowitem forum_title">
|
||||
<h1 itemprop="name">{{.Title}}</h1>
|
||||
</div>
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_active_memory_head"}}</h1>
|
||||
<select form="timeRangeForm" class="typeSelector to_right autoSubmitRedirect" name="mtype">
|
||||
<option value="0"{{if eq .MemType 0}} selected{{end}}>{{lang "panel_stats_memory_type_total"}}</option>
|
||||
<option value="1"{{if eq .MemType 1}} selected{{end}}>{{lang "panel_stats_memory_type_stack"}}</option>
|
||||
<option value="2"{{if eq .MemType 2}} selected{{end}}>{{lang "panel_stats_memory_type_heap"}}</option>
|
||||
<select form="timeRangeForm"class="typeSelector to_right autoSubmitRedirect"name="mtype">
|
||||
<option value="0"{{if eq .MemType 0}}selected{{end}}>{{lang "panel_stats_memory_type_total"}}</option>
|
||||
<option value="1"{{if eq .MemType 1}}selected{{end}}>{{lang "panel_stats_memory_type_stack"}}</option>
|
||||
<option value="2"{{if eq .MemType 2}}selected{{end}}>{{lang "panel_stats_memory_type_heap"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit"></noscript>
|
||||
<noscript><input form="timeRangeForm"type="submit"></noscript>
|
||||
{{template "panel_analytics_time_range_month.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/active-memory/" method="get"></form>
|
||||
<div id="panel_analytics_memory" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_memory_chart_aria"}}"></div>
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/active-memory/"method="get"></form>
|
||||
<div id="panel_analytics_memory"class="colstack_graph_holder">
|
||||
<div class="ct_chart"aria-label="{{lang "panel_stats_memory_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_memory_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_memory_table_aria"}}">
|
||||
<div id="panel_analytics_memory_table"class="colstack_item rowlist"aria-label="{{lang "panel_stats_memory_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_to_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}24_hour_time{{else}}date{{end}}">{{.Time}}</a>
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
{{template "panel_analytics_time_range_month.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/memory/" method="get"></form>
|
||||
<div id="panel_analytics_memory" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_memory_chart_aria"}}"></div>
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/memory/"method="get"></form>
|
||||
<div id="panel_analytics_memory"class="colstack_graph_holder">
|
||||
<div class="ct_chart"aria-label="{{lang "panel_stats_memory_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_memory_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_memory_table_aria"}}">
|
||||
<div id="panel_analytics_memory_table"class="colstack_item rowlist"aria-label="{{lang "panel_stats_memory_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}to_24_hour_time{{else}}to_date{{end}}">{{.Time}}</a>
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_perf_head"}}</h1>
|
||||
<select form="timeRangeForm" class="typeSelector to_right autoSubmitRedirect" name="type">
|
||||
<option value="0"{{if eq .PerfType 0}} selected{{end}}>{{lang "panel_stats_perf_low"}}</option>
|
||||
<option value="1"{{if eq .PerfType 1}} selected{{end}}>{{lang "panel_stats_perf_high"}}</option>
|
||||
<option value="2"{{if eq .PerfType 2}} selected{{end}}>{{lang "panel_stats_perf_avg"}}</option>
|
||||
<select form="timeRangeForm"class="typeSelector to_right autoSubmitRedirect" name="type">
|
||||
<option value="0"{{if eq .PerfType 0}}selected{{end}}>{{lang "panel_stats_perf_low"}}</option>
|
||||
<option value="1"{{if eq .PerfType 1}}selected{{end}}>{{lang "panel_stats_perf_high"}}</option>
|
||||
<option value="2"{{if eq .PerfType 2}}selected{{end}}>{{lang "panel_stats_perf_avg"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit"></noscript>
|
||||
<noscript><input form="timeRangeForm"type="submit"></noscript>
|
||||
{{template "panel_analytics_time_range_month.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/perf/" method="get"></form>
|
||||
<div id="panel_analytics_memory" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_perf_chart_aria"}}"></div>
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/perf/" method="get"></form>
|
||||
<div id="panel_analytics_memory"class="colstack_graph_holder">
|
||||
<div class="ct_chart"aria-label="{{lang "panel_stats_perf_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_perf_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_perf_table_aria"}}">
|
||||
<div id="panel_analytics_perf_table"class="colstack_item rowlist"aria-label="{{lang "panel_stats_perf_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_to_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}24_hour_time{{else}}date{{end}}">{{.Time}}</a>
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/posts/" method="get"></form>
|
||||
<div id="panel_analytics_posts" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_post_counts_chart_aria"}}"></div>
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/posts/"method="get"></form>
|
||||
<div id="panel_analytics_posts"class="colstack_graph_holder">
|
||||
<div class="ct_chart"aria-label="{{lang "panel_stats_post_counts_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_posts_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_post_counts_table_aria"}}">
|
||||
<div id="panel_analytics_posts_table"class="colstack_item rowlist"aria-label="{{lang "panel_stats_post_counts_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}to_24_hour_time{{else}}to_date{{end}}">{{.Time}}</a>
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/referrer/{{.Agent}}" method="get"></form>
|
||||
<div id="panel_analytics_referrers" class="colstack_graph_holder">
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/referrer/{{.Agent}}"method="get"></form>
|
||||
<div id="panel_analytics_referrers"class="colstack_graph_holder">
|
||||
<div class="ct_chart"></div>
|
||||
</div>
|
||||
{{template "panel_analytics_script.html" . }}
|
|
@ -1,19 +1,19 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_referrers_head"}}</h1>
|
||||
<select form="timeRangeForm" class="spamSelector to_right autoSubmitRedirect" name="spam">
|
||||
<option value="0"{{if not .ShowSpam}} selected{{end}}>{{lang "panel_stats_spam_hide"}}</option>
|
||||
<option value="1"{{if .ShowSpam}} selected{{end}}>{{lang "panel_stats_spam_show"}}</option>
|
||||
<select form="timeRangeForm"class="spamSelector to_right autoSubmitRedirect"name="spam">
|
||||
<option value="0"{{if not .ShowSpam}}selected{{end}}>{{lang "panel_stats_spam_hide"}}</option>
|
||||
<option value="1"{{if .ShowSpam}}selected{{end}}>{{lang "panel_stats_spam_show"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit"></noscript>
|
||||
<noscript><input form="timeRangeForm"type="submit"></noscript>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/referrers/" method="get"></form>
|
||||
<div id="panel_analytics_referrers" class="colstack_item rowlist">
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/referrers/"method="get"></form>
|
||||
<div id="panel_analytics_referrers"class="colstack_item rowlist">
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/referrer/{{.Agent}}" class="panel_upshift">{{.Agent}}</a>
|
||||
<a href="/panel/analytics/referrer/{{.Agent}}"class="panel_upshift">{{.Agent}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_referrers_no_referrers"}}</div>{{end}}
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/route/{{.Route}}" method="get"></form>
|
||||
<div id="panel_analytics_views" class="colstack_graph_holder">
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/route/{{.Route}}"method="get"></form>
|
||||
<div id="panel_analytics_views"class="colstack_graph_holder">
|
||||
<div class="ct_chart"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><a>{{lang "panel_stats_details_head"}}</a></div>
|
||||
</div>
|
||||
<div id="panel_analytics_views_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_route_views_table_aria"}}">
|
||||
<div id="panel_analytics_views_table"class="colstack_item rowlist"aria-label="{{lang "panel_stats_route_views_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_to_24_hour_time">{{.Time}}</a>
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/routes/" method="get"></form>
|
||||
<div id="panel_analytics_routes_chart" class="colstack_graph_holder">
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/routes/"method="get"></form>
|
||||
<div id="panel_analytics_routes_chart"class="colstack_graph_holder">
|
||||
<div class="ct_chart"></div>
|
||||
</div>
|
||||
<div id="panel_analytics_routes" class="colstack_item rowlist">
|
||||
<div id="panel_analytics_routes"class="colstack_item rowlist">
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/route/{{.Route}}" class="panel_upshift">{{.Route}}</a>
|
||||
<a href="/panel/analytics/route/{{.Route}}"class="panel_upshift">{{.Route}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_routes_no_routes"}}</div>{{end}}
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/routes-perf/" method="get"></form>
|
||||
<div id="panel_analytics_routes_chart" class="colstack_graph_holder">
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/routes-perf/"method="get"></form>
|
||||
<div id="panel_analytics_routes_chart"class="colstack_graph_holder">
|
||||
<div class="ct_chart"></div>
|
||||
</div>
|
||||
<div id="panel_analytics_routes" class="colstack_item rowlist">
|
||||
<div id="panel_analytics_routes"class="colstack_item rowlist">
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/route/{{.Route}}" class="panel_upshift">{{.Route}}</a>
|
||||
<a href="/panel/analytics/route/{{.Route}}"class="panel_upshift">{{.Route}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{.Unit}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_routes_no_routes"}}</div>{{end}}
|
||||
|
|
|
@ -13,7 +13,7 @@ let legendNames = [{{range .Graph.Legends}}
|
|||
addInitHook("after_phrases", () => {
|
||||
addInitHook("end_init", () => {
|
||||
addInitHook("analytics_loaded", () => {
|
||||
buildStatsChart(rawLabels, seriesData, "{{.TimeRange}}",legendNames);
|
||||
buildStatsChart(rawLabels,seriesData,"{{.TimeRange}}",legendNames);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,8 +13,8 @@ let legendNames = [{{range .Graph.Legends}}
|
|||
addInitHook("after_phrases", () => {
|
||||
addInitHook("end_init", () => {
|
||||
addInitHook("analytics_loaded", () => {
|
||||
memStuff(window, document, Chartist);
|
||||
buildStatsChart(rawLabels, seriesData, "{{.TimeRange}}",legendNames,1);
|
||||
memStuff(window,document,Chartist);
|
||||
buildStatsChart(rawLabels,seriesData,"{{.TimeRange}}",legendNames,1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,8 +13,8 @@ let legendNames = [{{range .Graph.Legends}}
|
|||
addInitHook("after_phrases", () => {
|
||||
addInitHook("end_init", () => {
|
||||
addInitHook("analytics_loaded", () => {
|
||||
perfStuff(window, document, Chartist);
|
||||
buildStatsChart(rawLabels, seriesData, "{{.TimeRange}}",legendNames,2);
|
||||
perfStuff(window,document,Chartist);
|
||||
buildStatsChart(rawLabels,seriesData,"{{.TimeRange}}",legendNames,2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/system/{{.Agent}}" method="get"></form>
|
||||
<div id="panel_analytics_systems" class="colstack_graph_holder">
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/system/{{.Agent}}"method="get"></form>
|
||||
<div id="panel_analytics_systems"class="colstack_graph_holder">
|
||||
<div class="ct_chart"></div>
|
||||
</div>
|
||||
{{template "panel_analytics_script.html" . }}
|
|
@ -4,14 +4,14 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/systems/" method="get"></form>
|
||||
<div id="panel_analytics_systems_chart" class="colstack_graph_holder">
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/systems/"method="get"></form>
|
||||
<div id="panel_analytics_systems_chart"class="colstack_graph_holder">
|
||||
<div class="ct_chart"></div>
|
||||
</div>
|
||||
<div id="panel_analytics_systems" class="colstack_item rowlist">
|
||||
<div id="panel_analytics_systems"class="colstack_item rowlist">
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/system/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
||||
<a href="/panel/analytics/system/{{.Agent}}"class="panel_upshift">{{.FriendlyAgent}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_operating_systems_no_operating_systems"}}</div>{{end}}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<select form="timeRangeForm" class="timeRangeSelector to_right autoSubmitRedirect" name="timeRange">
|
||||
<option value="one-month"{{if eq .TimeRange "one-month"}} selected{{end}}>{{lang "panel_stats_time_range_one_month"}}</option>
|
||||
<option value="one-week"{{if eq .TimeRange "one-week"}} selected{{end}}>{{lang "panel_stats_time_range_one_week"}}</option>
|
||||
<option value="two-days"{{if eq .TimeRange "two-days"}} selected{{end}}>{{lang "panel_stats_time_range_two_days"}}</option>
|
||||
<option value="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>{{lang "panel_stats_time_range_one_day"}}</option>
|
||||
<option value="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>{{lang "panel_stats_time_range_twelve_hours"}}</option>
|
||||
<option value="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>{{lang "panel_stats_time_range_six_hours"}}</option>
|
||||
<select form="timeRangeForm"class="timeRangeSelector to_right autoSubmitRedirect"sname="timeRange">
|
||||
<option value="one-month"{{if eq .TimeRange "one-month"}}selected{{end}}>{{lang "panel_stats_time_range_one_month"}}</option>
|
||||
<option value="one-week"{{if eq .TimeRange "one-week"}}selected{{end}}>{{lang "panel_stats_time_range_one_week"}}</option>
|
||||
<option value="two-days"{{if eq .TimeRange "two-days"}}selected{{end}}>{{lang "panel_stats_time_range_two_days"}}</option>
|
||||
<option value="one-day"{{if eq .TimeRange "one-day"}}selected{{end}}>{{lang "panel_stats_time_range_one_day"}}</option>
|
||||
<option value="twelve-hours"{{if eq .TimeRange "twelve-hours"}}selected{{end}}>{{lang "panel_stats_time_range_twelve_hours"}}</option>
|
||||
<option value="six-hours"{{if eq .TimeRange "six-hours"}}selected{{end}}>{{lang "panel_stats_time_range_six_hours"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit"></noscript>
|
||||
<noscript><input form="timeRangeForm"type="submit"></noscript>
|
|
@ -4,16 +4,16 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/topics/" method="get"></form>
|
||||
<div id="panel_analytics_topics" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_topic_counts_chart_aria"}}"></div>
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/topics/"method="get"></form>
|
||||
<div id="panel_analytics_topics"class="colstack_graph_holder">
|
||||
<div class="ct_chart"aria-label="{{lang "panel_stats_topic_counts_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_topics_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_topic_counts_table_aria"}}">
|
||||
<div id="panel_analytics_topics_table"class="colstack_item rowlist"aria-label="{{lang "panel_stats_topic_counts_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_to_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}24_hour_time{{else}}date{{end}}">{{.Time}}</a>
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/views/" method="get"></form>
|
||||
<div id="panel_analytics_views" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_requests_chart_aria"}}"></div>
|
||||
<form id="timeRangeForm"name="timeRangeForm"action="/panel/analytics/views/"method="get"></form>
|
||||
<div id="panel_analytics_views"class="colstack_graph_holder">
|
||||
<div class="ct_chart"aria-label="{{lang "panel_stats_requests_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_views_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_requests_table_aria"}}">
|
||||
<div id="panel_analytics_views_table"class="colstack_item rowlist"aria-label="{{lang "panel_stats_requests_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_to_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}24_hour_time{{else}}date{{end}}">{{.Time}}</a>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>{{lang "panel_backups_head"}}</h1></div>
|
||||
</div>
|
||||
<div id="panel_backups" class="colstack_item rowlist">
|
||||
<div id="panel_backups"class="colstack_item rowlist">
|
||||
{{range .Backups}}
|
||||
<div class="rowitem panel_compactrow">
|
||||
<span>{{.SQLURL}}</span>
|
||||
<span class="panel_floater">
|
||||
<a href="/panel/backups/{{.SQLURL}}" class="panel_tag panel_right_button">{{lang "panel_backups_download"}}</a>
|
||||
<a href="/panel/backups/{{.SQLURL}}"class="panel_tag panel_right_button">{{lang "panel_backups_download"}}</a>
|
||||
</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem rowmsg">{{lang "panel_backups_no_backups"}}</div>{{end}}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>{{.Name}}{{lang "panel_forum_head_suffix"}}</h1></div>
|
||||
</div>
|
||||
<div id="panel_forum" class="colstack_item the_form">
|
||||
<div id="panel_forum"class="colstack_item the_form">
|
||||
<form action="/panel/forums/edit/submit/{{.ID}}?s={{.CurrentUser.Session}}" method="post">
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_forum_name"}}</a></div>
|
||||
<div class="formitem"><input name="forum_name" type="text" value="{{.Name}}" placeholder="{{lang "panel_forum_name_placeholder"}}"></div>
|
||||
<div class="formitem"><input name="forum_name"type="text"value="{{.Name}}"placeholder="{{lang "panel_forum_name_placeholder"}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_forum_description"}}</a></div>
|
||||
<div class="formitem"><input name="forum_desc" type="text" value="{{.Desc}}" placeholder="{{lang "panel_forum_description_placeholder"}}"></div>
|
||||
<div class="formitem"><input name="forum_desc"type="text"value="{{.Desc}}"placeholder="{{lang "panel_forum_description_placeholder"}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_forum_active"}}</a></div>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<div class="formitem">
|
||||
<select name="forum_preset">
|
||||
<option{{if eq .Preset "all"}} selected{{end}} value="all">{{lang "panel_preset_everyone"}}</option>
|
||||
<option{{if eq .Preset "announce"}} selected{{end}} value="announce">{{lang "panel_preset_announcements"}}</option>
|
||||
<option{{if eq .Preset "announce"}} selected{{end}} value="announce">{{lang "panel_preset_announcements"}}</option>
|
||||
<option{{if eq .Preset "members"}} selected{{end}} value="members">{{lang "panel_preset_member_only"}}</option>
|
||||
<option{{if eq .Preset "staff"}} selected{{end}} value="staff">{{lang "panel_preset_staff_only"}}</option>
|
||||
<option{{if eq .Preset "admins"}} selected{{end}} value="admins">{{lang "panel_preset_admin_only"}}</option>
|
||||
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">{{lang "panel_forum_update_button"}}</button></div>
|
||||
<div class="formitem"><button name="panel-button"class="formbutton form_middle_button">{{lang "panel_forum_update_button"}}</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -42,17 +42,17 @@
|
|||
<h1>{{lang "panel_forum_permissions_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="forum_quick_perms" class="colstack_item rowlist formlist the_form">
|
||||
<div id="forum_quick_perms"class="colstack_item rowlist formlist the_form">
|
||||
{{range .Groups}}
|
||||
<div class="formrow">
|
||||
<div class="formitem editable_parent">
|
||||
<a>{{.Group.Name}}</a>
|
||||
<input name="gid" value="{{.Group.ID}}" type="hidden" class="editable_block" data-field="gid" data-type="hidden" data-value="{{.Group.ID}}">
|
||||
<input name="gid"value="{{.Group.ID}}"type="hidden"class="editable_block"data-field="gid"data-type="hidden"data-value="{{.Group.ID}}">
|
||||
<span class="edit_fields hide_on_edit rowsmall">{{lang "panel_forum_edit_button"}}</span>
|
||||
<div class="panel_floater">
|
||||
<span data-field="perm_preset" data-type="list" data-value="{{.Preset}}" class="editable_block perm_preset perm_preset_{{.Preset}}"></span>
|
||||
<a class="panel_right_button has_inner_button show_on_edit" href="/panel/forums/edit/perms/submit/{{$.ID}}"><button class='panel_tag submit_edit' type='submit'>{{lang "panel_forum_short_update_button"}}</button></a>
|
||||
<a class="panel_right_button has_inner_button show_on_edit" href="/panel/forums/edit/perms/{{$.ID}}-{{.Group.ID}}"><button class='panel_tag' type='submit'>{{lang "panel_forum_full_edit_button"}}</button></a>
|
||||
<span data-field="perm_preset"data-type="list"data-value="{{.Preset}}" class="editable_block perm_preset perm_preset_{{.Preset}}"></span>
|
||||
<a class="panel_right_button has_inner_button show_on_edit"href="/panel/forums/edit/perms/submit/{{$.ID}}"><button class='panel_tag submit_edit'type='submit'>{{lang "panel_forum_short_update_button"}}</button></a>
|
||||
<a class="panel_right_button has_inner_button show_on_edit"href="/panel/forums/edit/perms/{{$.ID}}-{{.Group.ID}}"><button class='panel_tag'type='submit'>{{lang "panel_forum_full_edit_button"}}</button></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>{{.Name}}{{lang "panel_forum_head_suffix"}}</h1></div>
|
||||
</div>
|
||||
<form action="/panel/forums/edit/perms/adv/submit/{{.ForumID}}-{{.GroupID}}?s={{.CurrentUser.Session}}" method="post">
|
||||
<form action="/panel/forums/edit/perms/adv/submit/{{.ForumID}}-{{.GroupID}}?s={{.CurrentUser.Session}}"method="post">
|
||||
<div class="colstack_item rowlist formlist the_form panel_forum_perms">
|
||||
{{range .Perms}}
|
||||
<div class="formrow">
|
||||
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
</div>{{end}}
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">{{lang "panel_forum_update_button"}}</button></div>
|
||||
<div class="formitem"><button name="panel-button"class="formbutton form_middle_button">{{lang "panel_forum_update_button"}}</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -1,7 +1,7 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>{{lang "panel_logs_mod_head"}}</h1></div>
|
||||
</div>
|
||||
<div id="panel_modlogs" class="colstack_item rowlist loglist">
|
||||
<div id="panel_modlogs"class="colstack_item rowlist loglist">
|
||||
{{range .Logs}}
|
||||
<div class="rowitem panel_compactrow">
|
||||
<span class="to_left">
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<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">
|
||||
<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 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 class="formitem"><input name="title"type="text"value="{{.Page.Title}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem">
|
||||
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="panel-button" class="formbutton">{{lang "panel_pages_edit_update_button"}}</button></div>
|
||||
<div class="formitem"><button name="panel-button"class="formbutton">{{lang "panel_pages_edit_update_button"}}</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -1,20 +1,20 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>{{lang "panel_plugins_head"}}</h1></div>
|
||||
</div>
|
||||
<div id="panel_plugins" class="colstack_item complex_rowlist">
|
||||
<div id="panel_plugins"class="colstack_item complex_rowlist">
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem editable_parent">
|
||||
<span class="panel_plugin_meta">
|
||||
<a {{if .URL}}href="{{.URL}}"{{end}}class="editable_block"class="panel_upshift">{{.Name}}</a><br>
|
||||
<a{{if .URL}} href="{{.URL}}"{{end}}class="editable_block"class="panel_upshift">{{.Name}}</a><br>
|
||||
<small style="margin-left:2px;">{{lang "panel_plugins_author_prefix"}}{{.Author}}</small>
|
||||
</span>
|
||||
<span class="to_right">
|
||||
{{if .Settings}}<a href="/panel/settings/" class="panel_tag panel_plugin_settings panel_right_button">{{lang "panel_plugins_settings"}}</a>{{end}}
|
||||
{{if .Active}}<a href="/panel/plugins/deactivate/{{.UName}}?s={{$.CurrentUser.Session}}" class="panel_tag panel_plugin_deactivate panel_right_button">{{lang "panel_plugins_deactivate"}}</a>
|
||||
{{if .Settings}}<a href="/panel/settings/"class="panel_tag panel_plugin_settings panel_right_button">{{lang "panel_plugins_settings"}}</a>{{end}}
|
||||
{{if .Active}}<a href="/panel/plugins/deactivate/{{.UName}}?s={{$.CurrentUser.Session}}"class="panel_tag panel_plugin_deactivate panel_right_button">{{lang "panel_plugins_deactivate"}}</a>
|
||||
{{else if .Installable}}
|
||||
{{/** TODO: Write a custom template interpreter to fix this nonsense **/}}
|
||||
{{if .Installed}}<a href="/panel/plugins/activate/{{.UName}}?s={{$.CurrentUser.Session}}" class="panel_tag panel_plugin_activate panel_right_button">{{lang "panel_plugins_activate"}}</a>{{else}}<a href="/panel/plugins/install/{{.UName}}?s={{$.CurrentUser.Session}}" class="panel_tag panel_plugin_install panel_right_button">{{lang "panel_plugins_install"}}</a>{{end}}
|
||||
{{else}}<a href="/panel/plugins/activate/{{.UName}}?s={{$.CurrentUser.Session}}" class="panel_tag panel_plugin_activate panel_right_button">{{lang "panel_plugins_activate"}}</a>{{end}}
|
||||
{{if .Installed}}<a href="/panel/plugins/activate/{{.UName}}?s={{$.CurrentUser.Session}}"class="panel_tag panel_plugin_activate panel_right_button">{{lang "panel_plugins_activate"}}</a>{{else}}<a href="/panel/plugins/install/{{.UName}}?s={{$.CurrentUser.Session}}"class="panel_tag panel_plugin_install panel_right_button">{{lang "panel_plugins_install"}}</a>{{end}}
|
||||
{{else}}<a href="/panel/plugins/activate/{{.UName}}?s={{$.CurrentUser.Session}}"class="panel_tag panel_plugin_activate panel_right_button">{{lang "panel_plugins_activate"}}</a>{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
<h2 class="hguide">{{lang "panel_hints_reorder"}}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_menu_item_holder" class="colstack_item rowlist">
|
||||
<div id="panel_menu_item_holder"class="colstack_item rowlist">
|
||||
{{range .ItemList}}
|
||||
<div class="panel_menu_item rowitem panel_compactrow editable_parent" data-miid="{{.ID}}">
|
||||
<div class="panel_menu_item rowitem panel_compactrow editable_parent"data-miid="{{.ID}}">
|
||||
<span class="grip"></span>
|
||||
<a href="/panel/themes/menus/item/edit/{{.ID}}" class="editable_block panel_upshift">{{.Name}}</a>
|
||||
<a href="/panel/themes/menus/item/edit/{{.ID}}"class="editable_block panel_upshift">{{.Name}}</a>
|
||||
<span class="panel_buttons">
|
||||
<a href="/panel/themes/menus/item/edit/{{.ID}}" class="panel_tag panel_right_button edit_button" aria-label="{{lang "panel_themes_menus_items_edit_button_aria"}}"></a>
|
||||
<a href="/panel/themes/menus/item/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="panel_tag panel_right_button delete_button" aria-label="{{lang "panel_themes_menus_items_delete_button_aria"}}"></a>
|
||||
<a href="/panel/themes/menus/item/edit/{{.ID}}"class="panel_tag panel_right_button edit_button"aria-label="{{lang "panel_themes_menus_items_edit_button_aria"}}"></a>
|
||||
<a href="/panel/themes/menus/item/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}"class="panel_tag panel_right_button delete_button"aria-label="{{lang "panel_themes_menus_items_delete_button_aria"}}"></a>
|
||||
</span>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
|
@ -21,9 +21,9 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>{{lang "panel_themes_menus_create_head"}}</h1></div>
|
||||
</div>
|
||||
<form action="/panel/themes/menus/item/create/submit/?s={{.CurrentUser.Session}}" method="post">
|
||||
<input name="mid" value="{{.MenuID}}" type="hidden">
|
||||
<div id="panel_themes_menu_item_create" class="colstack_item the_form">
|
||||
<form action="/panel/themes/menus/item/create/submit/?s={{.CurrentUser.Session}}"method="post">
|
||||
<input name="mid"value="{{.MenuID}}"type="hidden">
|
||||
<div id="panel_themes_menu_item_create"class="colstack_item the_form">
|
||||
{{/** TODO: Let an admin move a menu item from one menu to another? **/}}
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_name"}}</a></div>
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
{{if .CurrentUser.Loggedin}}
|
||||
{{if .CurrentUser.Perms.BanUsers}}
|
||||
<!-- TODO: Inline the display:none; CSS -->
|
||||
<div id="ban_user_head"class="colstack_item colstack_head hash_hide ban_user_hash" style="display:none;">
|
||||
<div id="ban_user_head"class="colstack_item colstack_head hash_hide ban_user_hash"style="display:none;">
|
||||
<div class="rowitem"><h1><a>{{lang "profile.ban_user_head"}}</a></h1></div>
|
||||
</div>
|
||||
<form id="ban_user_form"class="hash_hide ban_user_hash"action="/users/ban/submit/{{.ProfileOwner.ID}}?s={{.CurrentUser.Session}}"method="post"style="display:none;">
|
||||
|
@ -120,8 +120,8 @@
|
|||
|
||||
<div id="profile_comments_head"class="colstack_item colstack_head hash_hide">
|
||||
<div class="rowitem"><h1><a>{{lang "profile.comments_head"}}</a></h1></div>
|
||||
</div>
|
||||
<div id="profile_comments"class="colstack_item hash_hide">{{template "profile_comments_row.html" . }}</div>
|
||||
</div>{{if .ShowComments}}
|
||||
<div id="profile_comments"class="colstack_item hash_hide">{{template "profile_comments_row.html" . }}</div>{{end}}
|
||||
|
||||
{{if .CurrentUser.Loggedin}}
|
||||
{{if .CanComment}}
|
||||
|
|
Loading…
Reference in New Issue