Fixed a bug where it would use the wrong templates for Tempra Simple, Tempra Cursive, and Shadow
Likes are now done over AJAX. Posts you have liked are now visually differentiated from those which you have not. Added support for OR to the where parser. || and && now get translated to OR and AND in the where parser. Added support for ( and ) in the where parser. Added an adapter and builder method for getting the database version. Multiple wheres can now be chained with the micro and accumulator builders. Added the In method to the accumulator select builder. Added the GetConn method to the builder. /uploads/ files should now get cached properly. Added more tooltips for topic titles and usernames. Fixed a bug in the runners where old stale templates would be served. Fixed a bug where liking topics didn't work. Began moving the database initialisation logic out of {adapter}.go and into querygen. Tweaked the alert direction to show the newest alerts rather than the oldest. Tweaked the WS JS to have it handle messages more efficiently. Partially fixed an issue where inline edited posts would lack newlines until the page is refreshed. Used arrow functions in a few places in global.js to save a few characters. Schema: Added the liked, oldestItemLikedCreatedAt and lastLiked columns to the users table. Added the createdAt column to the likes table. MySQL Update Queries: ALTER TABLE `users` ADD COLUMN `liked` INT NOT NULL DEFAULT '0' AFTER `topics`; ALTER TABLE `users` ADD COLUMN `oldestItemLikedCreatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `liked`; ALTER TABLE `users` ADD COLUMN `lastLiked` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `oldestItemLikedCreatedAt`; ALTER TABLE `likes` ADD COLUMN `createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `sentBy`; delete from `likes`; delete from `activity_stream` where `event` = 'like'; delete from `activity_stream_matches` where `asid` not in(select `asid` from `activity_stream`); update `topics` set `likeCount` = 0; update `replies` set `likeCount` = 0;
This commit is contained in:
parent
2b86a17478
commit
74e09efb63
|
@ -20,3 +20,4 @@ logs/*
|
|||
*.log
|
||||
.DS_Store
|
||||
.vscode/launch.json
|
||||
config.go
|
||||
|
|
|
@ -44,6 +44,11 @@ We recommend changing the root password (that is the password for the user 'root
|
|||
It's entirely possible that your host might already have MySQL, so you might be able to skip this step, particularly if it's a managed VPS or a shared host (contrary to popular belief, it is possible, although the ecosystem in this regard is extremely immature). Or they might have a quicker and easier method of setting up MySQL.
|
||||
|
||||
|
||||
# Downloading
|
||||
|
||||
At some point, we'll have releases which you can download, but right now, you'll have to use the `git clone` command as mentioned down in the advanced setup section to download a copy of Gosora.
|
||||
|
||||
|
||||
# Installation Instructions
|
||||
|
||||
*Linux*
|
||||
|
|
|
@ -1,2 +1,11 @@
|
|||
echo Building the templates
|
||||
gosora.exe -build-templates
|
||||
|
||||
echo Rebuilding the executable
|
||||
go build -o gosora.exe
|
||||
if %errorlevel% neq 0 (
|
||||
pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
pause
|
|
@ -104,6 +104,10 @@ func (reply *Reply) Like(uid int) (err error) {
|
|||
return err
|
||||
}
|
||||
_, err = replyStmts.addLikesToReply.Exec(1, reply.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = userStmts.incrementLiked.Exec(1, uid)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -132,10 +132,10 @@ func CompileTemplates() error {
|
|||
|
||||
// Schemas to train the template compiler on what to expect
|
||||
// TODO: Add support for interface{}s
|
||||
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, BuildAvatar(62, ""), "", "", "", "", 0, 0, "0.0.0.0.0", 0}
|
||||
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, BuildAvatar(62, ""), "", "", "", "", 0, 0, 0, "0.0.0.0.0", 0}
|
||||
// TODO: Do a more accurate level calculation for this?
|
||||
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, BuildAvatar(1, ""), "", "", "", "", 58, 1000, "127.0.0.1", 0}
|
||||
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, BuildAvatar(2, ""), "", "", "", "", 42, 900, "::1", 0}
|
||||
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, BuildAvatar(1, ""), "", "", "", "", 58, 1000, 0, "127.0.0.1", 0}
|
||||
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, BuildAvatar(2, ""), "", "", "", "", 42, 900, 0, "::1", 0}
|
||||
headerVars := &HeaderVars{
|
||||
Site: Site,
|
||||
Settings: SettingBox.Load().(SettingMap),
|
||||
|
@ -373,6 +373,10 @@ func InitTemplates() error {
|
|||
return GetTmplPhrase(phraseName) // TODO: Log non-existent phrases?
|
||||
}
|
||||
|
||||
fmap["scope"] = func(name interface{}) interface{} {
|
||||
return ""
|
||||
}
|
||||
|
||||
// The interpreted templates...
|
||||
DebugLog("Loading the template files...")
|
||||
Templates.Funcs(fmap)
|
||||
|
|
|
@ -90,6 +90,7 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
|||
"divide": true,
|
||||
"dock": true,
|
||||
"lang": true,
|
||||
"scope": true,
|
||||
}
|
||||
|
||||
c.importMap = map[string]string{
|
||||
|
@ -687,6 +688,9 @@ ArgLoop:
|
|||
out = "w.Write(phrases[" + strconv.Itoa(len(c.langIndexToName)-1) + "])\n"
|
||||
literal = true
|
||||
break ArgLoop
|
||||
case "scope":
|
||||
literal = true
|
||||
break ArgLoop
|
||||
default:
|
||||
c.detail("Variable!")
|
||||
if len(node.Args) > (pos + 1) {
|
||||
|
|
|
@ -141,7 +141,7 @@ func init() {
|
|||
stick: acc.Update("topics").Set("sticky = 1").Where("tid = ?").Prepare(),
|
||||
unstick: acc.Update("topics").Set("sticky = 0").Where("tid = ?").Prepare(),
|
||||
hasLikedTopic: acc.Select("likes").Columns("targetItem").Where("sentBy = ? and targetItem = ? and targetType = 'topics'").Prepare(),
|
||||
createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy").Fields("?,?,?,?").Prepare(),
|
||||
createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy, createdAt").Fields("?,?,?,?,UTC_TIMESTAMP()").Prepare(),
|
||||
addLikesToTopic: acc.Update("topics").Set("likeCount = likeCount + ?").Where("tid = ?").Prepare(),
|
||||
delete: acc.Delete("topics").Where("tid = ?").Prepare(),
|
||||
edit: acc.Update("topics").Set("title = ?, content = ?, parsed_content = ?").Where("tid = ?").Prepare(), // TODO: Only run the content update bits on non-polls, does this matter?
|
||||
|
@ -205,20 +205,24 @@ func (topic *Topic) Unstick() (err error) {
|
|||
// TODO: Test this
|
||||
// TODO: Use a transaction for this
|
||||
func (topic *Topic) Like(score int, uid int) (err error) {
|
||||
var tid int // Unused
|
||||
err = topicStmts.hasLikedTopic.QueryRow(uid, topic.ID).Scan(&tid)
|
||||
var disp int // Unused
|
||||
err = topicStmts.hasLikedTopic.QueryRow(uid, topic.ID).Scan(&disp)
|
||||
if err != nil && err != ErrNoRows {
|
||||
return err
|
||||
} else if err != ErrNoRows {
|
||||
return ErrAlreadyLiked
|
||||
}
|
||||
|
||||
_, err = topicStmts.createLike.Exec(score, tid, "topics", uid)
|
||||
_, err = topicStmts.createLike.Exec(score, topic.ID, "topics", uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = topicStmts.addLikesToTopic.Exec(1, tid)
|
||||
_, err = topicStmts.addLikesToTopic.Exec(1, topic.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = userStmts.incrementLiked.Exec(1, uid)
|
||||
topic.cacheRemove()
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ type User struct {
|
|||
Tag string
|
||||
Level int
|
||||
Score int
|
||||
Liked int
|
||||
LastIP string // ! This part of the UserCache data might fall out of date
|
||||
TempGroup int
|
||||
}
|
||||
|
@ -71,6 +72,8 @@ type UserStmts struct {
|
|||
incrementPosts *sql.Stmt
|
||||
incrementBigposts *sql.Stmt
|
||||
incrementMegaposts *sql.Stmt
|
||||
incrementLiked *sql.Stmt
|
||||
decrementLiked *sql.Stmt
|
||||
updateLastIP *sql.Stmt
|
||||
|
||||
setPassword *sql.Stmt
|
||||
|
@ -92,7 +95,10 @@ func init() {
|
|||
incrementPosts: acc.SimpleUpdate("users", "posts = posts + ?", "uid = ?"),
|
||||
incrementBigposts: acc.SimpleUpdate("users", "posts = posts + ?, bigposts = bigposts + ?", "uid = ?"),
|
||||
incrementMegaposts: acc.SimpleUpdate("users", "posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?", "uid = ?"),
|
||||
updateLastIP: acc.SimpleUpdate("users", "last_ip = ?", "uid = ?"),
|
||||
incrementLiked: acc.SimpleUpdate("users", "liked = liked + ?, lastLiked = UTC_TIMESTAMP()", "uid = ?"),
|
||||
decrementLiked: acc.SimpleUpdate("users", "liked = liked - ?", "uid = ?"),
|
||||
//recalcLastLiked: acc...
|
||||
updateLastIP: acc.SimpleUpdate("users", "last_ip = ?", "uid = ?"),
|
||||
|
||||
setPassword: acc.SimpleUpdate("users", "password = ?, salt = ?", "uid = ?"),
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
|
|||
// TODO: Add an admin version of registerStmt with more flexibility?
|
||||
return &DefaultUserStore{
|
||||
cache: cache,
|
||||
get: acc.SimpleSelect("users", "name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group", "uid = ?", "", ""),
|
||||
get: acc.SimpleSelect("users", "name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group", "uid = ?", "", ""),
|
||||
exists: acc.SimpleSelect("users", "uid", "uid = ?", "", ""),
|
||||
register: acc.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt", "?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()"), // TODO: Implement user_count on users_groups here
|
||||
usernameExists: acc.SimpleSelect("users", "name", "name = ?", "", ""),
|
||||
|
@ -65,7 +65,7 @@ func (mus *DefaultUserStore) DirtyGet(id int) *User {
|
|||
}
|
||||
|
||||
user = &User{ID: id, Loggedin: true}
|
||||
err = mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
||||
err = mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup)
|
||||
|
||||
user.Init()
|
||||
if err == nil {
|
||||
|
@ -83,7 +83,7 @@ func (mus *DefaultUserStore) Get(id int) (*User, error) {
|
|||
}
|
||||
|
||||
user = &User{ID: id, Loggedin: true}
|
||||
err = mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
||||
err = mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup)
|
||||
|
||||
user.Init()
|
||||
if err == nil {
|
||||
|
@ -127,14 +127,14 @@ func (mus *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err erro
|
|||
qlist = qlist[0 : len(qlist)-1]
|
||||
|
||||
acc := qgen.Builder.Accumulator()
|
||||
rows, err := acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group").Where("uid IN(" + qlist + ")").Query(uidList...)
|
||||
rows, err := acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Where("uid IN(" + qlist + ")").Query(uidList...)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
user := &User{Loggedin: true}
|
||||
err := rows.Scan(&user.ID, &user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
||||
err := rows.Scan(&user.ID, &user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ func (mus *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err erro
|
|||
|
||||
func (mus *DefaultUserStore) BypassGet(id int) (*User, error) {
|
||||
user := &User{ID: id, Loggedin: true}
|
||||
err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
||||
err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup)
|
||||
|
||||
user.Init()
|
||||
return user, err
|
||||
|
@ -183,7 +183,7 @@ func (mus *DefaultUserStore) BypassGet(id int) (*User, error) {
|
|||
|
||||
func (mus *DefaultUserStore) Reload(id int) error {
|
||||
user := &User{ID: id, Loggedin: true}
|
||||
err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
||||
err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup)
|
||||
if err != nil {
|
||||
mus.cache.Remove(id)
|
||||
return err
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
var stmts *Stmts
|
||||
|
||||
var db *sql.DB
|
||||
var dbVersion string
|
||||
var dbAdapter string
|
||||
|
||||
// ErrNoRows is an alias of sql.ErrNoRows, just in case we end up with non-database/sql datastores
|
||||
|
|
|
@ -462,6 +462,32 @@ func init() {
|
|||
counters.SetReverseOSMapEnum(reverseOSMapEnum)
|
||||
}
|
||||
|
||||
type WriterIntercept struct {
|
||||
w http.ResponseWriter
|
||||
code int
|
||||
}
|
||||
|
||||
func NewWriterIntercept(w http.ResponseWriter) *WriterIntercept {
|
||||
return &WriterIntercept{w:w,code:200}
|
||||
}
|
||||
|
||||
func (writ *WriterIntercept) Header() http.Header {
|
||||
return writ.w.Header()
|
||||
}
|
||||
|
||||
func (writ *WriterIntercept) Write(pieces []byte) (int, error) {
|
||||
return writ.w.Write(pieces)
|
||||
}
|
||||
|
||||
func (writ *WriterIntercept) WriteHeader(code int) {
|
||||
writ.w.WriteHeader(code)
|
||||
writ.code = code
|
||||
}
|
||||
|
||||
func (writ *WriterIntercept) GetCode() int {
|
||||
return writ.code
|
||||
}
|
||||
|
||||
type GenRouter struct {
|
||||
UploadHandler func(http.ResponseWriter, *http.Request)
|
||||
extraRoutes map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError
|
||||
|
@ -471,7 +497,14 @@ type GenRouter struct {
|
|||
|
||||
func NewGenRouter(uploads http.Handler) *GenRouter {
|
||||
return &GenRouter{
|
||||
UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP,
|
||||
UploadHandler: func(w http.ResponseWriter, req *http.Request) {
|
||||
writ := NewWriterIntercept(w)
|
||||
http.StripPrefix("/uploads/",uploads).ServeHTTP(writ,req)
|
||||
if writ.GetCode() == 200 {
|
||||
w.Header().Set("Cache-Control", "max-age=" + strconv.Itoa(common.Day))
|
||||
w.Header().Set("Vary", "Accept-Encoding")
|
||||
}
|
||||
},
|
||||
extraRoutes: make(map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError),
|
||||
}
|
||||
}
|
||||
|
@ -1514,6 +1547,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err = common.ParseForm(w,req,user)
|
||||
if err != nil {
|
||||
router.handleError(err,w,req,user)
|
||||
return
|
||||
}
|
||||
|
||||
counters.RouteViewCounter.Bump(83)
|
||||
err = routeLikeTopicSubmit(w,req,user,extraData)
|
||||
default:
|
||||
|
@ -1588,6 +1627,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err = common.ParseForm(w,req,user)
|
||||
if err != nil {
|
||||
router.handleError(err,w,req,user)
|
||||
return
|
||||
}
|
||||
|
||||
counters.RouteViewCounter.Bump(88)
|
||||
err = routeReplyLikeSubmit(w,req,user,extraData)
|
||||
}
|
||||
|
|
|
@ -16,16 +16,17 @@ import (
|
|||
|
||||
// TODO: Refactor this
|
||||
func routeLikeTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError {
|
||||
isJs := (r.PostFormValue("isJs") == "1")
|
||||
tid, err := strconv.Atoi(stid)
|
||||
if err != nil {
|
||||
return common.PreError("Topic IDs can only ever be numbers.", w, r)
|
||||
return common.PreErrorJSQ("Topic IDs can only ever be numbers.", w, r, isJs)
|
||||
}
|
||||
|
||||
topic, err := common.Topics.Get(tid)
|
||||
if err == ErrNoRows {
|
||||
return common.PreError("The requested topic doesn't exist.", w, r)
|
||||
return common.PreErrorJSQ("The requested topic doesn't exist.", w, r, isJs)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
// TODO: Add hooks to make use of headerLite
|
||||
|
@ -34,55 +35,62 @@ func routeLikeTopicSubmit(w http.ResponseWriter, r *http.Request, user common.Us
|
|||
return ferr
|
||||
}
|
||||
if !user.Perms.ViewTopic || !user.Perms.LikeItem {
|
||||
return common.NoPermissions(w, r, user)
|
||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||
}
|
||||
if topic.CreatedBy == user.ID {
|
||||
return common.LocalError("You can't like your own topics", w, r, user)
|
||||
return common.LocalErrorJSQ("You can't like your own topics", w, r, user, isJs)
|
||||
}
|
||||
|
||||
_, err = common.Users.Get(topic.CreatedBy)
|
||||
if err != nil && err == ErrNoRows {
|
||||
return common.LocalError("The target user doesn't exist", w, r, user)
|
||||
return common.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
score := 1
|
||||
err = topic.Like(score, user.ID)
|
||||
//log.Print("likeErr: ", err)
|
||||
if err == common.ErrAlreadyLiked {
|
||||
return common.LocalError("You already liked this", w, r, user)
|
||||
return common.LocalErrorJSQ("You already liked this", w, r, user, isJs)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
err = common.AddActivityAndNotifyTarget(user.ID, topic.CreatedBy, "like", "topic", tid)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
if !isJs {
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
} else {
|
||||
_, _ = w.Write(successJSONBytes)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func routeReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
||||
isJs := (r.PostFormValue("isJs") == "1")
|
||||
|
||||
rid, err := strconv.Atoi(srid)
|
||||
if err != nil {
|
||||
return common.PreError("The provided Reply ID is not a valid number.", w, r)
|
||||
return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
|
||||
}
|
||||
|
||||
reply, err := common.Rstore.Get(rid)
|
||||
if err == ErrNoRows {
|
||||
return common.PreError("You can't like something which doesn't exist!", w, r)
|
||||
return common.PreErrorJSQ("You can't like something which doesn't exist!", w, r, isJs)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
var fid int
|
||||
err = stmts.getTopicFID.QueryRow(reply.ParentID).Scan(&fid)
|
||||
if err == ErrNoRows {
|
||||
return common.PreError("The parent topic doesn't exist.", w, r)
|
||||
return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
// TODO: Add hooks to make use of headerLite
|
||||
|
@ -91,32 +99,36 @@ func routeReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user common.Us
|
|||
return ferr
|
||||
}
|
||||
if !user.Perms.ViewTopic || !user.Perms.LikeItem {
|
||||
return common.NoPermissions(w, r, user)
|
||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||
}
|
||||
if reply.CreatedBy == user.ID {
|
||||
return common.LocalError("You can't like your own replies", w, r, user)
|
||||
return common.LocalErrorJSQ("You can't like your own replies", w, r, user, isJs)
|
||||
}
|
||||
|
||||
_, err = common.Users.Get(reply.CreatedBy)
|
||||
if err != nil && err != ErrNoRows {
|
||||
return common.LocalError("The target user doesn't exist", w, r, user)
|
||||
return common.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
err = reply.Like(user.ID)
|
||||
if err == common.ErrAlreadyLiked {
|
||||
return common.LocalError("You've already liked this!", w, r, user)
|
||||
return common.LocalErrorJSQ("You've already liked this!", w, r, user, isJs)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
err = common.AddActivityAndNotifyTarget(user.ID, reply.CreatedBy, "like", "post", rid)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther)
|
||||
if !isJs {
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther)
|
||||
} else {
|
||||
_, _ = w.Write(successJSONBytes)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
4
mssql.go
4
mssql.go
|
@ -47,8 +47,6 @@ func initMSSQL() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: Fetch the database version
|
||||
|
||||
// Set the number of max open connections
|
||||
db.SetMaxOpenConns(64)
|
||||
db.SetMaxIdleConns(32)
|
||||
|
@ -76,7 +74,7 @@ func initMSSQL() (err error) {
|
|||
|
||||
// TODO: Is there a less noisy way of doing this for tests?
|
||||
log.Print("Preparing getActivityFeedByWatcher statement.")
|
||||
getActivityFeedByWatcherStmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM [activity_stream_matches] INNER JOIN [activity_stream] ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE [watcher] = ? ORDER BY activity_stream.asid ASC OFFSET 0 ROWS FETCH NEXT 8 ROWS ONLY")
|
||||
getActivityFeedByWatcherStmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM [activity_stream_matches] INNER JOIN [activity_stream] ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE [watcher] = ? ORDER BY activity_stream.asid DESC OFFSET 0 ROWS FETCH NEXT 8 ROWS ONLY")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
31
mysql.go
31
mysql.go
|
@ -9,11 +9,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
//import "time"
|
||||
|
||||
"./common"
|
||||
"./query_gen/lib"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
|
@ -27,28 +24,20 @@ func init() {
|
|||
}
|
||||
|
||||
func initMySQL() (err error) {
|
||||
var _dbpassword string
|
||||
if common.DbConfig.Password != "" {
|
||||
_dbpassword = ":" + common.DbConfig.Password
|
||||
}
|
||||
|
||||
// TODO: Move this bit to the query gen lib
|
||||
// Open the database connection
|
||||
db, err = sql.Open("mysql", common.DbConfig.Username+_dbpassword+"@tcp("+common.DbConfig.Host+":"+common.DbConfig.Port+")/"+common.DbConfig.Dbname+"?collation="+dbCollation+"&parseTime=true")
|
||||
err = qgen.Builder.Init("mysql", map[string]string{
|
||||
"host": common.DbConfig.Host,
|
||||
"port": common.DbConfig.Port,
|
||||
"name": common.DbConfig.Dbname,
|
||||
"username": common.DbConfig.Username,
|
||||
"password": common.DbConfig.Password,
|
||||
"collation": dbCollation,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure that the connection is alive
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Fetch the database version
|
||||
db.QueryRow("SELECT VERSION()").Scan(&dbVersion)
|
||||
|
||||
// Set the number of max open connections
|
||||
db = qgen.Builder.GetConn()
|
||||
db.SetMaxOpenConns(64)
|
||||
db.SetMaxIdleConns(32)
|
||||
|
||||
|
@ -70,7 +59,7 @@ func initMySQL() (err error) {
|
|||
|
||||
// TODO: Is there a less noisy way of doing this for tests?
|
||||
log.Print("Preparing getActivityFeedByWatcher statement.")
|
||||
stmts.getActivityFeedByWatcher, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM `activity_stream_matches` INNER JOIN `activity_stream` ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE `watcher` = ? ORDER BY activity_stream.asid ASC LIMIT 8")
|
||||
stmts.getActivityFeedByWatcher, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM `activity_stream_matches` INNER JOIN `activity_stream` ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE `watcher` = ? ORDER BY activity_stream.asid DESC LIMIT 8")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
|
||||
"../query_gen/lib"
|
||||
)
|
||||
|
||||
func main() {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
// Capture panics instead of closing the window at a superhuman speed before the user can read the message on Windows
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
fmt.Println(r)
|
||||
debug.PrintStack()
|
||||
pressAnyKey(scanner)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
err := patcher(scanner)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func pressAnyKey(scanner *bufio.Scanner) {
|
||||
fmt.Println("Please press enter to exit...")
|
||||
for scanner.Scan() {
|
||||
_ = scanner.Text()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func patcher(scanner *bufio.Scanner) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
/*func eachUserQuick(handle func(int)) error {
|
||||
stmt, err := qgen.Builder.Select("users").Orderby("uid desc").Limit(1).Prepare()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var topID int
|
||||
err := stmt.QueryRow(topID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 1; i <= topID; i++ {
|
||||
err = handle(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
func eachUser(handle func(int)) error {
|
||||
stmt, err := qgen.Builder.Select("users").Prepare()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rows, err := stmt.Query()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var uid int
|
||||
err := rows.Scan(&uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = handle(uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
9
pgsql.go
9
pgsql.go
|
@ -14,10 +14,10 @@ import (
|
|||
)
|
||||
|
||||
// TODO: Add support for SSL for all database drivers, not just pgsql
|
||||
var db_sslmode = "disable" // verify-full
|
||||
var dbSslmode = "disable" // verify-full
|
||||
|
||||
func init() {
|
||||
db_adapter = "pgsql"
|
||||
dbAdapter = "pgsql"
|
||||
_initDatabase = initPgsql
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ func initPgsql() (err error) {
|
|||
_dbpassword = " password='" + _escape_bit(common.DbConfig.Password) + "'"
|
||||
}
|
||||
// TODO: Move this bit to the query gen lib
|
||||
db, err = sql.Open("postgres", "host='"+_escape_bit(common.DbConfig.Host)+"' port='"+_escape_bit(common.DbConfig.Port)+"' user='"+_escape_bit(common.DbConfig.Username)+"' dbname='"+_escape_bit(common.Config.Dbname)+"'"+_dbpassword+" sslmode='"+db_sslmode+"'")
|
||||
db, err = sql.Open("postgres", "host='"+_escape_bit(common.DbConfig.Host)+"' port='"+_escape_bit(common.DbConfig.Port)+"' user='"+_escape_bit(common.DbConfig.Username)+"' dbname='"+_escape_bit(common.Config.Dbname)+"'"+_dbpassword+" sslmode='"+dbSslmode+"'")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -39,9 +39,6 @@ func initPgsql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// Fetch the database version
|
||||
db.QueryRow("SELECT VERSION()").Scan(&db_version)
|
||||
|
||||
// Set the number of max open connections. How many do we need? Might need to do some tests.
|
||||
db.SetMaxOpenConns(64)
|
||||
db.SetMaxIdleConns(32)
|
||||
|
|
|
@ -153,7 +153,7 @@ function runWebSockets() {
|
|||
console.log("The WebSockets connection was closed");
|
||||
}
|
||||
conn.onmessage = function(event) {
|
||||
//console.log("WS_Message:", event.data);
|
||||
//console.log("WSMessage:", event.data);
|
||||
if(event.data[0] == "{") {
|
||||
try {
|
||||
var data = JSON.parse(event.data);
|
||||
|
@ -200,14 +200,15 @@ function runWebSockets() {
|
|||
|
||||
var messages = event.data.split('\r');
|
||||
for(var i = 0; i < messages.length; i++) {
|
||||
//console.log("Message: ",messages[i]);
|
||||
if(messages[i].startsWith("set ")) {
|
||||
//msgblocks = messages[i].split(' ',3);
|
||||
let msgblocks = SplitN(messages[i]," ",3);
|
||||
let message = messages[i];
|
||||
//console.log("Message: ",message);
|
||||
if(message.startsWith("set ")) {
|
||||
//msgblocks = message.split(' ',3);
|
||||
let msgblocks = SplitN(message," ",3);
|
||||
if(msgblocks.length < 3) continue;
|
||||
document.querySelector(msgblocks[1]).innerHTML = msgblocks[2];
|
||||
} else if(messages[i].startsWith("set-class ")) {
|
||||
let msgblocks = SplitN(messages[i]," ",3);
|
||||
} else if(message.startsWith("set-class ")) {
|
||||
let msgblocks = SplitN(message," ",3);
|
||||
if(msgblocks.length < 3) continue;
|
||||
document.querySelector(msgblocks[1]).className = msgblocks[2];
|
||||
}
|
||||
|
@ -220,8 +221,45 @@ $(document).ready(function(){
|
|||
if(window["WebSocket"]) runWebSockets();
|
||||
else conn = false;
|
||||
|
||||
$(".open_edit").click(function(event){
|
||||
//console.log("clicked on .open_edit");
|
||||
$(".add_like").click(function(event) {
|
||||
event.preventDefault();
|
||||
let likeButton = this;
|
||||
let target = this.closest("a").getAttribute("href");
|
||||
console.log("target: ", target);
|
||||
likeButton.classList.remove("add_like");
|
||||
likeButton.classList.add("remove_like");
|
||||
let controls = likeButton.closest(".controls");
|
||||
let hadLikes = controls.classList.contains("has_likes");
|
||||
if(!hadLikes) controls.classList.add("has_likes");
|
||||
let likeCountNode = controls.getElementsByClassName("like_count")[0];
|
||||
console.log("likeCountNode",likeCountNode);
|
||||
likeCountNode.innerHTML = parseInt(likeCountNode.innerHTML) + 1;
|
||||
|
||||
$.ajax({
|
||||
url: target,
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: { isJs: 1 },
|
||||
error: ajaxError,
|
||||
success: function (data, status, xhr) {
|
||||
if("success" in data) {
|
||||
if(data["success"] == "1") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// addNotice("Failed to add a like: {err}")
|
||||
likeButton.classList.add("add_like");
|
||||
likeButton.classList.remove("remove_like");
|
||||
if(!hadLikes) controls.classList.remove("has_likes");
|
||||
likeCountNode.innerHTML = parseInt(likeCountNode.innerHTML) - 1;
|
||||
console.log("data", data);
|
||||
console.log("status", status);
|
||||
console.log("xhr", xhr);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(".open_edit").click((event) => {
|
||||
event.preventDefault();
|
||||
$(".hide_on_edit").hide();
|
||||
$(".show_on_edit").show();
|
||||
|
@ -229,17 +267,17 @@ $(document).ready(function(){
|
|||
|
||||
$(".topic_item .submit_edit").click(function(event){
|
||||
event.preventDefault();
|
||||
//console.log("clicked on .topic_item .submit_edit");
|
||||
$(".topic_name").html($(".topic_name_input").val());
|
||||
$(".topic_content").html($(".topic_content_input").val());
|
||||
$(".topic_status_e:not(.open_edit)").html($(".topic_status_input").val());
|
||||
let topicNameInput = $(".topic_name_input").val();
|
||||
$(".topic_name").html(topicNameInput);
|
||||
$(".topic_name").attr(topicNameInput);
|
||||
let topicContentInput = $('.topic_content_input').val();
|
||||
$(".topic_content").html(topicContentInput.replace(/(\n)+/g,"<br />"));
|
||||
let topicStatusInput = $('.topic_status_input').val();
|
||||
$(".topic_status_e:not(.open_edit)").html(topicStatusInput);
|
||||
|
||||
$(".hide_on_edit").show();
|
||||
$(".show_on_edit").hide();
|
||||
|
||||
let topicNameInput = $('.topic_name_input').val();
|
||||
let topicStatusInput = $('.topic_status_input').val();
|
||||
let topicContentInput = $('.topic_content_input').val();
|
||||
let formAction = this.form.getAttribute("action");
|
||||
//console.log("New Topic Name: ", topicNameInput);
|
||||
//console.log("New Topic Status: ", topicStatusInput);
|
||||
|
@ -284,8 +322,7 @@ $(document).ready(function(){
|
|||
});
|
||||
});
|
||||
|
||||
$(".edit_field").click(function(event)
|
||||
{
|
||||
$(".edit_field").click(function(event) {
|
||||
event.preventDefault();
|
||||
let blockParent = $(this).closest('.editable_parent');
|
||||
let block = blockParent.find('.editable_block').eq(0);
|
||||
|
@ -395,7 +432,7 @@ $(document).ready(function(){
|
|||
}
|
||||
});
|
||||
|
||||
$(this).click(function() {
|
||||
$(this).click(() => {
|
||||
$(".selectedAlert").removeClass("selectedAlert");
|
||||
$("#back").removeClass("alertActive");
|
||||
});
|
||||
|
@ -421,9 +458,7 @@ $(document).ready(function(){
|
|||
document.getElementById("back").className += " alertActive"
|
||||
});
|
||||
|
||||
$("input,textarea,select,option").keyup(function(event){
|
||||
event.stopPropagation();
|
||||
})
|
||||
$("input,textarea,select,option").keyup(event => event.stopPropagation())
|
||||
|
||||
$(".create_topic_link").click((event) => {
|
||||
event.preventDefault();
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package qgen
|
||||
|
||||
import "database/sql"
|
||||
import (
|
||||
"database/sql"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type accDeleteBuilder struct {
|
||||
table string
|
||||
|
@ -10,7 +13,10 @@ type accDeleteBuilder struct {
|
|||
}
|
||||
|
||||
func (delete *accDeleteBuilder) Where(where string) *accDeleteBuilder {
|
||||
delete.where = where
|
||||
if delete.where != "" {
|
||||
delete.where += " AND "
|
||||
}
|
||||
delete.where += where
|
||||
return delete
|
||||
}
|
||||
|
||||
|
@ -32,7 +38,10 @@ func (update *accUpdateBuilder) Set(set string) *accUpdateBuilder {
|
|||
}
|
||||
|
||||
func (update *accUpdateBuilder) Where(where string) *accUpdateBuilder {
|
||||
update.where = where
|
||||
if update.where != "" {
|
||||
update.where += " AND "
|
||||
}
|
||||
update.where += where
|
||||
return update
|
||||
}
|
||||
|
||||
|
@ -59,6 +68,28 @@ func (selectItem *accSelectBuilder) Columns(columns string) *accSelectBuilder {
|
|||
}
|
||||
|
||||
func (selectItem *accSelectBuilder) Where(where string) *accSelectBuilder {
|
||||
if selectItem.where != "" {
|
||||
selectItem.where += " AND "
|
||||
}
|
||||
selectItem.where += where
|
||||
return selectItem
|
||||
}
|
||||
|
||||
// TODO: Don't implement the SQL at the accumulator level but the adapter level
|
||||
func (selectItem *accSelectBuilder) In(column string, inList []int) *accSelectBuilder {
|
||||
if len(inList) == 0 {
|
||||
return selectItem
|
||||
}
|
||||
|
||||
var where = column + " IN("
|
||||
for _, item := range inList {
|
||||
where += strconv.Itoa(item) + ","
|
||||
}
|
||||
where = where[:len(where)-1] + ")"
|
||||
if selectItem.where != "" {
|
||||
where += " AND " + selectItem.where
|
||||
}
|
||||
|
||||
selectItem.where = where
|
||||
return selectItem
|
||||
}
|
||||
|
@ -140,7 +171,10 @@ type accCountBuilder struct {
|
|||
}
|
||||
|
||||
func (count *accCountBuilder) Where(where string) *accCountBuilder {
|
||||
count.where = where
|
||||
if count.where != "" {
|
||||
count.where += " AND "
|
||||
}
|
||||
count.where += where
|
||||
return count
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,25 @@ func (build *builder) Accumulator() *Accumulator {
|
|||
return &Accumulator{build.conn, build.adapter, nil}
|
||||
}
|
||||
|
||||
// TODO: Move this method out of builder?
|
||||
func (build *builder) Init(adapter string, config map[string]string) error {
|
||||
err := build.SetAdapter(adapter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn, err := build.adapter.BuildConn(config)
|
||||
build.conn = conn
|
||||
return err
|
||||
}
|
||||
|
||||
func (build *builder) SetConn(conn *sql.DB) {
|
||||
build.conn = conn
|
||||
}
|
||||
|
||||
func (build *builder) GetConn() *sql.DB {
|
||||
return build.conn
|
||||
}
|
||||
|
||||
func (build *builder) SetAdapter(name string) error {
|
||||
adap, err := GetAdapter(name)
|
||||
if err != nil {
|
||||
|
@ -36,6 +51,11 @@ func (build *builder) GetAdapter() Adapter {
|
|||
return build.adapter
|
||||
}
|
||||
|
||||
func (build *builder) DbVersion() (dbVersion string) {
|
||||
build.conn.QueryRow(build.adapter.DbVersion()).Scan(&dbVersion)
|
||||
return dbVersion
|
||||
}
|
||||
|
||||
func (build *builder) Begin() (*sql.Tx, error) {
|
||||
return build.conn.Begin()
|
||||
}
|
||||
|
|
|
@ -44,7 +44,10 @@ func (delete *deletePrebuilder) Table(table string) *deletePrebuilder {
|
|||
}
|
||||
|
||||
func (delete *deletePrebuilder) Where(where string) *deletePrebuilder {
|
||||
delete.where = where
|
||||
if delete.where != "" {
|
||||
delete.where += " AND "
|
||||
}
|
||||
delete.where += where
|
||||
return delete
|
||||
}
|
||||
|
||||
|
@ -76,7 +79,10 @@ func (update *updatePrebuilder) Set(set string) *updatePrebuilder {
|
|||
}
|
||||
|
||||
func (update *updatePrebuilder) Where(where string) *updatePrebuilder {
|
||||
update.where = where
|
||||
if update.where != "" {
|
||||
update.where += " AND "
|
||||
}
|
||||
update.where += where
|
||||
return update
|
||||
}
|
||||
|
||||
|
@ -113,7 +119,10 @@ func (selectItem *selectPrebuilder) Columns(columns string) *selectPrebuilder {
|
|||
}
|
||||
|
||||
func (selectItem *selectPrebuilder) Where(where string) *selectPrebuilder {
|
||||
selectItem.where = where
|
||||
if selectItem.where != "" {
|
||||
selectItem.where += " AND "
|
||||
}
|
||||
selectItem.where += where
|
||||
return selectItem
|
||||
}
|
||||
|
||||
|
@ -205,7 +214,10 @@ func (count *countPrebuilder) Table(table string) *countPrebuilder {
|
|||
}
|
||||
|
||||
func (count *countPrebuilder) Where(where string) *countPrebuilder {
|
||||
count.where = where
|
||||
if count.where != "" {
|
||||
count.where += " AND "
|
||||
}
|
||||
count.where += where
|
||||
return count
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package qgen
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
"strconv"
|
||||
|
@ -34,6 +35,15 @@ func (adapter *MssqlAdapter) GetStmts() map[string]DBStmt {
|
|||
return adapter.Buffer
|
||||
}
|
||||
|
||||
// TODO: Implement this
|
||||
func (adapter *MssqlAdapter) BuildConn(config map[string]string) (*sql.DB, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (adapter *MssqlAdapter) DbVersion() string {
|
||||
return "SELECT CONCAT(SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition'))"
|
||||
}
|
||||
|
||||
// TODO: Convert any remaining stringy types to nvarchar
|
||||
// We may need to change the CreateTable API to better suit Mssql and the other database drivers which are coming up
|
||||
func (adapter *MssqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) (string, error) {
|
||||
|
@ -249,7 +259,7 @@ func (adapter *MssqlAdapter) SimpleUpsert(name string, table string, columns str
|
|||
switch token.Type {
|
||||
case "substitute":
|
||||
querystr += " ?"
|
||||
case "function", "operator", "number":
|
||||
case "function", "operator", "number", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
|
@ -314,7 +324,7 @@ func (adapter *MssqlAdapter) SimpleUpdate(name string, table string, set string,
|
|||
switch token.Type {
|
||||
case "substitute":
|
||||
querystr += " ?"
|
||||
case "function", "operator", "number":
|
||||
case "function", "operator", "number", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
|
@ -339,7 +349,7 @@ func (adapter *MssqlAdapter) SimpleUpdate(name string, table string, set string,
|
|||
for _, loc := range processWhere(where) {
|
||||
for _, token := range loc.Expr {
|
||||
switch token.Type {
|
||||
case "function", "operator", "number", "substitute":
|
||||
case "function", "operator", "number", "substitute", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
|
@ -381,7 +391,7 @@ func (adapter *MssqlAdapter) SimpleDelete(name string, table string, where strin
|
|||
switch token.Type {
|
||||
case "substitute":
|
||||
querystr += " ?"
|
||||
case "function", "operator", "number":
|
||||
case "function", "operator", "number", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
|
@ -451,7 +461,7 @@ func (adapter *MssqlAdapter) SimpleSelect(name string, table string, columns str
|
|||
case "substitute":
|
||||
substituteCount++
|
||||
querystr += " ?" + strconv.Itoa(substituteCount)
|
||||
case "function", "operator", "number":
|
||||
case "function", "operator", "number", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
// MSSQL seems to convert the formats? so we'll compare it with a regular date. Do this with the other methods too?
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
|
@ -576,7 +586,7 @@ func (adapter *MssqlAdapter) SimpleLeftJoin(name string, table1 string, table2 s
|
|||
case "substitute":
|
||||
substituteCount++
|
||||
querystr += " ?" + strconv.Itoa(substituteCount)
|
||||
case "function", "operator", "number":
|
||||
case "function", "operator", "number", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
|
@ -706,7 +716,7 @@ func (adapter *MssqlAdapter) SimpleInnerJoin(name string, table1 string, table2
|
|||
case "substitute":
|
||||
substituteCount++
|
||||
querystr += " ?" + strconv.Itoa(substituteCount)
|
||||
case "function", "operator", "number":
|
||||
case "function", "operator", "number", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
|
@ -827,7 +837,7 @@ func (adapter *MssqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel D
|
|||
case "substitute":
|
||||
substituteCount++
|
||||
querystr += " ?" + strconv.Itoa(substituteCount)
|
||||
case "function", "operator", "number":
|
||||
case "function", "operator", "number", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
|
@ -951,7 +961,7 @@ func (adapter *MssqlAdapter) simpleJoin(name string, ins DBInsert, sel DBJoin, j
|
|||
case "substitute":
|
||||
substituteCount++
|
||||
querystr += " ?" + strconv.Itoa(substituteCount)
|
||||
case "function", "operator", "number":
|
||||
case "function", "operator", "number", "or":
|
||||
// TODO: Split the function case off to speed things up
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
|
@ -1046,7 +1056,7 @@ func (adapter *MssqlAdapter) SimpleCount(name string, table string, where string
|
|||
for _, loc := range processWhere(where) {
|
||||
for _, token := range loc.Expr {
|
||||
switch token.Type {
|
||||
case "function", "operator", "number", "substitute":
|
||||
case "function", "operator", "number", "substitute", "or":
|
||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||
token.Contents = "GETUTCDATE()"
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
/* WIP Under Construction */
|
||||
package qgen
|
||||
|
||||
//import "fmt"
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
var ErrNoCollation = errors.New("You didn't provide a collation")
|
||||
|
||||
func init() {
|
||||
Registry = append(Registry,
|
||||
&MysqlAdapter{Name: "mysql", Buffer: make(map[string]DBStmt)},
|
||||
|
@ -33,6 +37,30 @@ func (adapter *MysqlAdapter) GetStmts() map[string]DBStmt {
|
|||
return adapter.Buffer
|
||||
}
|
||||
|
||||
func (adapter *MysqlAdapter) BuildConn(config map[string]string) (*sql.DB, error) {
|
||||
dbCollation, ok := config["collation"]
|
||||
if !ok {
|
||||
return nil, ErrNoCollation
|
||||
}
|
||||
var dbpassword string
|
||||
if config["password"] != "" {
|
||||
dbpassword = ":" + config["password"]
|
||||
}
|
||||
|
||||
// Open the database connection
|
||||
db, err := sql.Open("mysql", config["username"]+dbpassword+"@tcp("+config["host"]+":"+config["port"]+")/"+config["name"]+"?collation="+dbCollation+"&parseTime=true")
|
||||
if err != nil {
|
||||
return db, err
|
||||
}
|
||||
|
||||
// Make sure that the connection is alive
|
||||
return db, db.Ping()
|
||||
}
|
||||
|
||||
func (adapter *MysqlAdapter) DbVersion() string {
|
||||
return "SELECT VERSION()"
|
||||
}
|
||||
|
||||
func (adapter *MysqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) (string, error) {
|
||||
if name == "" {
|
||||
return "", errors.New("You need a name for this statement")
|
||||
|
@ -239,7 +267,7 @@ func (adapter *MysqlAdapter) SimpleUpdate(name string, table string, set string,
|
|||
querystr += "`" + item.Column + "` ="
|
||||
for _, token := range item.Expr {
|
||||
switch token.Type {
|
||||
case "function", "operator", "number", "substitute":
|
||||
case "function", "operator", "number", "substitute", "or":
|
||||
querystr += " " + token.Contents
|
||||
case "column":
|
||||
querystr += " `" + token.Contents + "`"
|
||||
|
@ -278,7 +306,7 @@ func (adapter *MysqlAdapter) SimpleDelete(name string, table string, where strin
|
|||
for _, loc := range processWhere(where) {
|
||||
for _, token := range loc.Expr {
|
||||
switch token.Type {
|
||||
case "function", "operator", "number", "substitute":
|
||||
case "function", "operator", "number", "substitute", "or":
|
||||
querystr += " " + token.Contents
|
||||
case "column":
|
||||
querystr += " `" + token.Contents + "`"
|
||||
|
@ -316,7 +344,7 @@ func (adapter *MysqlAdapter) buildWhere(where string) (querystr string, err erro
|
|||
for _, loc := range processWhere(where) {
|
||||
for _, token := range loc.Expr {
|
||||
switch token.Type {
|
||||
case "function", "operator", "number", "substitute":
|
||||
case "function", "operator", "number", "substitute", "or":
|
||||
querystr += " " + token.Contents
|
||||
case "column":
|
||||
querystr += " `" + token.Contents + "`"
|
||||
|
@ -344,7 +372,7 @@ func (adapter *MysqlAdapter) buildFlexiWhere(where string, dateCutoff *dateCutof
|
|||
for _, loc := range processWhere(where) {
|
||||
for _, token := range loc.Expr {
|
||||
switch token.Type {
|
||||
case "function", "operator", "number", "substitute":
|
||||
case "function", "operator", "number", "substitute", "or":
|
||||
querystr += " " + token.Contents
|
||||
case "column":
|
||||
querystr += " `" + token.Contents + "`"
|
||||
|
@ -544,7 +572,7 @@ func (adapter *MysqlAdapter) buildJoinWhere(where string) (querystr string, err
|
|||
for _, loc := range processWhere(where) {
|
||||
for _, token := range loc.Expr {
|
||||
switch token.Type {
|
||||
case "function", "operator", "number", "substitute":
|
||||
case "function", "operator", "number", "substitute", "or":
|
||||
querystr += " " + token.Contents
|
||||
case "column":
|
||||
halves := strings.Split(token.Contents, ".")
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
/* WIP Under Really Heavy Construction */
|
||||
package qgen
|
||||
|
||||
import "strings"
|
||||
import "strconv"
|
||||
import "errors"
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registry = append(Registry,
|
||||
|
@ -30,6 +33,16 @@ func (adapter *PgsqlAdapter) GetStmts() map[string]DBStmt {
|
|||
return adapter.Buffer
|
||||
}
|
||||
|
||||
// TODO: Implement this
|
||||
func (adapter *PgsqlAdapter) BuildConn(config map[string]string) (*sql.DB, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// TODO: Implement this
|
||||
func (adapter *PgsqlAdapter) DbVersion() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// TODO: Implement this
|
||||
// We may need to change the CreateTable API to better suit PGSQL and the other database drivers which are coming up
|
||||
func (adapter *PgsqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) (string, error) {
|
||||
|
@ -167,7 +180,7 @@ func (adapter *PgsqlAdapter) SimpleUpdate(name string, table string, set string,
|
|||
token.Contents = "LOCALTIMESTAMP()"
|
||||
}
|
||||
querystr += " " + token.Contents
|
||||
case "operator", "number", "substitute":
|
||||
case "operator", "number", "substitute", "or":
|
||||
querystr += " " + token.Contents
|
||||
case "column":
|
||||
querystr += " `" + token.Contents + "`"
|
||||
|
@ -193,7 +206,7 @@ func (adapter *PgsqlAdapter) SimpleUpdate(name string, table string, set string,
|
|||
token.Contents = "LOCALTIMESTAMP()"
|
||||
}
|
||||
querystr += " " + token.Contents
|
||||
case "operator", "number", "substitute":
|
||||
case "operator", "number", "substitute", "or":
|
||||
querystr += " " + token.Contents
|
||||
case "column":
|
||||
querystr += " `" + token.Contents + "`"
|
||||
|
|
|
@ -98,6 +98,9 @@ type DBStmt struct {
|
|||
|
||||
type Adapter interface {
|
||||
GetName() string
|
||||
BuildConn(config map[string]string) (*sql.DB, error)
|
||||
DbVersion() string
|
||||
|
||||
CreateTable(name string, table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) (string, error)
|
||||
SimpleInsert(name string, table string, columns string, fields string) (string, error)
|
||||
SimpleUpdate(name string, table string, set string, where string) (string, error)
|
||||
|
|
|
@ -166,7 +166,12 @@ func (where *DBWhere) parseOperator(segment string, i int) int {
|
|||
|
||||
// TODO: Make this case insensitive
|
||||
func normalizeAnd(in string) string {
|
||||
return strings.Replace(in, " and ", " AND ", -1)
|
||||
in = strings.Replace(in, " and ", " AND ", -1)
|
||||
return strings.Replace(in, " && ", " AND ", -1)
|
||||
}
|
||||
func normalizeOr(in string) string {
|
||||
in = strings.Replace(in, " or ", " OR ", -1)
|
||||
return strings.Replace(in, " || ", " OR ", -1)
|
||||
}
|
||||
|
||||
// TODO: Write tests for this
|
||||
|
@ -175,6 +180,7 @@ func processWhere(wherestr string) (where []DBWhere) {
|
|||
return where
|
||||
}
|
||||
wherestr = normalizeAnd(wherestr)
|
||||
wherestr = normalizeOr(wherestr)
|
||||
|
||||
for _, segment := range strings.Split(wherestr, " AND ") {
|
||||
var tmpWhere = &DBWhere{[]DBToken{}}
|
||||
|
@ -184,10 +190,16 @@ func processWhere(wherestr string) (where []DBWhere) {
|
|||
switch {
|
||||
case '0' <= char && char <= '9':
|
||||
i = tmpWhere.parseNumber(segment, i)
|
||||
// TODO: Sniff the third byte offset from char or it's non-existent to avoid matching uppercase strings which start with OR
|
||||
case char == 'O' && (i+1) < len(segment) && segment[i+1] == 'R':
|
||||
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"OR", "or"})
|
||||
i += 1
|
||||
case ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_':
|
||||
i = tmpWhere.parseColumn(segment, i)
|
||||
case char == '\'':
|
||||
i = tmpWhere.parseString(segment, i)
|
||||
case char == ')' && i < (len(segment)-1):
|
||||
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{")", "operator"})
|
||||
case isOpByte(char):
|
||||
i = tmpWhere.parseOperator(segment, i)
|
||||
case char == '?':
|
||||
|
@ -335,11 +347,11 @@ func processLimit(limitstr string) (limiter DBLimit) {
|
|||
}
|
||||
|
||||
func isOpByte(char byte) bool {
|
||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/'
|
||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/' || char == '(' || char == ')'
|
||||
}
|
||||
|
||||
func isOpRune(char rune) bool {
|
||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/'
|
||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/' || char == '(' || char == ')'
|
||||
}
|
||||
|
||||
func processFields(fieldstr string) (fields []DBField) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* WIP Under Construction */
|
||||
package main
|
||||
|
||||
import "./lib"
|
||||
|
@ -11,7 +10,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"password", "varchar", 100, false, false, ""},
|
||||
|
||||
qgen.DBTableColumn{"salt", "varchar", 80, false, false, "''"},
|
||||
qgen.DBTableColumn{"group", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"group", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"active", "boolean", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"is_super_admin", "boolean", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||
|
@ -30,6 +29,12 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"bigposts", "int", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"megaposts", "int", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"topics", "int", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"liked", "int", 0, false, false, "0"},
|
||||
|
||||
// These two are to bound liked queries with little bits of information we know about the user to reduce the server load
|
||||
qgen.DBTableColumn{"oldestItemLikedCreatedAt", "datetime", 0, false, false, ""}, // For internal use only, semantics may change
|
||||
qgen.DBTableColumn{"lastLiked", "datetime", 0, false, false, ""}, // For internal use only, semantics may change
|
||||
|
||||
//qgen.DBTableColumn{"penalty_count","int",0,false,false,"0"},
|
||||
qgen.DBTableColumn{"temp_group", "int", 0, false, false, "0"}, // For temporary groups, set this to zero when a temporary group isn't in effect
|
||||
},
|
||||
|
@ -106,7 +111,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.Install.CreateTable("emails", "", "",
|
||||
[]qgen.DBTableColumn{
|
||||
qgen.DBTableColumn{"email", "varchar", 200, false, false, ""},
|
||||
qgen.DBTableColumn{"uid", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"validated", "boolean", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"token", "varchar", 200, false, false, "''"},
|
||||
},
|
||||
|
@ -153,7 +158,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"lastReplyAt", "datetime", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"lastReplyBy", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"createdBy", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"is_closed", "boolean", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"sticky", "boolean", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"parentID", "int", 0, false, false, "2"},
|
||||
|
@ -178,7 +183,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"content", "text", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"parsed_content", "text", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"createdBy", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"lastEdit", "int", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"lastEditBy", "int", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"lastUpdated", "datetime", 0, false, false, ""},
|
||||
|
@ -200,7 +205,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"sectionTable", "varchar", 200, false, false, "forums"},
|
||||
qgen.DBTableColumn{"originID", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"originTable", "varchar", 200, false, false, "replies"},
|
||||
qgen.DBTableColumn{"uploadedBy", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"uploadedBy", "int", 0, false, false, ""}, // TODO; Make this a foreign key
|
||||
qgen.DBTableColumn{"path", "varchar", 200, false, false, ""},
|
||||
},
|
||||
[]qgen.DBTableKey{
|
||||
|
@ -215,6 +220,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"contentID", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"contentType", "varchar", 100, false, false, "replies"},
|
||||
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||
// TODO: Add a createdBy column?
|
||||
},
|
||||
[]qgen.DBTableKey{
|
||||
qgen.DBTableKey{"reviseID", "primary"},
|
||||
|
@ -247,7 +253,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.Install.CreateTable("polls_votes", "utf8mb4", "utf8mb4_general_ci",
|
||||
[]qgen.DBTableColumn{
|
||||
qgen.DBTableColumn{"pollID", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"uid", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"option", "int", 0, false, false, "0"},
|
||||
qgen.DBTableColumn{"castAt", "createdAt", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
|
||||
|
@ -258,11 +264,11 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.Install.CreateTable("users_replies", "utf8mb4", "utf8mb4_general_ci",
|
||||
[]qgen.DBTableColumn{
|
||||
qgen.DBTableColumn{"rid", "int", 0, false, true, ""},
|
||||
qgen.DBTableColumn{"uid", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"content", "text", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"parsed_content", "text", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"createdBy", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"lastEdit", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"lastEditBy", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
|
||||
|
@ -277,7 +283,8 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"weight", "tinyint", 0, false, false, "1"},
|
||||
qgen.DBTableColumn{"targetItem", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"targetType", "varchar", 50, false, false, "replies"},
|
||||
qgen.DBTableColumn{"sentBy", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"sentBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"recalc", "tinyint", 0, false, false, "0"},
|
||||
},
|
||||
[]qgen.DBTableKey{},
|
||||
|
@ -285,8 +292,8 @@ func createTables(adapter qgen.Adapter) error {
|
|||
|
||||
qgen.Install.CreateTable("activity_stream_matches", "", "",
|
||||
[]qgen.DBTableColumn{
|
||||
qgen.DBTableColumn{"watcher", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"asid", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"watcher", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"asid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
},
|
||||
[]qgen.DBTableKey{},
|
||||
)
|
||||
|
@ -294,7 +301,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.Install.CreateTable("activity_stream", "", "",
|
||||
[]qgen.DBTableColumn{
|
||||
qgen.DBTableColumn{"asid", "int", 0, false, true, ""},
|
||||
qgen.DBTableColumn{"actor", "int", 0, false, false, ""}, /* the one doing the act */
|
||||
qgen.DBTableColumn{"actor", "int", 0, false, false, ""}, /* the one doing the act */ // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"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 */
|
||||
qgen.DBTableColumn{"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 */
|
||||
qgen.DBTableColumn{"elementType", "varchar", 50, false, false, ""}, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
|
||||
|
@ -307,7 +314,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
|
||||
qgen.Install.CreateTable("activity_subscriptions", "", "",
|
||||
[]qgen.DBTableColumn{
|
||||
qgen.DBTableColumn{"user", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"user", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"targetID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
|
||||
qgen.DBTableColumn{"targetType", "varchar", 50, false, false, ""}, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
|
||||
qgen.DBTableColumn{"level", "int", 0, false, false, "0"}, /* 0: Mentions (aka the global default for any post), 1: Replies To You, 2: All Replies*/
|
||||
|
@ -378,7 +385,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"elementID", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"elementType", "varchar", 100, false, false, ""},
|
||||
qgen.DBTableColumn{"ipaddress", "varchar", 200, false, false, ""},
|
||||
qgen.DBTableColumn{"actorID", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"actorID", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"doneAt", "datetime", 0, false, false, ""},
|
||||
},
|
||||
[]qgen.DBTableKey{},
|
||||
|
@ -390,7 +397,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"elementID", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"elementType", "varchar", 100, false, false, ""},
|
||||
qgen.DBTableColumn{"ipaddress", "varchar", 200, false, false, ""},
|
||||
qgen.DBTableColumn{"actorID", "int", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"actorID", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||
qgen.DBTableColumn{"doneAt", "datetime", 0, false, false, ""},
|
||||
},
|
||||
[]qgen.DBTableKey{},
|
||||
|
|
|
@ -302,6 +302,32 @@ func init() {
|
|||
counters.SetReverseOSMapEnum(reverseOSMapEnum)
|
||||
}
|
||||
|
||||
type WriterIntercept struct {
|
||||
w http.ResponseWriter
|
||||
code int
|
||||
}
|
||||
|
||||
func NewWriterIntercept(w http.ResponseWriter) *WriterIntercept {
|
||||
return &WriterIntercept{w:w,code:200}
|
||||
}
|
||||
|
||||
func (writ *WriterIntercept) Header() http.Header {
|
||||
return writ.w.Header()
|
||||
}
|
||||
|
||||
func (writ *WriterIntercept) Write(pieces []byte) (int, error) {
|
||||
return writ.w.Write(pieces)
|
||||
}
|
||||
|
||||
func (writ *WriterIntercept) WriteHeader(code int) {
|
||||
writ.w.WriteHeader(code)
|
||||
writ.code = code
|
||||
}
|
||||
|
||||
func (writ *WriterIntercept) GetCode() int {
|
||||
return writ.code
|
||||
}
|
||||
|
||||
type GenRouter struct {
|
||||
UploadHandler func(http.ResponseWriter, *http.Request)
|
||||
extraRoutes map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError
|
||||
|
@ -311,7 +337,14 @@ type GenRouter struct {
|
|||
|
||||
func NewGenRouter(uploads http.Handler) *GenRouter {
|
||||
return &GenRouter{
|
||||
UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP,
|
||||
UploadHandler: func(w http.ResponseWriter, req *http.Request) {
|
||||
writ := NewWriterIntercept(w)
|
||||
http.StripPrefix("/uploads/",uploads).ServeHTTP(writ,req)
|
||||
if writ.GetCode() == 200 {
|
||||
w.Header().Set("Cache-Control", "max-age=" + strconv.Itoa(common.Day))
|
||||
w.Header().Set("Vary", "Accept-Encoding")
|
||||
}
|
||||
},
|
||||
extraRoutes: make(map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func buildTopicRoutes() {
|
|||
Action("routes.LockTopicSubmit", "/topic/lock/submit/").LitBefore("req.URL.Path += extraData"),
|
||||
Action("routes.UnlockTopicSubmit", "/topic/unlock/submit/", "extraData"),
|
||||
Action("routes.MoveTopicSubmit", "/topic/move/submit/", "extraData"),
|
||||
Action("routeLikeTopicSubmit", "/topic/like/submit/", "extraData"),
|
||||
Action("routeLikeTopicSubmit", "/topic/like/submit/", "extraData").Before("ParseForm"),
|
||||
)
|
||||
addRouteGroup(topicGroup)
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ func buildReplyRoutes() {
|
|||
UploadAction("routes.CreateReplySubmit", "/reply/create/").MaxSizeVar("common.Config.MaxRequestSize"), // TODO: Rename the route so it's /reply/create/submit/
|
||||
Action("routes.ReplyEditSubmit", "/reply/edit/submit/", "extraData"),
|
||||
Action("routes.ReplyDeleteSubmit", "/reply/delete/submit/", "extraData"),
|
||||
Action("routeReplyLikeSubmit", "/reply/like/submit/", "extraData"),
|
||||
Action("routeReplyLikeSubmit", "/reply/like/submit/", "extraData").Before("ParseForm"),
|
||||
)
|
||||
addRouteGroup(replyGroup)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ import (
|
|||
)
|
||||
|
||||
type TopicStmts struct {
|
||||
getReplies *sql.Stmt
|
||||
getReplies *sql.Stmt
|
||||
getLikedTopic *sql.Stmt
|
||||
}
|
||||
|
||||
var topicStmts TopicStmts
|
||||
|
@ -29,7 +30,8 @@ var topicStmts TopicStmts
|
|||
func init() {
|
||||
common.DbInits.Add(func(acc *qgen.Accumulator) error {
|
||||
topicStmts = TopicStmts{
|
||||
getReplies: acc.SimpleLeftJoin("replies", "users", "replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.actionType", "replies.createdBy = users.uid", "replies.tid = ?", "replies.rid ASC", "?,?"),
|
||||
getReplies: acc.SimpleLeftJoin("replies", "users", "replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.actionType", "replies.createdBy = users.uid", "replies.tid = ?", "replies.rid ASC", "?,?"),
|
||||
getLikedTopic: acc.Select("likes").Columns("targetItem").Where("sentBy = ? && targetItem = ? && targetType = 'topics'").Prepare(),
|
||||
}
|
||||
return acc.FirstError()
|
||||
})
|
||||
|
@ -107,12 +109,25 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit
|
|||
poll = pPoll.Copy()
|
||||
}
|
||||
|
||||
if topic.LikeCount > 0 && user.Liked > 0 {
|
||||
var disp int // Discard this value
|
||||
err = topicStmts.getLikedTopic.QueryRow(user.ID, topic.ID).Scan(&disp)
|
||||
if err == nil {
|
||||
topic.Liked = true
|
||||
} else if err != nil && err != sql.ErrNoRows {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the offset
|
||||
offset, page, lastPage := common.PageOffset(topic.PostCount, page, common.Config.ItemsPerPage)
|
||||
tpage := common.TopicPage{topic.Title, user, headerVars, []common.ReplyUser{}, topic, poll, page, lastPage}
|
||||
|
||||
// Get the replies if we have any...
|
||||
if topic.PostCount > 0 {
|
||||
var likedMap = make(map[int]int)
|
||||
var likedQueryList = []int{user.ID}
|
||||
|
||||
rows, err := topicStmts.getReplies.Query(topic.ID, offset, common.Config.ItemsPerPage)
|
||||
if err == sql.ErrNoRows {
|
||||
return common.LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.", w, r, user)
|
||||
|
@ -171,7 +186,11 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit
|
|||
replyItem.ActionIcon = ""
|
||||
}
|
||||
}
|
||||
replyItem.Liked = false
|
||||
|
||||
if replyItem.LikeCount > 0 {
|
||||
likedMap[replyItem.ID] = len(tpage.ItemList)
|
||||
likedQueryList = append(likedQueryList, replyItem.ID)
|
||||
}
|
||||
|
||||
common.RunVhook("topic_reply_row_assign", &tpage, &replyItem)
|
||||
// TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis?
|
||||
|
@ -181,6 +200,28 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit
|
|||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
// TODO: Add a config setting to disable the liked query for a burst of extra speed
|
||||
if user.Liked > 0 && len(likedQueryList) > 1 /*&& user.LastLiked <= time.Now()*/ {
|
||||
rows, err := qgen.Builder.Accumulator().Select("likes").Columns("targetItem").Where("sentBy = ? AND targetType = 'replies'").In("targetItem", likedQueryList[1:]).Query(user.ID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var likeRid int
|
||||
err := rows.Scan(&likeRid)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
tpage.ItemList[likedMap[likeRid]].Liked = true
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if common.RunPreRenderHook("pre_render_view_topic", w, r, &user, &tpage) {
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
echo "Generating the dynamic code"
|
||||
go generate
|
||||
|
||||
echo "Building Gosora"
|
||||
go build -o Gosora
|
||||
|
||||
echo "Building the templates"
|
||||
./Gosora -build-templates
|
||||
|
||||
echo "Building Gosora... Again"
|
||||
go build -o Gosora
|
||||
|
||||
echo "Running Gosora"
|
||||
./Gosora
|
|
@ -1,8 +1,14 @@
|
|||
echo "Generating the dynamic code"
|
||||
go generate
|
||||
|
||||
echo "Building Gosora"
|
||||
go build -o Gosora -tags no_ws
|
||||
|
||||
echo "Building the templates"
|
||||
./Gosora -build-templates
|
||||
|
||||
echo "Building Gosora... Again"
|
||||
go build -o Gosora -tags no_ws
|
||||
|
||||
echo "Running Gosora"
|
||||
./Gosora
|
||||
|
|
|
@ -46,6 +46,13 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Building the executable... again
|
||||
go build -o gosora.exe -tags no_ws
|
||||
if %errorlevel% neq 0 (
|
||||
pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Running Gosora
|
||||
gosora.exe
|
||||
pause
|
7
run.bat
7
run.bat
|
@ -46,6 +46,13 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Building the executable... again
|
||||
go build -o gosora.exe
|
||||
if %errorlevel% neq 0 (
|
||||
pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Running Gosora
|
||||
gosora.exe
|
||||
rem Or you could redirect the output to a file
|
||||
|
|
|
@ -46,6 +46,13 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Building the executable... again
|
||||
go build -o gosora.exe -tags mssql
|
||||
if %errorlevel% neq 0 (
|
||||
pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Running Gosora
|
||||
gosora.exe
|
||||
pause
|
|
@ -3,5 +3,6 @@ CREATE TABLE [likes] (
|
|||
[targetItem] int not null,
|
||||
[targetType] nvarchar (50) DEFAULT 'replies' not null,
|
||||
[sentBy] int not null,
|
||||
[createdAt] datetime not null,
|
||||
[recalc] tinyint DEFAULT 0 not null
|
||||
);
|
|
@ -21,6 +21,9 @@ CREATE TABLE [users] (
|
|||
[bigposts] int DEFAULT 0 not null,
|
||||
[megaposts] int DEFAULT 0 not null,
|
||||
[topics] int DEFAULT 0 not null,
|
||||
[liked] int DEFAULT 0 not null,
|
||||
[oldestItemLikedCreatedAt] datetime not null,
|
||||
[lastLiked] datetime not null,
|
||||
[temp_group] int DEFAULT 0 not null,
|
||||
primary key([uid]),
|
||||
unique([name])
|
||||
|
|
|
@ -3,5 +3,6 @@ CREATE TABLE `likes` (
|
|||
`targetItem` int not null,
|
||||
`targetType` varchar(50) DEFAULT 'replies' not null,
|
||||
`sentBy` int not null,
|
||||
`createdAt` datetime not null,
|
||||
`recalc` tinyint DEFAULT 0 not null
|
||||
);
|
|
@ -21,6 +21,9 @@ CREATE TABLE `users` (
|
|||
`bigposts` int DEFAULT 0 not null,
|
||||
`megaposts` int DEFAULT 0 not null,
|
||||
`topics` int DEFAULT 0 not null,
|
||||
`liked` int DEFAULT 0 not null,
|
||||
`oldestItemLikedCreatedAt` datetime not null,
|
||||
`lastLiked` datetime not null,
|
||||
`temp_group` int DEFAULT 0 not null,
|
||||
primary key(`uid`),
|
||||
unique(`name`)
|
||||
|
|
|
@ -3,5 +3,6 @@ CREATE TABLE `likes` (
|
|||
`targetItem` int not null,
|
||||
`targetType` varchar (50) DEFAULT 'replies' not null,
|
||||
`sentBy` int not null,
|
||||
`createdAt` timestamp not null,
|
||||
`recalc` tinyint DEFAULT 0 not null
|
||||
);
|
|
@ -21,6 +21,9 @@ CREATE TABLE `users` (
|
|||
`bigposts` int DEFAULT 0 not null,
|
||||
`megaposts` int DEFAULT 0 not null,
|
||||
`topics` int DEFAULT 0 not null,
|
||||
`liked` int DEFAULT 0 not null,
|
||||
`oldestItemLikedCreatedAt` timestamp not null,
|
||||
`lastLiked` timestamp not null,
|
||||
`temp_group` int DEFAULT 0 not null,
|
||||
primary key(`uid`),
|
||||
unique(`name`)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"Version":"0"
|
||||
"DBVersion":"0",
|
||||
"DynamicFileVersion":"0"
|
||||
}
|
|
@ -3,9 +3,9 @@
|
|||
// Code generated by Gosora. More below:
|
||||
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||
package main
|
||||
import "strconv"
|
||||
import "net/http"
|
||||
import "./common"
|
||||
import "strconv"
|
||||
|
||||
var forum_tmpl_phrase_id int
|
||||
|
||||
|
@ -307,61 +307,67 @@ w.Write([]byte(item.Link))
|
|||
w.Write(forum_frags[58])
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(forum_frags[59])
|
||||
w.Write([]byte(item.Creator.Link))
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(forum_frags[60])
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write([]byte(item.Creator.Link))
|
||||
w.Write(forum_frags[61])
|
||||
if item.IsClosed {
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(forum_frags[62])
|
||||
w.Write(phrases[44])
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(forum_frags[63])
|
||||
}
|
||||
if item.Sticky {
|
||||
if item.IsClosed {
|
||||
w.Write(forum_frags[64])
|
||||
w.Write(phrases[45])
|
||||
w.Write(phrases[44])
|
||||
w.Write(forum_frags[65])
|
||||
}
|
||||
w.Write(forum_frags[66])
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(forum_frags[67])
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(forum_frags[68])
|
||||
if item.Sticky {
|
||||
w.Write(forum_frags[66])
|
||||
w.Write(phrases[45])
|
||||
w.Write(forum_frags[67])
|
||||
}
|
||||
w.Write(forum_frags[68])
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(forum_frags[69])
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(forum_frags[70])
|
||||
if item.Sticky {
|
||||
w.Write(forum_frags[71])
|
||||
} else {
|
||||
if item.IsClosed {
|
||||
w.Write(forum_frags[70])
|
||||
}
|
||||
}
|
||||
w.Write(forum_frags[71])
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
w.Write(forum_frags[72])
|
||||
w.Write([]byte(item.LastUser.Avatar))
|
||||
}
|
||||
}
|
||||
w.Write(forum_frags[73])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(forum_frags[74])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(forum_frags[75])
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
w.Write(forum_frags[74])
|
||||
w.Write([]byte(item.LastUser.Avatar))
|
||||
w.Write(forum_frags[75])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(forum_frags[76])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(forum_frags[77])
|
||||
w.Write([]byte(item.RelativeLastReplyAt))
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
w.Write(forum_frags[78])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(forum_frags[79])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(forum_frags[80])
|
||||
w.Write([]byte(item.RelativeLastReplyAt))
|
||||
w.Write(forum_frags[81])
|
||||
}
|
||||
} else {
|
||||
w.Write(forum_frags[79])
|
||||
w.Write(forum_frags[82])
|
||||
w.Write(phrases[46])
|
||||
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write(forum_frags[80])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||
w.Write(forum_frags[81])
|
||||
w.Write(phrases[47])
|
||||
w.Write(forum_frags[82])
|
||||
}
|
||||
w.Write(forum_frags[83])
|
||||
}
|
||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||
w.Write(forum_frags[84])
|
||||
w.Write(phrases[47])
|
||||
w.Write(forum_frags[85])
|
||||
}
|
||||
w.Write(forum_frags[86])
|
||||
}
|
||||
w.Write(forum_frags[87])
|
||||
if tmpl_forum_vars.LastPage > 1 {
|
||||
w.Write(paginator_frags[0])
|
||||
if tmpl_forum_vars.Page > 1 {
|
||||
|
@ -397,7 +403,7 @@ w.Write(paginator_frags[13])
|
|||
}
|
||||
w.Write(paginator_frags[14])
|
||||
}
|
||||
w.Write(forum_frags[85])
|
||||
w.Write(forum_frags[88])
|
||||
w.Write(footer_frags[0])
|
||||
w.Write([]byte(common.BuildWidget("footer",tmpl_forum_vars.Header)))
|
||||
w.Write(footer_frags[1])
|
||||
|
|
984
template_list.go
984
template_list.go
File diff suppressed because it is too large
Load Diff
|
@ -187,73 +187,77 @@ w.Write([]byte(tmpl_profile_vars.ProfileOwner.Name))
|
|||
w.Write(profile_frags[3])
|
||||
w.Write([]byte(tmpl_profile_vars.ProfileOwner.Name))
|
||||
w.Write(profile_frags[4])
|
||||
if tmpl_profile_vars.ProfileOwner.Tag != "" {
|
||||
w.Write([]byte(tmpl_profile_vars.ProfileOwner.Name))
|
||||
w.Write(profile_frags[5])
|
||||
w.Write([]byte(tmpl_profile_vars.ProfileOwner.Tag))
|
||||
if tmpl_profile_vars.ProfileOwner.Tag != "" {
|
||||
w.Write(profile_frags[6])
|
||||
}
|
||||
w.Write([]byte(tmpl_profile_vars.ProfileOwner.Tag))
|
||||
w.Write(profile_frags[7])
|
||||
if !tmpl_profile_vars.CurrentUser.Loggedin {
|
||||
w.Write([]byte(tmpl_profile_vars.ProfileOwner.Tag))
|
||||
w.Write(profile_frags[8])
|
||||
w.Write(phrases[19])
|
||||
}
|
||||
w.Write(profile_frags[9])
|
||||
} else {
|
||||
if !tmpl_profile_vars.CurrentUser.Loggedin {
|
||||
w.Write(profile_frags[10])
|
||||
w.Write(phrases[20])
|
||||
w.Write(phrases[19])
|
||||
w.Write(profile_frags[11])
|
||||
if tmpl_profile_vars.CurrentUser.IsSuperMod && !tmpl_profile_vars.ProfileOwner.IsSuperMod {
|
||||
w.Write(profile_frags[12])
|
||||
if tmpl_profile_vars.ProfileOwner.IsBanned {
|
||||
w.Write(profile_frags[13])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||
w.Write(profile_frags[14])
|
||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||
w.Write(profile_frags[15])
|
||||
w.Write(phrases[21])
|
||||
w.Write(profile_frags[16])
|
||||
} else {
|
||||
w.Write(profile_frags[12])
|
||||
w.Write(phrases[20])
|
||||
w.Write(profile_frags[13])
|
||||
if tmpl_profile_vars.CurrentUser.IsSuperMod && !tmpl_profile_vars.ProfileOwner.IsSuperMod {
|
||||
w.Write(profile_frags[14])
|
||||
if tmpl_profile_vars.ProfileOwner.IsBanned {
|
||||
w.Write(profile_frags[15])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||
w.Write(profile_frags[16])
|
||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||
w.Write(profile_frags[17])
|
||||
w.Write(phrases[22])
|
||||
w.Write(phrases[21])
|
||||
w.Write(profile_frags[18])
|
||||
}
|
||||
} else {
|
||||
w.Write(profile_frags[19])
|
||||
}
|
||||
w.Write(phrases[22])
|
||||
w.Write(profile_frags[20])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||
}
|
||||
w.Write(profile_frags[21])
|
||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||
}
|
||||
w.Write(profile_frags[22])
|
||||
w.Write(phrases[23])
|
||||
w.Write(profile_frags[23])
|
||||
w.Write(phrases[24])
|
||||
w.Write(profile_frags[24])
|
||||
}
|
||||
w.Write(profile_frags[25])
|
||||
if tmpl_profile_vars.CurrentUser.Perms.BanUsers {
|
||||
w.Write(profile_frags[26])
|
||||
w.Write(phrases[25])
|
||||
w.Write(profile_frags[27])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||
w.Write(profile_frags[28])
|
||||
w.Write(profile_frags[23])
|
||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||
w.Write(profile_frags[29])
|
||||
w.Write(profile_frags[30])
|
||||
w.Write(phrases[26])
|
||||
w.Write(profile_frags[31])
|
||||
w.Write(phrases[27])
|
||||
w.Write(profile_frags[32])
|
||||
w.Write(phrases[28])
|
||||
w.Write(profile_frags[33])
|
||||
w.Write(phrases[29])
|
||||
w.Write(profile_frags[34])
|
||||
w.Write(phrases[30])
|
||||
w.Write(profile_frags[35])
|
||||
w.Write(phrases[31])
|
||||
w.Write(profile_frags[36])
|
||||
w.Write(profile_frags[24])
|
||||
w.Write(phrases[23])
|
||||
w.Write(profile_frags[25])
|
||||
w.Write(phrases[24])
|
||||
w.Write(profile_frags[26])
|
||||
}
|
||||
w.Write(profile_frags[27])
|
||||
if tmpl_profile_vars.CurrentUser.Perms.BanUsers {
|
||||
w.Write(profile_frags[28])
|
||||
w.Write(phrases[25])
|
||||
w.Write(profile_frags[29])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||
w.Write(profile_frags[30])
|
||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||
w.Write(profile_frags[31])
|
||||
w.Write(profile_frags[32])
|
||||
w.Write(phrases[26])
|
||||
w.Write(profile_frags[33])
|
||||
w.Write(phrases[27])
|
||||
w.Write(profile_frags[34])
|
||||
w.Write(phrases[28])
|
||||
w.Write(profile_frags[35])
|
||||
w.Write(phrases[29])
|
||||
w.Write(profile_frags[36])
|
||||
w.Write(phrases[30])
|
||||
w.Write(profile_frags[37])
|
||||
w.Write(phrases[32])
|
||||
w.Write(phrases[31])
|
||||
w.Write(profile_frags[38])
|
||||
}
|
||||
w.Write(profile_frags[39])
|
||||
w.Write(phrases[32])
|
||||
w.Write(profile_frags[40])
|
||||
if tmpl_profile_vars.Header.Theme.BgAvatars {
|
||||
if len(tmpl_profile_vars.ItemList) != 0 {
|
||||
for _, item := range tmpl_profile_vars.ItemList {
|
||||
|
@ -363,20 +367,20 @@ w.Write(profile_comments_row_frags[49])
|
|||
}
|
||||
}
|
||||
}
|
||||
w.Write(profile_frags[39])
|
||||
if !tmpl_profile_vars.CurrentUser.IsBanned {
|
||||
w.Write(profile_frags[40])
|
||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||
w.Write(profile_frags[41])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||
if !tmpl_profile_vars.CurrentUser.IsBanned {
|
||||
w.Write(profile_frags[42])
|
||||
w.Write(phrases[45])
|
||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||
w.Write(profile_frags[43])
|
||||
w.Write(phrases[46])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||
w.Write(profile_frags[44])
|
||||
}
|
||||
w.Write(phrases[45])
|
||||
w.Write(profile_frags[45])
|
||||
w.Write(phrases[46])
|
||||
w.Write(profile_frags[46])
|
||||
}
|
||||
w.Write(profile_frags[47])
|
||||
w.Write(profile_frags[48])
|
||||
w.Write(footer_frags[0])
|
||||
w.Write([]byte(common.BuildWidget("footer",tmpl_profile_vars.Header)))
|
||||
w.Write(footer_frags[1])
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
// Code generated by Gosora. More below:
|
||||
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||
package main
|
||||
import "strconv"
|
||||
import "net/http"
|
||||
import "./common"
|
||||
import "strconv"
|
||||
|
||||
var topic_tmpl_phrase_id int
|
||||
|
||||
|
@ -245,376 +245,385 @@ w.Write(phrases[22])
|
|||
w.Write(topic_frags[16])
|
||||
}
|
||||
w.Write(topic_frags[17])
|
||||
w.Write(phrases[23])
|
||||
w.Write(topic_frags[18])
|
||||
if tmpl_topic_vars.Topic.Sticky {
|
||||
w.Write(phrases[23])
|
||||
w.Write(topic_frags[19])
|
||||
if tmpl_topic_vars.Topic.Sticky {
|
||||
w.Write(topic_frags[20])
|
||||
} else {
|
||||
if tmpl_topic_vars.Topic.IsClosed {
|
||||
w.Write(topic_frags[20])
|
||||
}
|
||||
}
|
||||
w.Write(topic_frags[21])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Title))
|
||||
}
|
||||
}
|
||||
w.Write(topic_frags[22])
|
||||
if tmpl_topic_vars.Topic.IsClosed {
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Title))
|
||||
w.Write(topic_frags[23])
|
||||
w.Write(phrases[24])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Title))
|
||||
w.Write(topic_frags[24])
|
||||
w.Write(phrases[25])
|
||||
if tmpl_topic_vars.Topic.IsClosed {
|
||||
w.Write(topic_frags[25])
|
||||
w.Write(phrases[24])
|
||||
w.Write(topic_frags[26])
|
||||
w.Write(phrases[25])
|
||||
w.Write(topic_frags[27])
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.EditTopic {
|
||||
w.Write(topic_frags[26])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Title))
|
||||
w.Write(topic_frags[27])
|
||||
w.Write(phrases[26])
|
||||
w.Write(topic_frags[28])
|
||||
w.Write(phrases[27])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Title))
|
||||
w.Write(topic_frags[29])
|
||||
}
|
||||
w.Write(phrases[26])
|
||||
w.Write(topic_frags[30])
|
||||
if tmpl_topic_vars.Poll.ID > 0 {
|
||||
w.Write(phrases[27])
|
||||
w.Write(topic_frags[31])
|
||||
w.Write(phrases[28])
|
||||
w.Write(topic_frags[32])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.ClassName))
|
||||
w.Write(topic_frags[33])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Avatar))
|
||||
w.Write(topic_frags[34])
|
||||
w.Write([]byte(tmpl_topic_vars.Header.Theme.Name))
|
||||
w.Write(topic_frags[35])
|
||||
if tmpl_topic_vars.Topic.ContentLines <= 5 {
|
||||
w.Write(topic_frags[36])
|
||||
}
|
||||
w.Write(topic_frags[32])
|
||||
if tmpl_topic_vars.Poll.ID > 0 {
|
||||
w.Write(topic_frags[33])
|
||||
w.Write(phrases[28])
|
||||
w.Write(topic_frags[34])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.ClassName))
|
||||
w.Write(topic_frags[35])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Avatar))
|
||||
w.Write(topic_frags[36])
|
||||
w.Write([]byte(tmpl_topic_vars.Header.Theme.Name))
|
||||
w.Write(topic_frags[37])
|
||||
if tmpl_topic_vars.Topic.ContentLines <= 5 {
|
||||
w.Write(topic_frags[38])
|
||||
}
|
||||
w.Write(topic_frags[39])
|
||||
if len(tmpl_topic_vars.Poll.QuickOptions) != 0 {
|
||||
for _, item := range tmpl_topic_vars.Poll.QuickOptions {
|
||||
w.Write(topic_frags[38])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Poll.ID)))
|
||||
w.Write(topic_frags[39])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[40])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Poll.ID)))
|
||||
w.Write(topic_frags[41])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[42])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[43])
|
||||
w.Write([]byte(item.Value))
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[44])
|
||||
}
|
||||
}
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[45])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Poll.ID)))
|
||||
w.Write([]byte(item.Value))
|
||||
w.Write(topic_frags[46])
|
||||
w.Write(phrases[29])
|
||||
}
|
||||
}
|
||||
w.Write(topic_frags[47])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Poll.ID)))
|
||||
w.Write(topic_frags[48])
|
||||
w.Write(phrases[30])
|
||||
w.Write(phrases[29])
|
||||
w.Write(topic_frags[49])
|
||||
w.Write(phrases[31])
|
||||
w.Write(topic_frags[50])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Poll.ID)))
|
||||
w.Write(topic_frags[50])
|
||||
w.Write(phrases[30])
|
||||
w.Write(topic_frags[51])
|
||||
}
|
||||
w.Write(phrases[31])
|
||||
w.Write(topic_frags[52])
|
||||
w.Write(phrases[32])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Poll.ID)))
|
||||
w.Write(topic_frags[53])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.ClassName))
|
||||
}
|
||||
w.Write(topic_frags[54])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Avatar))
|
||||
w.Write(topic_frags[55])
|
||||
w.Write([]byte(tmpl_topic_vars.Header.Theme.Name))
|
||||
w.Write(phrases[32])
|
||||
w.Write(topic_frags[56])
|
||||
if tmpl_topic_vars.Topic.ContentLines <= 5 {
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.ClassName))
|
||||
w.Write(topic_frags[57])
|
||||
}
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Avatar))
|
||||
w.Write(topic_frags[58])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.ContentHTML))
|
||||
w.Write([]byte(tmpl_topic_vars.Header.Theme.Name))
|
||||
w.Write(topic_frags[59])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Content))
|
||||
if tmpl_topic_vars.Topic.ContentLines <= 5 {
|
||||
w.Write(topic_frags[60])
|
||||
w.Write(phrases[33])
|
||||
}
|
||||
w.Write(topic_frags[61])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.UserLink))
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.ContentHTML))
|
||||
w.Write(topic_frags[62])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.CreatedByName))
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Content))
|
||||
w.Write(topic_frags[63])
|
||||
if tmpl_topic_vars.CurrentUser.Perms.LikeItem {
|
||||
if tmpl_topic_vars.Topic.LikeCount > 0 {
|
||||
w.Write(topic_frags[64])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
}
|
||||
w.Write(topic_frags[65])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(phrases[33])
|
||||
w.Write(topic_frags[66])
|
||||
if tmpl_topic_vars.Topic.Liked {
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.UserLink))
|
||||
w.Write(topic_frags[67])
|
||||
w.Write(phrases[34])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.CreatedByName))
|
||||
w.Write(topic_frags[68])
|
||||
w.Write(phrases[35])
|
||||
if tmpl_topic_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_frags[69])
|
||||
} else {
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[70])
|
||||
w.Write(phrases[36])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[71])
|
||||
w.Write(phrases[37])
|
||||
w.Write(topic_frags[72])
|
||||
}
|
||||
w.Write(topic_frags[73])
|
||||
if tmpl_topic_vars.Topic.Liked {
|
||||
w.Write(topic_frags[72])
|
||||
w.Write(phrases[34])
|
||||
w.Write(topic_frags[73])
|
||||
w.Write(phrases[35])
|
||||
w.Write(topic_frags[74])
|
||||
}
|
||||
} else {
|
||||
w.Write(topic_frags[75])
|
||||
w.Write(phrases[36])
|
||||
w.Write(topic_frags[76])
|
||||
w.Write(phrases[37])
|
||||
w.Write(topic_frags[77])
|
||||
}
|
||||
w.Write(topic_frags[78])
|
||||
if tmpl_topic_vars.Topic.Liked {
|
||||
w.Write(topic_frags[79])
|
||||
} else {
|
||||
w.Write(topic_frags[80])
|
||||
}
|
||||
w.Write(topic_frags[81])
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.EditTopic {
|
||||
w.Write(topic_frags[76])
|
||||
w.Write(topic_frags[82])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[77])
|
||||
w.Write(topic_frags[83])
|
||||
w.Write(phrases[38])
|
||||
w.Write(topic_frags[78])
|
||||
w.Write(topic_frags[84])
|
||||
w.Write(phrases[39])
|
||||
w.Write(topic_frags[79])
|
||||
w.Write(topic_frags[85])
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.DeleteTopic {
|
||||
w.Write(topic_frags[80])
|
||||
w.Write(topic_frags[86])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[81])
|
||||
w.Write(topic_frags[87])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[82])
|
||||
w.Write(topic_frags[88])
|
||||
w.Write(phrases[40])
|
||||
w.Write(topic_frags[83])
|
||||
w.Write(topic_frags[89])
|
||||
w.Write(phrases[41])
|
||||
w.Write(topic_frags[84])
|
||||
w.Write(topic_frags[90])
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.CloseTopic {
|
||||
if tmpl_topic_vars.Topic.IsClosed {
|
||||
w.Write(topic_frags[85])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[86])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[87])
|
||||
w.Write(phrases[42])
|
||||
w.Write(topic_frags[88])
|
||||
w.Write(phrases[43])
|
||||
w.Write(topic_frags[89])
|
||||
} else {
|
||||
w.Write(topic_frags[90])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[91])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[92])
|
||||
w.Write(phrases[44])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[93])
|
||||
w.Write(phrases[45])
|
||||
w.Write(phrases[42])
|
||||
w.Write(topic_frags[94])
|
||||
w.Write(phrases[43])
|
||||
w.Write(topic_frags[95])
|
||||
} else {
|
||||
w.Write(topic_frags[96])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[97])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[98])
|
||||
w.Write(phrases[44])
|
||||
w.Write(topic_frags[99])
|
||||
w.Write(phrases[45])
|
||||
w.Write(topic_frags[100])
|
||||
}
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.PinTopic {
|
||||
if tmpl_topic_vars.Topic.Sticky {
|
||||
w.Write(topic_frags[95])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[96])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[97])
|
||||
w.Write(phrases[46])
|
||||
w.Write(topic_frags[98])
|
||||
w.Write(phrases[47])
|
||||
w.Write(topic_frags[99])
|
||||
} else {
|
||||
w.Write(topic_frags[100])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[101])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[102])
|
||||
w.Write(phrases[48])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[103])
|
||||
w.Write(phrases[49])
|
||||
w.Write(phrases[46])
|
||||
w.Write(topic_frags[104])
|
||||
w.Write(phrases[47])
|
||||
w.Write(topic_frags[105])
|
||||
} else {
|
||||
w.Write(topic_frags[106])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[107])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[108])
|
||||
w.Write(phrases[48])
|
||||
w.Write(topic_frags[109])
|
||||
w.Write(phrases[49])
|
||||
w.Write(topic_frags[110])
|
||||
}
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_frags[105])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.IPAddress))
|
||||
w.Write(topic_frags[106])
|
||||
w.Write(phrases[50])
|
||||
w.Write(topic_frags[107])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.IPAddress))
|
||||
w.Write(topic_frags[108])
|
||||
}
|
||||
w.Write(topic_frags[109])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[110])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[111])
|
||||
w.Write(phrases[51])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.IPAddress))
|
||||
w.Write(topic_frags[112])
|
||||
w.Write(phrases[52])
|
||||
w.Write(phrases[50])
|
||||
w.Write(topic_frags[113])
|
||||
if tmpl_topic_vars.Topic.LikeCount > 0 {
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.IPAddress))
|
||||
w.Write(topic_frags[114])
|
||||
w.Write(phrases[53])
|
||||
}
|
||||
w.Write(topic_frags[115])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.LikeCount)))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[116])
|
||||
w.Write(phrases[54])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[117])
|
||||
}
|
||||
if tmpl_topic_vars.Topic.Tag != "" {
|
||||
w.Write(phrases[51])
|
||||
w.Write(topic_frags[118])
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Tag))
|
||||
w.Write(phrases[52])
|
||||
w.Write(topic_frags[119])
|
||||
} else {
|
||||
w.Write(phrases[53])
|
||||
w.Write(topic_frags[120])
|
||||
w.Write(phrases[55])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.LikeCount)))
|
||||
w.Write(topic_frags[121])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level)))
|
||||
w.Write(phrases[54])
|
||||
w.Write(topic_frags[122])
|
||||
w.Write(phrases[56])
|
||||
if tmpl_topic_vars.Topic.Tag != "" {
|
||||
w.Write(topic_frags[123])
|
||||
}
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Tag))
|
||||
w.Write(topic_frags[124])
|
||||
w.Write(phrases[57])
|
||||
} else {
|
||||
w.Write(topic_frags[125])
|
||||
w.Write(phrases[55])
|
||||
w.Write(topic_frags[126])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level)))
|
||||
w.Write(topic_frags[127])
|
||||
w.Write(phrases[56])
|
||||
w.Write(topic_frags[128])
|
||||
}
|
||||
w.Write(topic_frags[129])
|
||||
w.Write(phrases[57])
|
||||
w.Write(topic_frags[130])
|
||||
if len(tmpl_topic_vars.ItemList) != 0 {
|
||||
for _, item := range tmpl_topic_vars.ItemList {
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_frags[126])
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_frags[127])
|
||||
w.Write([]byte(item.ActionType))
|
||||
w.Write(topic_frags[128])
|
||||
} else {
|
||||
w.Write(topic_frags[129])
|
||||
w.Write([]byte(item.ClassName))
|
||||
w.Write(topic_frags[130])
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_frags[131])
|
||||
w.Write([]byte(tmpl_topic_vars.Header.Theme.Name))
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_frags[132])
|
||||
if item.ContentLines <= 5 {
|
||||
w.Write([]byte(item.ActionType))
|
||||
w.Write(topic_frags[133])
|
||||
}
|
||||
} else {
|
||||
w.Write(topic_frags[134])
|
||||
w.Write(topic_frags[135])
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write([]byte(item.ClassName))
|
||||
w.Write(topic_frags[136])
|
||||
w.Write([]byte(item.UserLink))
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_frags[137])
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write([]byte(tmpl_topic_vars.Header.Theme.Name))
|
||||
w.Write(topic_frags[138])
|
||||
if item.ContentLines <= 5 {
|
||||
w.Write(topic_frags[139])
|
||||
}
|
||||
w.Write(topic_frags[140])
|
||||
w.Write(topic_frags[141])
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(topic_frags[142])
|
||||
if item.LikeCount > 0 {
|
||||
w.Write(topic_frags[143])
|
||||
}
|
||||
w.Write(topic_frags[144])
|
||||
w.Write([]byte(item.UserLink))
|
||||
w.Write(topic_frags[145])
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topic_frags[146])
|
||||
if tmpl_topic_vars.CurrentUser.Perms.LikeItem {
|
||||
if item.Liked {
|
||||
w.Write(topic_frags[139])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[140])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[141])
|
||||
w.Write(phrases[58])
|
||||
w.Write(topic_frags[142])
|
||||
w.Write(phrases[59])
|
||||
w.Write(topic_frags[143])
|
||||
} else {
|
||||
w.Write(topic_frags[144])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[145])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[146])
|
||||
w.Write(phrases[60])
|
||||
w.Write(topic_frags[147])
|
||||
w.Write(phrases[61])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[148])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[149])
|
||||
w.Write(phrases[58])
|
||||
w.Write(topic_frags[150])
|
||||
w.Write(phrases[59])
|
||||
w.Write(topic_frags[151])
|
||||
} else {
|
||||
w.Write(topic_frags[152])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[153])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[154])
|
||||
w.Write(phrases[60])
|
||||
w.Write(topic_frags[155])
|
||||
w.Write(phrases[61])
|
||||
w.Write(topic_frags[156])
|
||||
}
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_frags[149])
|
||||
w.Write(topic_frags[157])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[150])
|
||||
w.Write(topic_frags[158])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[151])
|
||||
w.Write(topic_frags[159])
|
||||
w.Write(phrases[62])
|
||||
w.Write(topic_frags[152])
|
||||
w.Write(topic_frags[160])
|
||||
w.Write(phrases[63])
|
||||
w.Write(topic_frags[153])
|
||||
w.Write(topic_frags[161])
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.DeleteReply {
|
||||
w.Write(topic_frags[154])
|
||||
w.Write(topic_frags[162])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[155])
|
||||
w.Write(topic_frags[163])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[156])
|
||||
w.Write(topic_frags[164])
|
||||
w.Write(phrases[64])
|
||||
w.Write(topic_frags[157])
|
||||
w.Write(topic_frags[165])
|
||||
w.Write(phrases[65])
|
||||
w.Write(topic_frags[158])
|
||||
w.Write(topic_frags[166])
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_frags[159])
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_frags[160])
|
||||
w.Write(phrases[66])
|
||||
w.Write(topic_frags[161])
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_frags[162])
|
||||
}
|
||||
w.Write(topic_frags[163])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[164])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[165])
|
||||
w.Write(phrases[67])
|
||||
w.Write(topic_frags[166])
|
||||
w.Write(phrases[68])
|
||||
w.Write(topic_frags[167])
|
||||
if item.LikeCount > 0 {
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_frags[168])
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(phrases[66])
|
||||
w.Write(topic_frags[169])
|
||||
w.Write(phrases[69])
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_frags[170])
|
||||
}
|
||||
if item.Tag != "" {
|
||||
w.Write(topic_frags[171])
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_frags[172])
|
||||
} else {
|
||||
w.Write(topic_frags[173])
|
||||
w.Write(phrases[70])
|
||||
w.Write(topic_frags[174])
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write(topic_frags[175])
|
||||
w.Write(phrases[71])
|
||||
w.Write(topic_frags[176])
|
||||
}
|
||||
w.Write(topic_frags[177])
|
||||
}
|
||||
}
|
||||
}
|
||||
w.Write(topic_frags[178])
|
||||
if tmpl_topic_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write(topic_frags[179])
|
||||
w.Write(phrases[72])
|
||||
w.Write(topic_frags[180])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[173])
|
||||
w.Write(phrases[67])
|
||||
w.Write(topic_frags[174])
|
||||
w.Write(phrases[68])
|
||||
w.Write(topic_frags[175])
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topic_frags[176])
|
||||
w.Write(phrases[69])
|
||||
w.Write(topic_frags[177])
|
||||
if item.Tag != "" {
|
||||
w.Write(topic_frags[178])
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(topic_frags[179])
|
||||
} else {
|
||||
w.Write(topic_frags[180])
|
||||
w.Write(phrases[70])
|
||||
w.Write(topic_frags[181])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write(topic_frags[182])
|
||||
w.Write(phrases[73])
|
||||
w.Write(phrases[71])
|
||||
w.Write(topic_frags[183])
|
||||
w.Write(phrases[74])
|
||||
}
|
||||
w.Write(topic_frags[184])
|
||||
w.Write(phrases[75])
|
||||
}
|
||||
}
|
||||
}
|
||||
w.Write(topic_frags[185])
|
||||
w.Write(phrases[76])
|
||||
if tmpl_topic_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write(topic_frags[186])
|
||||
if tmpl_topic_vars.CurrentUser.Perms.UploadFiles {
|
||||
w.Write(phrases[72])
|
||||
w.Write(topic_frags[187])
|
||||
w.Write(phrases[77])
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_frags[188])
|
||||
}
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_frags[189])
|
||||
}
|
||||
w.Write(phrases[73])
|
||||
w.Write(topic_frags[190])
|
||||
w.Write(phrases[74])
|
||||
w.Write(topic_frags[191])
|
||||
w.Write(phrases[75])
|
||||
w.Write(topic_frags[192])
|
||||
w.Write(phrases[76])
|
||||
w.Write(topic_frags[193])
|
||||
if tmpl_topic_vars.CurrentUser.Perms.UploadFiles {
|
||||
w.Write(topic_frags[194])
|
||||
w.Write(phrases[77])
|
||||
w.Write(topic_frags[195])
|
||||
}
|
||||
w.Write(topic_frags[196])
|
||||
}
|
||||
w.Write(topic_frags[197])
|
||||
w.Write(footer_frags[0])
|
||||
w.Write([]byte(common.BuildWidget("footer",tmpl_topic_vars.Header)))
|
||||
w.Write(footer_frags[1])
|
||||
|
|
|
@ -227,178 +227,173 @@ w.Write(phrases[22])
|
|||
w.Write(topic_alt_frags[13])
|
||||
}
|
||||
w.Write(topic_alt_frags[14])
|
||||
w.Write(phrases[23])
|
||||
w.Write(topic_alt_frags[15])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(phrases[23])
|
||||
w.Write(topic_alt_frags[16])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[17])
|
||||
if tmpl_topic_alt_vars.Topic.Sticky {
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[18])
|
||||
if tmpl_topic_alt_vars.Topic.Sticky {
|
||||
w.Write(topic_alt_frags[19])
|
||||
} else {
|
||||
if tmpl_topic_alt_vars.Topic.IsClosed {
|
||||
w.Write(topic_alt_frags[19])
|
||||
}
|
||||
}
|
||||
w.Write(topic_alt_frags[20])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Title))
|
||||
}
|
||||
}
|
||||
w.Write(topic_alt_frags[21])
|
||||
if tmpl_topic_alt_vars.Topic.IsClosed {
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Title))
|
||||
w.Write(topic_alt_frags[22])
|
||||
w.Write(phrases[24])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Title))
|
||||
w.Write(topic_alt_frags[23])
|
||||
w.Write(phrases[25])
|
||||
if tmpl_topic_alt_vars.Topic.IsClosed {
|
||||
w.Write(topic_alt_frags[24])
|
||||
w.Write(phrases[24])
|
||||
w.Write(topic_alt_frags[25])
|
||||
w.Write(phrases[25])
|
||||
w.Write(topic_alt_frags[26])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic {
|
||||
w.Write(topic_alt_frags[25])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Title))
|
||||
w.Write(topic_alt_frags[26])
|
||||
w.Write(phrases[26])
|
||||
w.Write(topic_alt_frags[27])
|
||||
w.Write(phrases[27])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Title))
|
||||
w.Write(topic_alt_frags[28])
|
||||
}
|
||||
w.Write(phrases[26])
|
||||
w.Write(topic_alt_frags[29])
|
||||
if tmpl_topic_alt_vars.Poll.ID > 0 {
|
||||
w.Write(phrases[27])
|
||||
w.Write(topic_alt_frags[30])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
}
|
||||
w.Write(topic_alt_frags[31])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
if tmpl_topic_alt_vars.Poll.ID > 0 {
|
||||
w.Write(topic_alt_frags[32])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write(topic_alt_frags[33])
|
||||
w.Write(phrases[28])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write(topic_alt_frags[34])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Avatar))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[35])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.UserLink))
|
||||
w.Write(phrases[28])
|
||||
w.Write(topic_alt_frags[36])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedByName))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Avatar))
|
||||
w.Write(topic_alt_frags[37])
|
||||
if tmpl_topic_alt_vars.Topic.Tag != "" {
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.UserLink))
|
||||
w.Write(topic_alt_frags[38])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Tag))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedByName))
|
||||
w.Write(topic_alt_frags[39])
|
||||
} else {
|
||||
if tmpl_topic_alt_vars.Topic.Tag != "" {
|
||||
w.Write(topic_alt_frags[40])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Tag))
|
||||
w.Write(topic_alt_frags[41])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[42])
|
||||
w.Write(phrases[29])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.Level)))
|
||||
w.Write(topic_alt_frags[41])
|
||||
}
|
||||
w.Write(topic_alt_frags[42])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write(topic_alt_frags[43])
|
||||
if len(tmpl_topic_alt_vars.Poll.QuickOptions) != 0 {
|
||||
for _, item := range tmpl_topic_alt_vars.Poll.QuickOptions {
|
||||
}
|
||||
w.Write(topic_alt_frags[44])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write(topic_alt_frags[45])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
if len(tmpl_topic_alt_vars.Poll.QuickOptions) != 0 {
|
||||
for _, item := range tmpl_topic_alt_vars.Poll.QuickOptions {
|
||||
w.Write(topic_alt_frags[46])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write(topic_alt_frags[47])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[48])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[49])
|
||||
w.Write([]byte(item.Value))
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[50])
|
||||
}
|
||||
}
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[51])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write([]byte(item.Value))
|
||||
w.Write(topic_alt_frags[52])
|
||||
w.Write(phrases[30])
|
||||
}
|
||||
}
|
||||
w.Write(topic_alt_frags[53])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write(topic_alt_frags[54])
|
||||
w.Write(phrases[31])
|
||||
w.Write(phrases[30])
|
||||
w.Write(topic_alt_frags[55])
|
||||
w.Write(phrases[32])
|
||||
w.Write(topic_alt_frags[56])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write(topic_alt_frags[56])
|
||||
w.Write(phrases[31])
|
||||
w.Write(topic_alt_frags[57])
|
||||
}
|
||||
w.Write(phrases[32])
|
||||
w.Write(topic_alt_frags[58])
|
||||
w.Write(phrases[33])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Poll.ID)))
|
||||
w.Write(topic_alt_frags[59])
|
||||
w.Write(phrases[34])
|
||||
}
|
||||
w.Write(topic_alt_frags[60])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Avatar))
|
||||
w.Write(topic_alt_frags[61])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.UserLink))
|
||||
w.Write(phrases[33])
|
||||
w.Write(topic_alt_frags[62])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedByName))
|
||||
w.Write(phrases[34])
|
||||
w.Write(topic_alt_frags[63])
|
||||
if tmpl_topic_alt_vars.Topic.Tag != "" {
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Avatar))
|
||||
w.Write(topic_alt_frags[64])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Tag))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.UserLink))
|
||||
w.Write(topic_alt_frags[65])
|
||||
} else {
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedByName))
|
||||
w.Write(topic_alt_frags[66])
|
||||
if tmpl_topic_alt_vars.Topic.Tag != "" {
|
||||
w.Write(topic_alt_frags[67])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Tag))
|
||||
w.Write(topic_alt_frags[68])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[69])
|
||||
w.Write(phrases[35])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.Level)))
|
||||
w.Write(topic_alt_frags[67])
|
||||
}
|
||||
w.Write(topic_alt_frags[68])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.ContentHTML))
|
||||
w.Write(topic_alt_frags[69])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
||||
w.Write(topic_alt_frags[70])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem {
|
||||
}
|
||||
w.Write(topic_alt_frags[71])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.ContentHTML))
|
||||
w.Write(topic_alt_frags[72])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
||||
w.Write(topic_alt_frags[73])
|
||||
w.Write(phrases[36])
|
||||
if tmpl_topic_alt_vars.Topic.LikeCount > 0 {
|
||||
w.Write(topic_alt_frags[74])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic {
|
||||
w.Write(topic_alt_frags[75])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
if tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_alt_frags[76])
|
||||
w.Write(phrases[37])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[77])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[78])
|
||||
if tmpl_topic_alt_vars.Topic.Liked {
|
||||
w.Write(topic_alt_frags[79])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[80])
|
||||
}
|
||||
w.Write(topic_alt_frags[81])
|
||||
w.Write(phrases[36])
|
||||
w.Write(topic_alt_frags[82])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic {
|
||||
w.Write(topic_alt_frags[83])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[84])
|
||||
w.Write(phrases[37])
|
||||
w.Write(topic_alt_frags[85])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteTopic {
|
||||
w.Write(topic_alt_frags[78])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[79])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[80])
|
||||
w.Write(phrases[38])
|
||||
w.Write(topic_alt_frags[81])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CloseTopic {
|
||||
if tmpl_topic_alt_vars.Topic.IsClosed {
|
||||
w.Write(topic_alt_frags[82])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[83])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[84])
|
||||
w.Write(phrases[39])
|
||||
w.Write(topic_alt_frags[85])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[86])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[87])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[88])
|
||||
w.Write(phrases[40])
|
||||
w.Write(phrases[38])
|
||||
w.Write(topic_alt_frags[89])
|
||||
}
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.PinTopic {
|
||||
if tmpl_topic_alt_vars.Topic.Sticky {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CloseTopic {
|
||||
if tmpl_topic_alt_vars.Topic.IsClosed {
|
||||
w.Write(topic_alt_frags[90])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[91])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[92])
|
||||
w.Write(phrases[41])
|
||||
w.Write(phrases[39])
|
||||
w.Write(topic_alt_frags[93])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[94])
|
||||
|
@ -406,208 +401,222 @@ w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
|||
w.Write(topic_alt_frags[95])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[96])
|
||||
w.Write(phrases[42])
|
||||
w.Write(phrases[40])
|
||||
w.Write(topic_alt_frags[97])
|
||||
}
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.PinTopic {
|
||||
if tmpl_topic_alt_vars.Topic.Sticky {
|
||||
w.Write(topic_alt_frags[98])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[99])
|
||||
w.Write(phrases[43])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[100])
|
||||
w.Write(phrases[44])
|
||||
w.Write(phrases[41])
|
||||
w.Write(topic_alt_frags[101])
|
||||
}
|
||||
} else {
|
||||
w.Write(topic_alt_frags[102])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[103])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[104])
|
||||
w.Write(phrases[45])
|
||||
w.Write(phrases[42])
|
||||
w.Write(topic_alt_frags[105])
|
||||
}
|
||||
w.Write(topic_alt_frags[106])
|
||||
if tmpl_topic_alt_vars.Topic.LikeCount > 0 {
|
||||
w.Write(topic_alt_frags[107])
|
||||
}
|
||||
w.Write(topic_alt_frags[108])
|
||||
if tmpl_topic_alt_vars.Topic.LikeCount > 0 {
|
||||
w.Write(topic_alt_frags[109])
|
||||
w.Write(phrases[46])
|
||||
w.Write(topic_alt_frags[110])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.LikeCount)))
|
||||
w.Write(topic_alt_frags[111])
|
||||
}
|
||||
w.Write(topic_alt_frags[112])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.RelativeCreatedAt))
|
||||
w.Write(topic_alt_frags[113])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_frags[114])
|
||||
w.Write(topic_alt_frags[106])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress))
|
||||
w.Write(topic_alt_frags[115])
|
||||
w.Write(phrases[47])
|
||||
w.Write(topic_alt_frags[116])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress))
|
||||
w.Write(topic_alt_frags[117])
|
||||
w.Write(topic_alt_frags[107])
|
||||
w.Write(phrases[43])
|
||||
w.Write(topic_alt_frags[108])
|
||||
w.Write(phrases[44])
|
||||
w.Write(topic_alt_frags[109])
|
||||
}
|
||||
w.Write(topic_alt_frags[110])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[111])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[112])
|
||||
w.Write(phrases[45])
|
||||
w.Write(topic_alt_frags[113])
|
||||
}
|
||||
w.Write(topic_alt_frags[114])
|
||||
w.Write(phrases[46])
|
||||
w.Write(topic_alt_frags[115])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.LikeCount)))
|
||||
w.Write(topic_alt_frags[116])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.RelativeCreatedAt))
|
||||
w.Write(topic_alt_frags[117])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_frags[118])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress))
|
||||
w.Write(topic_alt_frags[119])
|
||||
w.Write(phrases[47])
|
||||
w.Write(topic_alt_frags[120])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress))
|
||||
w.Write(topic_alt_frags[121])
|
||||
}
|
||||
w.Write(topic_alt_frags[122])
|
||||
if len(tmpl_topic_alt_vars.ItemList) != 0 {
|
||||
for _, item := range tmpl_topic_alt_vars.ItemList {
|
||||
w.Write(topic_alt_frags[119])
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_frags[120])
|
||||
}
|
||||
w.Write(topic_alt_frags[121])
|
||||
w.Write(phrases[48])
|
||||
w.Write(topic_alt_frags[122])
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_alt_frags[123])
|
||||
w.Write([]byte(item.UserLink))
|
||||
w.Write(topic_alt_frags[124])
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_frags[125])
|
||||
if item.Tag != "" {
|
||||
}
|
||||
w.Write(topic_alt_frags[126])
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(phrases[48])
|
||||
w.Write(topic_alt_frags[127])
|
||||
} else {
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_alt_frags[128])
|
||||
w.Write([]byte(item.UserLink))
|
||||
w.Write(topic_alt_frags[129])
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topic_alt_frags[130])
|
||||
if item.Tag != "" {
|
||||
w.Write(topic_alt_frags[131])
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(topic_alt_frags[132])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[133])
|
||||
w.Write(phrases[49])
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write(topic_alt_frags[129])
|
||||
}
|
||||
w.Write(topic_alt_frags[130])
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_frags[131])
|
||||
}
|
||||
w.Write(topic_alt_frags[132])
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_frags[133])
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_alt_frags[134])
|
||||
w.Write([]byte(item.ActionType))
|
||||
}
|
||||
w.Write(topic_alt_frags[135])
|
||||
} else {
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_frags[136])
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
}
|
||||
w.Write(topic_alt_frags[137])
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_frags[138])
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_alt_frags[139])
|
||||
w.Write([]byte(item.ActionType))
|
||||
w.Write(topic_alt_frags[140])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[141])
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(topic_alt_frags[142])
|
||||
if item.LikeCount > 0 {
|
||||
w.Write(topic_alt_frags[143])
|
||||
}
|
||||
w.Write(topic_alt_frags[144])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_alt_frags[138])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[139])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[140])
|
||||
w.Write(phrases[50])
|
||||
w.Write(topic_alt_frags[141])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_alt_frags[142])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[143])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[144])
|
||||
w.Write(phrases[51])
|
||||
w.Write(topic_alt_frags[145])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply {
|
||||
w.Write(topic_alt_frags[146])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[147])
|
||||
w.Write(topic_alt_frags[146])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[147])
|
||||
if item.Liked {
|
||||
w.Write(topic_alt_frags[148])
|
||||
w.Write(phrases[52])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[149])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_frags[150])
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(phrases[50])
|
||||
w.Write(topic_alt_frags[151])
|
||||
w.Write(phrases[53])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_alt_frags[152])
|
||||
w.Write(phrases[54])
|
||||
w.Write(topic_alt_frags[153])
|
||||
}
|
||||
w.Write(topic_alt_frags[154])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[155])
|
||||
w.Write(topic_alt_frags[153])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[156])
|
||||
w.Write(phrases[55])
|
||||
w.Write(topic_alt_frags[157])
|
||||
w.Write(topic_alt_frags[154])
|
||||
w.Write(phrases[51])
|
||||
w.Write(topic_alt_frags[155])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply {
|
||||
w.Write(topic_alt_frags[156])
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[157])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[158])
|
||||
if item.LikeCount > 0 {
|
||||
w.Write(phrases[52])
|
||||
w.Write(topic_alt_frags[159])
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_frags[160])
|
||||
if item.LikeCount > 0 {
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_alt_frags[161])
|
||||
w.Write(phrases[56])
|
||||
w.Write(phrases[53])
|
||||
w.Write(topic_alt_frags[162])
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(phrases[54])
|
||||
w.Write(topic_alt_frags[163])
|
||||
}
|
||||
w.Write(topic_alt_frags[164])
|
||||
w.Write([]byte(item.RelativeCreatedAt))
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_frags[165])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[166])
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(phrases[55])
|
||||
w.Write(topic_alt_frags[167])
|
||||
w.Write([]byte(item.IPAddress))
|
||||
}
|
||||
w.Write(topic_alt_frags[168])
|
||||
}
|
||||
w.Write(phrases[56])
|
||||
w.Write(topic_alt_frags[169])
|
||||
}
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topic_alt_frags[170])
|
||||
}
|
||||
}
|
||||
w.Write([]byte(item.RelativeCreatedAt))
|
||||
w.Write(topic_alt_frags[171])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_frags[172])
|
||||
w.Write(phrases[57])
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_alt_frags[173])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Avatar))
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_alt_frags[174])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Link))
|
||||
}
|
||||
w.Write(topic_alt_frags[175])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Name))
|
||||
}
|
||||
w.Write(topic_alt_frags[176])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Tag != "" {
|
||||
}
|
||||
}
|
||||
w.Write(topic_alt_frags[177])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Tag))
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write(topic_alt_frags[178])
|
||||
} else {
|
||||
w.Write(phrases[57])
|
||||
w.Write(topic_alt_frags[179])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Avatar))
|
||||
w.Write(topic_alt_frags[180])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Link))
|
||||
w.Write(topic_alt_frags[181])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Name))
|
||||
w.Write(topic_alt_frags[182])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Tag != "" {
|
||||
w.Write(topic_alt_frags[183])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Tag))
|
||||
w.Write(topic_alt_frags[184])
|
||||
} else {
|
||||
w.Write(topic_alt_frags[185])
|
||||
w.Write(phrases[58])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.CurrentUser.Level)))
|
||||
w.Write(topic_alt_frags[180])
|
||||
}
|
||||
w.Write(topic_alt_frags[181])
|
||||
w.Write(phrases[59])
|
||||
w.Write(topic_alt_frags[182])
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[183])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[184])
|
||||
w.Write(phrases[60])
|
||||
w.Write(topic_alt_frags[185])
|
||||
w.Write(phrases[61])
|
||||
w.Write(topic_alt_frags[186])
|
||||
w.Write(phrases[62])
|
||||
}
|
||||
w.Write(topic_alt_frags[187])
|
||||
w.Write(phrases[63])
|
||||
w.Write(phrases[59])
|
||||
w.Write(topic_alt_frags[188])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.UploadFiles {
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_frags[189])
|
||||
w.Write(phrases[64])
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_frags[190])
|
||||
}
|
||||
w.Write(phrases[60])
|
||||
w.Write(topic_alt_frags[191])
|
||||
}
|
||||
w.Write(phrases[61])
|
||||
w.Write(topic_alt_frags[192])
|
||||
w.Write(phrases[62])
|
||||
w.Write(topic_alt_frags[193])
|
||||
w.Write(phrases[63])
|
||||
w.Write(topic_alt_frags[194])
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.UploadFiles {
|
||||
w.Write(topic_alt_frags[195])
|
||||
w.Write(phrases[64])
|
||||
w.Write(topic_alt_frags[196])
|
||||
}
|
||||
w.Write(topic_alt_frags[197])
|
||||
}
|
||||
w.Write(topic_alt_frags[198])
|
||||
w.Write(footer_frags[0])
|
||||
w.Write([]byte(common.BuildWidget("footer",tmpl_topic_alt_vars.Header)))
|
||||
w.Write(footer_frags[1])
|
||||
|
|
|
@ -317,67 +317,75 @@ w.Write([]byte(item.Link))
|
|||
w.Write(topics_frags[62])
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(topics_frags[63])
|
||||
if item.ForumName != "" {
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(topics_frags[64])
|
||||
w.Write([]byte(item.ForumLink))
|
||||
if item.ForumName != "" {
|
||||
w.Write(topics_frags[65])
|
||||
w.Write([]byte(item.ForumName))
|
||||
w.Write([]byte(item.ForumLink))
|
||||
w.Write(topics_frags[66])
|
||||
}
|
||||
w.Write([]byte(item.ForumName))
|
||||
w.Write(topics_frags[67])
|
||||
w.Write([]byte(item.Creator.Link))
|
||||
w.Write([]byte(item.ForumName))
|
||||
w.Write(topics_frags[68])
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
}
|
||||
w.Write(topics_frags[69])
|
||||
if item.IsClosed {
|
||||
w.Write([]byte(item.Creator.Link))
|
||||
w.Write(topics_frags[70])
|
||||
w.Write(phrases[44])
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(topics_frags[71])
|
||||
}
|
||||
if item.Sticky {
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(topics_frags[72])
|
||||
w.Write(phrases[45])
|
||||
if item.IsClosed {
|
||||
w.Write(topics_frags[73])
|
||||
}
|
||||
w.Write(phrases[44])
|
||||
w.Write(topics_frags[74])
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(topics_frags[75])
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topics_frags[76])
|
||||
}
|
||||
if item.Sticky {
|
||||
w.Write(topics_frags[75])
|
||||
w.Write(phrases[45])
|
||||
w.Write(topics_frags[76])
|
||||
}
|
||||
w.Write(topics_frags[77])
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(topics_frags[78])
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topics_frags[79])
|
||||
if item.Sticky {
|
||||
w.Write(topics_frags[80])
|
||||
} else {
|
||||
if item.IsClosed {
|
||||
w.Write(topics_frags[78])
|
||||
}
|
||||
}
|
||||
w.Write(topics_frags[79])
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
w.Write(topics_frags[80])
|
||||
w.Write([]byte(item.LastUser.Avatar))
|
||||
w.Write(topics_frags[81])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
}
|
||||
}
|
||||
w.Write(topics_frags[82])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_frags[83])
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
w.Write(topics_frags[83])
|
||||
w.Write([]byte(item.LastUser.Avatar))
|
||||
w.Write(topics_frags[84])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_frags[85])
|
||||
w.Write([]byte(item.RelativeLastReplyAt))
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_frags[86])
|
||||
}
|
||||
} else {
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
w.Write(topics_frags[87])
|
||||
w.Write(phrases[46])
|
||||
if tmpl_topics_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_frags[88])
|
||||
w.Write(phrases[47])
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_frags[89])
|
||||
}
|
||||
w.Write([]byte(item.RelativeLastReplyAt))
|
||||
w.Write(topics_frags[90])
|
||||
}
|
||||
} else {
|
||||
w.Write(topics_frags[91])
|
||||
w.Write(phrases[46])
|
||||
if tmpl_topics_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write(topics_frags[92])
|
||||
w.Write(phrases[47])
|
||||
w.Write(topics_frags[93])
|
||||
}
|
||||
w.Write(topics_frags[94])
|
||||
}
|
||||
w.Write(topics_frags[95])
|
||||
if tmpl_topics_vars.LastPage > 1 {
|
||||
w.Write(paginator_frags[0])
|
||||
if tmpl_topics_vars.Page > 1 {
|
||||
|
@ -413,7 +421,7 @@ w.Write(paginator_frags[13])
|
|||
}
|
||||
w.Write(paginator_frags[14])
|
||||
}
|
||||
w.Write(topics_frags[92])
|
||||
w.Write(topics_frags[96])
|
||||
w.Write(footer_frags[0])
|
||||
w.Write([]byte(common.BuildWidget("footer",tmpl_topics_vars.Header)))
|
||||
w.Write(footer_frags[1])
|
||||
|
|
|
@ -82,8 +82,8 @@
|
|||
<span class="selector"></span>
|
||||
<a href="{{.Creator.Link}}"><img src="{{.Creator.Avatar}}" height="64" alt="{{.Creator.Name}}'s Avatar" title="{{.Creator.Name}}'s Avatar" /></a>
|
||||
<span class="topic_inner_left">
|
||||
<a class="rowtopic" href="{{.Link}}" itemprop="itemListElement"><span>{{.Title}}</span></a>
|
||||
<br /><a class="rowsmall starter" href="{{.Creator.Link}}">{{.Creator.Name}}</a>
|
||||
<a class="rowtopic" href="{{.Link}}" itemprop="itemListElement" title="{{.Title}}"><span>{{.Title}}</span></a>
|
||||
<br /><a class="rowsmall starter" href="{{.Creator.Link}}" title="{{.Creator.Name}}">{{.Creator.Name}}</a>
|
||||
{{/** TODO: Avoid the double '|' when both .IsClosed and .Sticky are set to true. We could probably do this with CSS **/}}
|
||||
{{if .IsClosed}}<span class="rowsmall topic_status_e topic_status_closed" title="{{lang "status_closed_tooltip"}}"> | 🔒︎</span>{{end}}
|
||||
{{if .Sticky}}<span class="rowsmall topic_status_e topic_status_sticky" title="{{lang "status_pinned_tooltip"}}"> | 📍︎</span>{{end}}
|
||||
|
@ -96,7 +96,7 @@
|
|||
<div class="rowitem topic_right passive datarow {{if .Sticky}}topic_sticky{{else if .IsClosed}}topic_closed{{end}}">
|
||||
<a href="{{.LastUser.Link}}"><img src="{{.LastUser.Avatar}}" height="64" alt="{{.LastUser.Name}}'s Avatar" title="{{.LastUser.Name}}'s Avatar" /></a>
|
||||
<span>
|
||||
<a href="{{.LastUser.Link}}" class="lastName" style="font-size: 14px;">{{.LastUser.Name}}</a><br>
|
||||
<a href="{{.LastUser.Link}}" class="lastName" style="font-size: 14px;" title="{{.LastUser.Name}}">{{.LastUser.Name}}</a><br>
|
||||
<span class="rowsmall lastReplyAt">{{.RelativeLastReplyAt}}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<img src="{{.ProfileOwner.Avatar}}" class="avatar" alt="{{.ProfileOwner.Name}}'s Avatar" title="{{.ProfileOwner.Name}}'s Avatar" />
|
||||
</div>
|
||||
<div class="rowitem nameRow">
|
||||
<span class="profileName">{{.ProfileOwner.Name}}</span>{{if .ProfileOwner.Tag}}<span class="username">{{.ProfileOwner.Tag}}</span>{{end}}
|
||||
<span class="profileName" title="{{.ProfileOwner.Name}}">{{.ProfileOwner.Name}}</span>{{if .ProfileOwner.Tag}}<span class="username" title="{{.ProfileOwner.Tag}}">{{.ProfileOwner.Tag}}</span>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="passiveBlock">
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
<main>
|
||||
|
||||
<div class="rowblock rowhead topic_block" aria-label="{{lang "topic_opening_post_aria"}}">
|
||||
<div {{scope "topic_title_block"}} class="rowblock rowhead topic_block" aria-label="{{lang "topic_opening_post_aria"}}">
|
||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.IsClosed}} topic_closed_head{{end}}">
|
||||
<h1 class='topic_name hide_on_edit'>{{.Topic.Title}}</h1>
|
||||
<h1 class='topic_name hide_on_edit' title='{{.Topic.Title}}'>{{.Topic.Title}}</h1>
|
||||
{{if .Topic.IsClosed}}<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='{{lang "status_closed_tooltip"}}' aria-label='{{lang "topic_status_closed_aria"}}'>🔒︎</span>{{end}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}
|
||||
<input form='edit_topic_form' class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" aria-label="{{lang "topic_title_input_aria"}}" />
|
||||
|
@ -47,16 +47,16 @@
|
|||
</article>
|
||||
{{end}}
|
||||
|
||||
<article itemscope itemtype="http://schema.org/CreativeWork" class="rowblock post_container top_post" aria-label="{{lang "topic_opening_post_aria"}}">
|
||||
<article {{scope "opening_post"}} itemscope itemtype="http://schema.org/CreativeWork" class="rowblock post_container top_post" aria-label="{{lang "topic_opening_post_aria"}}">
|
||||
<div class="rowitem passive editable_parent post_item {{.Topic.ClassName}}" style="background-image: url({{.Topic.Avatar}}), url(/static/{{.Header.Theme.Name}}/post-avatar-bg.jpg);background-position: 0px {{if le .Topic.ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;">
|
||||
<p class="hide_on_edit topic_content user_content" itemprop="text" style="margin:0;padding:0;">{{.Topic.ContentHTML}}</p>
|
||||
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea>
|
||||
|
||||
<span class="controls" aria-label="{{lang "topic_post_controls_aria"}}">
|
||||
<span class="controls{{if .Topic.LikeCount}} has_likes{{end}}" aria-label="{{lang "topic_post_controls_aria"}}">
|
||||
|
||||
<a href="{{.Topic.UserLink}}" class="username real_username" rel="author">{{.Topic.CreatedByName}}</a>
|
||||
{{if .CurrentUser.Perms.LikeItem}}<a href="/topic/like/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}" class="mod_button"{{if .Topic.Liked}} title="{{lang "topic_unlike_tooltip"}}" aria-label="{{lang "topic_unlike_aria"}}"{{else}} title="{{lang "topic_like_tooltip"}}" aria-label="{{lang "topic_like_aria"}}"{{end}} style="color:#202020;">
|
||||
<button class="username like_label"{{if .Topic.Liked}} style="background-color:#D6FFD6;"{{end}}></button></a>{{end}}
|
||||
<button class="username like_label {{if .Topic.Liked}}remove_like{{else}}add_like{{end}}"></button></a>{{end}}
|
||||
|
||||
{{if .CurrentUser.Perms.EditTopic}}<a href='/topic/edit/{{.Topic.ID}}' class="mod_button open_edit" style="font-weight:normal;" title="{{lang "topic_edit_tooltip"}}" aria-label="{{lang "topic_edit_aria"}}"><button class="username edit_label"></button></a>{{end}}
|
||||
|
||||
|
@ -68,7 +68,7 @@
|
|||
{{if .CurrentUser.Perms.ViewIPs}}<a class="mod_button" href='/users/ips/?ip={{.Topic.IPAddress}}' style="font-weight:normal;" title="{{lang "topic_ip_tooltip"}}" aria-label="The poster's IP is {{.Topic.IPAddress}}"><button class="username ip_label"></button></a>{{end}}
|
||||
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="mod_button report_item" style="font-weight:normal;" title="{{lang "topic_flag_tooltip"}}" aria-label="{{lang "topic_flag_aria"}}" rel="nofollow"><button class="username flag_label"></button></a>
|
||||
|
||||
{{if .Topic.LikeCount}}<a class="username hide_on_micro like_count" aria-label="{{lang "topic_like_count_aria"}}">{{.Topic.LikeCount}}</a><a class="username hide_on_micro like_count_label" title="{{lang "topic_like_count_tooltip"}}"></a>{{end}}
|
||||
<a class="username hide_on_micro like_count" aria-label="{{lang "topic_like_count_aria"}}">{{.Topic.LikeCount}}</a><a class="username hide_on_micro like_count_label" title="{{lang "topic_like_count_tooltip"}}"></a>
|
||||
|
||||
{{if .Topic.Tag}}<a class="username hide_on_micro user_tag">{{.Topic.Tag}}</a>{{else}}<a class="username hide_on_micro level" aria-label="{{lang "topic_level_aria"}}">{{.Topic.Level}}</a><a class="username hide_on_micro level_label" style="float:right;" title="{{lang "topic_level_tooltip"}}"></a>{{end}}
|
||||
|
||||
|
@ -82,14 +82,14 @@
|
|||
<span itemprop="text">{{.ActionType}}</span>
|
||||
</article>
|
||||
{{else}}
|
||||
<article itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item {{.ClassName}}" style="background-image: url({{.Avatar}}), url(/static/{{$.Header.Theme.Name}}/post-avatar-bg.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;">
|
||||
<article {{scope "post"}} itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item {{.ClassName}}" style="background-image: url({{.Avatar}}), url(/static/{{$.Header.Theme.Name}}/post-avatar-bg.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;">
|
||||
{{/** TODO: We might end up with <br>s in the inline editor, fix this **/}}
|
||||
<p class="editable_block user_content" itemprop="text" style="margin:0;padding:0;">{{.ContentHtml}}</p>
|
||||
|
||||
<span class="controls">
|
||||
<span class="controls{{if .LikeCount}} has_likes{{end}}">
|
||||
|
||||
<a href="{{.UserLink}}" class="username real_username" rel="author">{{.CreatedByName}}</a>
|
||||
{{if $.CurrentUser.Perms.LikeItem}}{{if .Liked}}<a href="/reply/like/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic_post_like_tooltip"}}" aria-label="{{lang "topic_post_like_aria"}}" style="color:#202020;"><button class="username like_label" style="background-color:#D6FFD6;"></button></a>{{else}}<a href="/reply/like/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic_post_unlike_tooltip"}}" aria-label="{{lang "topic_post_unlike_aria"}}" style="color:#202020;"><button class="username like_label"></button></a>{{end}}{{end}}
|
||||
{{if $.CurrentUser.Perms.LikeItem}}{{if .Liked}}<a href="/reply/like/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic_post_like_tooltip"}}" aria-label="{{lang "topic_post_like_aria"}}" style="color:#202020;"><button class="username like_label remove_like"></button></a>{{else}}<a href="/reply/like/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic_post_unlike_tooltip"}}" aria-label="{{lang "topic_post_unlike_aria"}}" style="color:#202020;"><button class="username like_label add_like"></button></a>{{end}}{{end}}
|
||||
|
||||
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic_post_edit_tooltip"}}" aria-label="{{lang "topic_post_edit_aria"}}"><button class="username edit_item edit_label"></button></a>{{end}}
|
||||
|
||||
|
@ -97,7 +97,7 @@
|
|||
{{if $.CurrentUser.Perms.ViewIPs}}<a class="mod_button" href='/users/ips/?ip={{.IPAddress}}' style="font-weight:normal;" title="{{lang "topic_post_ip_tooltip"}}" aria-label="The poster's IP is {{.IPAddress}}"><button class="username ip_label"></button></a>{{end}}
|
||||
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="mod_button report_item" title="{{lang "topic_post_flag_tooltip"}}" aria-label="{{lang "topic_post_flag_aria"}}" rel="nofollow"><button class="username report_item flag_label"></button></a>
|
||||
|
||||
{{if .LikeCount}}<a class="username hide_on_micro like_count">{{.LikeCount}}</a><a class="username hide_on_micro like_count_label" title="{{lang "topic_post_like_count_tooltip"}}"></a>{{end}}
|
||||
<a class="username hide_on_micro like_count">{{.LikeCount}}</a><a class="username hide_on_micro like_count_label" title="{{lang "topic_post_like_count_tooltip"}}"></a>
|
||||
|
||||
{{if .Tag}}<a class="username hide_on_micro user_tag">{{.Tag}}</a>{{else}}<a class="username hide_on_micro level" aria-label="{{lang "topic_post_level_aria"}}">{{.Level}}</a><a class="username hide_on_micro level_label" style="float:right;" title="{{lang "topic_post_level_tooltip"}}"></a>{{end}}
|
||||
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
<main>
|
||||
|
||||
<div class="rowblock rowhead topic_block" aria-label="{{lang "topic_opening_post_aria"}}">
|
||||
<div {{scope "topic_title_block"}} class="rowblock rowhead topic_block" aria-label="{{lang "topic_opening_post_aria"}}">
|
||||
<form action='/topic/edit/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}' method="post">
|
||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.IsClosed}} topic_closed_head{{end}}">
|
||||
<h1 class='topic_name hide_on_edit'>{{.Topic.Title}}</h1>
|
||||
<h1 class='topic_name hide_on_edit' title='{{.Topic.Title}}'>{{.Topic.Title}}</h1>
|
||||
{{/** TODO: Inline this CSS **/}}
|
||||
{{if .Topic.IsClosed}}<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='{{lang "status_closed_tooltip"}}' aria-label='{{lang "topic_status_closed_aria"}}' style="font-weight:normal;float: right;position:relative;top:-5px;">🔒︎</span>{{end}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}
|
||||
|
@ -54,7 +54,7 @@
|
|||
</div>
|
||||
</article>
|
||||
{{end}}
|
||||
<article itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item top_post" aria-label="{{lang "topic_opening_post_aria"}}">
|
||||
<article {{scope "opening_post"}} itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item top_post" aria-label="{{lang "topic_opening_post_aria"}}">
|
||||
<div class="userinfo" aria-label="{{lang "topic_userinfo_aria"}}">
|
||||
<div class="avatar_item" style="background-image: url({{.Topic.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<a href="{{.Topic.UserLink}}" class="the_name" rel="author">{{.Topic.CreatedByName}}</a>
|
||||
|
@ -63,9 +63,9 @@
|
|||
<div class="content_container">
|
||||
<div class="hide_on_edit topic_content user_content" itemprop="text">{{.Topic.ContentHTML}}</div>
|
||||
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea>
|
||||
<div class="button_container">
|
||||
<div class="controls button_container{{if .Topic.LikeCount}} has_likes{{end}}">
|
||||
{{if .CurrentUser.Loggedin}}
|
||||
{{if .CurrentUser.Perms.LikeItem}}<a href="/topic/like/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}" class="action_button like_item add_like" aria-label="{{lang "topic_like_aria"}}" data-action="like"></a>{{end}}
|
||||
{{if .CurrentUser.Perms.LikeItem}}<a href="/topic/like/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}" class="action_button like_item {{if .Topic.Liked}}remove_like{{else}}add_like{{end}}" aria-label="{{lang "topic_like_aria"}}" data-action="like"></a>{{end}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}<a href="/topic/edit/{{.Topic.ID}}" class="action_button open_edit" aria-label="{{lang "topic_edit_aria"}}" data-action="edit"></a>{{end}}
|
||||
{{if .CurrentUser.Perms.DeleteTopic}}<a href="/topic/delete/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}" class="action_button delete_item" aria-label="{{lang "topic_delete_aria"}}" data-action="delete"></a>{{end}}
|
||||
{{if .CurrentUser.Perms.CloseTopic}}
|
||||
|
@ -76,8 +76,8 @@
|
|||
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="action_button report_item" aria-label="{{lang "topic_report_aria"}}" data-action="report"></a>
|
||||
<a href="#" class="action_button button_menu"></a>
|
||||
{{end}}
|
||||
<div class="action_button_right{{if .Topic.LikeCount}} has_likes{{end}}">
|
||||
{{if .Topic.LikeCount}}<a class="action_button like_count hide_on_micro" aria-label="{{lang "topic_like_count_aria"}}">{{.Topic.LikeCount}}</a>{{end}}
|
||||
<div class="action_button_right">
|
||||
<a class="action_button like_count hide_on_micro" aria-label="{{lang "topic_like_count_aria"}}">{{.Topic.LikeCount}}</a>
|
||||
<a class="action_button created_at hide_on_mobile">{{.Topic.RelativeCreatedAt}}</a>
|
||||
{{if .CurrentUser.Perms.ViewIPs}}<a href="/users/ips/?ip={{.Topic.IPAddress}}" title="{{lang "topic_ip_full_tooltip"}}" class="action_button ip_item hide_on_mobile" aria-hidden="true">{{.Topic.IPAddress}}</a>{{end}}
|
||||
</div>
|
||||
|
@ -86,7 +86,7 @@
|
|||
</article>
|
||||
|
||||
{{range .ItemList}}
|
||||
<article itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item {{if .ActionType}}action_item{{end}}">
|
||||
<article {{scope "post"}} itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item {{if .ActionType}}action_item{{end}}">
|
||||
<div class="userinfo" aria-label="{{lang "topic_userinfo_aria"}}">
|
||||
<div class="avatar_item" style="background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<a href="{{.UserLink}}" class="the_name" rel="author">{{.CreatedByName}}</a>
|
||||
|
@ -99,17 +99,17 @@
|
|||
{{else}}
|
||||
{{/** TODO: We might end up with <br>s in the inline editor, fix this **/}}
|
||||
<div class="editable_block user_content" itemprop="text">{{.ContentHtml}}</div>
|
||||
<div class="button_container">
|
||||
<div class="controls button_container{{if .LikeCount}} has_likes{{end}}">
|
||||
{{if $.CurrentUser.Loggedin}}
|
||||
{{if $.CurrentUser.Perms.LikeItem}}<a href="/reply/like/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="action_button like_item add_like" aria-label="{{lang "topic_post_like_aria"}}" data-action="like"></a>{{end}}
|
||||
{{if $.CurrentUser.Perms.LikeItem}}<a href="/reply/like/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="action_button like_item {{if .Liked}}remove_like{{else}}add_like{{end}}" aria-label="{{lang "topic_post_like_aria"}}" data-action="like"></a>{{end}}
|
||||
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="action_button edit_item" aria-label="{{lang "topic_post_edit_aria"}}" data-action="edit"></a>{{end}}
|
||||
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="action_button delete_item" aria-label="{{lang "topic_post_delete_aria"}}" data-action="delete"></a>{{end}}
|
||||
{{if $.CurrentUser.Perms.ViewIPs}}<a href="/users/ips/?ip={{.IPAddress}}" title="{{lang "topic_ip_full_tooltip"}}" class="action_button ip_item_button hide_on_big" aria-label="{{lang "topic_ip_full_aria"}}" data-action="ip"></a>{{end}}
|
||||
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="action_button report_item" aria-label="{{lang "topic_report_aria"}}" data-action="report"></a>
|
||||
<a href="#" class="action_button button_menu"></a>
|
||||
{{end}}
|
||||
<div class="action_button_right{{if .LikeCount}} has_likes{{end}}">
|
||||
{{if .LikeCount}}<a class="action_button like_count hide_on_micro" aria-label="{{lang "topic_post_like_count_tooltip"}}">{{.LikeCount}}</a>{{end}}
|
||||
<div class="action_button_right">
|
||||
<a class="action_button like_count hide_on_micro" aria-label="{{lang "topic_post_like_count_tooltip"}}">{{.LikeCount}}</a>
|
||||
<a class="action_button created_at hide_on_mobile">{{.RelativeCreatedAt}}</a>
|
||||
{{if $.CurrentUser.Perms.ViewIPs}}<a href="/users/ips/?ip={{.IPAddress}}" title="IP Address" class="action_button ip_item hide_on_mobile" aria-hidden="true">{{.IPAddress}}</a>{{end}}
|
||||
</div>
|
||||
|
|
|
@ -107,8 +107,8 @@
|
|||
<span class="selector"></span>
|
||||
<a href="{{.Creator.Link}}"><img src="{{.Creator.Avatar}}" height="64" alt="{{.Creator.Name}}'s Avatar" title="{{.Creator.Name}}'s Avatar" /></a>
|
||||
<span class="topic_inner_left">
|
||||
<a class="rowtopic" href="{{.Link}}" itemprop="itemListElement"><span>{{.Title}}</span></a> {{if .ForumName}}<a class="rowsmall parent_forum" href="{{.ForumLink}}">{{.ForumName}}</a>{{end}}
|
||||
<br /><a class="rowsmall starter" href="{{.Creator.Link}}">{{.Creator.Name}}</a>
|
||||
<a class="rowtopic" href="{{.Link}}" itemprop="itemListElement" title="{{.Title}}"><span>{{.Title}}</span></a> {{if .ForumName}}<a class="rowsmall parent_forum" href="{{.ForumLink}}" title="{{.ForumName}}">{{.ForumName}}</a>{{end}}
|
||||
<br /><a class="rowsmall starter" href="{{.Creator.Link}}" title="{{.Creator.Name}}">{{.Creator.Name}}</a>
|
||||
{{/** TODO: Avoid the double '|' when both .IsClosed and .Sticky are set to true. We could probably do this with CSS **/}}
|
||||
{{if .IsClosed}}<span class="rowsmall topic_status_e topic_status_closed" title="{{lang "status_closed_tooltip"}}"> | 🔒︎</span>{{end}}
|
||||
{{if .Sticky}}<span class="rowsmall topic_status_e topic_status_sticky" title="{{lang "status_pinned_tooltip"}}"> | 📍︎</span>{{end}}
|
||||
|
@ -121,7 +121,7 @@
|
|||
<div class="rowitem topic_right passive datarow {{if .Sticky}}topic_sticky{{else if .IsClosed}}topic_closed{{end}}">
|
||||
<a href="{{.LastUser.Link}}"><img src="{{.LastUser.Avatar}}" height="64" alt="{{.LastUser.Name}}'s Avatar" title="{{.LastUser.Name}}'s Avatar" /></a>
|
||||
<span>
|
||||
<a href="{{.LastUser.Link}}" class="lastName" style="font-size: 14px;">{{.LastUser.Name}}</a><br>
|
||||
<a href="{{.LastUser.Link}}" class="lastName" style="font-size: 14px;" title="{{.LastUser.Name}}">{{.LastUser.Name}}</a><br>
|
||||
<span class="rowsmall lastReplyAt">{{.RelativeLastReplyAt}}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -1002,12 +1002,18 @@ textarea {
|
|||
display: inline-flex;
|
||||
margin-left: auto;
|
||||
}
|
||||
.like_count {
|
||||
display: none;
|
||||
}
|
||||
.has_likes .like_count {
|
||||
display: block;
|
||||
}
|
||||
.like_count:after {
|
||||
content: "{{index .Phrases "topic_like_count_suffix"}}";
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.post_item .add_like:after,
|
||||
.post_item .add_like:after, .post_item .remove_like:after,
|
||||
.created_at:before,
|
||||
.ip_item:before {
|
||||
border-left: 1px solid var(--element-border-color);
|
||||
|
@ -1018,15 +1024,19 @@ textarea {
|
|||
.created_at:before, .ip_item:before {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.post_item .add_like:after {
|
||||
.post_item .add_like:after, .post_item .remove_like:after {
|
||||
margin-left: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
/* TODO: Use a less bold bold */
|
||||
.post_item .remove_like:before {
|
||||
font-weight: bold;
|
||||
}
|
||||
.created_at {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.add_like:before {
|
||||
.add_like:before, .remove_like:before {
|
||||
content: "{{index .Phrases "topic_plus_one"}}";
|
||||
}
|
||||
.button_container .open_edit:after, .edit_item:after{
|
||||
|
@ -1651,10 +1661,10 @@ textarea {
|
|||
padding-top: 15px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.action_button:not(.add_like) {
|
||||
.action_button:not(.add_like):not(.remove_like) {
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
}
|
||||
.action_button_right.has_likes {
|
||||
.has_likes .action_button_right {
|
||||
margin-left: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1664,7 +1674,7 @@ textarea {
|
|||
.post_item:not(.top_post) .like_item {
|
||||
border-bottom: 1px solid var(--element-border-color);
|
||||
}
|
||||
.post_item .add_like:after {
|
||||
.post_item .add_like:after, .post_item .remove_like:after {
|
||||
border-left: none;
|
||||
margin: inherit;
|
||||
}
|
||||
|
@ -1810,7 +1820,7 @@ textarea {
|
|||
.button_menu_pane .action_button:nth-last-child(-n+8) {
|
||||
border-bottom: none;
|
||||
}
|
||||
.button_menu_pane .action_button:after, .button_menu_pane .add_like:before {
|
||||
.button_menu_pane .action_button:after, .button_menu_pane .add_like:before, .button_menu_pane .remove_like:before {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
|
|
@ -336,16 +336,19 @@ a {
|
|||
content: "{{index .Phrases "topic_level"}}";
|
||||
}
|
||||
|
||||
.like_count_label, .like_count {
|
||||
display: none;
|
||||
}
|
||||
.like_count_label:before {
|
||||
content: "{{index .Phrases "topics_likes_suffix"}}";
|
||||
}
|
||||
.like_count_label {
|
||||
.has_likes .like_count_label {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
float: left;
|
||||
line-height: 19px;
|
||||
}
|
||||
.like_count {
|
||||
.has_likes .like_count {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
float: left;
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
"FullImage": "shadow.png",
|
||||
"URL": "github.com/Azareal/Gosora",
|
||||
"BgAvatars":true,
|
||||
"Templates": [
|
||||
{
|
||||
"Name": "topic",
|
||||
"Source": "topic"
|
||||
}
|
||||
],
|
||||
"Resources": [
|
||||
{
|
||||
"Name":"shadow/misc.js",
|
||||
|
|
|
@ -716,6 +716,12 @@ button.username {
|
|||
margin-right: auto;
|
||||
}
|
||||
|
||||
.like_count {
|
||||
display: none;
|
||||
}
|
||||
.has_likes .like_count {
|
||||
display: block;
|
||||
}
|
||||
.like_label:before {
|
||||
content: "😀";
|
||||
}
|
||||
|
@ -961,7 +967,7 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
|||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.add_like:before {
|
||||
.add_like:before, .remove_like:before {
|
||||
content: "{{index .Phrases "topic_plus_one"}}";
|
||||
}
|
||||
.button_container .open_edit:after, .edit_item:after {
|
||||
|
|
|
@ -9,5 +9,11 @@
|
|||
"HideFromThemes": true,
|
||||
"BgAvatars":true,
|
||||
"URL": "github.com/Azareal/Gosora",
|
||||
"Templates": [
|
||||
{
|
||||
"Name": "topic",
|
||||
"Source": "topic"
|
||||
}
|
||||
],
|
||||
"Docks":["rightSidebar"]
|
||||
}
|
||||
|
|
|
@ -647,6 +647,12 @@ button.username {
|
|||
.mod_button {
|
||||
margin-right: 4px;
|
||||
}
|
||||
.like_count_label, .like_count {
|
||||
display: none;
|
||||
}
|
||||
.has_likes .like_count_label, .has_likes .like_count {
|
||||
display: block;
|
||||
}
|
||||
.like_label:before, .like_count_label:before {
|
||||
content: "😀";
|
||||
}
|
||||
|
@ -674,7 +680,7 @@ button.username {
|
|||
.pin_label:before, .unpin_label:before {
|
||||
content: "📌";
|
||||
}
|
||||
.unpin_label, .unlock_label {
|
||||
.remove_like, .unpin_label, .unlock_label {
|
||||
background-color: #D6FFD6;
|
||||
}
|
||||
.lock_label:before, .unlock_label:before {
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
"URL": "github.com/Azareal/Gosora",
|
||||
"BgAvatars":true,
|
||||
"Docks":["rightSidebar"],
|
||||
"Templates": [
|
||||
{
|
||||
"Name": "topic",
|
||||
"Source": "topic"
|
||||
}
|
||||
],
|
||||
"Resources": [
|
||||
{
|
||||
"Name":"tempra-simple/misc.js",
|
||||
|
|
Loading…
Reference in New Issue