diff --git a/common/alerts.go b/common/alerts.go index 02131cc4..d6a76630 100644 --- a/common/alerts.go +++ b/common/alerts.go @@ -54,7 +54,7 @@ func BuildAlert(asid int, event string, elementType string, actorID int, targetU actor, err := Users.Get(actorID) if err != nil { - return "", errors.New("Unable to find the actor") + return "", errors.New(GetErrorPhrase("alerts_no_actor")) } /*if elementType != "forum" { @@ -66,7 +66,7 @@ func BuildAlert(asid int, event string, elementType string, actorID int, targetU }*/ if event == "friend_invite" { - return buildAlertString(GetTmplPhrase("alerts_new_friend_invite"), []string{actor.Name}, actor.Link, actor.Avatar, asid), nil + return buildAlertString(GetTmplPhrase("alerts.new_friend_invite"), []string{actor.Name}, actor.Link, actor.Avatar, asid), nil } // Not that many events for us to handle in a forum @@ -79,13 +79,13 @@ func BuildAlert(asid int, event string, elementType string, actorID int, targetU } // Store the forum ID in the targetUser column instead of making a new one? o.O // Add an additional column for extra information later on when we add the ability to link directly to posts. We don't need the forum data for now... - return buildAlertString(GetTmplPhrase("alerts_forum_new_topic"), []string{actor.Name, topic.Title}, topic.Link, actor.Avatar, asid), nil + return buildAlertString(GetTmplPhrase("alerts.forum_new_topic"), []string{actor.Name, topic.Title}, topic.Link, actor.Avatar, asid), nil } - return buildAlertString(GetTmplPhrase("alerts_forum_unknown_action"), []string{actor.Name}, "", actor.Avatar, asid), nil + return buildAlertString(GetTmplPhrase("alerts.forum_unknown_action"), []string{actor.Name}, "", actor.Avatar, asid), nil } var url, area string - var phraseName = "alerts_" + elementType + var phraseName = "alerts." + elementType switch elementType { case "topic": topic, err := Topics.Get(elementID) @@ -102,7 +102,7 @@ func BuildAlert(asid int, event string, elementType string, actorID int, targetU targetUser, err = Users.Get(elementID) if err != nil { DebugLogf("Unable to find target user %d", elementID) - return "", errors.New("Unable to find the target user") + return "", errors.New(GetErrorPhrase("alerts_no_target_user")) } area = targetUser.Name url = targetUser.Link @@ -112,7 +112,7 @@ func BuildAlert(asid int, event string, elementType string, actorID int, targetU case "post": topic, err := TopicByReplyID(elementID) if err != nil { - return "", errors.New("Unable to find the linked reply or parent topic") + return "", errors.New(GetErrorPhrase("alerts_no_linked_topic_by_reply")) } url = topic.Link area = topic.Title @@ -120,7 +120,7 @@ func BuildAlert(asid int, event string, elementType string, actorID int, targetU phraseName += "_own" } default: - return "", errors.New("Invalid elementType") + return "", errors.New(GetErrorPhrase("alerts_invalid_elementtype")) } switch event { @@ -193,7 +193,6 @@ func NotifyWatchers(asid int64) error { if EnableWebsockets { go notifyWatchers(asid) } - return nil } diff --git a/common/routes_common.go b/common/routes_common.go index b931a351..9ab1be27 100644 --- a/common/routes_common.go +++ b/common/routes_common.go @@ -280,7 +280,9 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) { // TODO: Add a config setting to disable this header // TODO: Have this header cover more things - w.Header().Set("Content-Security-Policy", "upgrade-insecure-requests") + if Site.EnableSsl { + w.Header().Set("Content-Security-Policy", "upgrade-insecure-requests") + } if user == &GuestUser { usercpy.LastIP = host diff --git a/common/user_store.go b/common/user_store.go index 13b78a70..14f0d66f 100644 --- a/common/user_store.go +++ b/common/user_store.go @@ -58,7 +58,7 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) { getByName: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Where("name = ?").Prepare(), getOffset: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Orderby("uid ASC").Limit("?,?").Prepare(), exists: acc.SimpleSelect("users", "uid", "uid = ?", "", ""), - register: acc.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt", "?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()"), // TODO: Implement user_count on users_groups here + register: acc.Insert("users").Columns("name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt, lastLiked, oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here usernameExists: acc.SimpleSelect("users", "name", "name = ?", "", ""), userCount: acc.SimpleCount("users", "", ""), }, acc.FirstError() diff --git a/install/install/install.go b/install/install/install.go index 1acaefae..0583f51b 100644 --- a/install/install/install.go +++ b/install/install/install.go @@ -37,7 +37,7 @@ func createAdmin() error { } // Build the admin user query - adminUserStmt, err := qgen.Builder.SimpleInsert("users", "name, password, salt, email, group, is_super_admin, active, createdAt, lastActiveAt, message, last_ip", "'Admin',?,?,'admin@localhost',1,1,1,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','127.0.0.1'") + adminUserStmt, err := qgen.Builder.SimpleInsert("users", "name, password, salt, email, group, is_super_admin, active, createdAt, lastActiveAt, lastLiked, oldestItemLikedCreatedAt, message, last_ip", "'Admin',?,?,'admin@localhost',1,1,1,UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','127.0.0.1'") if err != nil { return err } diff --git a/langs/english.json b/langs/english.json index c6aa9458..54e531e0 100644 --- a/langs/english.json +++ b/langs/english.json @@ -98,7 +98,11 @@ "register_username_too_long_prefix":"The username is too long, max: ", "register_email_fail":"We were unable to send the email for you to confirm that this email address belongs to you. You may not have access to some functionality until you do so. Please ask an administrator for assistance.", + "alerts_no_actor":"Unable to find the actor", + "alerts_no_target_user":"Unable to find the target user", "alerts_no_linked_topic":"Unable to find the linked topic", + "alerts_no_linked_topic_by_reply":"Unable to find the linked reply or parent topic", + "alerts_invalid_elementtype":"Invalid elementType", "panel_groups_need_name":"The group name can't be left blank.", "panel_groups_cannot_edit_admin":"You need the EditGroupAdmin permission to edit an admin group.", @@ -315,30 +319,32 @@ "menu_login":"Login", "menu_register":"Register", - "alerts_forum_new_topic":"{0} created the topic {1}", - "alerts_forum_unknown_action":"{0} did something in a forum", - - "alerts_topic_own_reply":"{0} replied to your topic {1}", - "alerts_topic_reply":"{0} replied to {1}", - "alerts_topic_own_like":"{0} liked your topic {1}", - "alerts_topic_like":"{0} liked {1}", - "alerts_topic_own_mention":"{0} mentioned you in {1}", - "alerts_topic_mention":"{0} mentioned you in {1}", + "alerts.forum_new_topic":"{0} created the topic {1}", + "alerts.forum_unknown_action":"{0} did something in a forum", - "alerts_post_own_reply":"{0} replied to your post in {1}", - "alerts_post_reply":"{0} replied to {1}", - "alerts_post_own_like":"{0} liked your post in {1}", - "alerts_post_like":"{0} liked a post in {1}", - "alerts_post_own_mention":"{0} mentioned you in {1}", - "alerts_post_mention":"{0} mentioned you in {1}", + "alerts.topic_own_reply":"{0} replied to your topic {1}", + "alerts.topic_reply":"{0} replied to {1}", + "alerts.topic_own_like":"{0} liked your topic {1}", + "alerts.topic_like":"{0} liked {1}", + "alerts.topic_own_mention":"{0} mentioned you in {1}", + "alerts.topic_mention":"{0} mentioned you in {1}", - "alerts_user_own_reply":"{0} made a post on your profile", - "alerts_user_reply":"{0} posted on {1}'s profile", - "alerts_user_own_like":"{0} likes you", - "alerts_user_like":"{0} likes {1}", - "alerts_user_own_mention":"{0} mentioned you on your profile", - "alerts_user_mention":"{0} mentioned you on {1}'s profile", - "alerts_new_friend_invite":"You received a friend invite from {0}", + "alerts.post_own_reply":"{0} replied to your post in {1}", + "alerts.post_reply":"{0} replied to {1}", + "alerts.post_own_like":"{0} liked your post in {1}", + "alerts.post_like":"{0} liked a post in {1}", + "alerts.post_own_mention":"{0} mentioned you in {1}", + "alerts.post_mention":"{0} mentioned you in {1}", + + "alerts.user_own_reply":"{0} made a post on your profile", + "alerts.user_reply":"{0} posted on {1}'s profile", + "alerts.user_own_like":"{0} likes you", + "alerts.user_like":"{0} likes {1}", + "alerts.user_own_mention":"{0} mentioned you on your profile", + "alerts.user_mention":"{0} mentioned you on {1}'s profile", + "alerts.new_friend_invite":"You received a friend invite from {0}", + + "alerts.no_alerts":"You don't have any alerts", "topics_click_topics_to_select":"Click the topics to select them", "topics_new_topic":"New Topic", diff --git a/public/global.js b/public/global.js index 11bfd6f1..61d1fd3e 100644 --- a/public/global.js +++ b/public/global.js @@ -81,7 +81,7 @@ function updateAlertList(menuAlerts) { j++; } - if(outList == "") outList = "
You don't have any alerts
"; + if(outList == "") outList = "
"+phraseBox["alerts"]["alerts.no_alerts"]+"
"; alertListNode.innerHTML = outList; if(alertCount != 0) { @@ -489,7 +489,6 @@ function mainInit(){ $(".submit_edit").click(function(event) { event.preventDefault(); - //console.log("running .submit_edit event"); var outData = {isJs: "1"} var blockParent = $(this).closest('.editable_parent'); blockParent.find('.editable_block').each(function() { @@ -569,8 +568,9 @@ function mainInit(){ var fileList = this.files; // Truncate the number of files to 5 let files = []; - for(var i = 0; i < fileList.length && i < 5; i++) + for(var i = 0; i < fileList.length && i < 5; i++) { files[i] = fileList[i]; + } // Iterate over the files let totalSize = 0; diff --git a/public/init.js b/public/init.js index 0d9bab21..e6da919f 100644 --- a/public/init.js +++ b/public/init.js @@ -92,7 +92,7 @@ function DoNothingButPassBack(item) { } function fetchPhrases() { - fetch("/api/phrases/?query=status,topic_list") + fetch("/api/phrases/?query=status,topic_list,alerts") .then((resp) => resp.json()) .then((data) => { console.log("loaded phrase endpoint data"); diff --git a/query_gen/lib/mysql.go b/query_gen/lib/mysql.go index 591cd222..76482ded 100644 --- a/query_gen/lib/mysql.go +++ b/query_gen/lib/mysql.go @@ -141,6 +141,9 @@ func (adapter *MysqlAdapter) parseColumn(column DBTableColumn) (col DBTableColum // Make it easier to support Cassandra in the future if column.Type == "createdAt" { column.Type = "datetime" + if column.Default == "" { + column.Default = "UTC_TIMESTAMP()" + } } else if column.Type == "json" { column.Type = "text" } @@ -151,7 +154,9 @@ func (adapter *MysqlAdapter) parseColumn(column DBTableColumn) (col DBTableColum // TODO: Exclude the other variants of text like mediumtext and longtext too if column.Default != "" && column.Type != "text" { end = " DEFAULT " - if adapter.stringyType(column.Type) && column.Default != "''" { + if column.Type == "datetime" && column.Default[len(column.Default)-1] == ')' { + end += column.Default + } else if adapter.stringyType(column.Type) && column.Default != "''" { end += "'" + column.Default + "'" } else { end += column.Default diff --git a/query_gen/tables.go b/query_gen/tables.go index 3ebd0112..299ab3fa 100644 --- a/query_gen/tables.go +++ b/query_gen/tables.go @@ -204,12 +204,19 @@ func createTables(adapter qgen.Adapter) error { qgen.DBTableColumn{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key qgen.DBTableColumn{"is_closed", "boolean", 0, false, false, "0"}, qgen.DBTableColumn{"sticky", "boolean", 0, false, false, "0"}, + // TODO: Add an index for this qgen.DBTableColumn{"parentID", "int", 0, false, false, "2"}, qgen.DBTableColumn{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"}, qgen.DBTableColumn{"postCount", "int", 0, false, false, "1"}, qgen.DBTableColumn{"likeCount", "int", 0, false, false, "0"}, qgen.DBTableColumn{"words", "int", 0, false, false, "0"}, qgen.DBTableColumn{"views", "int", 0, false, false, "0"}, + //qgen.DBTableColumn{"dailyViews", "int", 0, false, false, "0"}, + //qgen.DBTableColumn{"weeklyViews", "int", 0, false, false, "0"}, + //qgen.DBTableColumn{"monthlyViews", "int", 0, false, false, "0"}, + // ? - A little hacky, maybe we could do something less likely to bite us with huge numbers of topics? + // TODO: Add an index for this? + //qgen.DBTableColumn{"lastMonth", "datetime", 0, false, false, ""}, qgen.DBTableColumn{"css_class", "varchar", 100, false, false, "''"}, qgen.DBTableColumn{"poll", "int", 0, false, false, "0"}, qgen.DBTableColumn{"data", "varchar", 200, false, false, "''"}, @@ -435,7 +442,7 @@ func createTables(adapter qgen.Adapter) error { []qgen.DBTableColumn{ qgen.DBTableColumn{"miid", "int", 0, false, true, ""}, qgen.DBTableColumn{"mid", "int", 0, false, false, ""}, - qgen.DBTableColumn{"name", "varchar", 200, false, false, ""}, + qgen.DBTableColumn{"name", "varchar", 200, false, false, "''"}, qgen.DBTableColumn{"htmlID", "varchar", 200, false, false, "''"}, qgen.DBTableColumn{"cssClass", "varchar", 200, false, false, "''"}, qgen.DBTableColumn{"position", "varchar", 100, false, false, ""}, @@ -590,5 +597,12 @@ func createTables(adapter qgen.Adapter) error { []qgen.DBTableKey{}, ) + /*qgen.Install.CreateTable("updates", "", "", + []qgen.DBTableColumn{ + qgen.DBTableColumn{"dbVersion", "int", 0, false, false, "0"}, + }, + []qgen.DBTableKey{}, + )*/ + return nil } diff --git a/routes.go b/routes.go index bf167d93..2fef4a7d 100644 --- a/routes.go +++ b/routes.go @@ -163,7 +163,7 @@ func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user common.User) c phrases = make(map[string]string) for _, positive := range positives { // ! Constrain it to topic and status phrases for now - if !strings.HasPrefix(positive, "topic") && !strings.HasPrefix(positive, "status") { + if !strings.HasPrefix(positive, "topic") && !strings.HasPrefix(positive, "status") && !strings.HasPrefix(positive, "alerts") { return common.PreErrorJS("Not implemented!", w, r) } pPhrases, ok := common.GetTmplPhrasesByPrefix(positive) @@ -176,7 +176,7 @@ func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user common.User) c } } else { // ! Constrain it to topic and status phrases for now - if !strings.HasPrefix(positives[0], "topic") && !strings.HasPrefix(positives[0], "status") { + if !strings.HasPrefix(positives[0], "topic") && !strings.HasPrefix(positives[0], "status") && !strings.HasPrefix(positives[0], "alerts") { return common.PreErrorJS("Not implemented!", w, r) } pPhrases, ok := common.GetTmplPhrasesByPrefix(positives[0])