The alert system is now fully functional.

This commit is contained in:
Azareal 2017-03-03 16:28:49 +00:00
parent cf480947d3
commit c7d058fe90
7 changed files with 192 additions and 109 deletions

View File

@ -136,8 +136,8 @@ CREATE TABLE `activity_stream`(
CREATE TABLE `activity_subscriptions`( CREATE TABLE `activity_subscriptions`(
`user` int not null, `user` int not null,
`targetID` int not null, `targetID` int not null, /* the ID of the element being acted upon */
`targetType` varchar(50) not null, `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*/ `level` tinyint DEFAULT 0 not null /* 0: Mentions (aka the global default for any post), 1: Replies, 2: Everyone*/
); );

View File

@ -33,6 +33,9 @@ var update_forum_cache_stmt *sql.Stmt
var create_like_stmt *sql.Stmt var create_like_stmt *sql.Stmt
var add_likes_to_topic_stmt *sql.Stmt var add_likes_to_topic_stmt *sql.Stmt
var add_likes_to_reply_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_topic_stmt *sql.Stmt
var edit_reply_stmt *sql.Stmt var edit_reply_stmt *sql.Stmt
var delete_reply_stmt *sql.Stmt var delete_reply_stmt *sql.Stmt
@ -238,6 +241,24 @@ func init_database(err error) {
log.Fatal(err) 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.") log.Print("Preparing edit_topic statement.")
edit_topic_stmt, err = db.Prepare("UPDATE topics SET title = ?, content = ?, parsed_content = ?, is_closed = ? WHERE tid = ?") edit_topic_stmt, err = db.Prepare("UPDATE topics SET title = ?, content = ?, parsed_content = ?, is_closed = ? WHERE tid = ?")
if err != nil { if err != nil {

View File

@ -310,51 +310,33 @@ func build_forum_permissions() error {
func strip_invalid_preset(preset string) string { func strip_invalid_preset(preset string) string {
switch(preset) { switch(preset) {
case "all": case "all","announce","members","staff","admins","archive":
case "announce":
case "members":
case "staff":
case "admins":
case "archive":
break break
default: default: return ""
return ""
} }
return preset return preset
} }
func preset_to_lang(preset string) string { func preset_to_lang(preset string) string {
switch(preset) { switch(preset) {
case "all": case "all": return ""//return "Everyone"
return ""//return "Everyone" case "announce": return "Announcements"
case "announce": case "members": return "Member Only"
return "Announcements" case "staff": return "Staff Only"
case "members": case "admins": return "Admin Only"
return "Member Only" case "archive": return "Archive"
case "staff":
return "Staff Only"
case "admins":
return "Admin Only"
case "archive":
return "Archive"
} }
return "" return ""
} }
func preset_to_emoji(preset string) string { func preset_to_emoji(preset string) string {
switch(preset) { switch(preset) {
case "all": case "all": return ""//return "Everyone"
return ""//return "Everyone" case "announce": return "📣"
case "announce": case "members": return "👪"
return "📣" case "staff": return "👮"
case "members": case "admins": return "👑"
return "👪" case "archive": return "☠️"
case "staff":
return "👮"
case "admins":
return "👑"
case "archive":
return "☠️"
} }
return "" return ""
} }

View File

@ -8,6 +8,70 @@ function post_link(event)
$.ajax({ url: form_action, type: "POST", dataType: "json", data: {js: "1"} }); $.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("<div class='alertItem'>"+data.errmsg+"</div>");
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 += "<div class='alertItem withAvatar' style='background-image:url(\""+msg.avatar+"\");'><a class='text"+size_dial+"' href=\""+msg.path+"\">"+mmsg+"</a></div>";
console.log(msg.avatar);
} else {
alist += "<div class='alertItem'><a href=\""+msg.path+"\" class='text"+size_dial+"'>"+mmsg+"</a></div>";
}
console.log(msg);
//console.log(mmsg);
}
if(alist == "") {
alist = "<div class='alertItem'>You don't have any alerts</div>"
}
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("<div class='alertItem'>"+errtxt+"</div>");
}
});
}
$(document).ready(function(){ $(document).ready(function(){
$(".open_edit").click(function(event){ $(".open_edit").click(function(event){
//console.log("Clicked on edit"); //console.log("Clicked on edit");
@ -162,63 +226,19 @@ $(document).ready(function(){
} }
}); });
$(".menu_alerts").click(function(event) { $('body').click(function() {
if($(this).hasClass("selectedAlert")) return; $(".selectedAlert").removeClass("selectedAlert");
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("<div class='alertItem'>"+data.errmsg+"</div>");
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 += "<div class='alertItem withAvatar' style='background-image:url(\""+msg.avatar+"\");'><div class='text'>"+mmsg+"</div></div>";
console.log(msg.avatar);
} else {
alist += "<div class='alertItem'>"+mmsg+"</div>";
}
console.log(msg);
console.log(mmsg);
}
if(alist == "") {
alist = "<div class='alertItem'>You don't have any alerts</div>"
}
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("<div class='alertItem'>"+errtxt+"</div>");
}
}); });
$(".menu_alerts").ready(function(){
load_alerts($(this));
});
$(".menu_alerts").click(function(event) {
event.stopPropagation();
if($(this).hasClass("selectedAlert")) return;
this.className += " selectedAlert";
load_alerts($(this));
}); });
this.onkeyup = function(event){ this.onkeyup = function(event){

View File

@ -727,7 +727,8 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
var words int var words int
var fid 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 { if err == sql.ErrNoRows {
PreError("The requested topic doesn't exist.",w,r) PreError("The requested topic doesn't exist.",w,r)
return return
@ -754,6 +755,15 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
return 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 := words_to_score(words,true)
score := 1 score := 1
_, err = create_like_stmt.Exec(score,tid,"topics",user.ID) _, 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 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) 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 tid int
var words 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 { if err == sql.ErrNoRows {
PreError("You can't like something which doesn't exist!",w,r) PreError("You can't like something which doesn't exist!",w,r)
return return
@ -823,6 +856,15 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
return 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 := words_to_score(words,false)
score := 1 score := 1
_, err = create_like_stmt.Exec(score,rid,"replies",user.ID) _, 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 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) 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) LocalErrorJS("Unable to find the target reply or parent topic",w,r)
return return
} }
url = build_topic_url(elementID) url = build_topic_url(topic.ID)
area = topic.Title area = topic.Title
if targetUser_id == user.ID { if targetUser_id == user.ID {
post_act = " your post in" post_act = " your post in"

View File

@ -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 { 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) out, val := c.compile_if_varsub(varname, varholder, template_name, val)
switch val.Kind() { switch val.Kind() {
case reflect.Int: case reflect.Int: out += " > 0"
out += " > 0" case reflect.Bool: // Do nothing
case reflect.Bool: case reflect.String: out += " != \"\""
// Do nothing case reflect.Int64: out += " > 0"
case reflect.String:
out += " != \"\""
case reflect.Int64:
out += " > 0"
default: default:
fmt.Println(varname) fmt.Println(varname)
fmt.Println(varholder) fmt.Println(varholder)

View File

@ -106,6 +106,10 @@ li:hover
.selectedAlert:hover { .selectedAlert:hover {
background: white; background: white;
color: black; color: black;
font-weight: bold;
}
.selectedAlert .alert_counter {
display: none;
} }
.menu_alerts .alertList { .menu_alerts .alertList {
display: none; display: none;
@ -117,7 +121,7 @@ li:hover
background: white; background: white;
font-size: 10px; font-size: 10px;
line-height: 16px; line-height: 16px;
width: 135px; width: 156px;
right: -15px; right: -15px;
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
border-left: 1px solid #ccc; border-left: 1px solid #ccc;
@ -130,21 +134,25 @@ li:hover
} }
.alertItem.withAvatar { .alertItem.withAvatar {
/*background-image: url('/uploads/avatar_1.jpg');*/ /*background-image: url('/uploads/avatar_1.jpg');*/
background-size: auto 56px; background-size: 36px;
background-repeat: no-repeat; background-repeat: no-repeat;
text-align: right; text-align: center;
padding-right: 12px; padding-right: 12px;
padding-left: 42px;
height: 46px; height: 46px;
} }
.alertItem.withAvatar:not(:last-child) { .alertItem.withAvatar:not(:last-child) {
border-bottom: 1px solid rgb(230,230,230); border-bottom: 1px solid rgb(230,230,230);
} }
.alertItem.withAvatar .text { .alertItem .text {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
float: right;
width: calc(100% - 20px);
height: 30px; height: 30px;
width: 100%;
color: black;
}
.alertItem .text.smaller {
font-size: 9px;
} }
#footer #footer
@ -967,10 +975,7 @@ blockquote p
border: 1px solid rgba(90,90,90,0.75); border: 1px solid rgba(90,90,90,0.75);
transition: transform 0.7s; transition: transform 0.7s;
} }
ul:hover ul:hover { transform: rotateX(-15deg); }
{
transform: rotateX(-15deg);
}
li li
{ {