Added the topic and user memory caches. Currently used in an extremely limited way, we plan to expand this!
Added a template minifier which strips out many types of whitespace. Stop the router from blocking the other goroutines. Content is no longer an interface{} in the TopicUser and Reply structs Allow plugins to add new routes without any potential race coditions occuring Use non-breaking spaces in the topic view to make it harder for the minifier to break things.
This commit is contained in:
parent
534ef10194
commit
399128c208
|
@ -0,0 +1,23 @@
|
|||
package main
|
||||
import "errors"
|
||||
|
||||
const CACHE_STATIC int = 0
|
||||
const CACHE_DYNAMIC int = 1
|
||||
const CACHE_SQL int = 2
|
||||
|
||||
var ErrStoreCapacityOverflow = errors.New("This datastore has already reached it's max capacity")
|
||||
|
||||
var users UserStore
|
||||
var topics TopicStore
|
||||
|
||||
type DataStore interface {
|
||||
Get(id int) (interface{}, error)
|
||||
GetUnsafe(id int) (interface{}, error)
|
||||
CascadeGet(id int) (interface{}, error)
|
||||
Add(item interface{}) error
|
||||
AddUnsafe(item interface{}) error
|
||||
Remove(id int) error
|
||||
RemoveUnsafe(id int) error
|
||||
GetLength() int
|
||||
GetCapacity() int
|
||||
}
|
|
@ -11,6 +11,9 @@ var dbport = "3306" // You probably won't need to change this
|
|||
var max_request_size = 5 * megabyte
|
||||
|
||||
// Misc
|
||||
var cache_topicuser = CACHE_STATIC
|
||||
var user_cache_capacity = 100 // The max number of users held in memory
|
||||
var topic_cache_capacity = 100 // The max number of topics held in memory
|
||||
var default_route = route_topics
|
||||
var default_group = 3 // Should be a setting
|
||||
var activation_group = 5 // Should be a setting
|
||||
|
|
1
data.sql
1
data.sql
|
@ -112,6 +112,7 @@ CREATE TABLE `users_replies`(
|
|||
|
||||
CREATE TABLE `likes`(
|
||||
`weight` tinyint DEFAULT 1 not null,
|
||||
/*`type` tinyint not null, /* Regular Post = 1, Big Post = 2, Mega Post = 3, etc.*/
|
||||
`targetItem` int not null,
|
||||
`targetType` varchar(50) DEFAULT 'replies' not null,
|
||||
`sentBy` int not null,
|
||||
|
|
|
@ -149,6 +149,9 @@ var dbport = "` + db_port + `" // You probably won't need to change this
|
|||
var max_request_size = 5 * megabyte
|
||||
|
||||
// Misc
|
||||
var cache_topicuser = CACHE_STATIC
|
||||
var user_cache_capacity = 100 // The max number of users held in memory
|
||||
var topic_cache_capacity = 100 // The max number of topics held in memory
|
||||
var default_route = route_topics
|
||||
var default_group = 3 // Should be a setting
|
||||
var activation_group = 5 // Should be a setting
|
||||
|
|
14
main.go
14
main.go
|
@ -51,9 +51,9 @@ func compile_templates() {
|
|||
|
||||
log.Print("Compiling the templates")
|
||||
|
||||
topic := TopicUser{1,"Blah",template.HTML("Hey there!"),0,false,false,"Date","Date",0,"","127.0.0.1",0,1,"","",no_css_tmpl,0,"","","","",58,false}
|
||||
topic := TopicUser{1,"Blah","Hey there!",0,false,false,"Date","Date",0,"","127.0.0.1",0,1,"",default_group,"",no_css_tmpl,0,"","","","",58,false}
|
||||
var replyList []Reply
|
||||
replyList = append(replyList, Reply{0,0,"",template.HTML("Yo!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
|
||||
replyList = append(replyList, Reply{0,0,"","Yo!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
|
||||
|
||||
var varList map[string]VarItem = make(map[string]VarItem)
|
||||
tpage := TopicPage{"Title",user,noticeList,replyList,topic,1,1,false}
|
||||
|
@ -80,7 +80,7 @@ func compile_templates() {
|
|||
topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage", topics_page, varList)
|
||||
|
||||
var topicList []TopicUser
|
||||
topicList = append(topicList,TopicUser{1,"Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"Admin","","",0,"","","","",58,false})
|
||||
topicList = append(topicList,TopicUser{1,"Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"Admin",default_group,"","",0,"","","","",58,false})
|
||||
forum_item := Forum{1,"General Forum",true,"all",0,"",0,"",0,""}
|
||||
forum_page := ForumPage{"General Forum",user,noticeList,topicList,forum_item,1,1,nil}
|
||||
forum_tmpl := c.compile_template("forum.html","templates/","ForumPage", forum_page, varList)
|
||||
|
@ -143,6 +143,14 @@ func main(){
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if cache_topicuser == CACHE_STATIC {
|
||||
users = NewStaticUserStore(user_cache_capacity)
|
||||
topics = NewStaticTopicStore(topic_cache_capacity)
|
||||
} else {
|
||||
users = NewSqlUserStore()
|
||||
topics = NewSqlTopicStore()
|
||||
}
|
||||
|
||||
log.Print("Loading the static files.")
|
||||
err = filepath.Walk("./public", func(path string, f os.FileInfo, err error) error {
|
||||
if f.IsDir() {
|
||||
|
|
24
mysql.go
24
mysql.go
|
@ -9,9 +9,11 @@ import "strconv"
|
|||
import "encoding/json"
|
||||
|
||||
var db *sql.DB
|
||||
var get_session_stmt *sql.Stmt
|
||||
var get_user_stmt *sql.Stmt
|
||||
var get_full_user_stmt *sql.Stmt
|
||||
var get_topic_list_stmt *sql.Stmt
|
||||
var get_topic_user_stmt *sql.Stmt
|
||||
var get_topic_stmt *sql.Stmt
|
||||
var get_topic_replies_stmt *sql.Stmt
|
||||
var get_topic_replies_offset_stmt *sql.Stmt
|
||||
var get_forum_topics_stmt *sql.Stmt
|
||||
|
@ -90,8 +92,20 @@ func init_database(err error) {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing get_session statement.")
|
||||
/*log.Print("Preparing get_session statement.")
|
||||
get_session_stmt, err = db.Prepare("select `uid`,`name`,`group`,`is_super_admin`,`session`,`email`,`avatar`,`message`,`url_prefix`,`url_name`,`level`,`score`,`last_ip` from `users` where `uid` = ? and `session` = ? AND `session` <> ''")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}*/
|
||||
|
||||
log.Print("Preparing get_user statement.")
|
||||
get_user_stmt, err = db.Prepare("select `name`,`group`,`is_super_admin`,`avatar`,`message`,`url_prefix`,`url_name`,`level` from `users` where `uid` = ?")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing get_full_user statement.")
|
||||
get_full_user_stmt, err = db.Prepare("select `name`,`group`,`is_super_admin`,`session`,`email`,`avatar`,`message`,`url_prefix`,`url_name`,`level`,`score`,`last_ip` from `users` where `uid` = ?")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -108,6 +122,12 @@ func init_database(err error) {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing get_topic statement.")
|
||||
get_topic_stmt, err = db.Prepare("select title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount from topics where tid = ?")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing get_topic_replies statement.")
|
||||
get_topic_replies_stmt, err = db.Prepare("select 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 from replies left join users ON replies.createdBy = users.uid where tid = ?")
|
||||
if err != nil {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
package main
|
||||
import "html/template"
|
||||
|
||||
func init() {
|
||||
plugins["helloworld"] = NewPlugin("helloworld","Hello World","Azareal","http://github.com/Azareal","","","",init_helloworld,nil,deactivate_helloworld)
|
||||
|
@ -17,7 +16,7 @@ func deactivate_helloworld() {
|
|||
func helloworld_reply(data interface{}) interface{} {
|
||||
reply := data.(Reply)
|
||||
reply.Content = "Hello World!"
|
||||
reply.ContentHtml = template.HTML("Hello World!")
|
||||
reply.ContentHtml = "Hello World!"
|
||||
reply.Tag = "Auto"
|
||||
return reply
|
||||
}
|
3
reply.go
3
reply.go
|
@ -7,9 +7,10 @@ type Reply struct
|
|||
ID int
|
||||
ParentID int
|
||||
Content string
|
||||
ContentHtml template.HTML
|
||||
ContentHtml string
|
||||
CreatedBy int
|
||||
CreatedByName string
|
||||
Group int
|
||||
CreatedAt string
|
||||
LastEdit int
|
||||
LastEditBy int
|
||||
|
|
13
router.go
13
router.go
|
@ -16,38 +16,45 @@ func NewRouter() *Router {
|
|||
}
|
||||
|
||||
func (router *Router) Handle(pattern string, handle http.Handler) {
|
||||
router.mu.Lock()
|
||||
router.routes[pattern] = handle.ServeHTTP
|
||||
router.mu.Unlock()
|
||||
}
|
||||
|
||||
func (router *Router) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request)) {
|
||||
router.mu.Lock()
|
||||
router.routes[pattern] = handle
|
||||
router.mu.Unlock()
|
||||
}
|
||||
|
||||
func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
router.mu.RLock()
|
||||
defer router.mu.RUnlock()
|
||||
|
||||
if req.URL.Path[0] != '/' {
|
||||
router.mu.RUnlock()
|
||||
w.WriteHeader(405)
|
||||
w.Write([]byte(""))
|
||||
return
|
||||
}
|
||||
|
||||
// Do something on the path to turn slashes facing the wrong way "\" into "/" slashes. If it's bytes, then alter the bytes in place for the maximum speed
|
||||
// Do something on the path to turn slashes facing the wrong way "\" into "/" slashes. Like what? Wouldn't that be slow? Might need to move to fasthttp for this
|
||||
|
||||
handle, ok := router.routes[req.URL.Path]
|
||||
if ok {
|
||||
router.mu.RUnlock()
|
||||
handle(w,req)
|
||||
return
|
||||
}
|
||||
|
||||
if req.URL.Path[len(req.URL.Path) - 1] == '/' {
|
||||
router.mu.RUnlock()
|
||||
NotFound(w,req)
|
||||
return
|
||||
}
|
||||
|
||||
handle, ok = router.routes[req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1]]
|
||||
if ok {
|
||||
router.mu.RUnlock()
|
||||
handle(w,req)
|
||||
return
|
||||
}
|
||||
|
@ -55,10 +62,12 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
|
||||
handle, ok = router.routes[req.URL.Path + "/"]
|
||||
if ok {
|
||||
router.mu.RUnlock()
|
||||
handle(w,req)
|
||||
return
|
||||
}
|
||||
|
||||
router.mu.RUnlock()
|
||||
NotFound(w,req)
|
||||
return
|
||||
}
|
38
routes.go
38
routes.go
|
@ -288,23 +288,20 @@ func route_forums(w http.ResponseWriter, r *http.Request){
|
|||
func route_topic_id(w http.ResponseWriter, r *http.Request){
|
||||
var(
|
||||
err error
|
||||
content string
|
||||
group int
|
||||
page int
|
||||
offset int
|
||||
replyList []Reply
|
||||
)
|
||||
|
||||
page, _ = strconv.Atoi(r.FormValue("page"))
|
||||
topic := TopicUser{Css: no_css_tmpl}
|
||||
topic.ID, err = strconv.Atoi(r.URL.Path[len("/topic/"):])
|
||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/"):])
|
||||
if err != nil {
|
||||
PreError("The provided TopicID is not a valid number.",w,r)
|
||||
return
|
||||
}
|
||||
|
||||
// Get the topic..
|
||||
err = get_topic_user_stmt.QueryRow(topic.ID).Scan(&topic.Title, &content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.CreatedByName, &topic.Avatar, &group, &topic.URLPrefix, &topic.URLName, &topic.Level)
|
||||
topic, err := get_topicuser(tid)
|
||||
if err == sql.ErrNoRows {
|
||||
NotFound(w,r)
|
||||
return
|
||||
|
@ -312,6 +309,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
|
|||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
topic.Css = no_css_tmpl
|
||||
|
||||
user, noticeList, ok := ForumSessionCheck(w,r,topic.ParentID)
|
||||
if !ok {
|
||||
|
@ -322,8 +320,8 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
|
|||
return
|
||||
}
|
||||
|
||||
topic.Content = template.HTML(parse_message(content))
|
||||
topic.ContentLines = strings.Count(content,"\n")
|
||||
topic.ContentLines = strings.Count(topic.Content,"\n")
|
||||
topic.Content = parse_message(topic.Content)
|
||||
|
||||
// We don't want users posting in locked topics...
|
||||
if topic.Is_Closed && !user.Is_Mod {
|
||||
|
@ -337,12 +335,12 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
|
|||
} else {
|
||||
topic.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(topic.CreatedBy),1)
|
||||
}
|
||||
if groups[group].Is_Mod || groups[group].Is_Admin {
|
||||
if groups[topic.Group].Is_Mod || groups[topic.Group].Is_Admin {
|
||||
topic.Css = staff_css_tmpl
|
||||
topic.Level = -1
|
||||
}
|
||||
|
||||
topic.Tag = groups[group].Tag
|
||||
topic.Tag = groups[topic.Group].Tag
|
||||
|
||||
if settings["url_tags"] == false {
|
||||
topic.URLName = ""
|
||||
|
@ -382,16 +380,16 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
|
|||
|
||||
replyItem := Reply{Css: no_css_tmpl}
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress, &replyItem.LikeCount)
|
||||
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &replyItem.Group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress, &replyItem.LikeCount)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
replyItem.ParentID = topic.ID
|
||||
replyItem.ContentHtml = template.HTML(parse_message(replyItem.Content))
|
||||
replyItem.ContentHtml = parse_message(replyItem.Content)
|
||||
replyItem.ContentLines = strings.Count(replyItem.Content,"\n")
|
||||
if groups[group].Is_Mod || groups[group].Is_Admin {
|
||||
if groups[replyItem.Group].Is_Mod || groups[replyItem.Group].Is_Admin {
|
||||
replyItem.Css = staff_css_tmpl
|
||||
replyItem.Level = -1
|
||||
} else {
|
||||
|
@ -405,7 +403,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
|
|||
replyItem.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyItem.CreatedBy),1)
|
||||
}
|
||||
|
||||
replyItem.Tag = groups[group].Tag
|
||||
replyItem.Tag = groups[replyItem.Group].Tag
|
||||
|
||||
/*if settings["url_tags"] == false {
|
||||
replyItem.URLName = ""
|
||||
|
@ -462,7 +460,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
|
|||
replyCss template.CSS
|
||||
replyLines int
|
||||
replyTag string
|
||||
group int
|
||||
replyGroup int
|
||||
|
||||
replyList []Reply
|
||||
)
|
||||
|
@ -479,7 +477,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
|
|||
puser = user
|
||||
} else {
|
||||
// Fetch the user data
|
||||
err = db.QueryRow("select `name`,`group`,`is_super_admin`,`avatar`,`message`,`url_prefix`,`url_name`,`level` from `users` where `uid` = ?", puser.ID).Scan(&puser.Name, &puser.Group, &puser.Is_Super_Admin, &puser.Avatar, &puser.Message, &puser.URLPrefix, &puser.URLName, &puser.Level)
|
||||
err = get_user_stmt.QueryRow(puser.ID).Scan(&puser.Name, &puser.Group, &puser.Is_Super_Admin, &puser.Avatar, &puser.Message, &puser.URLPrefix, &puser.URLName, &puser.Level)
|
||||
if err == sql.ErrNoRows {
|
||||
NotFound(w,r)
|
||||
return
|
||||
|
@ -516,14 +514,14 @@ func route_profile(w http.ResponseWriter, r *http.Request){
|
|||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &group)
|
||||
err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &replyGroup)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
replyLines = strings.Count(replyContent,"\n")
|
||||
if groups[group].Is_Mod || groups[group].Is_Admin {
|
||||
if groups[replyGroup].Is_Mod || groups[replyGroup].Is_Admin {
|
||||
replyCss = staff_css_tmpl
|
||||
} else {
|
||||
replyCss = no_css_tmpl
|
||||
|
@ -536,8 +534,8 @@ func route_profile(w http.ResponseWriter, r *http.Request){
|
|||
replyAvatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyCreatedBy),1)
|
||||
}
|
||||
|
||||
if groups[group].Tag != "" {
|
||||
replyTag = groups[group].Tag
|
||||
if groups[replyGroup].Tag != "" {
|
||||
replyTag = groups[replyGroup].Tag
|
||||
} else if puser.ID == replyCreatedBy {
|
||||
replyTag = "Profile Owner"
|
||||
} else {
|
||||
|
@ -547,7 +545,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
|
|||
replyLiked := false
|
||||
replyLikeCount := 0
|
||||
|
||||
replyList = append(replyList, Reply{rid,puser.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,"","","",0,"",replyLiked,replyLikeCount})
|
||||
replyList = append(replyList, Reply{rid,puser.ID,replyContent,parse_message(replyContent),replyCreatedBy,replyCreatedByName,replyGroup,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,"","","",0,"",replyLiked,replyLikeCount})
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||
package main
|
||||
import "strconv"
|
||||
import "io"
|
||||
import "strconv"
|
||||
|
||||
func init() {
|
||||
template_forum_handle = template_forum
|
||||
|
|
|
@ -97,25 +97,25 @@ var topic_23 []byte = []byte(`</p>
|
|||
var topic_24 []byte = []byte(`</textarea><br /><br />
|
||||
<a href="/user/`)
|
||||
var topic_25 []byte = []byte(`" class="username real_username">`)
|
||||
var topic_26 []byte = []byte(`</a>
|
||||
var topic_26 []byte = []byte(`</a>
|
||||
<a href="/topic/like/submit/`)
|
||||
var topic_27 []byte = []byte(`" class="mod_button" title="Love it" style="color:#202020;"><button class="username" style="`)
|
||||
var topic_28 []byte = []byte(`background-color:/*#eaffea*/#D6FFD6;`)
|
||||
var topic_29 []byte = []byte(`">😀</button></a>
|
||||
var topic_29 []byte = []byte(`">😀</button></a>
|
||||
`)
|
||||
var topic_30 []byte = []byte(`<a href='/topic/edit/`)
|
||||
var topic_31 []byte = []byte(`' class="mod_button open_edit" style="font-weight:normal;" title="Edit Topic"><button class="username">🖊️</button></a>
|
||||
var topic_31 []byte = []byte(`' class="mod_button open_edit" style="font-weight:normal;" title="Edit Topic"><button class="username">🖊️</button></a>
|
||||
<a href='/topic/delete/submit/`)
|
||||
var topic_32 []byte = []byte(`' class="mod_button" style="font-weight:normal;" title="Delete Topic"><button class="username">🗑️</button></a>
|
||||
var topic_32 []byte = []byte(`' class="mod_button" style="font-weight:normal;" title="Delete Topic"><button class="username">🗑️</button></a>
|
||||
`)
|
||||
var topic_33 []byte = []byte(`<a class="mod_button" href='/topic/unstick/submit/`)
|
||||
var topic_34 []byte = []byte(`' style="font-weight:normal;" title="Unpin Topic"><button class="username" style="background-color:/*#eaffea*/#D6FFD6;">📌</button></a>`)
|
||||
var topic_35 []byte = []byte(`<a href='/topic/stick/submit/`)
|
||||
var topic_36 []byte = []byte(`' class="mod_button" style="font-weight:normal;" title="Pin Topic"><button class="username">📌</button></a>`)
|
||||
var topic_37 []byte = []byte(`
|
||||
var topic_37 []byte = []byte(`
|
||||
<a href="/report/submit/`)
|
||||
var topic_38 []byte = []byte(`?session=`)
|
||||
var topic_39 []byte = []byte(`&type=topic" class="mod_button report_item" style="font-weight:normal;" title="Flag Topic"><button class="username">🚩</button></a>
|
||||
var topic_39 []byte = []byte(`&type=topic" class="mod_button report_item" style="font-weight:normal;" title="Flag Topic"><button class="username">🚩</button></a>
|
||||
`)
|
||||
var topic_40 []byte = []byte(`<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">`)
|
||||
var topic_41 []byte = []byte(`</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;margin-left:5px;" title="Like Count">😀</a>`)
|
||||
|
@ -138,20 +138,20 @@ var topic_52 []byte = []byte(`">
|
|||
var topic_53 []byte = []byte(`</p><br /><br />
|
||||
<a href="/user/`)
|
||||
var topic_54 []byte = []byte(`" class="username real_username">`)
|
||||
var topic_55 []byte = []byte(`</a>
|
||||
var topic_55 []byte = []byte(`</a>
|
||||
<a href="/reply/like/submit/`)
|
||||
var topic_56 []byte = []byte(`" class="mod_button" title="Love it" style="color:#202020;"><button class="username" style="`)
|
||||
var topic_57 []byte = []byte(`background-color:/*#eaffea*/#D6FFD6;`)
|
||||
var topic_58 []byte = []byte(`">😀</button></a>
|
||||
var topic_58 []byte = []byte(`">😀</button></a>
|
||||
`)
|
||||
var topic_59 []byte = []byte(`<a href="/reply/edit/submit/`)
|
||||
var topic_60 []byte = []byte(`" class="mod_button" title="Edit Reply"><button class="username edit_item">🖊️</button></a> `)
|
||||
var topic_60 []byte = []byte(`" class="mod_button" title="Edit Reply"><button class="username edit_item">🖊️</button></a> `)
|
||||
var topic_61 []byte = []byte(`<a href="/reply/delete/submit/`)
|
||||
var topic_62 []byte = []byte(`" class="mod_button" title="Delete Reply"><button class="username delete_item">🗑️</button></a> `)
|
||||
var topic_62 []byte = []byte(`" class="mod_button" title="Delete Reply"><button class="username delete_item">🗑️</button></a> `)
|
||||
var topic_63 []byte = []byte(`
|
||||
<a href="/report/submit/`)
|
||||
var topic_64 []byte = []byte(`?session=`)
|
||||
var topic_65 []byte = []byte(`&type=reply" class="mod_button" title="Flag Reply"><button class="username report_item">🚩</button></a>
|
||||
var topic_65 []byte = []byte(`&type=reply" class="mod_button" title="Flag Reply"><button class="username report_item">🚩</button></a>
|
||||
`)
|
||||
var topic_66 []byte = []byte(`<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">`)
|
||||
var topic_67 []byte = []byte(`</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;margin-left:5px;" title="Like Count">😀</a>`)
|
||||
|
|
|
@ -85,7 +85,7 @@ w.Write(profile_19)
|
|||
w.Write([]byte(string(item.Css)))
|
||||
}
|
||||
w.Write(profile_20)
|
||||
w.Write([]byte(string(item.ContentHtml)))
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(profile_21)
|
||||
w.Write([]byte(strconv.Itoa(item.CreatedBy)))
|
||||
w.Write(profile_22)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* 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 "html/template"
|
||||
import "io"
|
||||
|
||||
func init() {
|
||||
|
@ -92,9 +91,9 @@ w.Write(topic_21)
|
|||
w.Write([]byte(string(tmpl_topic_vars.Topic.Css)))
|
||||
}
|
||||
w.Write(topic_22)
|
||||
w.Write([]byte(string(tmpl_topic_vars.Topic.Content.(template.HTML))))
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Content))
|
||||
w.Write(topic_23)
|
||||
w.Write([]byte(string(tmpl_topic_vars.Topic.Content.(template.HTML))))
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Content))
|
||||
w.Write(topic_24)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.CreatedBy)))
|
||||
w.Write(topic_25)
|
||||
|
@ -156,7 +155,7 @@ w.Write(topic_51)
|
|||
w.Write([]byte(string(item.Css)))
|
||||
}
|
||||
w.Write(topic_52)
|
||||
w.Write([]byte(string(item.ContentHtml)))
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(topic_53)
|
||||
w.Write([]byte(strconv.Itoa(item.CreatedBy)))
|
||||
w.Write(topic_54)
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
package main
|
||||
import "io"
|
||||
import "strconv"
|
||||
import "html/template"
|
||||
|
||||
func init() {
|
||||
template_topic_alt_handle = template_topic_alt
|
||||
|
@ -117,9 +116,9 @@ w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.Level)))
|
|||
w.Write(topic_alt_34)
|
||||
}
|
||||
w.Write(topic_alt_35)
|
||||
w.Write([]byte(string(tmpl_topic_alt_vars.Topic.Content.(template.HTML))))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
||||
w.Write(topic_alt_36)
|
||||
w.Write([]byte(string(tmpl_topic_alt_vars.Topic.Content.(template.HTML))))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
||||
w.Write(topic_alt_37)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_38)
|
||||
|
@ -146,7 +145,7 @@ w.Write([]byte(strconv.Itoa(item.Level)))
|
|||
w.Write(topic_alt_48)
|
||||
}
|
||||
w.Write(topic_alt_49)
|
||||
w.Write([]byte(string(item.ContentHtml)))
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(topic_alt_50)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_alt_51)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||
package main
|
||||
import "io"
|
||||
import "strconv"
|
||||
import "io"
|
||||
|
||||
func init() {
|
||||
template_topics_handle = template_topics
|
||||
|
|
22
templates.go
22
templates.go
|
@ -12,6 +12,11 @@ import "text/template/parse"
|
|||
|
||||
var ctemplates []string
|
||||
var tmpl_ptr_map map[string]interface{} = make(map[string]interface{})
|
||||
var text_overlap_list map[string]int
|
||||
|
||||
func init() {
|
||||
text_overlap_list = make(map[string]int)
|
||||
}
|
||||
|
||||
type VarItem struct
|
||||
{
|
||||
|
@ -80,7 +85,11 @@ func (c *CTemplateSet) compile_template(name string, dir string, expects string,
|
|||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
content := string(res)
|
||||
if !debug {
|
||||
content = minify(content)
|
||||
}
|
||||
|
||||
tree := parse.New(name, c.funcMap)
|
||||
var treeSet map[string]*parse.Tree = make(map[string]*parse.Tree)
|
||||
|
@ -822,7 +831,11 @@ func (c *CTemplateSet) compile_subtemplate(pvarholder string, pholdreflect refle
|
|||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
content := string(res)
|
||||
if !debug {
|
||||
content = minify(content)
|
||||
}
|
||||
|
||||
tree := parse.New(node.Name, c.funcMap)
|
||||
var treeSet map[string]*parse.Tree = make(map[string]*parse.Tree)
|
||||
|
@ -860,3 +873,12 @@ func (c *CTemplateSet) compile_subtemplate(pvarholder string, pholdreflect refle
|
|||
func (c *CTemplateSet) compile_command(*parse.CommandNode) (out string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
func minify(data string) string {
|
||||
data = strings.Replace(data,"\t","",-1)
|
||||
data = strings.Replace(data,"\v","",-1)
|
||||
data = strings.Replace(data,"\n","",-1)
|
||||
data = strings.Replace(data,"\r","",-1)
|
||||
data = strings.Replace(data," "," ",-1)
|
||||
return data
|
||||
}
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
<div class="rowitem passive editable_parent post_item" style="border-bottom: none;{{if .Topic.Avatar}}background-image:url({{.Topic.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .Topic.ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;background-size:128px;padding-left:136px;{{.Topic.Css}}{{end}}">
|
||||
<p class="hide_on_edit topic_content user_content" style="margin:0;padding:0;">{{.Topic.Content}}</p>
|
||||
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea><br /><br />
|
||||
<a href="/user/{{.Topic.CreatedBy}}" class="username real_username">{{.Topic.CreatedByName}}</a>
|
||||
<a href="/topic/like/submit/{{.Topic.ID}}" class="mod_button" title="Love it" style="color:#202020;"><button class="username" style="{{if .Topic.Liked}}background-color:/*#eaffea*/#D6FFD6;{{end}}">😀</button></a>
|
||||
{{if .CurrentUser.Is_Mod}}<a href='/topic/edit/{{.Topic.ID}}' class="mod_button open_edit" style="font-weight:normal;" title="Edit Topic"><button class="username">🖊️</button></a>
|
||||
<a href='/topic/delete/submit/{{.Topic.ID}}' class="mod_button" style="font-weight:normal;" title="Delete Topic"><button class="username">🗑️</button></a>
|
||||
<a href="/user/{{.Topic.CreatedBy}}" class="username real_username">{{.Topic.CreatedByName}}</a>
|
||||
<a href="/topic/like/submit/{{.Topic.ID}}" class="mod_button" title="Love it" style="color:#202020;"><button class="username" style="{{if .Topic.Liked}}background-color:/*#eaffea*/#D6FFD6;{{end}}">😀</button></a>
|
||||
{{if .CurrentUser.Is_Mod}}<a href='/topic/edit/{{.Topic.ID}}' class="mod_button open_edit" style="font-weight:normal;" title="Edit Topic"><button class="username">🖊️</button></a>
|
||||
<a href='/topic/delete/submit/{{.Topic.ID}}' class="mod_button" style="font-weight:normal;" title="Delete Topic"><button class="username">🗑️</button></a>
|
||||
{{if .Topic.Sticky}}<a class="mod_button" href='/topic/unstick/submit/{{.Topic.ID}}' style="font-weight:normal;" title="Unpin Topic"><button class="username" style="background-color:/*#eaffea*/#D6FFD6;">📌</button></a>{{else}}<a href='/topic/stick/submit/{{.Topic.ID}}' class="mod_button" style="font-weight:normal;" title="Pin Topic"><button class="username">📌</button></a>{{end}}
|
||||
{{end}}
|
||||
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="mod_button report_item" style="font-weight:normal;" title="Flag Topic"><button class="username">🚩</button></a>
|
||||
{{end}}
|
||||
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="mod_button report_item" style="font-weight:normal;" title="Flag Topic"><button class="username">🚩</button></a>
|
||||
{{if .Topic.LikeCount}}<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">{{.Topic.LikeCount}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;margin-left:5px;" title="Like Count">😀</a>{{end}}
|
||||
{{if .Topic.Tag}}<a class="username hide_on_micro" style="float:right;color:#505050;font-size:16px;">{{.Topic.Tag}}</a>{{else}}<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">{{.Topic.Level}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;" title="Level">👑</a>{{end}}
|
||||
</div>
|
||||
|
@ -36,11 +36,11 @@
|
|||
<div class="rowblock post_container" style="overflow: hidden;">{{range .ItemList}}
|
||||
<div class="rowitem rowhead passive deletable_block editable_parent post_item" style="{{if .Avatar}}background-image:url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;background-size:128px;padding-left:136px;{{.Css}}{{end}}">
|
||||
<p class="editable_block user_content" style="margin: 0;padding: 0;">{{.ContentHtml}}</p><br /><br />
|
||||
<a href="/user/{{.CreatedBy}}" class="username real_username">{{.CreatedByName}}</a>
|
||||
<a href="/reply/like/submit/{{.ID}}" class="mod_button" title="Love it" style="color:#202020;"><button class="username" style="{{if .Liked}}background-color:/*#eaffea*/#D6FFD6;{{end}}">😀</button></a>
|
||||
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="mod_button" title="Edit Reply"><button class="username edit_item">🖊️</button></a> {{end}}
|
||||
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="mod_button" title="Delete Reply"><button class="username delete_item">🗑️</button></a> {{end}}
|
||||
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="mod_button" title="Flag Reply"><button class="username report_item">🚩</button></a>
|
||||
<a href="/user/{{.CreatedBy}}" class="username real_username">{{.CreatedByName}}</a>
|
||||
<a href="/reply/like/submit/{{.ID}}" class="mod_button" title="Love it" style="color:#202020;"><button class="username" style="{{if .Liked}}background-color:/*#eaffea*/#D6FFD6;{{end}}">😀</button></a>
|
||||
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="mod_button" title="Edit Reply"><button class="username edit_item">🖊️</button></a> {{end}}
|
||||
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="mod_button" title="Delete Reply"><button class="username delete_item">🗑️</button></a> {{end}}
|
||||
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="mod_button" title="Flag Reply"><button class="username report_item">🚩</button></a>
|
||||
{{if .LikeCount}}<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">{{.LikeCount}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;margin-left:5px;" title="Like Count">😀</a>{{end}}
|
||||
{{if .Tag}}<a class="username hide_on_micro" style="float: right;color:#505050;font-size:16px;">{{.Tag}}</a>{{else}}<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">{{.Level}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;" title="Level">👑{{end}}</a>
|
||||
</div>
|
||||
|
|
238
topic.go
238
topic.go
|
@ -1,5 +1,8 @@
|
|||
package main
|
||||
//import "fmt"
|
||||
import "sync"
|
||||
import "html/template"
|
||||
import "database/sql"
|
||||
|
||||
type Topic struct
|
||||
{
|
||||
|
@ -10,17 +13,19 @@ type Topic struct
|
|||
Is_Closed bool
|
||||
Sticky bool
|
||||
CreatedAt string
|
||||
LastReplyAt string
|
||||
ParentID int
|
||||
Status string // Deprecated. Marked for removal.
|
||||
IpAddress string
|
||||
PostCount int
|
||||
LikeCount int
|
||||
}
|
||||
|
||||
type TopicUser struct
|
||||
{
|
||||
ID int
|
||||
Title string
|
||||
Content interface{}
|
||||
Content string
|
||||
CreatedBy int
|
||||
Is_Closed bool
|
||||
Sticky bool
|
||||
|
@ -33,6 +38,7 @@ type TopicUser struct
|
|||
LikeCount int
|
||||
|
||||
CreatedByName string
|
||||
Group int
|
||||
Avatar string
|
||||
Css template.CSS
|
||||
ContentLines int
|
||||
|
@ -48,7 +54,7 @@ type TopicsRow struct
|
|||
{
|
||||
ID int
|
||||
Title string
|
||||
Content interface{}
|
||||
Content string
|
||||
CreatedBy int
|
||||
Is_Closed bool
|
||||
Sticky bool
|
||||
|
@ -72,3 +78,231 @@ type TopicsRow struct
|
|||
|
||||
ForumName string //TopicsRow
|
||||
}
|
||||
|
||||
type TopicStore interface {
|
||||
Get(id int) (*Topic, error)
|
||||
GetUnsafe(id int) (*Topic, error)
|
||||
CascadeGet(id int) (*Topic, error)
|
||||
Add(item *Topic) error
|
||||
AddUnsafe(item *Topic) error
|
||||
Remove(id int) error
|
||||
RemoveUnsafe(id int) error
|
||||
AddLastTopic(item *Topic, fid int) error
|
||||
GetLength() int
|
||||
GetCapacity() int
|
||||
}
|
||||
|
||||
type StaticTopicStore struct {
|
||||
items map[int]*Topic
|
||||
length int
|
||||
capacity int
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewStaticTopicStore(capacity int) *StaticTopicStore {
|
||||
return &StaticTopicStore{items:make(map[int]*Topic),capacity:capacity}
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) Get(id int) (*Topic, error) {
|
||||
sts.mu.RLock()
|
||||
item, ok := sts.items[id]
|
||||
sts.mu.RUnlock()
|
||||
if ok {
|
||||
return item, nil
|
||||
}
|
||||
return item, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) GetUnsafe(id int) (*Topic, error) {
|
||||
item, ok := sts.items[id]
|
||||
if ok {
|
||||
return item, nil
|
||||
}
|
||||
return item, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) {
|
||||
sts.mu.RLock()
|
||||
topic, ok := sts.items[id]
|
||||
sts.mu.RUnlock()
|
||||
if ok {
|
||||
return topic, nil
|
||||
}
|
||||
|
||||
topic = &Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
if err == nil {
|
||||
sts.Add(topic)
|
||||
}
|
||||
return topic, err
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) Add(item *Topic) error {
|
||||
if sts.length >= sts.capacity {
|
||||
return ErrStoreCapacityOverflow
|
||||
}
|
||||
sts.mu.Lock()
|
||||
sts.items[item.ID] = item
|
||||
sts.mu.Unlock()
|
||||
sts.length++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) AddUnsafe(item *Topic) error {
|
||||
if sts.length >= sts.capacity {
|
||||
return ErrStoreCapacityOverflow
|
||||
}
|
||||
sts.items[item.ID] = item
|
||||
sts.length++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) Remove(id int) error {
|
||||
sts.mu.Lock()
|
||||
delete(sts.items,id)
|
||||
sts.mu.Unlock()
|
||||
sts.length--
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) RemoveUnsafe(id int) error {
|
||||
delete(sts.items,id)
|
||||
sts.length--
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) AddLastTopic(item *Topic, fid int) error {
|
||||
// Coming Soon...
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) GetLength() int {
|
||||
return sts.length
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) SetCapacity(capacity int) {
|
||||
sts.capacity = capacity
|
||||
}
|
||||
|
||||
func (sts *StaticTopicStore) GetCapacity() int {
|
||||
return sts.capacity
|
||||
}
|
||||
|
||||
//type DynamicTopicStore struct {
|
||||
// items_expiries list.List
|
||||
// items map[int]*Topic
|
||||
//}
|
||||
|
||||
type SqlTopicStore struct {
|
||||
}
|
||||
|
||||
func NewSqlTopicStore() *SqlTopicStore {
|
||||
return &SqlTopicStore{}
|
||||
}
|
||||
|
||||
func (sus *SqlTopicStore) Get(id int) (*Topic, error) {
|
||||
topic := Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
return &topic, err
|
||||
}
|
||||
|
||||
func (sus *SqlTopicStore) GetUnsafe(id int) (*Topic, error) {
|
||||
topic := Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
return &topic, err
|
||||
}
|
||||
|
||||
func (sus *SqlTopicStore) CascadeGet(id int) (*Topic, error) {
|
||||
topic := Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
return &topic, err
|
||||
}
|
||||
|
||||
// Placeholder methods, the actual queries are done elsewhere
|
||||
func (sus *SqlTopicStore) Add(item *Topic) error {
|
||||
return nil
|
||||
}
|
||||
func (sus *SqlTopicStore) AddUnsafe(item *Topic) error {
|
||||
return nil
|
||||
}
|
||||
func (sus *SqlTopicStore) Remove(id int) error {
|
||||
return nil
|
||||
}
|
||||
func (sus *SqlTopicStore) RemoveUnsafe(id int) error {
|
||||
return nil
|
||||
}
|
||||
func (sts *SqlTopicStore) AddLastTopic(item *Topic, fid int) error {
|
||||
// Coming Soon...
|
||||
return nil
|
||||
}
|
||||
func (sts *SqlTopicStore) GetCapacity() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (sus *SqlTopicStore) GetLength() int {
|
||||
// Return the total number of topics on the forums
|
||||
return 0
|
||||
}
|
||||
|
||||
func get_topicuser(tid int) (TopicUser,error) {
|
||||
if cache_topicuser != CACHE_SQL {
|
||||
topic, err := topics.Get(tid)
|
||||
if err == nil {
|
||||
user, err := users.CascadeGet(topic.CreatedBy)
|
||||
if err != nil {
|
||||
return TopicUser{ID:tid}, err
|
||||
}
|
||||
|
||||
// We might be better off just passing seperate topic and user structs to the caller?
|
||||
return copy_topic_to_topicuser(topic, user), nil
|
||||
} else if users.GetLength() < users.GetCapacity() {
|
||||
topic, err = topics.CascadeGet(tid)
|
||||
if err != nil {
|
||||
return TopicUser{ID:tid}, err
|
||||
}
|
||||
user, err := users.CascadeGet(topic.CreatedBy)
|
||||
if err != nil {
|
||||
return TopicUser{ID:tid}, err
|
||||
}
|
||||
tu := copy_topic_to_topicuser(topic, user)
|
||||
//fmt.Printf("%+v\n", topic)
|
||||
//fmt.Println("")
|
||||
//fmt.Printf("%+v\n", user)
|
||||
//fmt.Println("")
|
||||
//fmt.Printf("%+v\n", tu)
|
||||
//fmt.Println("")
|
||||
return tu, nil
|
||||
}
|
||||
}
|
||||
|
||||
tu := TopicUser{ID:tid}
|
||||
err := get_topic_user_stmt.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.Is_Closed, &tu.Sticky, &tu.ParentID, &tu.IpAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||
|
||||
the_topic := Topic{ID:tu.ID, Title:tu.Title, Content:tu.Content, CreatedBy:tu.CreatedBy, Is_Closed:tu.Is_Closed, Sticky:tu.Sticky, CreatedAt:tu.CreatedAt, LastReplyAt:tu.LastReplyAt, ParentID:tu.ParentID, IpAddress:tu.IpAddress, PostCount:tu.PostCount, LikeCount:tu.LikeCount}
|
||||
//fmt.Printf("%+v\n", the_topic)
|
||||
topics.Add(&the_topic)
|
||||
return tu, err
|
||||
}
|
||||
|
||||
func copy_topic_to_topicuser(topic *Topic, user *User) (tu TopicUser) {
|
||||
tu.CreatedByName = user.Name
|
||||
tu.Group = user.Group
|
||||
tu.Avatar = user.Avatar
|
||||
tu.URLPrefix = user.URLPrefix
|
||||
tu.URLName = user.URLName
|
||||
tu.Level = user.Level
|
||||
|
||||
tu.ID = topic.ID
|
||||
tu.Title = topic.Title
|
||||
tu.Content = topic.Content
|
||||
tu.CreatedBy = topic.CreatedBy
|
||||
tu.Is_Closed = topic.Is_Closed
|
||||
tu.Sticky = topic.Sticky
|
||||
tu.CreatedAt = topic.CreatedAt
|
||||
tu.LastReplyAt = topic.LastReplyAt
|
||||
tu.ParentID = topic.ParentID
|
||||
tu.IpAddress = topic.IpAddress
|
||||
tu.PostCount = topic.PostCount
|
||||
tu.LikeCount = topic.LikeCount
|
||||
return tu
|
||||
}
|
194
user.go
194
user.go
|
@ -1,5 +1,6 @@
|
|||
package main
|
||||
//import "fmt"
|
||||
import "sync"
|
||||
import "strings"
|
||||
import "strconv"
|
||||
import "net"
|
||||
|
@ -42,6 +43,161 @@ type Email struct
|
|||
Token string
|
||||
}
|
||||
|
||||
type UserStore interface {
|
||||
Get(id int) (*User, error)
|
||||
GetUnsafe(id int) (*User, error)
|
||||
CascadeGet(id int) (*User, error)
|
||||
Add(item *User) error
|
||||
AddUnsafe(item *User) error
|
||||
Remove(id int) error
|
||||
RemoveUnsafe(id int) error
|
||||
GetLength() int
|
||||
GetCapacity() int
|
||||
}
|
||||
|
||||
type StaticUserStore struct {
|
||||
items map[int]*User
|
||||
length int
|
||||
capacity int
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewStaticUserStore(capacity int) *StaticUserStore {
|
||||
return &StaticUserStore{items:make(map[int]*User),capacity:capacity}
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) Get(id int) (*User, error) {
|
||||
sts.mu.RLock()
|
||||
item, ok := sts.items[id]
|
||||
sts.mu.RUnlock()
|
||||
if ok {
|
||||
return item, nil
|
||||
}
|
||||
return item, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) GetUnsafe(id int) (*User, error) {
|
||||
item, ok := sts.items[id]
|
||||
if ok {
|
||||
return item, nil
|
||||
}
|
||||
return item, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) CascadeGet(id int) (*User, error) {
|
||||
sts.mu.RLock()
|
||||
user, ok := sts.items[id]
|
||||
sts.mu.RUnlock()
|
||||
if ok {
|
||||
return user, nil
|
||||
}
|
||||
|
||||
user = &User{ID:id}
|
||||
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
|
||||
if err == nil {
|
||||
sts.Add(user)
|
||||
}
|
||||
return user, err
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) Add(item *User) error {
|
||||
if sts.length >= sts.capacity {
|
||||
return ErrStoreCapacityOverflow
|
||||
}
|
||||
sts.mu.Lock()
|
||||
sts.items[item.ID] = item
|
||||
sts.mu.Unlock()
|
||||
sts.length++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) AddUnsafe(item *User) error {
|
||||
if sts.length >= sts.capacity {
|
||||
return ErrStoreCapacityOverflow
|
||||
}
|
||||
sts.items[item.ID] = item
|
||||
sts.length++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) Remove(id int) error {
|
||||
sts.mu.Lock()
|
||||
delete(sts.items,id)
|
||||
sts.mu.Unlock()
|
||||
sts.length--
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) RemoveUnsafe(id int) error {
|
||||
delete(sts.items,id)
|
||||
sts.length--
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) GetLength() int {
|
||||
return sts.length
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) SetCapacity(capacity int) {
|
||||
sts.capacity = capacity
|
||||
}
|
||||
|
||||
func (sts *StaticUserStore) GetCapacity() int {
|
||||
return sts.capacity
|
||||
}
|
||||
|
||||
//type DynamicUserStore struct {
|
||||
// items_expiries list.List
|
||||
// items map[int]*User
|
||||
//}
|
||||
|
||||
type SqlUserStore struct {
|
||||
}
|
||||
|
||||
func NewSqlUserStore() *SqlUserStore {
|
||||
return &SqlUserStore{}
|
||||
}
|
||||
|
||||
func (sus *SqlUserStore) Get(id int) (*User, error) {
|
||||
user := User{ID:id}
|
||||
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
|
||||
return &user, err
|
||||
}
|
||||
|
||||
func (sus *SqlUserStore) GetUnsafe(id int) (*User, error) {
|
||||
user := User{ID:id}
|
||||
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
|
||||
return &user, err
|
||||
}
|
||||
|
||||
func (sus *SqlUserStore) CascadeGet(id int) (*User, error) {
|
||||
user := User{ID:id}
|
||||
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
|
||||
return &user, err
|
||||
}
|
||||
|
||||
// Placeholder methods, the actual queries are done elsewhere
|
||||
func (sus *SqlUserStore) Add(item *User) error {
|
||||
return nil
|
||||
}
|
||||
func (sus *SqlUserStore) AddUnsafe(item *User) error {
|
||||
return nil
|
||||
}
|
||||
func (sus *SqlUserStore) Remove(id int) error {
|
||||
return nil
|
||||
}
|
||||
func (sus *SqlUserStore) RemoveUnsafe(id int) error {
|
||||
return nil
|
||||
}
|
||||
func (sus *SqlUserStore) GetCapacity() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (sus *SqlUserStore) GetLength() int {
|
||||
// Return the total number of users registered on the forums
|
||||
return 0
|
||||
}
|
||||
|
||||
func SetPassword(uid int, password string) (error) {
|
||||
salt, err := GenerateSafeString(saltLength)
|
||||
if err != nil {
|
||||
|
@ -128,38 +284,40 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, noticeList
|
|||
return user, noticeList, success
|
||||
}
|
||||
|
||||
func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (user User, success bool) {
|
||||
func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (User,bool) {
|
||||
// Are there any session cookies..?
|
||||
cookie, err := r.Cookie("uid")
|
||||
if err != nil {
|
||||
user.Group = 6
|
||||
user.Perms = GuestPerms
|
||||
return user, true
|
||||
return User{ID:0,Group:6,Perms:GuestPerms}, true
|
||||
}
|
||||
user.ID, err = strconv.Atoi(cookie.Value)
|
||||
uid, err := strconv.Atoi(cookie.Value)
|
||||
if err != nil {
|
||||
user.Group = 6
|
||||
user.Perms = GuestPerms
|
||||
return user, true
|
||||
return User{ID:0,Group:6,Perms:GuestPerms}, true
|
||||
}
|
||||
cookie, err = r.Cookie("session")
|
||||
if err != nil {
|
||||
user.Group = 6
|
||||
user.Perms = GuestPerms
|
||||
return user, true
|
||||
return User{ID:0,Group:6,Perms:GuestPerms}, true
|
||||
}
|
||||
|
||||
// Is this session valid..?
|
||||
err = get_session_stmt.QueryRow(user.ID,cookie.Value).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
|
||||
user, err := users.CascadeGet(uid)
|
||||
if err == sql.ErrNoRows {
|
||||
user.ID = 0
|
||||
user.Session = ""
|
||||
user.Group = 6
|
||||
user.Perms = GuestPerms
|
||||
return user, true
|
||||
return *user, true
|
||||
} else if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return user, false
|
||||
return *user, false
|
||||
}
|
||||
|
||||
if user.Session == "" || cookie.Value != user.Session {
|
||||
user.ID = 0
|
||||
user.Session = ""
|
||||
user.Group = 6
|
||||
user.Perms = GuestPerms
|
||||
return *user, true
|
||||
}
|
||||
|
||||
user.Is_Admin = user.Is_Super_Admin || groups[user.Group].Is_Admin
|
||||
|
@ -187,17 +345,17 @@ func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (user User, succ
|
|||
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
LocalError("Bad IP",w,r,user)
|
||||
return user, false
|
||||
PreError("Bad IP",w,r)
|
||||
return *user, false
|
||||
}
|
||||
if host != user.Last_IP {
|
||||
_, err = update_last_ip_stmt.Exec(host, user.ID)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return user, false
|
||||
return *user, false
|
||||
}
|
||||
}
|
||||
return user, true
|
||||
return *user, true
|
||||
}
|
||||
|
||||
func words_to_score(wcount int, topic bool) (score int) {
|
||||
|
|
Loading…
Reference in New Issue