diff --git a/README.md b/README.md index 6a24e447..78b8400c 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,7 @@ Demo installation: https://gochan.org 5. Go to http://[gochan url]/manage?action=staff, log in (default username/password is admin/password), and create a new admin user (and any other staff users as necessary). Then delete the admin user for security. ## Configuration -1. Make sure to set `DBtype`, `DBhost`, `DBname`, `DBusername`, and `DBpassword`, since these are required to connect to your SQL database. Valid `DBtype` values are "mysql" and "postgres" (sqlite3 is no longer supported for stability reasons). - 1. To connect to a MySQL database, set `DBhost` to "ip:3306" or a different port, if necessary. - 2. To connect to a PostgreSQL database, set `DBhost` to the IP address or hostname. Using a UNIX socket may work as well, but it is currently untested. -2. Set `DomainRegex`,`SiteDomain`, since these are necessary in order to post and log in as a staff member. -3. If you want to see debugging info/noncritical warnings, set verbosity to 1. +See [config.md](config.md) ## Installation using Docker See [`docker/README.md`](docker/README.md) diff --git a/cmd/gochan/server.go b/cmd/gochan/server.go index 665a1be7..3efa2f76 100755 --- a/cmd/gochan/server.go +++ b/cmd/gochan/server.go @@ -130,7 +130,11 @@ func initServer() { server.namespaces = make(map[string]func(http.ResponseWriter, *http.Request)) // Check if Akismet API key is usable at startup. - if err = serverutil.CheckAkismetAPIKey(siteConfig.AkismetAPIKey); err != nil { + err = serverutil.CheckAkismetAPIKey(siteConfig.AkismetAPIKey) + if err == serverutil.ErrBlankAkismetKey { + gclog.Print(gclog.LErrorLog, err.Error(), ". Akismet spam protection won't be used.") + } else if err != nil { + gclog.Print(gclog.LErrorLog|gclog.LAccessLog, ". Akismet spam protection will be disabled.") siteConfig.AkismetAPIKey = "" } @@ -144,8 +148,8 @@ func initServer() { http.Redirect(writer, request, "https://www.youtube.com/watch?v=dQw4w9WgXcQ", http.StatusFound) } } - // Eventually plugins will be able to register new namespaces (assuming they ever get it working on Windows or macOS) - // or they will be restricted to something like /plugin + // Eventually plugins will be able to register new namespaces or they will be restricted to something + // like /plugin if systemCritical.UseFastCGI { err = fcgi.Serve(listener, server) diff --git a/config.md b/config.md new file mode 100644 index 00000000..726d8476 --- /dev/null +++ b/config.md @@ -0,0 +1,37 @@ +# gochan configuration +See [gochan.example.json](sample-configs/gochan.example.json) for an example gochan.json. + +## Server-critical stuff +* You'll need to edit some of the values (like `ListenIP` and `UseFastCGI` based on your system's setup. For an example nginx configuration, see [gochan-fastcgi.nginx](sample-configs/gochan-fastcgi.nginx) for FastCGI and [gochan-http.nginx](sample-configs/gochan-http.nginx) for passing through HTTP. +* `DocumentRoot` refers to the root directory on your filesystem where gochan will look for requested files. +* `TemplateDir` refers to the directory where gochan will load the templates from. +* `LogDir` refers to the directory where gochan will write the logs to. + +**Make sure gochan has read-write permission for `DocumentRoot` and `LogDir` and read permission for `TemplateDir`** + +## Database configuration +Valid `DBtype` values are "mysql" and "postgres" (sqlite3 is no longer supported for stability reasons, though that may or may not come back). +1. To connect to a MySQL database, set `DBhost` to "x.x.x.x:3306" (replacing x.x.x.x with your database server's IP or domain) or a different port, if necessary. You can also use a UNIX socket if you have it set up, like "unix(/var/run/mysqld/mysqld.sock)". +2. To connect to a PostgreSQL database, set `DBhost` to the IP address or hostname. Using a UNIX socket may work as well, but it is currently untested. +3. Set `SiteDomain`, since these are necessary in order to post and log in as a staff member. +3. If you want to see debugging info/noncritical warnings, set verbosity to 1. +4. If `DBprefix` is set (not required), all gochan table names will be prefixed with the `DBprefix` value. Once you run gochan for the first time, you really shouldn't edit this value, since gochan will assume the tables are missing. + +## Website configuration +* `SiteName` is used for the name displayed on the home page. +* `SiteSlogan` is used for the slogan (if set) on the home page. +* `SiteDomain` is used for links throughout the site. +* `WebRoot` is used as the prefix for boards, files, and pretty much everything on the site. If it isn't set, "/" will be used. + +## Styles +* `Styles` is an array, with each element representing a theme selectable by the user from the frontend settings screen. Each element should have `Name` string value and a `Filename` string value. Example: +```JSON +"Styles": [ + { "Name": "Pipes", "Filename": "pipes.css" } +] +``` +* If `DefaultStyle` is not set, the first element in `Styles` will be used. + +## Misc +* `ReservedTrips` is used for reserving secure tripcodes. It should be an array of strings. For example, if you have `abcd##ABCD` and someone posts with the name ##abcd, their name will instead show up as !!ABCD on the site. +* `BanColors` is used for the color of the text set by `BanMessage`, and can be used for setting per-user colors, if desired. It should be a string array, with each element being of the form `"username:color"`, where color is a valid HTML color (#000A0, green, etc) and username is the staff member who set the ban. If a color isn't set for the user, the style will be used to set the color. diff --git a/pkg/building/building.go b/pkg/building/building.go index 4d0e77f4..df8e7cca 100644 --- a/pkg/building/building.go +++ b/pkg/building/building.go @@ -49,6 +49,7 @@ func BuildFrontPage() error { "site_config": siteCfg, "sections": gcsql.AllSections, "boards": gcsql.AllBoards, + "board_config": config.GetBoardConfig(""), "recent_posts": recentPostsArr, }, frontFile, "text/html"); err != nil { return errors.New(gclog.Print(gclog.LErrorLog, diff --git a/pkg/config/config.go b/pkg/config/config.go index 9bcbebfd..38e433ea 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -47,10 +47,10 @@ var ( "PostsPerThreadPage": 50, "RepliesOnBoardPage": 3, "StickyRepliesOnBoardPage": 1, - "BanMsg": "USER WAS BANNED FOR THIS POST", + "BanMessage": "USER WAS BANNED FOR THIS POST", "EmbedWidth": 200, "EmbedHeight": 164, - "ExpandButton": true, + "EnableEmbeds": true, "ImagesOpenNewTab": true, "NewTabOnOutlinks": true, @@ -194,8 +194,8 @@ func (gcfg *GochanConfig) ValidateValues() error { gcfg.StickyRepliesOnBoardPage = defaults["StickyRepliesOnBoardPage"].(int) changed = true } - if gcfg.BanMsg == "" { - gcfg.BanMsg = defaults["BanMsg"].(string) + if gcfg.BanMessage == "" { + gcfg.BanMessage = defaults["BanMessage"].(string) changed = true } if gcfg.DateTimeFormat == "" { @@ -341,10 +341,10 @@ type PostConfig struct { StickyRepliesOnBoardPage int `description:"Same as above for stickied threads."` BanColors []string - BanMsg string `description:"The default public ban message."` + BanMessage string `description:"The default public ban message."` EmbedWidth int `description:"The width for inline/expanded videos."` EmbedHeight int `description:"The height for inline/expanded videos."` - ExpandButton bool `description:"If checked, adds [Embed] after a Youtube, Vimeo, etc link to toggle an inline video frame."` + EnableEmbeds bool `description:"If checked, adds [Embed] after a Youtube, Vimeo, etc link to toggle an inline video frame."` ImagesOpenNewTab bool `description:"If checked, thumbnails will open the respective image/video in a new tab instead of expanding them." ` NewTabOnOutlinks bool `description:"If checked, links to external sites will open in a new tab."` DisableBBcode bool `description:"If checked, gochan will not compile bbcode into HTML"` diff --git a/pkg/config/jsonvars_test.go b/pkg/config/jsonvars_test.go index 85444a9a..a938faf4 100644 --- a/pkg/config/jsonvars_test.go +++ b/pkg/config/jsonvars_test.go @@ -87,10 +87,10 @@ const ( "PostsPerThreadPage": 50, "RepliesOnBoardPage": 3, "StickyRepliesOnBoardPage": 1, - "BanMsg": "USER WAS BANNED FOR THIS POST", + "BanMessage": "USER WAS BANNED FOR THIS POST", "EmbedWidth": 200, "EmbedHeight": 164, - "ExpandButton": true, + "EnableEmbeds": true, "ImagesOpenNewTab": true, "MakeURLsHyperlinked": true, "NewTabOnOutlinks": true, diff --git a/pkg/manage/actions.go b/pkg/manage/actions.go index 96300aa7..c54b31e5 100644 --- a/pkg/manage/actions.go +++ b/pkg/manage/actions.go @@ -209,7 +209,7 @@ var actions = map[string]Action{ // boardCfg.StickyRepliesOnBoardPage = StickyRepliesOnBoardPage // } - // boardCfg.BanMsg = request.PostFormValue("BanMsg") + // boardCfg.BanMessage = request.PostFormValue("BanMessage") // EmbedWidth, err := strconv.Atoi(request.PostFormValue("EmbedWidth")) // if err != nil { // status += err.Error() + "
" @@ -224,7 +224,7 @@ var actions = map[string]Action{ // boardCfg.EmbedHeight = EmbedHeight // } - // boardCfg.ExpandButton = (request.PostFormValue("ExpandButton") == "on") + // boardCfg.EnableEmbeds = (request.PostFormValue("EnableEmbeds") == "on") // boardCfg.ImagesOpenNewTab = (request.PostFormValue("ImagesOpenNewTab") == "on") // boardCfg.NewTabOnOutlinks = (request.PostFormValue("NewTabOnOutlinks") == "on") // boardCfg.DateTimeFormat = request.PostFormValue("DateTimeFormat") diff --git a/pkg/serverutil/antispam.go b/pkg/serverutil/antispam.go index e5937f44..8a86d87e 100644 --- a/pkg/serverutil/antispam.go +++ b/pkg/serverutil/antispam.go @@ -11,10 +11,15 @@ import ( "github.com/gochan-org/gochan/pkg/gclog" ) +var ( + ErrBlankAkismetKey = errors.New("blank Akismet key") + ErrInvalidAkismetKey = errors.New("invalid Akismet key") +) + // CheckAkismetAPIKey checks the validity of the Akismet API key given in the config file. func CheckAkismetAPIKey(key string) error { if key == "" { - return errors.New("blank key given, Akismet spam checking won't be used") + return ErrBlankAkismetKey } resp, err := http.PostForm("https://rest.akismet.com/1.1/verify-key", url.Values{"key": {key}, "blog": {"http://" + config.GetSystemCriticalConfig().SiteDomain}}) if err != nil { @@ -30,9 +35,7 @@ func CheckAkismetAPIKey(key string) error { } if string(body) == "invalid" { // This should disable the Akismet checks if the API key is not valid. - errmsg := "Akismet API key is invalid, Akismet spam protection will be disabled." - gclog.Print(gclog.LErrorLog, errmsg) - return errors.New(errmsg) + return ErrInvalidAkismetKey } return nil } diff --git a/sample-configs/gochan.example.json b/sample-configs/gochan.example.json index 7bdf0dcf..2b532688 100644 --- a/sample-configs/gochan.example.json +++ b/sample-configs/gochan.example.json @@ -68,10 +68,10 @@ "admin:#0000A0", "somemod:blue" ], - "BanMsg": "USER WAS BANNED FOR THIS POST", + "BanMessage": "USER WAS BANNED FOR THIS POST", + "EnableEmbeds": true, "EmbedWidth": 200, "EmbedHeight": 164, - "ExpandButton": true, "ImagesOpenNewTab": true, "NewTabOnOutlinks": true,