Added the InternalErrorJS and LocalErrorJS error handler functions.
Hid the themes which aren't under construction yet from the Theme Manager. Fixed a bug in the BBCode parser where every post had ten spaces appended to them. Added the get_reply() internal API function for plugins to make use of. Added the bell to the theme. Fixed some bits of the Cosmo theme where the rowhead wasn't appearing. Added a "Don't have an account?" link to the login page. I began work on the alerts system, I took a little break, so it's a little further behind than you might expect, but it shouldn't take too long for me to finish it up. I haven't finished the back-end portions of it yet, so there's not much to see yet!
This commit is contained in:
parent
1d85224dbc
commit
9fce51a3d7
24
data.sql
24
data.sql
|
@ -112,13 +112,35 @@ 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.*/
|
||||
/*`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,
|
||||
`recalc` tinyint DEFAULT 0 not null
|
||||
);
|
||||
|
||||
CREATE TABLE `activity_stream_matches`(
|
||||
`watcher` int not null,
|
||||
`asid` int not null
|
||||
);
|
||||
|
||||
CREATE TABLE `activity_stream`(
|
||||
`asid` int not null AUTO_INCREMENT,
|
||||
`actor` int not null, /* the one doing the act */
|
||||
`targetUser` int not null, /* the user who created the item the actor is acting on, some items like forums may lack a targetUser field */
|
||||
`event` varchar(50) not null, /* 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 */
|
||||
`elementType` varchar(50) not null, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
|
||||
`elementID` int not null, /* the ID of the element being acted upon */
|
||||
primary key(`asid`)
|
||||
);
|
||||
|
||||
CREATE TABLE `activity_subscriptions`(
|
||||
`user` int not null,
|
||||
`targetID` int not null,
|
||||
`targetType` varchar(50) not null,
|
||||
`level` tinyint DEFAULT 0 not null /* 0: Mentions (aka the global default for any post), 1: Replies, 2: Everyone*/
|
||||
);
|
||||
|
||||
CREATE TABLE `settings`(
|
||||
`name` varchar(200) not null,
|
||||
`content` varchar(250) not null,
|
||||
|
|
11
errors.go
11
errors.go
|
@ -41,6 +41,12 @@ func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, is_js s
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(`{'errmsg': 'A problem has occured in the system.'}`))
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
func PreError(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(500)
|
||||
user := User{ID:0,Group:6,Perms:GuestPerms,}
|
||||
|
@ -91,6 +97,11 @@ func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user U
|
|||
}
|
||||
}
|
||||
|
||||
func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(`{'errmsg': '` + errmsg + `'}`))
|
||||
}
|
||||
|
||||
func NoPermissions(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
pi := Page{"Local Error",user,nList,tList,"You don't have permission to do that."}
|
||||
|
|
|
@ -10,12 +10,17 @@ import "net/http"
|
|||
import "net/http/httptest"
|
||||
import "io/ioutil"
|
||||
import "database/sql"
|
||||
import _ "github.com/go-sql-driver/mysql"
|
||||
//import _ "github.com/go-sql-driver/mysql"
|
||||
//import "github.com/erikstmartin/go-testdb"
|
||||
//import "github.com/husobee/vestigo"
|
||||
import "runtime/pprof"
|
||||
|
||||
var db_test *sql.DB
|
||||
var db_prod *sql.DB
|
||||
var gloinited bool = false
|
||||
|
||||
func gloinit() {
|
||||
var err error
|
||||
debug = false
|
||||
nogrouplog = true
|
||||
|
||||
|
@ -24,10 +29,15 @@ func gloinit() {
|
|||
//log.SetOutput(discard)
|
||||
|
||||
init_themes()
|
||||
var err error
|
||||
init_database(err)
|
||||
db_prod = db
|
||||
//db_test, err = sql.Open("testdb","")
|
||||
//if err != nil {
|
||||
// log.Fatal(err)
|
||||
//}
|
||||
|
||||
init_templates()
|
||||
db.SetMaxOpenConns(64)
|
||||
db_prod.SetMaxOpenConns(64)
|
||||
err = init_errors()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1368,6 +1378,35 @@ func TestForumGuestRoute(t *testing.T) {
|
|||
fmt.Println("No problems found in the forum-guest route!")
|
||||
}
|
||||
|
||||
/*func TestAlerts(t *testing.T) {
|
||||
if !gloinited {
|
||||
gloinit()
|
||||
}
|
||||
if !plugins_inited {
|
||||
init_plugins()
|
||||
}
|
||||
db = db_test
|
||||
alert_w := httptest.NewRecorder()
|
||||
alert_req := httptest.NewRequest("get","/api/?action=get&module=alerts",bytes.NewReader(nil))
|
||||
alert_handler := http.HandlerFunc(route_api)
|
||||
//testdb.StubQuery()
|
||||
testdb.SetQueryFunc(func(query string) (result sql.Rows, err error) {
|
||||
cols := []string{"asid","actor","targetUser","event","elementType","elementID"}
|
||||
rows := `1,1,0,like,post,5
|
||||
1,1,0,friend_invite,user,2`
|
||||
return testdb.RowsFromCSVString(cols,rows), nil
|
||||
})
|
||||
|
||||
alert_handler.ServeHTTP(alert_w,alert_req)
|
||||
fmt.Println(alert_w.Body)
|
||||
if alert_w.Code != 200 {
|
||||
panic("HTTP Error!")
|
||||
}
|
||||
|
||||
fmt.Println("No problems found in the alert handler!")
|
||||
db = db_prod
|
||||
}*/
|
||||
|
||||
/*func TestRoute(t *testing.T) {
|
||||
|
||||
}*/
|
4
main.go
4
main.go
|
@ -184,8 +184,7 @@ func main(){
|
|||
init_plugins()
|
||||
|
||||
router := NewRouter()
|
||||
router.HandleFunc("/static/", route_static) // In a directory to stop it clashing with the other paths
|
||||
|
||||
router.HandleFunc("/static/", route_static)
|
||||
fs_u := http.FileServer(http.Dir("./uploads"))
|
||||
router.Handle("/uploads/", http.StripPrefix("/uploads/",fs_u))
|
||||
|
||||
|
@ -260,6 +259,7 @@ func main(){
|
|||
router.HandleFunc("/panel/users/edit/", route_panel_users_edit)
|
||||
router.HandleFunc("/panel/users/edit/submit/", route_panel_users_edit_submit)
|
||||
router.HandleFunc("/panel/groups/", route_panel_groups)
|
||||
router.HandleFunc("/api/", route_api)
|
||||
//router.HandleFunc("/exit/", route_exit)
|
||||
|
||||
router.HandleFunc("/", default_route)
|
||||
|
|
|
@ -1412,6 +1412,9 @@ func route_panel_themes(w http.ResponseWriter, r *http.Request){
|
|||
|
||||
var themeList []interface{}
|
||||
for _, theme := range themes {
|
||||
if theme.HideFromThemes {
|
||||
continue
|
||||
}
|
||||
themeList = append(themeList,theme)
|
||||
}
|
||||
|
||||
|
|
21
mysql.go
21
mysql.go
|
@ -16,8 +16,10 @@ 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_by_reply_stmt *sql.Stmt
|
||||
var get_topic_replies_stmt *sql.Stmt
|
||||
var get_topic_replies_offset_stmt *sql.Stmt
|
||||
var get_post_stmt *sql.Stmt
|
||||
var get_forum_topics_stmt *sql.Stmt
|
||||
var get_forum_topics_offset_stmt *sql.Stmt
|
||||
var create_topic_stmt *sql.Stmt
|
||||
|
@ -37,6 +39,7 @@ var delete_reply_stmt *sql.Stmt
|
|||
var delete_topic_stmt *sql.Stmt
|
||||
var stick_topic_stmt *sql.Stmt
|
||||
var unstick_topic_stmt *sql.Stmt
|
||||
var get_activity_feed_by_watcher_stmt *sql.Stmt
|
||||
var update_last_ip_stmt *sql.Stmt
|
||||
var login_stmt *sql.Stmt
|
||||
var update_session_stmt *sql.Stmt
|
||||
|
@ -133,6 +136,12 @@ func init_database(err error) {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing get_topic_by_reply statement.")
|
||||
get_topic_by_reply_stmt, err = db.Prepare("select topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount from replies left join topics on replies.tid = topics.tid where rid = ?")
|
||||
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 {
|
||||
|
@ -145,6 +154,12 @@ func init_database(err error) {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing get_post statement.")
|
||||
get_post_stmt, err = db.Prepare("select content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount from replies where rid = ?")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing get_forum_topics statement.")
|
||||
get_forum_topics_stmt, err = db.Prepare("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid where topics.parentID = ? order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc")
|
||||
if err != nil {
|
||||
|
@ -259,6 +274,12 @@ func init_database(err error) {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing get_activity_feed_by_watcher statement.")
|
||||
get_activity_feed_by_watcher_stmt, 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` LEFT JOIN `activity_stream` ON activity_stream_matches.asid = activity_stream.asid WHERE `watcher` = ?")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing update_last_ip statement.")
|
||||
update_last_ip_stmt, err = db.Prepare("UPDATE users SET last_ip = ? WHERE uid = ?")
|
||||
if err != nil {
|
||||
|
|
|
@ -364,21 +364,20 @@ func bbcode_full_parse(data interface{}) interface{} {
|
|||
}
|
||||
}
|
||||
}
|
||||
//fmt.Println(outbytes)
|
||||
//fmt.Println(string(outbytes))
|
||||
if lastTag != i {
|
||||
outbytes = append(outbytes, msgbytes[lastTag:len(msgbytes) - 10]...)
|
||||
outbytes = append(outbytes, msgbytes[lastTag:]...)
|
||||
}
|
||||
if len(outbytes) != 0 {
|
||||
return string(outbytes)
|
||||
return string(outbytes[0:len(msgbytes) - 10])
|
||||
}
|
||||
|
||||
msg = string(msgbytes)
|
||||
msg = string(msgbytes[0:len(msgbytes) - 10])
|
||||
//msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
|
||||
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
|
||||
// Convert [code] into class="codequotes"
|
||||
} else {
|
||||
msg = string(msgbytes)
|
||||
msg = string(msgbytes[0:len(msgbytes) - 10])
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
|
23
reply.go
23
reply.go
|
@ -2,7 +2,7 @@
|
|||
package main
|
||||
import "html/template"
|
||||
|
||||
type Reply struct
|
||||
type Reply struct /* Should probably rename this to ReplyUser and rename ReplyShort to Reply */
|
||||
{
|
||||
ID int
|
||||
ParentID int
|
||||
|
@ -27,3 +27,24 @@ type Reply struct
|
|||
LikeCount int
|
||||
}
|
||||
|
||||
type ReplyShort struct
|
||||
{
|
||||
ID int
|
||||
ParentID int
|
||||
Content string
|
||||
CreatedBy int
|
||||
Group int
|
||||
CreatedAt string
|
||||
LastEdit int
|
||||
LastEditBy int
|
||||
ContentLines int
|
||||
IpAddress string
|
||||
Liked bool
|
||||
LikeCount int
|
||||
}
|
||||
|
||||
func get_reply(id int) (*ReplyShort, error) {
|
||||
reply := ReplyShort{ID:id}
|
||||
err := get_post_stmt.QueryRow(id).Scan(&reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IpAddress, &reply.LikeCount)
|
||||
return &reply, err
|
||||
}
|
||||
|
|
184
routes.go
184
routes.go
|
@ -1605,3 +1605,187 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
|
|||
http.SetCookie(w,&cookie)
|
||||
http.Redirect(w,r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_api(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseForm()
|
||||
is_js := r.PostFormValue("js")
|
||||
if is_js == "" {
|
||||
is_js = "0"
|
||||
}
|
||||
if err != nil {
|
||||
PreErrorJSQ("Bad Form",w,r,is_js)
|
||||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleSessionCheck(w,r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
action := r.FormValue("action")
|
||||
if action != "get" && action != "set" {
|
||||
PreErrorJSQ("Invalid Action",w,r,is_js)
|
||||
return
|
||||
}
|
||||
|
||||
module := r.FormValue("module")
|
||||
switch(module) {
|
||||
case "alerts": // A feed of events tailored for a specific user
|
||||
w.Header().Set("Content-Type","application/json")
|
||||
if !user.Loggedin {
|
||||
w.Write([]byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}]}`))
|
||||
return
|
||||
}
|
||||
|
||||
var msglist string
|
||||
var asid int
|
||||
var actor_id int
|
||||
var targetUser_id int
|
||||
var event string
|
||||
var elementType string
|
||||
var elementID int
|
||||
//---
|
||||
var targetUser *User
|
||||
|
||||
rows, err := get_activity_feed_by_watcher_stmt.Query(user.ID)
|
||||
if err != nil {
|
||||
InternalErrorJS(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&asid,&actor_id,&targetUser_id,&event,&elementType,&elementID)
|
||||
if err != nil {
|
||||
InternalErrorJS(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
actor, err := users.CascadeGet(actor_id)
|
||||
if err != nil {
|
||||
LocalErrorJS("Unable to find the actor",w,r)
|
||||
return
|
||||
}
|
||||
|
||||
/*if elementType != "forum" {
|
||||
targetUser, err = users.CascadeGet(targetUser_id)
|
||||
if err != nil {
|
||||
LocalErrorJS("Unable to find the target user",w,r)
|
||||
return
|
||||
}
|
||||
}*/
|
||||
|
||||
if event == "friend_invite" {
|
||||
msglist += `{"msg":"You received a friend invite from {0}","sub":["` + actor.Name + `"],"path":"/user/`+strconv.Itoa(actor.ID)+`"},`
|
||||
continue
|
||||
}
|
||||
|
||||
/*
|
||||
"You received a friend invite from {user}"
|
||||
"{x}{mentioned you on}{user}{'s profile}"
|
||||
"{x}{mentioned you in}{topic}"
|
||||
"{x}{likes}{you}"
|
||||
"{x}{liked}{your topic}{topic}"
|
||||
"{x}{liked}{your post on}{user}{'s profile}" todo
|
||||
"{x}{liked}{your post in}{topic}"
|
||||
"{x}{replied to}{your post in}{topic}" todo
|
||||
"{x}{created a new topic}{topic}"
|
||||
*/
|
||||
|
||||
var act string
|
||||
var post_act string
|
||||
var url string
|
||||
var area string
|
||||
var start_frag string
|
||||
var end_frag string
|
||||
switch(elementType) {
|
||||
case "forum":
|
||||
if event == "reply" {
|
||||
act = "created a new topic"
|
||||
topic, err := topics.CascadeGet(elementID)
|
||||
if err != nil {
|
||||
LocalErrorJS("Unable to find the linked topic",w,r)
|
||||
return
|
||||
}
|
||||
url = build_topic_url(elementID)
|
||||
area = topic.Title
|
||||
// Store the forum ID in the targetUser column instead of making a new one? o.O
|
||||
// Add an additional column for extra information later on when we add the ability to link directly to posts. We don't need the forum data for now..
|
||||
} else {
|
||||
act = "did something in a forum"
|
||||
}
|
||||
case "topic":
|
||||
topic, err := topics.CascadeGet(elementID)
|
||||
if err != nil {
|
||||
LocalErrorJS("Unable to find the linked topic",w,r)
|
||||
return
|
||||
}
|
||||
url = build_topic_url(elementID)
|
||||
area = topic.Title
|
||||
if targetUser_id == user.ID {
|
||||
post_act = " your topic"
|
||||
}
|
||||
case "user":
|
||||
targetUser, err = users.CascadeGet(elementID)
|
||||
if err != nil {
|
||||
LocalErrorJS("Unable to find the target user",w,r)
|
||||
return
|
||||
}
|
||||
area = targetUser.Name
|
||||
end_frag = "'s profile"
|
||||
url = build_profile_url(elementID)
|
||||
case "post":
|
||||
topic, err := get_topic_by_reply(elementID)
|
||||
if err != nil {
|
||||
LocalErrorJS("Unable to find the target reply or parent topic",w,r)
|
||||
return
|
||||
}
|
||||
url = build_topic_url(elementID)
|
||||
area = topic.Title
|
||||
if targetUser_id == user.ID {
|
||||
post_act = " your post in"
|
||||
}
|
||||
default:
|
||||
LocalErrorJS("Invalid elementType",w,r)
|
||||
}
|
||||
|
||||
if event == "like" {
|
||||
if elementType == "user" {
|
||||
act = "likes"
|
||||
end_frag = ""
|
||||
if targetUser.ID == user.ID {
|
||||
area = "you"
|
||||
}
|
||||
} else {
|
||||
act = "liked"
|
||||
}
|
||||
} else if event == "mention" {
|
||||
if elementType == "user" {
|
||||
act = "mentioned you on"
|
||||
} else {
|
||||
act = "mentioned you in"
|
||||
post_act = ""
|
||||
}
|
||||
}
|
||||
|
||||
msglist += `{"msg":"{0} ` + start_frag + act + post_act + ` {1}` + end_frag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `"},`
|
||||
}
|
||||
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
InternalErrorJS(err,w,r)
|
||||
return
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if len(msglist) != 0 {
|
||||
msglist = msglist[0:len(msglist)-1]
|
||||
}
|
||||
w.Write([]byte(`{"msgs":[`+msglist+`]}`))
|
||||
//case "topics":
|
||||
//case "forums":
|
||||
//case "users":
|
||||
//case "pages":
|
||||
default:
|
||||
PreErrorJSQ("Invalid Module",w,r,is_js)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,10 @@ w.Write(menu_5)
|
|||
w.Write(menu_6)
|
||||
}
|
||||
w.Write(menu_7)
|
||||
if !tmpl_forum_vars.CurrentUser.Loggedin {
|
||||
w.Write(menu_8)
|
||||
}
|
||||
w.Write(menu_9)
|
||||
w.Write(header_3)
|
||||
if len(tmpl_forum_vars.NoticeList) != 0 {
|
||||
for _, item := range tmpl_forum_vars.NoticeList {
|
||||
|
|
|
@ -32,6 +32,10 @@ w.Write(menu_5)
|
|||
w.Write(menu_6)
|
||||
}
|
||||
w.Write(menu_7)
|
||||
if !tmpl_forums_vars.CurrentUser.Loggedin {
|
||||
w.Write(menu_8)
|
||||
}
|
||||
w.Write(menu_9)
|
||||
w.Write(header_3)
|
||||
if len(tmpl_forums_vars.NoticeList) != 0 {
|
||||
for _, item := range tmpl_forums_vars.NoticeList {
|
||||
|
|
|
@ -40,6 +40,9 @@ var menu_6 []byte = []byte(`
|
|||
<li class="menu_left menu_login"><a href="/accounts/login/">Login</a></li>
|
||||
`)
|
||||
var menu_7 []byte = []byte(`
|
||||
<li class="menu_right menu_alerts">🔔︎<div class="alert_counter">`)
|
||||
var menu_8 []byte = []byte(`1`)
|
||||
var menu_9 []byte = []byte(`</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -32,6 +32,10 @@ w.Write(menu_5)
|
|||
w.Write(menu_6)
|
||||
}
|
||||
w.Write(menu_7)
|
||||
if !tmpl_profile_vars.CurrentUser.Loggedin {
|
||||
w.Write(menu_8)
|
||||
}
|
||||
w.Write(menu_9)
|
||||
w.Write(header_3)
|
||||
if len(tmpl_profile_vars.NoticeList) != 0 {
|
||||
for _, item := range tmpl_profile_vars.NoticeList {
|
||||
|
|
|
@ -32,6 +32,10 @@ w.Write(menu_5)
|
|||
w.Write(menu_6)
|
||||
}
|
||||
w.Write(menu_7)
|
||||
if !tmpl_topic_vars.CurrentUser.Loggedin {
|
||||
w.Write(menu_8)
|
||||
}
|
||||
w.Write(menu_9)
|
||||
w.Write(header_3)
|
||||
if len(tmpl_topic_vars.NoticeList) != 0 {
|
||||
for _, item := range tmpl_topic_vars.NoticeList {
|
||||
|
|
|
@ -32,6 +32,10 @@ w.Write(menu_5)
|
|||
w.Write(menu_6)
|
||||
}
|
||||
w.Write(menu_7)
|
||||
if !tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
||||
w.Write(menu_8)
|
||||
}
|
||||
w.Write(menu_9)
|
||||
w.Write(header_3)
|
||||
if len(tmpl_topic_alt_vars.NoticeList) != 0 {
|
||||
for _, item := range tmpl_topic_alt_vars.NoticeList {
|
||||
|
|
|
@ -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_topics_handle = template_topics
|
||||
|
@ -32,6 +32,10 @@ w.Write(menu_5)
|
|||
w.Write(menu_6)
|
||||
}
|
||||
w.Write(menu_7)
|
||||
if !tmpl_topics_vars.CurrentUser.Loggedin {
|
||||
w.Write(menu_8)
|
||||
}
|
||||
w.Write(menu_9)
|
||||
w.Write(header_3)
|
||||
if len(tmpl_topics_vars.NoticeList) != 0 {
|
||||
for _, item := range tmpl_topics_vars.NoticeList {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="colblock_left">
|
||||
<div class="rowitem"><a>My Account</a></div>
|
||||
<div class="rowitem rowhead"><a>My Account</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/avatar/">Change Avatar</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/username/">Change Username</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/critical/">Change Password</a></div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colblock_right">
|
||||
<div class="rowitem"><a>Edit Avatar</a></div>
|
||||
<div class="rowitem rowhead"><a>Edit Avatar</a></div>
|
||||
</div>
|
||||
{{ if .CurrentUser.Avatar }}
|
||||
<div class="colblock_right">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colblock_right">
|
||||
<div class="rowitem"><a>Emails</a></div>
|
||||
<div class="rowitem rowhead"><a>Emails</a></div>
|
||||
</div>
|
||||
<div class="colblock_right">
|
||||
{{range .ItemList}}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colblock_right">
|
||||
<div class="rowitem"><a>Edit Username</a></div>
|
||||
<div class="rowitem rowhead"><a>Edit Username</a></div>
|
||||
</div>
|
||||
<div class="colblock_right">
|
||||
<form action="/user/edit/username/submit/" method="post">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colblock_right">
|
||||
<div class="rowitem"><a>Edit Password</a></div>
|
||||
<div class="rowitem rowhead"><a>Edit Password</a></div>
|
||||
</div>
|
||||
<div class="colblock_right">
|
||||
<form action="/user/edit/critical/submit/" method="post">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem"><a>Create Topic</a></div>
|
||||
<div class="rowitem rowhead"><a>Create Topic</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<form action="/topic/create/submit/" method="post">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem"><a>Login</a></div>
|
||||
<div class="rowitem rowhead"><a>Login</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<form action="/accounts/login/submit/" method="post">
|
||||
|
@ -13,7 +13,8 @@
|
|||
<div class="formitem"><input name="password" type="password" autocomplete="current-password" placeholder="*****" /></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="login-button" class="formbutton">Login</div></div>
|
||||
<div class="formitem"><button name="login-button" class="formbutton">Login</div>
|
||||
<div class="formitem" style="color: #505050; font-size: 12px; font-weight: normal; float: right;">Don't have an account?</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<li class="menu_left menu_register"><a href="/accounts/create/">Register</a></li>
|
||||
<li class="menu_left menu_login"><a href="/accounts/login/">Login</a></li>
|
||||
{{end}}
|
||||
<li class="menu_right menu_alerts">🔔︎<div class="alert_counter">{{if not .CurrentUser.Loggedin}}1{{end}}</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem"><a>Create Account</a></div>
|
||||
<div class="rowitem rowhead"><a>Create Account</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<form action="/accounts/create/submit/" method="post">
|
||||
|
|
27
themes.go
27
themes.go
|
@ -26,6 +26,7 @@ type Theme struct
|
|||
FullImage string
|
||||
MobileFriendly bool
|
||||
Disabled bool
|
||||
HideFromThemes bool
|
||||
Tag string
|
||||
Settings map[string]ThemeSetting
|
||||
Templates []TemplateMapping
|
||||
|
@ -141,21 +142,7 @@ func map_theme_templates(theme Theme) {
|
|||
case *func(TopicPage,io.Writer):
|
||||
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
|
||||
overriden_templates[themeTmpl.Name] = true
|
||||
//log.Print("Topic Handle")
|
||||
//fmt.Println(template_topic_handle)
|
||||
//log.Print("Before")
|
||||
//fmt.Println(d_tmpl_ptr)
|
||||
//fmt.Println(*d_tmpl_ptr)
|
||||
//log.Print("Source")
|
||||
//fmt.Println(s_tmpl_ptr)
|
||||
//fmt.Println(*s_tmpl_ptr)
|
||||
*d_tmpl_ptr = *s_tmpl_ptr
|
||||
//log.Print("After")
|
||||
//fmt.Println(d_tmpl_ptr)
|
||||
//fmt.Println(*d_tmpl_ptr)
|
||||
//log.Print("Source")
|
||||
//fmt.Println(s_tmpl_ptr)
|
||||
//fmt.Println(*s_tmpl_ptr)
|
||||
default:
|
||||
log.Fatal("The source and destination templates are incompatible")
|
||||
}
|
||||
|
@ -236,19 +223,7 @@ func reset_template_overrides() {
|
|||
case func(TopicPage,io.Writer):
|
||||
switch d_ptr := dest_tmpl_ptr.(type) {
|
||||
case *func(TopicPage,io.Writer):
|
||||
//log.Print("Topic Handle")
|
||||
//fmt.Println(template_topic_handle)
|
||||
//log.Print("Before")
|
||||
//fmt.Println(d_ptr)
|
||||
//fmt.Println(*d_ptr)
|
||||
//log.Print("Origin")
|
||||
//fmt.Println(o_ptr)
|
||||
*d_ptr = o_ptr
|
||||
//log.Print("After")
|
||||
//fmt.Println(d_ptr)
|
||||
//fmt.Println(*d_ptr)
|
||||
//log.Print("Origin")
|
||||
//fmt.Println(o_ptr)
|
||||
default:
|
||||
log.Fatal("The origin and destination templates are incompatible")
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"Version": "Coming Soon",
|
||||
"Creator": "Azareal",
|
||||
"Disabled": true,
|
||||
"HideFromThemes": true,
|
||||
"Tag": "WIP",
|
||||
"Templates": [
|
||||
{
|
||||
|
|
|
@ -50,10 +50,7 @@ li
|
|||
padding-left: 1px;
|
||||
padding-right: 1px;
|
||||
|
||||
border: 1px solid #7a7a7a;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
border-left: none;
|
||||
border-right: 1px solid #7a7a7a;
|
||||
font-weight: normal;
|
||||
color: white;
|
||||
}
|
||||
|
@ -63,16 +60,10 @@ li a
|
|||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
li:hover a, li a:hover, li a:link, li a:visited
|
||||
{
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
li:hover
|
||||
{
|
||||
background: rgba(10,10,10,0.5);
|
||||
font-weight: normal;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.menu_right
|
||||
|
@ -85,17 +76,28 @@ li:hover
|
|||
padding-right: 10px;
|
||||
height: 38px;
|
||||
text-align: center;
|
||||
border-left: 1px solid #7a7a7a;
|
||||
}
|
||||
|
||||
.menu_right:hover
|
||||
{
|
||||
border: #282828 1px solid;
|
||||
background: #282828;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
height: 38px;
|
||||
.menu_alerts .alert_counter {
|
||||
position: relative;
|
||||
font-size: 9px;
|
||||
top: -24px;
|
||||
background-color: rgb(140,0,0);
|
||||
color: white;
|
||||
padding: 3px;
|
||||
width: 14px;
|
||||
left: 10px;
|
||||
line-height: 8px;
|
||||
border-radius: 20px;
|
||||
padding-top: 2.5px;
|
||||
height: 14px;
|
||||
opacity: 0.8;
|
||||
text-align: center;
|
||||
}
|
||||
.menu_alerts .alert_counter:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#footer
|
||||
{
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"Name": "shadow",
|
||||
"FriendlyName": "Shadow",
|
||||
"Version": "0.0.1",
|
||||
"Creator": "Azareal",
|
||||
"Disabled": true,
|
||||
"HideFromThemes": true
|
||||
}
|
|
@ -57,6 +57,31 @@ li a
|
|||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.menu_alerts {
|
||||
padding-left: 7px;
|
||||
padding-top: 2px;
|
||||
color: rgb(80,80,80);
|
||||
}
|
||||
.menu_alerts .alert_counter {
|
||||
position:relative;
|
||||
font-size: 9px;
|
||||
top: -24px;
|
||||
background-color: rgb(140,0,0);
|
||||
color: white;
|
||||
padding: 3px;
|
||||
width: 14px;
|
||||
left: 10px;
|
||||
line-height: 8px;
|
||||
border-radius: 20px;
|
||||
padding-top: 2.5px;
|
||||
height: 14px;
|
||||
opacity: 0.8;
|
||||
text-align: center;
|
||||
}
|
||||
.menu_alerts .alert_counter:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container
|
||||
{
|
||||
width: 90%;
|
||||
|
|
|
@ -55,6 +55,31 @@ li a
|
|||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.menu_alerts {
|
||||
padding-left: 7px;
|
||||
padding-top: 2px;
|
||||
color: rgb(80,80,80);
|
||||
}
|
||||
.menu_alerts .alert_counter {
|
||||
position:relative;
|
||||
font-size: 9px;
|
||||
top: -24px;
|
||||
background-color: rgb(140,0,0);
|
||||
color: white;
|
||||
padding: 3px;
|
||||
width: 14px;
|
||||
left: 10px;
|
||||
line-height: 8px;
|
||||
border-radius: 20px;
|
||||
padding-top: 2.5px;
|
||||
height: 14px;
|
||||
opacity: 0.8;
|
||||
text-align: center;
|
||||
}
|
||||
.menu_alerts .alert_counter:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container
|
||||
{
|
||||
width: 90%;
|
||||
|
|
11
topic.go
11
topic.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
//import "fmt"
|
||||
import "sync"
|
||||
import "strconv"
|
||||
import "html/template"
|
||||
import "database/sql"
|
||||
|
||||
|
@ -342,3 +343,13 @@ func copy_topic_to_topicuser(topic *Topic, user *User) (tu TopicUser) {
|
|||
tu.LikeCount = topic.LikeCount
|
||||
return tu
|
||||
}
|
||||
|
||||
func get_topic_by_reply(rid int) (*Topic, error) {
|
||||
topic := Topic{ID:0}
|
||||
err := get_topic_by_reply_stmt.QueryRow(rid).Scan(&topic.ID, &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 build_topic_url(tid int) string {
|
||||
return "/topic/" + strconv.Itoa(tid)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue