diff --git a/data.sql b/data.sql
index 0c9854a9..f9adb149 100644
--- a/data.sql
+++ b/data.sql
@@ -136,8 +136,8 @@ CREATE TABLE `activity_stream`(
CREATE TABLE `activity_subscriptions`(
`user` int not null,
- `targetID` int not null,
- `targetType` varchar(50) not null,
+ `targetID` int not null, /* the ID of the element being acted upon */
+ `targetType` varchar(50) not null, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
`level` tinyint DEFAULT 0 not null /* 0: Mentions (aka the global default for any post), 1: Replies, 2: Everyone*/
);
diff --git a/mysql.go b/mysql.go
index 1c970743..a3b29376 100644
--- a/mysql.go
+++ b/mysql.go
@@ -33,6 +33,9 @@ var update_forum_cache_stmt *sql.Stmt
var create_like_stmt *sql.Stmt
var add_likes_to_topic_stmt *sql.Stmt
var add_likes_to_reply_stmt *sql.Stmt
+var add_activity_stmt *sql.Stmt
+var notify_watchers_stmt *sql.Stmt
+var notify_one_stmt *sql.Stmt
var edit_topic_stmt *sql.Stmt
var edit_reply_stmt *sql.Stmt
var delete_reply_stmt *sql.Stmt
@@ -238,6 +241,24 @@ func init_database(err error) {
log.Fatal(err)
}
+ log.Print("Preparing add_activity statement.")
+ add_activity_stmt, err = db.Prepare("INSERT INTO activity_stream(actor,targetUser,event,elementType,elementID) VALUES(?,?,?,?,?)")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ log.Print("Preparing notify_watchers statement.")
+ notify_watchers_stmt, err = db.Prepare("INSERT INTO activity_stream_matches(watcher, asid) SELECT activity_subscriptions.user, ? AS asid FROM activity_subscriptions LEFT JOIN activity_stream ON activity_subscriptions.targetType=activity_stream.elementType and activity_subscriptions.targetID=activity_stream.elementID")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ log.Print("Preparing notify_one statement.")
+ notify_one_stmt, err = db.Prepare("INSERT INTO activity_stream_matches(watcher,asid) VALUES(?,?)")
+ if err != nil {
+ log.Fatal(err)
+ }
+
log.Print("Preparing edit_topic statement.")
edit_topic_stmt, err = db.Prepare("UPDATE topics SET title = ?, content = ?, parsed_content = ?, is_closed = ? WHERE tid = ?")
if err != nil {
diff --git a/permissions.go b/permissions.go
index 69360475..eb17e3ef 100644
--- a/permissions.go
+++ b/permissions.go
@@ -310,51 +310,33 @@ func build_forum_permissions() error {
func strip_invalid_preset(preset string) string {
switch(preset) {
- case "all":
- case "announce":
- case "members":
- case "staff":
- case "admins":
- case "archive":
+ case "all","announce","members","staff","admins","archive":
break
- default:
- return ""
+ default: return ""
}
return preset
}
func preset_to_lang(preset string) string {
switch(preset) {
- case "all":
- return ""//return "Everyone"
- case "announce":
- return "Announcements"
- case "members":
- return "Member Only"
- case "staff":
- return "Staff Only"
- case "admins":
- return "Admin Only"
- case "archive":
- return "Archive"
+ case "all": return ""//return "Everyone"
+ case "announce": return "Announcements"
+ case "members": return "Member Only"
+ case "staff": return "Staff Only"
+ case "admins": return "Admin Only"
+ case "archive": return "Archive"
}
return ""
}
func preset_to_emoji(preset string) string {
switch(preset) {
- case "all":
- return ""//return "Everyone"
- case "announce":
- return "📣"
- case "members":
- return "👪"
- case "staff":
- return "👮"
- case "admins":
- return "👑"
- case "archive":
- return "☠️"
+ case "all": return ""//return "Everyone"
+ case "announce": return "📣"
+ case "members": return "👪"
+ case "staff": return "👮"
+ case "admins": return "👑"
+ case "archive": return "☠️"
}
return ""
}
diff --git a/public/global.js b/public/global.js
index 3638e1c0..bf5b84e9 100644
--- a/public/global.js
+++ b/public/global.js
@@ -8,6 +8,70 @@ function post_link(event)
$.ajax({ url: form_action, type: "POST", dataType: "json", data: {js: "1"} });
}
+function load_alerts(menu_alerts)
+{
+ menu_alerts.find(".alert_counter").text("");
+ $.ajax({
+ type: 'get',
+ dataType: 'json',
+ url:'/api/?action=get&module=alerts&format=json',
+ success: function(data) {
+ if("errmsg" in data) {
+ console.log(data.errmsg);
+ menu_alerts.find(".alertList").html("
"+data.errmsg+"
");
+ return;
+ }
+
+ var alist = "";
+ for(var i in data.msgs) {
+ var msg = data.msgs[i];
+ var mmsg = msg.msg;
+
+ if("sub" in msg) {
+ for(var i = 0; i < msg.sub.length; i++) {
+ mmsg = mmsg.replace("\{"+i+"\}", msg.sub[i]);
+ console.log("Sub #" + i);
+ console.log(msg.sub[i]);
+ }
+ }
+
+ if(mmsg.length > 46) mmsg = mmsg.substring(0,43) + "...";
+ else if(mmsg.length > 35) size_dial = " smaller"; //9px
+ else size_dial = ""; // 10px
+
+ if("avatar" in msg) {
+ alist += "";
+ console.log(msg.avatar);
+ } else {
+ alist += "";
+ }
+ console.log(msg);
+ //console.log(mmsg);
+ }
+
+ if(alist == "") {
+ alist = "You don't have any alerts
"
+ }
+ menu_alerts.find(".alertList").html(alist);
+ if(data.msgs.length != 0) {
+ menu_alerts.find(".alert_counter").text(data.msgs.length);
+ }
+ },
+ error: function(magic,theStatus,error) {
+ try {
+ var data = JSON.parse(magic.responseText);
+ if("errmsg" in data)
+ {
+ console.log(data.errmsg);
+ errtxt = data.errmsg;
+ }
+ else errtxt = "Unable to get the alerts"
+ } catch(e) { errtxt = "Unable to get the alerts"; }
+ menu_alerts.find(".alertList").html(""+errtxt+"
");
+ }
+ });
+}
+
$(document).ready(function(){
$(".open_edit").click(function(event){
//console.log("Clicked on edit");
@@ -162,63 +226,19 @@ $(document).ready(function(){
}
});
+ $('body').click(function() {
+ $(".selectedAlert").removeClass("selectedAlert");
+ });
+
+ $(".menu_alerts").ready(function(){
+ load_alerts($(this));
+ });
+
$(".menu_alerts").click(function(event) {
+ event.stopPropagation();
if($(this).hasClass("selectedAlert")) return;
- var menu_alerts = $(this);
-
this.className += " selectedAlert";
- $.ajax({
- type: 'get',
- dataType: 'json',
- url:'/api/?action=get&module=alerts&format=json',
- success: function(data) {
- if("errmsg" in data) {
- console.log(data.errmsg);
- menu_alerts.find(".alertList").html(""+data.errmsg+"
");
- return;
- }
-
- var alist = "";
- for(var i in data.msgs) {
- var msg = data.msgs[i];
- var mmsg = msg.msg;
-
- if("sub" in msg) {
- for(var i = 0; i < msg.sub.length; i++) {
- mmsg = mmsg.replace("\{"+i+"\}", msg.sub[i]);
- console.log("Sub #" + i);
- console.log(msg.sub[i]);
- }
- }
-
- if("avatar" in msg) {
- alist += "";
- console.log(msg.avatar);
- } else {
- alist += ""+mmsg+"
";
- }
- console.log(msg);
- console.log(mmsg);
- }
-
- if(alist == "") {
- alist = "You don't have any alerts
"
- }
- menu_alerts.find(".alertList").html(alist);
- },
- error: function(magic,theStatus,error) {
- try {
- var data = JSON.parse(magic.responseText);
- if("errmsg" in data)
- {
- console.log(data.errmsg);
- errtxt = data.errmsg;
- }
- else errtxt = "Unable to get the alerts"
- } catch(e) { errtxt = "Unable to get the alerts"; }
- menu_alerts.find(".alertList").html(""+errtxt+"
");
- }
- });
+ load_alerts($(this));
});
this.onkeyup = function(event){
diff --git a/routes.go b/routes.go
index 9bb7c54f..9fce8a0d 100644
--- a/routes.go
+++ b/routes.go
@@ -727,7 +727,8 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
var words int
var fid int
- err = db.QueryRow("select parentID, words from topics where tid = ?", tid).Scan(&fid,&words)
+ var createdBy int
+ err = db.QueryRow("select parentID, words, createdBy from topics where tid = ?", tid).Scan(&fid,&words,&createdBy)
if err == sql.ErrNoRows {
PreError("The requested topic doesn't exist.",w,r)
return
@@ -754,6 +755,15 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
return
}
+ _, err = users.CascadeGet(createdBy)
+ if err != nil && err != sql.ErrNoRows {
+ LocalError("The target user doesn't exist",w,r,user)
+ return
+ } else if err != nil {
+ InternalError(err,w,r)
+ return
+ }
+
//score := words_to_score(words,true)
score := 1
_, err = create_like_stmt.Exec(score,tid,"topics",user.ID)
@@ -768,6 +778,28 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
return
}
+ res, err := add_activity_stmt.Exec(user.ID,createdBy,"like","topic",tid)
+ if err != nil {
+ InternalError(err,w,r)
+ return
+ }
+ lastId, err := res.LastInsertId()
+ if err != nil {
+ InternalError(err,w,r)
+ return
+ }
+
+ /*_, err = notify_watchers_stmt.Exec(lastId)
+ if err != nil {
+ InternalError(err,w,r)
+ return
+ }*/
+ _, err = notify_one_stmt.Exec(createdBy,lastId)
+ if err != nil {
+ InternalError(err,w,r)
+ return
+ }
+
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
}
@@ -786,7 +818,8 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
var tid int
var words int
- err = db.QueryRow("select tid, words from replies where rid = ?", rid).Scan(&tid, &words)
+ var createdBy int
+ err = db.QueryRow("select tid, words, createdBy from replies where rid = ?", rid).Scan(&tid, &words, &createdBy)
if err == sql.ErrNoRows {
PreError("You can't like something which doesn't exist!",w,r)
return
@@ -823,6 +856,15 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
return
}
+ _, err = users.CascadeGet(createdBy)
+ if err != nil && err != sql.ErrNoRows {
+ LocalError("The target user doesn't exist",w,r,user)
+ return
+ } else if err != nil {
+ InternalError(err,w,r)
+ return
+ }
+
//score := words_to_score(words,false)
score := 1
_, err = create_like_stmt.Exec(score,rid,"replies",user.ID)
@@ -837,6 +879,23 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
return
}
+ res, err := add_activity_stmt.Exec(user.ID,createdBy,"like","post",rid)
+ if err != nil {
+ InternalError(err,w,r)
+ return
+ }
+ lastId, err := res.LastInsertId()
+ if err != nil {
+ InternalError(err,w,r)
+ return
+ }
+
+ _, err = notify_one_stmt.Exec(createdBy,lastId)
+ if err != nil {
+ InternalError(err,w,r)
+ return
+ }
+
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
}
@@ -1748,7 +1807,7 @@ func route_api(w http.ResponseWriter, r *http.Request) {
LocalErrorJS("Unable to find the target reply or parent topic",w,r)
return
}
- url = build_topic_url(elementID)
+ url = build_topic_url(topic.ID)
area = topic.Title
if targetUser_id == user.ID {
post_act = " your post in"
diff --git a/templates.go b/templates.go
index 7e61540b..e8126475 100644
--- a/templates.go
+++ b/templates.go
@@ -743,14 +743,10 @@ func (c *CTemplateSet) compile_if_varsub(varname string, varholder string, templ
func (c *CTemplateSet) compile_boolsub(varname string, varholder string, template_name string, val reflect.Value) string {
out, val := c.compile_if_varsub(varname, varholder, template_name, val)
switch val.Kind() {
- case reflect.Int:
- out += " > 0"
- case reflect.Bool:
- // Do nothing
- case reflect.String:
- out += " != \"\""
- case reflect.Int64:
- out += " > 0"
+ case reflect.Int: out += " > 0"
+ case reflect.Bool: // Do nothing
+ case reflect.String: out += " != \"\""
+ case reflect.Int64: out += " > 0"
default:
fmt.Println(varname)
fmt.Println(varholder)
diff --git a/themes/cosmo/public/main.css b/themes/cosmo/public/main.css
index 510f1907..3ccdc7c1 100644
--- a/themes/cosmo/public/main.css
+++ b/themes/cosmo/public/main.css
@@ -106,6 +106,10 @@ li:hover
.selectedAlert:hover {
background: white;
color: black;
+ font-weight: bold;
+}
+.selectedAlert .alert_counter {
+ display: none;
}
.menu_alerts .alertList {
display: none;
@@ -117,7 +121,7 @@ li:hover
background: white;
font-size: 10px;
line-height: 16px;
- width: 135px;
+ width: 156px;
right: -15px;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
@@ -130,21 +134,25 @@ li:hover
}
.alertItem.withAvatar {
/*background-image: url('/uploads/avatar_1.jpg');*/
- background-size: auto 56px;
+ background-size: 36px;
background-repeat: no-repeat;
- text-align: right;
+ text-align: center;
padding-right: 12px;
+ padding-left: 42px;
height: 46px;
}
.alertItem.withAvatar:not(:last-child) {
border-bottom: 1px solid rgb(230,230,230);
}
-.alertItem.withAvatar .text {
+.alertItem .text {
overflow: hidden;
text-overflow: ellipsis;
- float: right;
- width: calc(100% - 20px);
height: 30px;
+ width: 100%;
+ color: black;
+}
+.alertItem .text.smaller {
+ font-size: 9px;
}
#footer
@@ -967,10 +975,7 @@ blockquote p
border: 1px solid rgba(90,90,90,0.75);
transition: transform 0.7s;
}
- ul:hover
- {
- transform: rotateX(-15deg);
- }
+ ul:hover { transform: rotateX(-15deg); }
li
{