diff --git a/alerts.go b/alerts.go index de567ccb..0aa57655 100644 --- a/alerts.go +++ b/alerts.go @@ -2,8 +2,10 @@ package main import "log" import "strings" +import "strconv" import "errors" +// These notes are for me, don't worry about it too much ^_^ /* "You received a friend invite from {user}" "{x}{mentioned you on}{user}{'s profile}" @@ -18,7 +20,7 @@ import "errors" "{x}{created a new topic}{topic}" */ -func build_alert(event string, elementType string, actor_id int, targetUser_id int, elementID int, user User /* The current user */) (string, error) { +func build_alert(asid int, event string, elementType string, actor_id int, targetUser_id int, elementID int, user User /* The current user */) (string, error) { var targetUser *User actor, err := users.CascadeGet(actor_id) @@ -35,7 +37,7 @@ func build_alert(event string, elementType string, actor_id int, targetUser_id i }*/ if event == "friend_invite" { - return `{"msg":"You received a friend invite from {0}","sub":["` + actor.Name + `"],"path":"`+actor.Link+`","avatar":"`+strings.Replace(actor.Avatar,"/","\\/",-1)+`"}`, nil + return `{"msg":"You received a friend invite from {0}","sub":["` + actor.Name + `"],"path":"`+actor.Link+`","avatar":"`+strings.Replace(actor.Avatar,"/","\\/",-1)+`","asid":"`+strconv.Itoa(asid)+`"}`, nil } var act, post_act, url, area string @@ -109,7 +111,7 @@ func build_alert(event string, elementType string, actor_id int, targetUser_id i case "reply": act = "replied to" } - return `{"msg":"{0} ` + start_frag + act + post_act + ` {1}` + end_frag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `","avatar":"` + actor.Avatar + `"}`, nil + return `{"msg":"{0} ` + start_frag + act + post_act + ` {1}` + end_frag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `","avatar":"` + actor.Avatar + `","asid":"`+strconv.Itoa(asid)+`"}`, nil } func notify_watchers(asid int64) { @@ -144,5 +146,5 @@ func notify_watchers(asid int64) { return } - _ = ws_hub.push_alerts(uids, event, elementType, actor_id, targetUser_id, elementID) + _ = ws_hub.push_alerts(uids, int(asid), event, elementType, actor_id, targetUser_id, elementID) } diff --git a/errors.go b/errors.go index 8b018b50..c3c93d92 100644 --- a/errors.go +++ b/errors.go @@ -118,6 +118,11 @@ func LoginRequired(w http.ResponseWriter, r *http.Request, user User) { fmt.Fprintln(w,b.String()) } +func PreErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) { + w.WriteHeader(500) + w.Write([]byte(`{"errmsg":"` + errmsg + `"}`)) +} + func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, is_js string) { w.WriteHeader(500) if is_js == "0" { diff --git a/gen_mysql.go b/gen_mysql.go index e2f3b888..9956a83f 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -109,6 +109,7 @@ var delete_reply_stmt *sql.Stmt var delete_topic_stmt *sql.Stmt var delete_profile_reply_stmt *sql.Stmt var delete_forum_perms_by_forum_stmt *sql.Stmt +var delete_activity_stream_match_stmt *sql.Stmt var report_exists_stmt *sql.Stmt var group_count_stmt *sql.Stmt var modlog_count_stmt *sql.Stmt @@ -734,6 +735,12 @@ func _gen_mysql() (err error) { return err } + log.Print("Preparing delete_activity_stream_match statement.") + delete_activity_stream_match_stmt, err = db.Prepare("DELETE FROM `activity_stream_matches` WHERE `watcher` = ? AND `asid` = ?") + if err != nil { + return err + } + log.Print("Preparing report_exists statement.") report_exists_stmt, err = db.Prepare("SELECT COUNT(*) AS `count` FROM `topics` WHERE `data` = ? AND `data` != '' AND `parentID` = 1") if err != nil { diff --git a/mysql.sql b/mysql.sql index 48d98ddb..df3d4537 100644 --- a/mysql.sql +++ b/mysql.sql @@ -238,7 +238,7 @@ INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`) VALUES ('Awaiting INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`tag`) VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest'); INSERT INTO forums(`name`,`active`) VALUES ('Reports',0); -INSERT INTO forums(`name`,`lastTopicTime`) VALUES ('General',UTC_TIMESTAMP()); +INSERT INTO forums(`name`,`lastTopicTime`,`lastTopicID`,`lastReplyer`,`lastReplyerID`,`lastTopic`) VALUES ('General',UTC_TIMESTAMP(),1,"Admin",1,'Test Topic'); INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (1,1,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"PinTopic":true,"CloseTopic":true}'); INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (2,1,'{"ViewTopic":true,"CreateReply":true,"CloseTopic":true}'); INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (3,1,'{}'); diff --git a/no_websockets.go b/no_websockets.go index 5d76f851..62410c28 100644 --- a/no_websockets.go +++ b/no_websockets.go @@ -28,11 +28,11 @@ func (hub *WS_Hub) push_message(_ int, _ string) error { return ws_nouser } -func(hub *WS_Hub) push_alert(_ int, _ string, _ string, _ int, _ int, _ int) error { +func(hub *WS_Hub) push_alert(_ int, _ int, _ string, _ string, _ int, _ int, _ int) error { return ws_nouser } -func(hub *WS_Hub) push_alerts(_ []int, _ string, _ string, _ int, _ int, _ int) error { +func(hub *WS_Hub) push_alerts(_ []int, _ int, _ string, _ string, _ int, _ int, _ int) error { return ws_nouser } diff --git a/public/global.js b/public/global.js index b876ad45..e558e322 100644 --- a/public/global.js +++ b/public/global.js @@ -1,3 +1,4 @@ +'use strict'; var form_vars = {}; var alertList = []; var alertCount = 0; @@ -11,6 +12,14 @@ function post_link(event) $.ajax({ url: form_action, type: "POST", dataType: "json", data: {js: "1"} }); } +function bind_to_alerts() { + $(".alertItem.withAvatar a").click(function(event) { + event.stopPropagation(); + $.ajax({ url: "/api/?action=set&module=dismiss-alert", type: "POST", dataType: "json", data: { asid: $(this).attr("data-asid") } }); + }); +} + +// TO-DO: Add the ability for users to dismiss alerts function load_alerts(menu_alerts) { var alertListNode = menu_alerts.getElementsByClassName("alertList")[0]; @@ -19,7 +28,7 @@ function load_alerts(menu_alerts) $.ajax({ type: 'get', dataType: 'json', - url:'/api/?action=get&module=alerts&format=json', + url:'/api/?action=get&module=alerts', success: function(data) { if("errmsg" in data) { alertListNode.innerHTML = "
"+data.errmsg+"
"; @@ -41,8 +50,8 @@ function load_alerts(menu_alerts) } if("avatar" in msg) { - alist += "
"+mmsg+"
"; - alertList.push("
"+mmsg+"
"); + alist += "
"+mmsg+"
"; + alertList.push("
"+mmsg+"
"); anyAvatar = true } else { alist += "
"+mmsg+"
"; @@ -65,6 +74,8 @@ function load_alerts(menu_alerts) menu_alerts.classList.remove("has_alerts"); } alertCount = data.msgCount; + + bind_to_alerts(); }, error: function(magic,theStatus,error) { try { @@ -123,26 +134,26 @@ $(document).ready(function(){ if ("msg" in data) { var msg = data.msg - if("sub" in data) { - for(var i = 0; i < data.sub.length; i++) { + if("sub" in data) + for(var i = 0; i < data.sub.length; i++) msg = msg.replace("\{"+i+"\}", data.sub[i]); - } - } - if("avatar" in data) alertList.push("
"+msg+"
"); + if("avatar" in data) alertList.push("
"+msg+"
"); else alertList.push("
"+msg+"
"); if(alertList.length > 8) alertList.shift(); //console.log("post alertList",alertList); alertCount++; var alist = "" - for (var i = 0; i < alertList.length; i++) { - alist += alertList[i]; - } + for (var i = 0; i < alertList.length; i++) alist += alertList[i]; //console.log(alist); - $("#general_alerts").find(".alertList").html(alist); // Add support for other alert feeds like PM Alerts - $("#general_alerts").find(".alert_counter").text(alertCount); + // TO-DO: Add support for other alert feeds like PM Alerts + var general_alerts = document.getElementById("general_alerts"); + var alertListNode = general_alerts.getElementsByClassName("alertList")[0]; + var alertCounterNode = general_alerts.getElementsByClassName("alert_counter")[0]; + alertListNode.innerHTML = alist; + alertCounterNode.textContent = alertCount; // TO-DO: Add some sort of notification queue to avoid flooding the end-user with notices? // TO-DO: Use the site name instead of "Something Happened" @@ -153,6 +164,8 @@ $(document).ready(function(){ }); setTimeout(n.close.bind(n), 8000); } + + bind_to_alerts(); } } @@ -337,6 +350,7 @@ $(document).ready(function(){ }); }); + // This one's for Tempra Conflux $(".ip_item").each(function(){ var ip = this.textContent; if(ip.length > 10){ diff --git a/query_gen/main.go b/query_gen/main.go index 6840e560..c671681d 100644 --- a/query_gen/main.go +++ b/query_gen/main.go @@ -391,6 +391,10 @@ func write_deletes(adapter qgen.DB_Adapter) error { adapter.SimpleDelete("delete_forum_perms_by_forum","forums_permissions","fid = ?") + adapter.SimpleDelete("delete_activity_stream_match","activity_stream_matches","watcher = ? AND asid = ?") + + //adapter.SimpleDelete("delete_activity_stream_matches_by_watcher","activity_stream_matches","watcher = ?") + return nil } diff --git a/routes.go b/routes.go index 71b05b6a..912e82a5 100644 --- a/routes.go +++ b/routes.go @@ -841,7 +841,7 @@ func route_topic_create_submit(w http.ResponseWriter, r *http.Request, user User return } - err = fstore.UpdateLastTopic(topic_name,int(lastId),user.Name,user.ID,"",fid) + err = fstore.UpdateLastTopic(topic_name,int(lastId),user.Name,user.ID,time.Now().Format("2006-01-02 15:04:05"),fid) if err != nil && err != ErrNoRows { InternalError(err,w) } @@ -896,8 +896,8 @@ func route_create_reply(w http.ResponseWriter, r *http.Request, user User) { InternalError(err,w) return } - _, err = update_forum_cache_stmt.Exec(topic.Title,tid,user.Name,user.ID,1) - if err != nil { + err = fstore.UpdateLastTopic(topic.Title,tid,user.Name,user.ID,time.Now().Format("2006-01-02 15:04:05"),topic.ParentID) + if err != nil && err != ErrNoRows { InternalError(err,w) return } @@ -1027,7 +1027,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request, user User) { } // Live alerts, if the poster is online and WebSockets is enabled - _ = ws_hub.push_alert(topic.CreatedBy,"like","topic",user.ID,topic.CreatedBy,tid) + _ = ws_hub.push_alert(topic.CreatedBy,int(lastId),"like","topic",user.ID,topic.CreatedBy,tid) // Reload the topic... err = topics.Load(tid) @@ -1137,7 +1137,7 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request, user User) } // Live alerts, if the poster is online and WebSockets is enabled - _ = ws_hub.push_alert(reply.CreatedBy,"like","post",user.ID,reply.CreatedBy,rid) + _ = ws_hub.push_alert(reply.CreatedBy,int(lastId),"like","post",user.ID,reply.CreatedBy,rid) http.Redirect(w,r,"/topic/" + strconv.Itoa(reply.ParentID),http.StatusSeeOther) } @@ -1896,37 +1896,37 @@ func route_register_submit(w http.ResponseWriter, r *http.Request, user User) { http.Redirect(w,r,"/",http.StatusSeeOther) } +// TO-DO: We don't need support XML here to support sitemaps, we could handle those elsewhere var phrase_login_alerts []byte = []byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}]}`) func route_api(w http.ResponseWriter, r *http.Request, user User) { + w.Header().Set("Content-Type","application/json") err := r.ParseForm() - format := r.FormValue("format") - // TO-DO: Change is_js from a string to a boolean value - var is_js string - if format == "json" { - is_js = "1" - } else { // html - is_js = "0" - } if err != nil { - PreErrorJSQ("Bad Form",w,r,is_js) + PreErrorJS("Bad Form",w,r) return } action := r.FormValue("action") if action != "get" && action != "set" { - PreErrorJSQ("Invalid Action",w,r,is_js) + PreErrorJS("Invalid Action",w,r) return } module := r.FormValue("module") switch(module) { - case "alerts": // A feed of events tailored for a specific user - if format != "json" { - PreError("You can only fetch alerts in the JSON format!",w,r) + case "dismiss-alert": + asid, err := strconv.Atoi(r.FormValue("asid")) + if err != nil { + PreErrorJS("Invalid asid",w,r) return } - w.Header().Set("Content-Type","application/json") + _, err = delete_activity_stream_match_stmt.Exec(user.ID,asid) + if err != nil { + InternalError(err,w) + return + } + case "alerts": // A feed of events tailored for a specific user if !user.Loggedin { w.Write(phrase_login_alerts) return @@ -1938,10 +1938,10 @@ func route_api(w http.ResponseWriter, r *http.Request, user User) { err = get_activity_count_by_watcher_stmt.QueryRow(user.ID).Scan(&msgCount) if err == ErrNoRows { - PreError("Couldn't find the parent topic",w,r) + PreErrorJS("Couldn't find the parent topic",w,r) return } else if err != nil { - InternalError(err,w) + InternalErrorJS(err,w,r) return } @@ -1958,7 +1958,7 @@ func route_api(w http.ResponseWriter, r *http.Request, user User) { InternalErrorJS(err,w,r) return } - res, err := build_alert(event, elementType, actor_id, targetUser_id, elementID, user) + res, err := build_alert(asid, event, elementType, actor_id, targetUser_id, elementID, user) if err != nil { LocalErrorJS(err.Error(),w,r) return @@ -1988,6 +1988,6 @@ func route_api(w http.ResponseWriter, r *http.Request, user User) { return }*/ default: - PreErrorJSQ("Invalid Module",w,r,is_js) + PreErrorJS("Invalid Module",w,r) } } diff --git a/template_list.go b/template_list.go index 914dc54d..409f1aa4 100644 --- a/template_list.go +++ b/template_list.go @@ -25,11 +25,9 @@ var header_8 []byte = []byte(`"; - +var header_10 []byte = []byte(`
`) var menu_0 []byte = []byte(``) var forum_8 []byte = []byte(` -
-
+ diff --git a/templates/account-menu.html b/templates/account-menu.html index 8e324573..01c77356 100644 --- a/templates/account-menu.html +++ b/templates/account-menu.html @@ -7,7 +7,8 @@ - + + {{/** TO-DO: Add an alerts page with pagination to go through alerts which either don't fit in the alerts drop-down or which have already been dismissed. Bear in mind though that dismissed alerts older than two weeks might be purged to save space and to speed up the database **/}}
diff --git a/templates/forum.html b/templates/forum.html index 5af2066c..1b6b8f25 100644 --- a/templates/forum.html +++ b/templates/forum.html @@ -4,8 +4,8 @@ {{if ne .LastPage .Page}} {{end}} -
-
{{.Title}} +
+ {{if ne .CurrentUser.ID 0}} {{if .CurrentUser.Perms.CreateTopic}} diff --git a/templates/header.html b/templates/header.html index bc3988cd..13d548ef 100644 --- a/templates/header.html +++ b/templates/header.html @@ -15,9 +15,7 @@ - +
{{template "menu.html" .}}
diff --git a/themes/shadow/public/main.css b/themes/shadow/public/main.css index 02d9ff2c..d666c3a9 100644 --- a/themes/shadow/public/main.css +++ b/themes/shadow/public/main.css @@ -129,6 +129,7 @@ a { .opthead, .rowhead, .colstack_head { padding-bottom: 0px; padding-top: 3px !important; + white-space: nowrap; } .rowblock:not(.opthead):not(.colstack_head):not(.rowhead) .rowitem { @@ -212,12 +213,24 @@ a { .like_label:before { content: "+1"; } -.edit_label:before { content: "Edit"; } -.trash_label:before { content: "Delete"; } -.pin_label:before { content: "Pin"; } -.unpin_label:before { content: "Unpin"; } -.flag_label:before { content: "Flag"; } -.level_label:before { content: "Level"; } +.edit_label:before { + content: "Edit"; +} +.trash_label:before { + content: "Delete"; +} +.pin_label:before { + content: "Pin"; +} +.unpin_label:before { + content: "Unpin"; +} +.flag_label:before { + content: "Flag"; +} +.level_label:before { + content: "Level"; +} .like_count_label:before { content: "likes"; @@ -252,11 +265,9 @@ a { .formrow.real_first_child, .formrow:first-child { margin-top: 8px; } - .formrow.real_first_child .formitem, .formrow:first-child .formitem { padding-top: 12px; } - .formrow:last-child .formitem { padding-bottom: 12px; } diff --git a/websockets.go b/websockets.go index 5cd92c85..e2355b10 100644 --- a/websockets.go +++ b/websockets.go @@ -87,7 +87,7 @@ func (hub *WS_Hub) push_message(targetUser int, msg string) error { return nil } -func(hub *WS_Hub) push_alert(targetUser int, event string, elementType string, actor_id int, targetUser_id int, elementID int) error { +func(hub *WS_Hub) push_alert(targetUser int, asid int, event string, elementType string, actor_id int, targetUser_id int, elementID int) error { //log.Print("In push_alert") hub.users.RLock() ws_user, ok := hub.online_users[targetUser] @@ -97,7 +97,7 @@ func(hub *WS_Hub) push_alert(targetUser int, event string, elementType string, a } //log.Print("Building alert") - alert, err := build_alert(event, elementType, actor_id, targetUser_id, elementID, *ws_user.User) + alert, err := build_alert(asid, event, elementType, actor_id, targetUser_id, elementID, *ws_user.User) if err != nil { return err } @@ -113,7 +113,7 @@ func(hub *WS_Hub) push_alert(targetUser int, event string, elementType string, a return nil } -func(hub *WS_Hub) push_alerts(users []int, event string, elementType string, actor_id int, targetUser_id int, elementID int) error { +func(hub *WS_Hub) push_alerts(users []int, asid int, event string, elementType string, actor_id int, targetUser_id int, elementID int) error { //log.Print("In push_alerts") var ws_users []*WS_User hub.users.RLock() @@ -133,7 +133,7 @@ func(hub *WS_Hub) push_alerts(users []int, event string, elementType string, act } //log.Print("Building alert") - alert, err := build_alert(event, elementType, actor_id, targetUser_id, elementID, *ws_user.User) + alert, err := build_alert(asid, event, elementType, actor_id, targetUser_id, elementID, *ws_user.User) if err != nil { errs = append(errs,err) }