Did a bit of refactoring on the template system.
Refactored the ReplyStore. Added the Create method to the ProfileReplyStore. Fixed a potential issue with the topics and replies generated by the installer. Refactored the accumulator. Refactored global.js Added more tests.
This commit is contained in:
parent
aab949cb2d
commit
569b424ac8
|
@ -52,7 +52,6 @@ type Stmts struct {
|
||||||
addActivity *sql.Stmt
|
addActivity *sql.Stmt
|
||||||
notifyOne *sql.Stmt
|
notifyOne *sql.Stmt
|
||||||
addEmail *sql.Stmt
|
addEmail *sql.Stmt
|
||||||
createProfileReply *sql.Stmt
|
|
||||||
addSubscription *sql.Stmt
|
addSubscription *sql.Stmt
|
||||||
addForumPermsToForum *sql.Stmt
|
addForumPermsToForum *sql.Stmt
|
||||||
addPlugin *sql.Stmt
|
addPlugin *sql.Stmt
|
||||||
|
@ -438,13 +437,6 @@ func _gen_mssql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing createProfileReply statement.")
|
|
||||||
stmts.createProfileReply, err = db.Prepare("INSERT INTO [users_replies] ([uid],[content],[parsed_content],[createdAt],[createdBy],[ipaddress]) VALUES (?,?,?,GETUTCDATE(),?,?)")
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Bad Query: ","INSERT INTO [users_replies] ([uid],[content],[parsed_content],[createdAt],[createdBy],[ipaddress]) VALUES (?,?,?,GETUTCDATE(),?,?)")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing addSubscription statement.")
|
log.Print("Preparing addSubscription statement.")
|
||||||
stmts.addSubscription, err = db.Prepare("INSERT INTO [activity_subscriptions] ([user],[targetID],[targetType],[level]) VALUES (?,?,?,2)")
|
stmts.addSubscription, err = db.Prepare("INSERT INTO [activity_subscriptions] ([user],[targetID],[targetType],[level]) VALUES (?,?,?,2)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -54,7 +54,6 @@ type Stmts struct {
|
||||||
addActivity *sql.Stmt
|
addActivity *sql.Stmt
|
||||||
notifyOne *sql.Stmt
|
notifyOne *sql.Stmt
|
||||||
addEmail *sql.Stmt
|
addEmail *sql.Stmt
|
||||||
createProfileReply *sql.Stmt
|
|
||||||
addSubscription *sql.Stmt
|
addSubscription *sql.Stmt
|
||||||
addForumPermsToForum *sql.Stmt
|
addForumPermsToForum *sql.Stmt
|
||||||
addPlugin *sql.Stmt
|
addPlugin *sql.Stmt
|
||||||
|
@ -396,12 +395,6 @@ func _gen_mysql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing createProfileReply statement.")
|
|
||||||
stmts.createProfileReply, err = db.Prepare("INSERT INTO `users_replies`(`uid`,`content`,`parsed_content`,`createdAt`,`createdBy`,`ipaddress`) VALUES (?,?,?,UTC_TIMESTAMP(),?,?)")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing addSubscription statement.")
|
log.Print("Preparing addSubscription statement.")
|
||||||
stmts.addSubscription, err = db.Prepare("INSERT INTO `activity_subscriptions`(`user`,`targetID`,`targetType`,`level`) VALUES (?,?,?,2)")
|
stmts.addSubscription, err = db.Prepare("INSERT INTO `activity_subscriptions`(`user`,`targetID`,`targetType`,`level`) VALUES (?,?,?,2)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -559,17 +559,13 @@ func routeProfileReplyCreate(w http.ResponseWriter, r *http.Request, user User)
|
||||||
}
|
}
|
||||||
|
|
||||||
content := html.EscapeString(preparseMessage(r.PostFormValue("reply-content")))
|
content := html.EscapeString(preparseMessage(r.PostFormValue("reply-content")))
|
||||||
_, err = stmts.createProfileReply.Exec(uid, content, parseMessage(content, 0, ""), user.ID, ipaddress)
|
_, err = prstore.Create(uid, content, user.ID, ipaddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return InternalError(err, w, r)
|
return InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
var userName string
|
if !users.Exists(uid) {
|
||||||
err = stmts.getUserName.QueryRow(uid).Scan(&userName)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return LocalError("The profile you're trying to post on doesn't exist.", w, r, user)
|
return LocalError("The profile you're trying to post on doesn't exist.", w, r, user)
|
||||||
} else if err != nil {
|
|
||||||
return InternalError(err, w, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
|
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
|
||||||
|
|
56
misc_test.go
56
misc_test.go
|
@ -550,6 +550,8 @@ func topicStoreTest(t *testing.T) {
|
||||||
t.Error("The number of topics should be bigger than zero")
|
t.Error("The number of topics should be bigger than zero")
|
||||||
t.Error("count", count)
|
t.Error("count", count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Test topic creation and retrieving that created topic plus reload and inspecting the cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestForumStore(t *testing.T) {
|
func TestForumStore(t *testing.T) {
|
||||||
|
@ -737,16 +739,28 @@ func TestReplyStore(t *testing.T) {
|
||||||
|
|
||||||
reply, err := rstore.Get(1)
|
reply, err := rstore.Get(1)
|
||||||
expectNilErr(t, err)
|
expectNilErr(t, err)
|
||||||
|
expect(t, reply.ID == 1, fmt.Sprintf("RID #1 has the wrong ID. It should be 1 not %d", reply.ID))
|
||||||
|
expect(t, reply.ParentID == 1, fmt.Sprintf("The parent topic of RID #1 should be 1 not %d", reply.ParentID))
|
||||||
|
expect(t, reply.CreatedBy == 1, fmt.Sprintf("The creator of RID #1 should be 1 not %d", reply.CreatedBy))
|
||||||
|
expect(t, reply.Content == "A reply!", fmt.Sprintf("The contents of RID #1 should be 'A reply!' not %s", reply.Content))
|
||||||
|
expect(t, reply.IPAddress == "::1", fmt.Sprintf("The IPAddress of RID#1 should be '::1' not %s", reply.IPAddress))
|
||||||
|
|
||||||
if reply.ID != 1 {
|
_, err = rstore.Get(2)
|
||||||
t.Errorf("RID #1 has the wrong ID. It should be 1 not %d", reply.ID)
|
recordMustNotExist(t, err, "RID #2 shouldn't exist")
|
||||||
}
|
|
||||||
if reply.ParentID != 1 {
|
// TODO: Test Create and Get
|
||||||
t.Errorf("The parent topic of RID #1 should be 1 not %d", reply.ParentID)
|
//Create(tid int, content string, ipaddress string, fid int, uid int) (id int, err error)
|
||||||
}
|
rid, err := rstore.Create(1, "Fofofo", "::1", 2, 1)
|
||||||
if reply.CreatedBy != 1 {
|
expectNilErr(t, err)
|
||||||
t.Errorf("The creator of RID #1 should be 1 not %d", reply.CreatedBy)
|
expect(t, rid == 2, fmt.Sprintf("The next reply ID should be 2 not %d", rid))
|
||||||
}
|
|
||||||
|
reply, err = rstore.Get(2)
|
||||||
|
expectNilErr(t, err)
|
||||||
|
expect(t, reply.ID == 2, fmt.Sprintf("RID #2 has the wrong ID. It should be 2 not %d", reply.ID))
|
||||||
|
expect(t, reply.ParentID == 1, fmt.Sprintf("The parent topic of RID #2 should be 1 not %d", reply.ParentID))
|
||||||
|
expect(t, reply.CreatedBy == 1, fmt.Sprintf("The creator of RID #2 should be 1 not %d", reply.CreatedBy))
|
||||||
|
expect(t, reply.Content == "Fofofo", fmt.Sprintf("The contents of RID #2 should be 'Fofofo' not %s", reply.Content))
|
||||||
|
expect(t, reply.IPAddress == "::1", fmt.Sprintf("The IPAddress of RID #2 should be '::1' not %s", reply.IPAddress))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProfileReplyStore(t *testing.T) {
|
func TestProfileReplyStore(t *testing.T) {
|
||||||
|
@ -758,10 +772,30 @@ func TestProfileReplyStore(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := prstore.Get(-1)
|
_, err := prstore.Get(-1)
|
||||||
recordMustNotExist(t, err, "RID #-1 shouldn't exist")
|
recordMustNotExist(t, err, "PRID #-1 shouldn't exist")
|
||||||
|
|
||||||
_, err = prstore.Get(0)
|
_, err = prstore.Get(0)
|
||||||
recordMustNotExist(t, err, "RID #0 shouldn't exist")
|
recordMustNotExist(t, err, "PRID #0 shouldn't exist")
|
||||||
|
|
||||||
|
_, err = prstore.Get(1)
|
||||||
|
recordMustNotExist(t, err, "PRID #0 shouldn't exist")
|
||||||
|
|
||||||
|
var profileID = 1
|
||||||
|
prid, err := prstore.Create(profileID, "Haha", 1, "::1")
|
||||||
|
expect(t, err == nil, "Unable to create a profile reply")
|
||||||
|
expect(t, prid == 1, "The first profile reply should have an ID of 1")
|
||||||
|
|
||||||
|
profileReply, err := prstore.Get(1)
|
||||||
|
expect(t, err == nil, "PRID #1 should exist")
|
||||||
|
expect(t, profileReply.ID == 1, fmt.Sprintf("The profile reply should have an ID of 1 not %d", profileReply.ID))
|
||||||
|
expect(t, profileReply.ParentID == 1, fmt.Sprintf("The parent ID of the profile reply should be 1 not %d", profileReply.ParentID))
|
||||||
|
expect(t, profileReply.Content == "Haha", fmt.Sprintf("The profile reply's contents should be 'Haha' not '%s'", profileReply.Content))
|
||||||
|
expect(t, profileReply.CreatedBy == 1, fmt.Sprintf("The profile reply's creator should be 1 not %d", profileReply.CreatedBy))
|
||||||
|
expect(t, profileReply.IPAddress == "::1", fmt.Sprintf("The profile reply's IP Address should be '::1' not '%s'", profileReply.IPAddress))
|
||||||
|
|
||||||
|
//Get(id int) (*Reply, error)
|
||||||
|
//Create(profileID int, content string, createdBy int, ipaddress string) (id int, err error)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSlugs(t *testing.T) {
|
func TestSlugs(t *testing.T) {
|
||||||
|
|
|
@ -174,7 +174,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||||
msg = "[rand]18446744073709551615[/rand]" // Unsigned 64-bit MAX
|
msg = "[rand]18446744073709551615[/rand]" // Unsigned 64-bit MAX
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcodeFullParse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
conv, err = strconv.Atoi(res)
|
_, err = strconv.Atoi(res)
|
||||||
if err != nil && res != "<span style='color: red;'>[Invalid Number]</span>[rand]18446744073709551615[/rand]" {
|
if err != nil && res != "<span style='color: red;'>[Invalid Number]</span>[rand]18446744073709551615[/rand]" {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected a number between 0 and 18446744073709551615")
|
t.Error("Expected a number between 0 and 18446744073709551615")
|
||||||
|
@ -182,7 +182,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||||
msg = "[rand]170141183460469231731687303715884105727[/rand]" // Signed 128-bit MAX
|
msg = "[rand]170141183460469231731687303715884105727[/rand]" // Signed 128-bit MAX
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcodeFullParse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
conv, err = strconv.Atoi(res)
|
_, err = strconv.Atoi(res)
|
||||||
if err != nil && res != "<span style='color: red;'>[Invalid Number]</span>[rand]170141183460469231731687303715884105727[/rand]" {
|
if err != nil && res != "<span style='color: red;'>[Invalid Number]</span>[rand]170141183460469231731687303715884105727[/rand]" {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected a number between 0 and 170141183460469231731687303715884105727")
|
t.Error("Expected a number between 0 and 170141183460469231731687303715884105727")
|
||||||
|
|
|
@ -10,22 +10,22 @@ var prstore ProfileReplyStore
|
||||||
|
|
||||||
type ProfileReplyStore interface {
|
type ProfileReplyStore interface {
|
||||||
Get(id int) (*Reply, error)
|
Get(id int) (*Reply, error)
|
||||||
|
Create(profileID int, content string, createdBy int, ipaddress string) (id int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor this to stop using the global stmt store
|
// TODO: Refactor this to stop using the global stmt store
|
||||||
// TODO: Add more methods to this like Create()
|
// TODO: Add more methods to this like Create()
|
||||||
type SQLProfileReplyStore struct {
|
type SQLProfileReplyStore struct {
|
||||||
get *sql.Stmt
|
get *sql.Stmt
|
||||||
|
create *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSQLProfileReplyStore() (*SQLProfileReplyStore, error) {
|
func NewSQLProfileReplyStore() (*SQLProfileReplyStore, error) {
|
||||||
getUserReplyStmt, err := qgen.Builder.SimpleSelect("users_replies", "uid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress", "rid = ?", "", "")
|
acc := qgen.Builder.Accumulator()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &SQLProfileReplyStore{
|
return &SQLProfileReplyStore{
|
||||||
get: getUserReplyStmt,
|
get: acc.SimpleSelect("users_replies", "uid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress", "rid = ?", "", ""),
|
||||||
}, nil
|
create: acc.SimpleInsert("users_replies", "uid, content, parsed_content, createdAt, createdBy, ipaddress", "?,?,?,UTC_TIMESTAMP(),?,?"),
|
||||||
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *SQLProfileReplyStore) Get(id int) (*Reply, error) {
|
func (store *SQLProfileReplyStore) Get(id int) (*Reply, error) {
|
||||||
|
@ -33,3 +33,17 @@ func (store *SQLProfileReplyStore) Get(id int) (*Reply, error) {
|
||||||
err := store.get.QueryRow(id).Scan(&reply.ParentID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IPAddress)
|
err := store.get.QueryRow(id).Scan(&reply.ParentID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IPAddress)
|
||||||
return &reply, err
|
return &reply, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (store *SQLProfileReplyStore) Create(profileID int, content string, createdBy int, ipaddress string) (id int, err error) {
|
||||||
|
res, err := store.create.Exec(profileID, content, parseMessage(content, 0, ""), createdBy, ipaddress)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
lastID, err := res.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we reload the user?
|
||||||
|
return int(lastID), err
|
||||||
|
}
|
||||||
|
|
268
public/global.js
268
public/global.js
|
@ -34,72 +34,72 @@ function bindToAlerts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add the ability for users to dismiss alerts
|
// TODO: Add the ability for users to dismiss alerts
|
||||||
function loadAlerts(menu_alerts)
|
function loadAlerts(menuAlerts)
|
||||||
{
|
{
|
||||||
var alertListNode = menu_alerts.getElementsByClassName("alertList")[0];
|
var alertListNode = menuAlerts.getElementsByClassName("alertList")[0];
|
||||||
var alertCounterNode = menu_alerts.getElementsByClassName("alert_counter")[0];
|
var alertCounterNode = menuAlerts.getElementsByClassName("alert_counter")[0];
|
||||||
alertCounterNode.textContent = "0";
|
alertCounterNode.textContent = "0";
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'get',
|
type: 'get',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
url:'/api/?action=get&module=alerts',
|
url:'/api/?action=get&module=alerts',
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
if("errmsg" in data) {
|
if("errmsg" in data) {
|
||||||
alertListNode.innerHTML = "<div class='alertItem'>"+data.errmsg+"</div>";
|
alertListNode.innerHTML = "<div class='alertItem'>"+data.errmsg+"</div>";
|
||||||
return;
|
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 + ":",msg.sub[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if("avatar" in msg) {
|
|
||||||
alist += "<div class='alertItem withAvatar' style='background-image:url(\""+msg.avatar+"\");'><a class='text' data-asid='"+msg.asid+"' href=\""+msg.path+"\">"+mmsg+"</a></div>";
|
|
||||||
alertList.push("<div class='alertItem withAvatar' style='background-image:url(\""+msg.avatar+"\");'><a class='text' data-asid='"+msg.asid+"' href=\""+msg.path+"\">"+mmsg+"</a></div>");
|
|
||||||
} else {
|
|
||||||
alist += "<div class='alertItem'><a href=\""+msg.path+"\" class='text'>"+mmsg+"</a></div>";
|
|
||||||
alertList.push("<div class='alertItem'><a href=\""+msg.path+"\" class='text'>"+mmsg+"</a></div>");
|
|
||||||
}
|
|
||||||
//console.log(msg);
|
|
||||||
//console.log(mmsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(alist == "") alist = "<div class='alertItem'>You don't have any alerts</div>";
|
|
||||||
alertListNode.innerHTML = alist;
|
|
||||||
|
|
||||||
if(data.msgCount != 0 && data.msgCount != undefined) {
|
|
||||||
alertCounterNode.textContent = data.msgCount;
|
|
||||||
menu_alerts.classList.add("has_alerts");
|
|
||||||
} else {
|
|
||||||
menu_alerts.classList.remove("has_alerts");
|
|
||||||
}
|
|
||||||
alertCount = data.msgCount;
|
|
||||||
|
|
||||||
bindToAlerts();
|
|
||||||
},
|
|
||||||
error: function(magic,theStatus,error) {
|
|
||||||
var errtxt
|
|
||||||
try {
|
|
||||||
var data = JSON.parse(magic.responseText);
|
|
||||||
if("errmsg" in data) errtxt = data.errmsg;
|
|
||||||
else errtxt = "Unable to get the alerts";
|
|
||||||
} catch(err) {
|
|
||||||
errtxt = "Unable to get the alerts";
|
|
||||||
console.log(magic.responseText);
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
console.log("error: ",error);
|
|
||||||
alertListNode.innerHTML = "<div class='alertItem'>"+errtxt+"</div>";
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
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 + ":",msg.sub[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if("avatar" in msg) {
|
||||||
|
alist += "<div class='alertItem withAvatar' style='background-image:url(\""+msg.avatar+"\");'><a class='text' data-asid='"+msg.asid+"' href=\""+msg.path+"\">"+mmsg+"</a></div>";
|
||||||
|
alertList.push("<div class='alertItem withAvatar' style='background-image:url(\""+msg.avatar+"\");'><a class='text' data-asid='"+msg.asid+"' href=\""+msg.path+"\">"+mmsg+"</a></div>");
|
||||||
|
} else {
|
||||||
|
alist += "<div class='alertItem'><a href=\""+msg.path+"\" class='text'>"+mmsg+"</a></div>";
|
||||||
|
alertList.push("<div class='alertItem'><a href=\""+msg.path+"\" class='text'>"+mmsg+"</a></div>");
|
||||||
|
}
|
||||||
|
//console.log(msg);
|
||||||
|
//console.log(mmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(alist == "") alist = "<div class='alertItem'>You don't have any alerts</div>";
|
||||||
|
alertListNode.innerHTML = alist;
|
||||||
|
|
||||||
|
if(data.msgCount != 0 && data.msgCount != undefined) {
|
||||||
|
alertCounterNode.textContent = data.msgCount;
|
||||||
|
menuAlerts.classList.add("has_alerts");
|
||||||
|
} else {
|
||||||
|
menuAlerts.classList.remove("has_alerts");
|
||||||
|
}
|
||||||
|
alertCount = data.msgCount;
|
||||||
|
|
||||||
|
bindToAlerts();
|
||||||
|
},
|
||||||
|
error: function(magic,theStatus,error) {
|
||||||
|
let errtxt
|
||||||
|
try {
|
||||||
|
var data = JSON.parse(magic.responseText);
|
||||||
|
if("errmsg" in data) errtxt = data.errmsg;
|
||||||
|
else errtxt = "Unable to get the alerts";
|
||||||
|
} catch(err) {
|
||||||
|
errtxt = "Unable to get the alerts";
|
||||||
|
console.log(magic.responseText);
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
console.log("error", error);
|
||||||
|
alertListNode.innerHTML = "<div class='alertItem'>"+errtxt+"</div>";
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function SplitN(data,ch,n) {
|
function SplitN(data,ch,n) {
|
||||||
|
@ -121,84 +121,86 @@ function SplitN(data,ch,n) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
function runWebSockets() {
|
||||||
if(window["WebSocket"]) {
|
if(window.location.protocol == "https:")
|
||||||
if(window.location.protocol == "https:")
|
conn = new WebSocket("wss://" + document.location.host + "/ws/");
|
||||||
conn = new WebSocket("wss://" + document.location.host + "/ws/");
|
else conn = new WebSocket("ws://" + document.location.host + "/ws/");
|
||||||
else conn = new WebSocket("ws://" + document.location.host + "/ws/");
|
|
||||||
|
|
||||||
conn.onopen = function() {
|
conn.onopen = function() {
|
||||||
console.log("The WebSockets connection was opened");
|
console.log("The WebSockets connection was opened");
|
||||||
conn.send("page " + document.location.pathname + '\r');
|
conn.send("page " + document.location.pathname + '\r');
|
||||||
// TODO: Don't ask again, if it's denied. We could have a setting in the UCP which automatically requests this when someone flips desktop notifications on
|
// TODO: Don't ask again, if it's denied. We could have a setting in the UCP which automatically requests this when someone flips desktop notifications on
|
||||||
Notification.requestPermission();
|
Notification.requestPermission();
|
||||||
}
|
}
|
||||||
conn.onclose = function() {
|
conn.onclose = function() {
|
||||||
conn = false;
|
conn = false;
|
||||||
console.log("The WebSockets connection was closed");
|
console.log("The WebSockets connection was closed");
|
||||||
}
|
}
|
||||||
conn.onmessage = function(event) {
|
conn.onmessage = function(event) {
|
||||||
//console.log("WS_Message:", event.data);
|
//console.log("WS_Message:", event.data);
|
||||||
if(event.data[0] == "{") {
|
if(event.data[0] == "{") {
|
||||||
try {
|
try {
|
||||||
var data = JSON.parse(event.data);
|
var data = JSON.parse(event.data);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
|
||||||
|
|
||||||
if ("msg" in data) {
|
|
||||||
var msg = data.msg
|
|
||||||
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("<div class='alertItem withAvatar' style='background-image:url(\""+data.avatar+"\");'><a class='text' data-asid='"+data.asid+"' href=\""+data.path+"\">"+msg+"</a></div>");
|
|
||||||
else alertList.push("<div class='alertItem'><a href=\""+data.path+"\" class='text'>"+msg+"</a></div>");
|
|
||||||
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];
|
|
||||||
|
|
||||||
//console.log(alist);
|
|
||||||
// TODO: 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;
|
|
||||||
|
|
||||||
// TODO: Add some sort of notification queue to avoid flooding the end-user with notices?
|
|
||||||
// TODO: Use the site name instead of "Something Happened"
|
|
||||||
if(Notification.permission === "granted") {
|
|
||||||
var n = new Notification("Something Happened",{
|
|
||||||
body: msg,
|
|
||||||
icon: data.avatar,
|
|
||||||
});
|
|
||||||
setTimeout(n.close.bind(n), 8000);
|
|
||||||
}
|
|
||||||
|
|
||||||
bindToAlerts();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var messages = event.data.split('\r');
|
if ("msg" in data) {
|
||||||
for(var i = 0; i < messages.length; i++) {
|
var msg = data.msg
|
||||||
//console.log("Message: ",messages[i]);
|
if("sub" in data)
|
||||||
if(messages[i].startsWith("set ")) {
|
for(var i = 0; i < data.sub.length; i++)
|
||||||
//msgblocks = messages[i].split(' ',3);
|
msg = msg.replace("\{"+i+"\}", data.sub[i]);
|
||||||
let msgblocks = SplitN(messages[i]," ",3);
|
|
||||||
if(msgblocks.length < 3) continue;
|
if("avatar" in data) alertList.push("<div class='alertItem withAvatar' style='background-image:url(\""+data.avatar+"\");'><a class='text' data-asid='"+data.asid+"' href=\""+data.path+"\">"+msg+"</a></div>");
|
||||||
document.querySelector(msgblocks[1]).innerHTML = msgblocks[2];
|
else alertList.push("<div class='alertItem'><a href=\""+data.path+"\" class='text'>"+msg+"</a></div>");
|
||||||
} else if(messages[i].startsWith("set-class ")) {
|
if(alertList.length > 8) alertList.shift();
|
||||||
let msgblocks = SplitN(messages[i]," ",3);
|
//console.log("post alertList",alertList);
|
||||||
if(msgblocks.length < 3) continue;
|
alertCount++;
|
||||||
document.querySelector(msgblocks[1]).className = msgblocks[2];
|
|
||||||
|
var alist = ""
|
||||||
|
for (var i = 0; i < alertList.length; i++) alist += alertList[i];
|
||||||
|
|
||||||
|
//console.log(alist);
|
||||||
|
// TODO: Add support for other alert feeds like PM Alerts
|
||||||
|
var generalAlerts = document.getElementById("general_alerts");
|
||||||
|
var alertListNode = generalAlerts.getElementsByClassName("alertList")[0];
|
||||||
|
var alertCounterNode = generalAlerts.getElementsByClassName("alert_counter")[0];
|
||||||
|
alertListNode.innerHTML = alist;
|
||||||
|
alertCounterNode.textContent = alertCount;
|
||||||
|
|
||||||
|
// TODO: Add some sort of notification queue to avoid flooding the end-user with notices?
|
||||||
|
// TODO: Use the site name instead of "Something Happened"
|
||||||
|
if(Notification.permission === "granted") {
|
||||||
|
var n = new Notification("Something Happened",{
|
||||||
|
body: msg,
|
||||||
|
icon: data.avatar,
|
||||||
|
});
|
||||||
|
setTimeout(n.close.bind(n), 8000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindToAlerts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages = event.data.split('\r');
|
||||||
|
for(var i = 0; i < messages.length; i++) {
|
||||||
|
//console.log("Message: ",messages[i]);
|
||||||
|
if(messages[i].startsWith("set ")) {
|
||||||
|
//msgblocks = messages[i].split(' ',3);
|
||||||
|
let msgblocks = SplitN(messages[i]," ",3);
|
||||||
|
if(msgblocks.length < 3) continue;
|
||||||
|
document.querySelector(msgblocks[1]).innerHTML = msgblocks[2];
|
||||||
|
} else if(messages[i].startsWith("set-class ")) {
|
||||||
|
let msgblocks = SplitN(messages[i]," ",3);
|
||||||
|
if(msgblocks.length < 3) continue;
|
||||||
|
document.querySelector(msgblocks[1]).className = msgblocks[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
if(window["WebSocket"]) runWebSockets();
|
||||||
else conn = false;
|
else conn = false;
|
||||||
|
|
||||||
$(".open_edit").click(function(event){
|
$(".open_edit").click(function(event){
|
||||||
|
|
|
@ -115,9 +115,7 @@ func (build *accBuilder) Purge(table string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.Purge("_builder", table))
|
return build.prepare(build.adapter.Purge("_builder", table))
|
||||||
}
|
}
|
||||||
|
|
||||||
// These ones support transactions
|
func (build *accBuilder) prepareTx(tx *sql.Tx, res string, err error) (stmt *sql.Stmt) {
|
||||||
func (build *accBuilder) SimpleSelectTx(tx *sql.Tx, table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt) {
|
|
||||||
res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
build.recordError(err)
|
build.recordError(err)
|
||||||
return nil
|
return nil
|
||||||
|
@ -127,70 +125,40 @@ func (build *accBuilder) SimpleSelectTx(tx *sql.Tx, table string, columns string
|
||||||
return stmt
|
return stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These ones support transactions
|
||||||
|
func (build *accBuilder) SimpleSelectTx(tx *sql.Tx, table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt) {
|
||||||
|
res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit)
|
||||||
|
return build.prepareTx(tx, res, err)
|
||||||
|
}
|
||||||
|
|
||||||
func (build *accBuilder) SimpleCountTx(tx *sql.Tx, table string, where string, limit string) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleCountTx(tx *sql.Tx, table string, where string, limit string) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.SimpleCount("_builder", table, where, limit)
|
res, err := build.adapter.SimpleCount("_builder", table, where, limit)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *accBuilder) SimpleLeftJoinTx(tx *sql.Tx, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleLeftJoinTx(tx *sql.Tx, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.SimpleLeftJoin("_builder", table1, table2, columns, joiners, where, orderby, limit)
|
res, err := build.adapter.SimpleLeftJoin("_builder", table1, table2, columns, joiners, where, orderby, limit)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *accBuilder) SimpleInnerJoinTx(tx *sql.Tx, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleInnerJoinTx(tx *sql.Tx, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.SimpleInnerJoin("_builder", table1, table2, columns, joiners, where, orderby, limit)
|
res, err := build.adapter.SimpleInnerJoin("_builder", table1, table2, columns, joiners, where, orderby, limit)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *accBuilder) CreateTableTx(tx *sql.Tx, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (stmt *sql.Stmt) {
|
func (build *accBuilder) CreateTableTx(tx *sql.Tx, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.CreateTable("_builder", table, charset, collation, columns, keys)
|
res, err := build.adapter.CreateTable("_builder", table, charset, collation, columns, keys)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *accBuilder) SimpleInsertTx(tx *sql.Tx, table string, columns string, fields string) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleInsertTx(tx *sql.Tx, table string, columns string, fields string) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.SimpleInsert("_builder", table, columns, fields)
|
res, err := build.adapter.SimpleInsert("_builder", table, columns, fields)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *accBuilder) SimpleInsertSelectTx(tx *sql.Tx, ins DB_Insert, sel DB_Select) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleInsertSelectTx(tx *sql.Tx, ins DB_Insert, sel DB_Select) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.SimpleInsertSelect("_builder", ins, sel)
|
res, err := build.adapter.SimpleInsertSelect("_builder", ins, sel)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *accBuilder) SimpleInsertLeftJoinTx(tx *sql.Tx, ins DB_Insert, sel DB_Join) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleInsertLeftJoinTx(tx *sql.Tx, ins DB_Insert, sel DB_Join) (stmt *sql.Stmt) {
|
||||||
|
@ -206,45 +174,21 @@ func (build *accBuilder) SimpleInsertLeftJoinTx(tx *sql.Tx, ins DB_Insert, sel D
|
||||||
|
|
||||||
func (build *accBuilder) SimpleInsertInnerJoinTx(tx *sql.Tx, ins DB_Insert, sel DB_Join) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleInsertInnerJoinTx(tx *sql.Tx, ins DB_Insert, sel DB_Join) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.SimpleInsertInnerJoin("_builder", ins, sel)
|
res, err := build.adapter.SimpleInsertInnerJoin("_builder", ins, sel)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *accBuilder) SimpleUpdateTx(tx *sql.Tx, table string, set string, where string) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleUpdateTx(tx *sql.Tx, table string, set string, where string) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.SimpleUpdate("_builder", table, set, where)
|
res, err := build.adapter.SimpleUpdate("_builder", table, set, where)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *accBuilder) SimpleDeleteTx(tx *sql.Tx, table string, where string) (stmt *sql.Stmt) {
|
func (build *accBuilder) SimpleDeleteTx(tx *sql.Tx, table string, where string) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.SimpleDelete("_builder", table, where)
|
res, err := build.adapter.SimpleDelete("_builder", table, where)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// I don't know why you need this, but here it is x.x
|
// I don't know why you need this, but here it is x.x
|
||||||
func (build *accBuilder) PurgeTx(tx *sql.Tx, table string) (stmt *sql.Stmt) {
|
func (build *accBuilder) PurgeTx(tx *sql.Tx, table string) (stmt *sql.Stmt) {
|
||||||
res, err := build.adapter.Purge("_builder", table)
|
res, err := build.adapter.Purge("_builder", table)
|
||||||
if err != nil {
|
return build.prepareTx(tx, res, err)
|
||||||
build.recordError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
stmt, err = tx.Prepare(res)
|
|
||||||
build.recordError(err)
|
|
||||||
return stmt
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,9 +212,9 @@ func seedTables(adapter qgen.DB_Adapter) error {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
qgen.Install.SimpleInsert("topics", "title, content, parsed_content, createdAt, lastReplyAt, lastReplyBy, createdBy, parentID", "'Test Topic','A topic automatically generated by the software.','A topic automatically generated by the software.',UTC_TIMESTAMP(),UTC_TIMESTAMP(),1,1,2")
|
qgen.Install.SimpleInsert("topics", "title, content, parsed_content, createdAt, lastReplyAt, lastReplyBy, createdBy, parentID, ipaddress", "'Test Topic','A topic automatically generated by the software.','A topic automatically generated by the software.',UTC_TIMESTAMP(),UTC_TIMESTAMP(),1,1,2,'::1'")
|
||||||
|
|
||||||
qgen.Install.SimpleInsert("replies", "tid, content, parsed_content, createdAt, createdBy, lastUpdated, lastEdit, lastEditBy", "1,'A reply!','A reply!',UTC_TIMESTAMP(),1,UTC_TIMESTAMP(),0,0")
|
qgen.Install.SimpleInsert("replies", "tid, content, parsed_content, createdAt, createdBy, lastUpdated, lastEdit, lastEditBy, ipaddress", "1,'A reply!','A reply!',UTC_TIMESTAMP(),1,UTC_TIMESTAMP(),0,0,'::1'")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -328,8 +328,6 @@ func writeInserts(adapter qgen.DB_Adapter) error {
|
||||||
|
|
||||||
adapter.SimpleInsert("addEmail", "emails", "email, uid, validated, token", "?,?,?,?")
|
adapter.SimpleInsert("addEmail", "emails", "email, uid, validated, token", "?,?,?,?")
|
||||||
|
|
||||||
adapter.SimpleInsert("createProfileReply", "users_replies", "uid, content, parsed_content, createdAt, createdBy, ipaddress", "?,?,?,UTC_TIMESTAMP(),?,?")
|
|
||||||
|
|
||||||
adapter.SimpleInsert("addSubscription", "activity_subscriptions", "user, targetID, targetType, level", "?,?,?,2")
|
adapter.SimpleInsert("addSubscription", "activity_subscriptions", "user, targetID, targetType, level", "?,?,?,2")
|
||||||
|
|
||||||
adapter.SimpleInsert("addForumPermsToForum", "forums_permissions", "gid,fid,preset,permissions", "?,?,?,?")
|
adapter.SimpleInsert("addForumPermsToForum", "forums_permissions", "gid,fid,preset,permissions", "?,?,?,?")
|
||||||
|
|
|
@ -16,18 +16,11 @@ type SQLReplyStore struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSQLReplyStore() (*SQLReplyStore, error) {
|
func NewSQLReplyStore() (*SQLReplyStore, error) {
|
||||||
getReplyStmt, err := qgen.Builder.SimpleSelect("replies", "tid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount", "rid = ?", "", "")
|
acc := qgen.Builder.Accumulator()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
createReplyStmt, err := qgen.Builder.SimpleInsert("replies", "tid, content, parsed_content, createdAt, lastUpdated, ipaddress, words, createdBy", "?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &SQLReplyStore{
|
return &SQLReplyStore{
|
||||||
get: getReplyStmt,
|
get: acc.SimpleSelect("replies", "tid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount", "rid = ?", "", ""),
|
||||||
create: createReplyStmt,
|
create: acc.SimpleInsert("replies", "tid, content, parsed_content, createdAt, lastUpdated, ipaddress, words, createdBy", "?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?"),
|
||||||
}, nil
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *SQLReplyStore) Get(id int) (*Reply, error) {
|
func (store *SQLReplyStore) Get(id int) (*Reply, error) {
|
||||||
|
|
|
@ -5,16 +5,48 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"text/template/parse"
|
||||||
)
|
)
|
||||||
|
|
||||||
var tagFinder *regexp.Regexp
|
var tagFinder *regexp.Regexp
|
||||||
|
var limeFuncMap = map[string]interface{}{
|
||||||
|
"and": "&&",
|
||||||
|
"not": "!",
|
||||||
|
"or": "||",
|
||||||
|
"eq": true,
|
||||||
|
"ge": true,
|
||||||
|
"gt": true,
|
||||||
|
"le": true,
|
||||||
|
"lt": true,
|
||||||
|
"ne": true,
|
||||||
|
"add": true,
|
||||||
|
"subtract": true,
|
||||||
|
"multiply": true,
|
||||||
|
"divide": true,
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
tagFinder = regexp.MustCompile(`(?s)\{\{(.*)\}\}`)
|
tagFinder = regexp.MustCompile(`(?s)\{\{(.*)\}\}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mangoParse(tmpl string) error {
|
||||||
|
tree := parse.New(name, funcMap)
|
||||||
|
var treeSet = make(map[string]*parse.Tree)
|
||||||
|
tree, err = tree.Parse(content, "{{", "}}", treeSet, limeFuncMap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
treeLength := len(tree.Root.Nodes)
|
||||||
|
log.Print("treeLength", treeLength)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func icecreamSoup(tmpl string) error {
|
func icecreamSoup(tmpl string) error {
|
||||||
|
if config.MinifyTemplates {
|
||||||
|
tmpl = minify(tmpl)
|
||||||
|
}
|
||||||
tagIndices := tagFinder.FindAllStringIndex(tmpl, -1)
|
tagIndices := tagFinder.FindAllStringIndex(tmpl, -1)
|
||||||
if tagIndices != nil && len(tagIndices) > 0 {
|
if tagIndices != nil && len(tagIndices) > 0 {
|
||||||
|
|
||||||
|
|
|
@ -25,5 +25,5 @@ INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (3,2,'{"View
|
||||||
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (4,2,'{"ViewTopic":true}');
|
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (4,2,'{"ViewTopic":true}');
|
||||||
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (5,2,'{"ViewTopic":true}');
|
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (5,2,'{"ViewTopic":true}');
|
||||||
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (6,2,'{"ViewTopic":true}');
|
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (6,2,'{"ViewTopic":true}');
|
||||||
INSERT INTO [topics] ([title],[content],[parsed_content],[createdAt],[lastReplyAt],[lastReplyBy],[createdBy],[parentID]) VALUES ('TestTopic','Atopicautomaticallygeneratedbythesoftware.','Atopicautomaticallygeneratedbythesoftware.',GETUTCDATE(),GETUTCDATE(),1,1,2);
|
INSERT INTO [topics] ([title],[content],[parsed_content],[createdAt],[lastReplyAt],[lastReplyBy],[createdBy],[parentID],[ipaddress]) VALUES ('TestTopic','Atopicautomaticallygeneratedbythesoftware.','Atopicautomaticallygeneratedbythesoftware.',GETUTCDATE(),GETUTCDATE(),1,1,2,'::1');
|
||||||
INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[createdBy],[lastUpdated],[lastEdit],[lastEditBy]) VALUES (1,'Areply!','Areply!',GETUTCDATE(),1,GETUTCDATE(),0,0);
|
INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[createdBy],[lastUpdated],[lastEdit],[lastEditBy],[ipaddress]) VALUES (1,'Areply!','Areply!',GETUTCDATE(),1,GETUTCDATE(),0,0,'::1');
|
||||||
|
|
|
@ -25,5 +25,5 @@ INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (3,2,'{"ViewT
|
||||||
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (4,2,'{"ViewTopic":true}');
|
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (4,2,'{"ViewTopic":true}');
|
||||||
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (5,2,'{"ViewTopic":true}');
|
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (5,2,'{"ViewTopic":true}');
|
||||||
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (6,2,'{"ViewTopic":true}');
|
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (6,2,'{"ViewTopic":true}');
|
||||||
INSERT INTO `topics`(`title`,`content`,`parsed_content`,`createdAt`,`lastReplyAt`,`lastReplyBy`,`createdBy`,`parentID`) VALUES ('TestTopic','Atopicautomaticallygeneratedbythesoftware.','Atopicautomaticallygeneratedbythesoftware.',UTC_TIMESTAMP(),UTC_TIMESTAMP(),1,1,2);
|
INSERT INTO `topics`(`title`,`content`,`parsed_content`,`createdAt`,`lastReplyAt`,`lastReplyBy`,`createdBy`,`parentID`,`ipaddress`) VALUES ('TestTopic','Atopicautomaticallygeneratedbythesoftware.','Atopicautomaticallygeneratedbythesoftware.',UTC_TIMESTAMP(),UTC_TIMESTAMP(),1,1,2,'::1');
|
||||||
INSERT INTO `replies`(`tid`,`content`,`parsed_content`,`createdAt`,`createdBy`,`lastUpdated`,`lastEdit`,`lastEditBy`) VALUES (1,'Areply!','Areply!',UTC_TIMESTAMP(),1,UTC_TIMESTAMP(),0,0);
|
INSERT INTO `replies`(`tid`,`content`,`parsed_content`,`createdAt`,`createdBy`,`lastUpdated`,`lastEdit`,`lastEditBy`,`ipaddress`) VALUES (1,'Areply!','Areply!',UTC_TIMESTAMP(),1,UTC_TIMESTAMP(),0,0,'::1');
|
||||||
|
|
|
@ -498,6 +498,8 @@ var topic_alt_104 = []byte(`
|
||||||
`)
|
`)
|
||||||
var profile_0 = []byte(`
|
var profile_0 = []byte(`
|
||||||
|
|
||||||
|
<div id="profile_container">
|
||||||
|
|
||||||
<div id="profile_left_lane" class="colstack_left">
|
<div id="profile_left_lane" class="colstack_left">
|
||||||
<!--<header class="colstack_item colstack_head rowhead">
|
<!--<header class="colstack_item colstack_head rowhead">
|
||||||
<div class="rowitem"><h1>Profile</h1></div>
|
<div class="rowitem"><h1>Profile</h1></div>
|
||||||
|
@ -639,6 +641,8 @@ var profile_42 = []byte(`' type="hidden" />
|
||||||
var profile_43 = []byte(`
|
var profile_43 = []byte(`
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
`)
|
`)
|
||||||
var profile_44 = []byte(`
|
var profile_44 = []byte(`
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
55
templates.go
55
templates.go
|
@ -121,24 +121,7 @@ func (c *CTemplateSet) compileTemplate(name string, dir string, expects string,
|
||||||
c.FragmentCursor = make(map[string]int)
|
c.FragmentCursor = make(map[string]int)
|
||||||
c.FragmentCursor[fname] = 0
|
c.FragmentCursor[fname] = 0
|
||||||
|
|
||||||
subtree := c.tlist[fname]
|
out += c.rootIterate(c.tlist[fname], varholder, holdreflect, fname)
|
||||||
if dev.TemplateDebug {
|
|
||||||
fmt.Println(subtree.Root)
|
|
||||||
}
|
|
||||||
|
|
||||||
treeLength := len(subtree.Root.Nodes)
|
|
||||||
for index, node := range subtree.Root.Nodes {
|
|
||||||
if dev.TemplateDebug {
|
|
||||||
fmt.Println("Node: " + node.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
c.previousNode = c.currentNode
|
|
||||||
c.currentNode = node.Type()
|
|
||||||
if treeLength != (index + 1) {
|
|
||||||
c.nextNode = subtree.Root.Nodes[index+1].Type()
|
|
||||||
}
|
|
||||||
out += c.compileSwitch(varholder, holdreflect, fname, node)
|
|
||||||
}
|
|
||||||
|
|
||||||
var importList string
|
var importList string
|
||||||
if c.doImports {
|
if c.doImports {
|
||||||
|
@ -178,6 +161,26 @@ w.Write([]byte(`, " + ", -1)
|
||||||
return fout, nil
|
return fout, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CTemplateSet) rootIterate(tree *parse.Tree, varholder string, holdreflect reflect.Value, fname string) (out string) {
|
||||||
|
if dev.TemplateDebug {
|
||||||
|
fmt.Println(tree.Root)
|
||||||
|
}
|
||||||
|
treeLength := len(tree.Root.Nodes)
|
||||||
|
for index, node := range tree.Root.Nodes {
|
||||||
|
if dev.TemplateDebug {
|
||||||
|
fmt.Println("Node: ", node.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
c.previousNode = c.currentNode
|
||||||
|
c.currentNode = node.Type()
|
||||||
|
if treeLength != (index + 1) {
|
||||||
|
c.nextNode = tree.Root.Nodes[index+1].Type()
|
||||||
|
}
|
||||||
|
out += c.compileSwitch(varholder, holdreflect, fname, node)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compileSwitch(varholder string, holdreflect reflect.Value, templateName string, node interface{}) (out string) {
|
func (c *CTemplateSet) compileSwitch(varholder string, holdreflect reflect.Value, templateName string, node interface{}) (out string) {
|
||||||
if dev.TemplateDebug {
|
if dev.TemplateDebug {
|
||||||
fmt.Println("in compileSwitch")
|
fmt.Println("in compileSwitch")
|
||||||
|
@ -449,7 +452,6 @@ func (c *CTemplateSet) compileVarswitch(varholder string, holdreflect reflect.Va
|
||||||
fmt.Println("Chain Node:", n.Node)
|
fmt.Println("Chain Node:", n.Node)
|
||||||
fmt.Println("Chain Node Args:", node.Args)
|
fmt.Println("Chain Node Args:", node.Args)
|
||||||
}
|
}
|
||||||
break
|
|
||||||
case *parse.IdentifierNode:
|
case *parse.IdentifierNode:
|
||||||
if dev.TemplateDebug {
|
if dev.TemplateDebug {
|
||||||
fmt.Println("Identifier Node:", node)
|
fmt.Println("Identifier Node:", node)
|
||||||
|
@ -957,7 +959,6 @@ func (c *CTemplateSet) compileSubtemplate(pvarholder string, pholdreflect reflec
|
||||||
case *parse.DotNode:
|
case *parse.DotNode:
|
||||||
varholder = pvarholder
|
varholder = pvarholder
|
||||||
holdreflect = pholdreflect
|
holdreflect = pholdreflect
|
||||||
break
|
|
||||||
case *parse.NilNode:
|
case *parse.NilNode:
|
||||||
panic("Nil is not a command x.x")
|
panic("Nil is not a command x.x")
|
||||||
default:
|
default:
|
||||||
|
@ -995,19 +996,7 @@ func (c *CTemplateSet) compileSubtemplate(pvarholder string, pholdreflect reflec
|
||||||
c.localVars[fname]["."] = VarItemReflect{".", varholder, holdreflect}
|
c.localVars[fname]["."] = VarItemReflect{".", varholder, holdreflect}
|
||||||
c.FragmentCursor[fname] = 0
|
c.FragmentCursor[fname] = 0
|
||||||
|
|
||||||
treeLength := len(subtree.Root.Nodes)
|
out += c.rootIterate(subtree, varholder, holdreflect, fname)
|
||||||
for index, node := range subtree.Root.Nodes {
|
|
||||||
if dev.TemplateDebug {
|
|
||||||
fmt.Println("Node:", node.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
c.previousNode = c.currentNode
|
|
||||||
c.currentNode = node.Type()
|
|
||||||
if treeLength != (index + 1) {
|
|
||||||
c.nextNode = subtree.Root.Nodes[index+1].Type()
|
|
||||||
}
|
|
||||||
out += c.compileSwitch(varholder, holdreflect, fname, node)
|
|
||||||
}
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
{{template "header.html" . }}
|
{{template "header.html" . }}
|
||||||
|
|
||||||
|
<div id="profile_container">
|
||||||
|
|
||||||
<div id="profile_left_lane" class="colstack_left">
|
<div id="profile_left_lane" class="colstack_left">
|
||||||
<!--<header class="colstack_item colstack_head rowhead">
|
<!--<header class="colstack_item colstack_head rowhead">
|
||||||
<div class="rowitem"><h1>Profile</h1></div>
|
<div class="rowitem"><h1>Profile</h1></div>
|
||||||
|
@ -98,6 +100,8 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
{{/** Quick subpage switcher **/}}
|
{{/** Quick subpage switcher **/}}
|
||||||
{{/** TODO: Stop inlining this **/}}
|
{{/** TODO: Stop inlining this **/}}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
Loading…
Reference in New Issue