From ce9195c841a97374992e5adda10eb442fc11d190 Mon Sep 17 00:00:00 2001 From: Azareal Date: Wed, 13 Sep 2017 16:09:13 +0100 Subject: [PATCH] Revamped Tempra Conflux. Updated the readme. Added more comments. The forumView cache for MemoryForumStore now excludes Social Groups. Moved the word filter logic into it's own file. You can now change the language via the configuration file. Moved the inline CSS into the CSS files. --- README.md | 6 +- forum_store.go | 19 +- general_test.go | 4 +- group_store.go | 3 + install/install.go | 17 +- install/mysql.go | 2 +- langs/english.json | 4 + main.go | 62 ++---- misc_test.go | 2 +- mysql.go | 6 +- no_websockets.go | 19 +- pages.go | 4 +- phrases.go | 14 +- plugin_test.go | 11 +- routes.go | 4 +- site.go | 21 +- tasks.go | 6 + template_list.go | 10 +- templates/footer.html | 2 +- templates/topic_alt.html | 8 +- themes/shadow/public/main.css | 7 + themes/tempra-conflux/public/main.css | 269 ++++++++++++++++++++------ themes/tempra-simple/public/main.css | 24 ++- topic.go | 6 + topic_store.go | 7 + user.go | 8 +- user_store.go | 1 + utils.go | 6 + websockets.go | 50 +++-- word_filters.go | 45 +++++ 30 files changed, 443 insertions(+), 204 deletions(-) create mode 100644 group_store.go create mode 100644 word_filters.go diff --git a/README.md b/README.md index 82dfe48e..760971bc 100644 --- a/README.md +++ b/README.md @@ -152,15 +152,11 @@ We're looking for ways to clean-up the plugin system so that all of them (except ![Tempra Conflux Mobile](https://github.com/Azareal/Gosora/blob/master/images/tempra-conflux-control-panel.png) -![Cosmo Conflux Theme](https://github.com/Azareal/Gosora/blob/master/images/cosmo-conflux.png) - -![Cosmo Theme](https://github.com/Azareal/Gosora/blob/master/images/cosmo.png) - More images in the /images/ folder. Beware though, some of them are *really* outdated. # Dependencies -* Go 1.8 +* Go 1.9 * MariaDB (or any other MySQL compatible database engine). We'll allow other database engines in the future. diff --git a/forum_store.go b/forum_store.go index 60b2c2c6..6b868e40 100644 --- a/forum_store.go +++ b/forum_store.go @@ -1,4 +1,9 @@ -/* Work in progress. Check back later! */ +/* +* +* Gosora Forum Store +* Copyright Azareal 2017 - 2018 +* + */ package main import ( @@ -15,6 +20,7 @@ var forumCreateMutex sync.Mutex var forumPerms map[int]map[int]ForumPerms // [gid][fid]Perms var fstore ForumStore +// ForumStore is an interface for accessing the forums and the metadata stored on them type ForumStore interface { LoadForums() error DirtyGet(id int) *Forum @@ -43,9 +49,9 @@ type ForumStore interface { GetGlobalCount() int } +// MemoryForumStore is a struct which holds an arbitrary number of forums in memory, usually all of them, although we might introduce functionality to hold a smaller subset in memory for sites with an extremely large number of forums type MemoryForumStore struct { - //forums map[int]*Forum - forums sync.Map + forums sync.Map // map[int]*Forum forumView atomic.Value // []*Forum //fids []int forumCount int @@ -56,6 +62,7 @@ type MemoryForumStore struct { getForumCount *sql.Stmt } +// NewMemoryForumStore gives you a new instance of MemoryForumStore func NewMemoryForumStore() *MemoryForumStore { getStmt, err := qgen.Builder.SimpleSelect("forums", "name, desc, active, preset, parentID, parentType, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime", "fid = ?", "", "") if err != nil { @@ -81,6 +88,7 @@ func NewMemoryForumStore() *MemoryForumStore { } } +// TODO: Add support for subforums func (mfs *MemoryForumStore) LoadForums() error { log.Print("Adding the uncategorised forum") forumUpdateMutex.Lock() @@ -89,7 +97,7 @@ func (mfs *MemoryForumStore) LoadForums() error { var forumView []*Forum addForum := func(forum *Forum) { mfs.forums.Store(forum.ID, forum) - if forum.Active && forum.Name != "" { + if forum.Active && forum.Name != "" && forum.ParentType == "" { forumView = append(forumView, forum) } } @@ -132,7 +140,8 @@ func (mfs *MemoryForumStore) rebuildView() { var forumView []*Forum mfs.forums.Range(func(_ interface{}, value interface{}) bool { forum := value.(*Forum) - if forum.Active && forum.Name != "" { + // ? - ParentType blank means that it doesn't have a parent + if forum.Active && forum.Name != "" && forum.ParentType == "" { forumView = append(forumView, forum) } return true diff --git a/general_test.go b/general_test.go index c135986c..dae0b06d 100644 --- a/general_test.go +++ b/general_test.go @@ -124,7 +124,7 @@ func BenchmarkTopicAdminRouteParallel(b *testing.B) { for pb.Next() { topicW.Body.Reset() - route_topic_id(topicW, topicReqAdmin, user) + routeTopicID(topicW, topicReqAdmin, user) } }) } @@ -143,7 +143,7 @@ func BenchmarkTopicGuestRouteParallel(b *testing.B) { topicReq := httptest.NewRequest("get", "/topic/1", bytes.NewReader(nil)) for pb.Next() { topicW.Body.Reset() - route_topic_id(topicW, topicReq, guestUser) + routeTopicID(topicW, topicReq, guestUser) } }) } diff --git a/group_store.go b/group_store.go new file mode 100644 index 00000000..9ae4f57a --- /dev/null +++ b/group_store.go @@ -0,0 +1,3 @@ +package main + +// TODO: Coming Soon. Probably in the next commit or two diff --git a/install/install.go b/install/install.go index 5a9c7b19..8e06525e 100644 --- a/install/install.go +++ b/install/install.go @@ -146,22 +146,23 @@ func main() { func init() { // Site Info -site.Name = "` + siteName + `" // Should be a setting in the database -site.Email = "" // Should be a setting in the database -site.Url = "` + siteURL + `" +site.Name = "` + siteName + `" +site.Email = "" +site.URL = "` + siteURL + `" site.Port = "` + serverPort + `" site.EnableSsl = false site.EnableEmails = false site.HasProxy = false // Cloudflare counts as this, if it's sitting in the middle config.SslPrivkey = "" config.SslFullchain = "" +site.Language = "english" // Database details -db_config.Host = "` + dbHost + `" -db_config.Username = "` + dbUsername + `" -db_config.Password = "` + dbPassword + `" -db_config.Dbname = "` + dbName + `" -db_config.Port = "` + dbPort + `" // You probably won't need to change this +dbConfig.Host = "` + dbHost + `" +dbConfig.Username = "` + dbUsername + `" +dbConfig.Password = "` + dbPassword + `" +dbConfig.Dbname = "` + dbName + `" +dbConfig.Port = "` + dbPort + `" // You probably won't need to change this // Limiters config.MaxRequestSize = 5 * megabyte diff --git a/install/mysql.go b/install/mysql.go index 6644c994..e7565ea7 100644 --- a/install/mysql.go +++ b/install/mysql.go @@ -53,7 +53,7 @@ func _initMysql() (err error) { if err == sql.ErrNoRows { fmt.Println("Unable to find the database. Attempting to create it") - _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + dbName + "") + _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + dbName) if err != nil { return err } diff --git a/langs/english.json b/langs/english.json index 795ad9e8..80f8e589 100644 --- a/langs/english.json +++ b/langs/english.json @@ -39,5 +39,9 @@ }, "SettingLabels": { "activation_type": "Activate All,Email Activation,Admin Approval" + }, + "Accounts": { + "VerifyEmailSubject": "Validate Your Email @ {{name}}", + "VerifyEmailBody": "Dear {{username}}, following your registration on our forums, we ask you to validate your email, so that we can confirm that this email actually belongs to you.\n\nClick on the following link to do so. {{schema}}://{{url}}/user/edit/token/{{token}}\n\nIf you haven't created an account here, then please feel free to ignore this email.\nWe're sorry for the inconvenience this may have caused." } } \ No newline at end of file diff --git a/main.go b/main.go index d69c8c3e..ab91e574 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,9 @@ -/* Copyright Azareal 2016 - 2018 */ +/* +* +* Gosora Main File +* Copyright Azareal 2016 - 2018 +* + */ package main import ( @@ -8,7 +13,6 @@ import ( "net/http" "os" "strings" - "sync/atomic" "time" //"runtime/pprof" ) @@ -27,8 +31,6 @@ const terabyte int = gigabyte * 1024 const saltLength int = 32 const sessionLength int = 80 -var enableWebsockets = false // Don't change this, the value is overwritten by an initialiser - var router *GenRouter var startTime time.Time @@ -41,55 +43,13 @@ var groupCapCount int var staticFiles = make(map[string]SFile) var logWriter = io.MultiWriter(os.Stderr) -type WordFilter struct { - ID int - Find string - Replacement string -} -type WordFilterBox map[int]WordFilter - -var wordFilterBox atomic.Value // An atomic value holding a WordFilterBox - -func init() { - wordFilterBox.Store(WordFilterBox(make(map[int]WordFilter))) -} - -func LoadWordFilters() error { - rows, err := get_word_filters_stmt.Query() - if err != nil { - return err - } - defer rows.Close() - - var wordFilters = WordFilterBox(make(map[int]WordFilter)) - var wfid int - var find string - var replacement string - - for rows.Next() { - err := rows.Scan(&wfid, &find, &replacement) - if err != nil { - return err - } - wordFilters[wfid] = WordFilter{ID: wfid, Find: find, Replacement: replacement} - } - wordFilterBox.Store(wordFilters) - return rows.Err() -} - -func addWordFilter(id int, find string, replacement string) { - wordFilters := wordFilterBox.Load().(WordFilterBox) - wordFilters[id] = WordFilter{ID: id, Find: find, Replacement: replacement} - wordFilterBox.Store(wordFilters) -} - func processConfig() { - config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.Url, -1) + config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.URL, -1) if site.Port != "80" && site.Port != "443" { - site.Url = strings.TrimSuffix(site.Url, "/") - site.Url = strings.TrimSuffix(site.Url, "\\") - site.Url = strings.TrimSuffix(site.Url, ":") - site.Url = site.Url + ":" + site.Port + site.URL = strings.TrimSuffix(site.URL, "/") + site.URL = strings.TrimSuffix(site.URL, "\\") + site.URL = strings.TrimSuffix(site.URL, ":") + site.URL = site.URL + ":" + site.Port } } diff --git a/misc_test.go b/misc_test.go index e95e00f2..13f77b9c 100644 --- a/misc_test.go +++ b/misc_test.go @@ -137,7 +137,7 @@ func TestForumStore(t *testing.T) { func TestSlugs(t *testing.T) { var res string - var msgList []ME_Pair + var msgList []MEPair msgList = addMEPair(msgList, "Unknown", "unknown") msgList = addMEPair(msgList, "Unknown2", "unknown2") diff --git a/mysql.go b/mysql.go index 648b92fb..ce7d84c5 100644 --- a/mysql.go +++ b/mysql.go @@ -27,12 +27,12 @@ func init() { func _initDatabase() (err error) { var _dbpassword string - if db_config.Password != "" { - _dbpassword = ":" + db_config.Password + if dbConfig.Password != "" { + _dbpassword = ":" + dbConfig.Password } // Open the database connection - db, err = sql.Open("mysql", db_config.Username+_dbpassword+"@tcp("+db_config.Host+":"+db_config.Port+")/"+db_config.Dbname+"?collation="+dbCollation) + db, err = sql.Open("mysql", dbConfig.Username+_dbpassword+"@tcp("+dbConfig.Host+":"+dbConfig.Port+")/"+dbConfig.Dbname+"?collation="+dbCollation) if err != nil { return err } diff --git a/no_websockets.go b/no_websockets.go index c0abe425..8f8d30a4 100644 --- a/no_websockets.go +++ b/no_websockets.go @@ -5,33 +5,36 @@ package main import "errors" import "net/http" -var wsHub WS_Hub +// TODO: Disable WebSockets on high load? Add a Control Panel interface for disabling it? +var enableWebsockets = false // Put this in caps for consistency with the other constants? + +var wsHub WSHub var errWsNouser = errors.New("This user isn't connected via WebSockets") -type WS_Hub struct { +type WSHub struct { } -func (_ *WS_Hub) guestCount() int { +func (_ *WSHub) guestCount() int { return 0 } -func (_ *WS_Hub) userCount() int { +func (_ *WSHub) userCount() int { return 0 } -func (hub *WS_Hub) broadcastMessage(_ string) error { +func (hub *WSHub) broadcastMessage(_ string) error { return nil } -func (hub *WS_Hub) pushMessage(_ int, _ string) error { +func (hub *WSHub) pushMessage(_ int, _ string) error { return errWsNouser } -func (hub *WS_Hub) pushAlert(_ int, _ int, _ string, _ string, _ int, _ int, _ int) error { +func (hub *WSHub) pushAlert(_ int, _ int, _ string, _ string, _ int, _ int, _ int) error { return errWsNouser } -func (hub *WS_Hub) pushAlerts(_ []int, _ int, _ string, _ string, _ int, _ int, _ int) error { +func (hub *WSHub) pushAlerts(_ []int, _ int, _ string, _ string, _ int, _ int, _ int) error { return errWsNouser } diff --git a/pages.go b/pages.go index 2d8ece76..29ff778c 100644 --- a/pages.go +++ b/pages.go @@ -207,10 +207,10 @@ type PanelEditForumPage struct { Groups []GroupForumPermPreset } -type NameLangPair struct { +/*type NameLangPair struct { Name string LangStr string -} +}*/ type NameLangToggle struct { Name string diff --git a/phrases.go b/phrases.go index e5390388..746dd865 100644 --- a/phrases.go +++ b/phrases.go @@ -19,7 +19,6 @@ import ( // TODO: Let the admin edit phrases from inside the Control Panel? How should we persist these? Should we create a copy of the langpack or edit the primaries? Use the changeLangpack mutex for this? // nolint Be quiet megacheck, this *is* used -var currentLanguage = "english" var currentLangPack atomic.Value var langpackCount int // TODO: Use atomics for this @@ -40,6 +39,7 @@ type LanguagePack struct { GlobalPerms map[string]string LocalPerms map[string]string SettingLabels map[string]string + Accounts map[string]string // TODO: Apply these phrases in the software proper } // TODO: Add the ability to edit language JSON files from the Control Panel and automatically scan the files for changes @@ -86,9 +86,9 @@ func initPhrases() error { return errors.New("You don't have any language packs") } - langPack, ok := langpacks.Load(currentLanguage) + langPack, ok := langpacks.Load(site.Language) if !ok { - return errors.New("Couldn't find the " + currentLanguage + " language pack") + return errors.New("Couldn't find the " + site.Language + " language pack") } currentLangPack.Store(langPack) return nil @@ -139,6 +139,14 @@ func GetAllSettingLabels() map[string]string { return currentLangPack.Load().(*LanguagePack).SettingLabels } +func GetAccountPhrase(name string) string { + res, ok := currentLangPack.Load().(*LanguagePack).Accounts[name] + if !ok { + return "{name}" + } + return res +} + // ? - Use runtime reflection for updating phrases? // TODO: Implement these func AddPhrase() { diff --git a/plugin_test.go b/plugin_test.go index c6e12cdd..87936d3a 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -3,22 +3,21 @@ package main import "strconv" import "testing" -// TODO: Replace the soft tabs with hard ones // go test -v -type ME_Pair struct { +type MEPair struct { Msg string Expects string } -func addMEPair(msgList []ME_Pair, msg string, expects string) []ME_Pair { - return append(msgList, ME_Pair{msg, expects}) +func addMEPair(msgList []MEPair, msg string, expects string) []MEPair { + return append(msgList, MEPair{msg, expects}) } func TestBBCodeRender(t *testing.T) { //t.Skip() var res string - var msgList []ME_Pair + var msgList []MEPair msgList = addMEPair(msgList, "hi", "hi") msgList = addMEPair(msgList, "😀", "😀") msgList = addMEPair(msgList, "[b]😀[/b]", "😀") @@ -190,7 +189,7 @@ func TestBBCodeRender(t *testing.T) { func TestMarkdownRender(t *testing.T) { //t.Skip() var res string - var msgList []ME_Pair + var msgList []MEPair msgList = addMEPair(msgList, "hi", "hi") msgList = addMEPair(msgList, "**hi**", "hi") msgList = addMEPair(msgList, "_hi_", "hi") diff --git a/routes.go b/routes.go index 2e7120ac..6f521e0a 100644 --- a/routes.go +++ b/routes.go @@ -1,7 +1,7 @@ /* * -* Gosora Route Handlers -* Copyright Azareal 2016 - 2018 +* Gosora Route Handlers +* Copyright Azareal 2016 - 2018 * */ package main diff --git a/site.go b/site.go index c0b2dbab..0f061814 100644 --- a/site.go +++ b/site.go @@ -2,24 +2,23 @@ package main import "net/http" -// TODO: Add a langPack configuration item or setting - -var site = &Site{Name: "Magical Fairy Land"} -var db_config = DB_Config{Host: "localhost"} +var site = &Site{Name: "Magical Fairy Land", Language: "english"} +var dbConfig = DBConfig{Host: "localhost"} var config Config var dev DevConfig type Site struct { - Name string - Email string - Url string + Name string // ? - Move this into the settings table? + Email string // ? - Move this into the settings table? + URL string Port string EnableSsl bool EnableEmails bool HasProxy bool + Language string // ? - Move this into the settings table? } -type DB_Config struct { +type DBConfig struct { Host string Username string Password string @@ -44,13 +43,13 @@ type Config struct { DefaultRoute func(http.ResponseWriter, *http.Request, User) DefaultGroup int ActivationGroup int - StaffCss string + StaffCss string // ? - Move this into the settings table? Might be better to implement this as Group CSS UncategorisedForumVisible bool MinifyTemplates bool MultiServer bool - Noavatar string - ItemsPerPage int + Noavatar string // ? - Move this into the settings table? + ItemsPerPage int // ? - Move this into the settings table? } type DevConfig struct { diff --git a/tasks.go b/tasks.go index c81bdf08..11a5e71f 100644 --- a/tasks.go +++ b/tasks.go @@ -1,3 +1,9 @@ +/* +* +* Gosora Task System +* Copyright Azareal 2017 - 2018 +* + */ package main import "time" diff --git a/template_list.go b/template_list.go index cc0e824c..4d3c982e 100644 --- a/template_list.go +++ b/template_list.go @@ -246,7 +246,7 @@ var topic_91 = []byte(` `) var footer_0 = []byte(`