The alert system is now fully functional.
This commit is contained in:
parent
cf480947d3
commit
c7d058fe90
4
data.sql
4
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*/
|
||||
);
|
||||
|
||||
|
21
mysql.go
21
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 {
|
||||
|
@ -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 ""
|
||||
}
|
||||
|
128
public/global.js
128
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("<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(){
|
||||
$(".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("<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>");
|
||||
}
|
||||
});
|
||||
load_alerts($(this));
|
||||
});
|
||||
|
||||
this.onkeyup = function(event){
|
||||
|
65
routes.go
65
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"
|
||||
|
12
templates.go
12
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)
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user