Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ COPY --from=0 /go/src/github.com/jamiefdhurst/journal/web web
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends --assume-yes libsqlite3-0

ENV GOPATH "/go"
ENV J_ARTICLES_PER_PAGE ""
ENV J_CREATE ""
ENV J_DB_PATH ""
ENV J_DESCRIPTION ""
ENV J_EDIT ""
ENV J_GA_CODE ""
ENV J_PORT ""
ENV J_POSTS_PER_PAGE ""
ENV J_THEME ""
ENV J_TITLE ""

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.test
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
FROM golang:1.22-bookworm
LABEL org.opencontainers.image.source=https://github.com/jamiefdhurst/journal

ENV J_ARTICLES_PER_PAGE ""
ENV J_CREATE ""
ENV J_DB_PATH ""
ENV J_DESCRIPTION ""
ENV J_EDIT ""
ENV J_GA_CODE ""
ENV J_PORT ""
ENV J_POSTS_PER_PAGE ""
ENV J_THEME ""
ENV J_TITLE ""

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ any additional environment variables.

### General Configuration

* `J_ARTICLES_PER_PAGE` - Articles to display per page, default `20`
* `J_CREATE` - Set to `0` to disable article creation
* `J_CREATE` - Set to `0` to disable post creation
* `J_DB_PATH` - Path to SQLite DB - default is `$GOPATH/data/journal.db`
* `J_DESCRIPTION` - Set the HTML description of the Journal
* `J_EDIT` - Set to `0` to disable article modification
* `J_EXCERPT_WORDS` - The length of the article shown as a preview/excerpt in the index, default `50`
* `J_EDIT` - Set to `0` to disable post modification
* `J_EXCERPT_WORDS` - The length of the post shown as a preview/excerpt in the index, default `50`
* `J_GA_CODE` - Google Analytics tag value, starts with `UA-`, or ignore to disable Google Analytics
* `J_PORT` - Port to expose over HTTP, default is `3000`
* `J_POSTS_PER_PAGE` - Posts to display per page, default `20`
* `J_THEME` - Theme to use from within the _web/themes_ folder, defaults to `default`
* `J_TITLE` - Set the title of the Journal

Expand Down
53 changes: 27 additions & 26 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ type Container struct {

// Configuration can be modified through environment variables
type Configuration struct {
ArticlesPerPage int
DatabasePath string
Description string
EnableCreate bool
EnableEdit bool
ExcerptWords int
GoogleAnalyticsCode string
Port string
PostsPerPage int
SSLCertificate string
SSLKey string
StaticPath string
Expand All @@ -61,20 +61,20 @@ type Configuration struct {
// DefaultConfiguration returns the default settings for the app
func DefaultConfiguration() Configuration {
return Configuration{
ArticlesPerPage: 20,
DatabasePath: os.Getenv("GOPATH") + "/data/journal.db",
Description: "A private journal containing Jamie's innermost thoughts",
Description: "A fantastic journal containing some thoughts, ideas and reflections",
EnableCreate: true,
EnableEdit: true,
ExcerptWords: 50,
GoogleAnalyticsCode: "",
Port: "3000",
PostsPerPage: 20,
SSLCertificate: "",
SSLKey: "",
StaticPath: "web/static",
Theme: "default",
ThemePath: "web/themes",
Title: "Jamie's Journal",
Title: "A Fantastic Journal",
SessionKey: "",
SessionName: "journal-session",
CookieDomain: "",
Expand All @@ -99,9 +99,14 @@ func ApplyEnvConfiguration(config *Configuration) {
return dotenvVars[key]
}

// J_ARTICLES_PER_PAGE is deprecated, but it's checked first
articles, _ := strconv.Atoi(getEnv("J_ARTICLES_PER_PAGE"))
if articles > 0 {
config.ArticlesPerPage = articles
config.PostsPerPage = articles
}
posts, _ := strconv.Atoi(getEnv("J_POSTS_PER_PAGE"))
if posts > 0 {
config.PostsPerPage = posts
}
database := getEnv("J_DB_PATH")
if database != "" {
Expand All @@ -128,8 +133,25 @@ func ApplyEnvConfiguration(config *Configuration) {
if port != "" {
config.Port = port
}

config.SSLCertificate = getEnv("J_SSL_CERT")
config.SSLKey = getEnv("J_SSL_KEY")
staticPath := getEnv("J_STATIC_PATH")
if staticPath != "" {
config.StaticPath = staticPath
}
theme := getEnv("J_THEME")
if theme != "" {
config.Theme = theme
}
themePath := getEnv("J_THEME_PATH")
if themePath != "" {
config.ThemePath = themePath
}
title := getEnv("J_TITLE")
if title != "" {
config.Title = title
}

sessionKey := getEnv("J_SESSION_KEY")
if sessionKey != "" {
Expand All @@ -151,40 +173,19 @@ func ApplyEnvConfiguration(config *Configuration) {
if sessionName != "" {
config.SessionName = sessionName
}

cookieDomain := getEnv("J_COOKIE_DOMAIN")
if cookieDomain != "" {
config.CookieDomain = cookieDomain
}

cookieMaxAge, _ := strconv.Atoi(getEnv("J_COOKIE_MAX_AGE"))
if cookieMaxAge > 0 {
config.CookieMaxAge = cookieMaxAge
}

cookieHTTPOnly := getEnv("J_COOKIE_HTTPONLY")
if cookieHTTPOnly == "0" || cookieHTTPOnly == "false" {
config.CookieHTTPOnly = false
}

if config.SSLCertificate != "" {
config.CookieSecure = true
}

staticPath := getEnv("J_STATIC_PATH")
if staticPath != "" {
config.StaticPath = staticPath
}
theme := getEnv("J_THEME")
if theme != "" {
config.Theme = theme
}
themePath := getEnv("J_THEME_PATH")
if themePath != "" {
config.ThemePath = themePath
}
title := getEnv("J_TITLE")
if title != "" {
config.Title = title
}
}
36 changes: 31 additions & 5 deletions internal/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import (
func TestDefaultConfiguration(t *testing.T) {
config := DefaultConfiguration()

if config.ArticlesPerPage != 20 {
t.Errorf("Expected ArticlesPerPage 20, got %d", config.ArticlesPerPage)
}
if config.Port != "3000" {
t.Errorf("Expected Port '3000', got %q", config.Port)
}
if config.PostsPerPage != 20 {
t.Errorf("Expected PostsPerPage 20, got %d", config.PostsPerPage)
}
if config.SessionName != "journal-session" {
t.Errorf("Expected SessionName 'journal-session', got %q", config.SessionName)
}
Expand Down Expand Up @@ -389,8 +389,8 @@ J_COOKIE_MAX_AGE=3600
if config.Description != "A test journal" {
t.Errorf("Expected Description 'A test journal' from .env, got %q", config.Description)
}
if config.ArticlesPerPage != 15 {
t.Errorf("Expected ArticlesPerPage 15 from .env, got %d", config.ArticlesPerPage)
if config.PostsPerPage != 15 {
t.Errorf("Expected PostsPerPage 15 from .env, got %d", config.PostsPerPage)
}
if config.CookieMaxAge != 3600 {
t.Errorf("Expected CookieMaxAge 3600 from .env, got %d", config.CookieMaxAge)
Expand Down Expand Up @@ -455,3 +455,29 @@ func TestApplyEnvConfiguration_NoDotEnvFile(t *testing.T) {
t.Errorf("Expected default Port '3000', got %q", config.Port)
}
}

func TestApplyEnvConfiguration_ArticlesDeprecated(t *testing.T) {
// Save current working directory
originalWd, _ := os.Getwd()
defer os.Chdir(originalWd)

// Create a temporary directory for testing
tmpDir := t.TempDir()
os.Chdir(tmpDir)

// Create a .env file
envContent := `
J_POSTS_PER_PAGE=15
J_ARTICLES_PER_PAGE=10
`
if err := os.WriteFile(filepath.Join(tmpDir, ".env"), []byte(envContent), 0644); err != nil {
t.Fatalf("Failed to create .env file: %v", err)
}

config := DefaultConfiguration()
ApplyEnvConfiguration(&config)

if config.PostsPerPage != 15 {
t.Errorf("Expected PostsPerPage 15 from .env, got %d", config.PostsPerPage)
}
}
2 changes: 1 addition & 1 deletion internal/app/controller/apiv1/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type List struct {
}

func ListData(request *http.Request, js model.Journals) ([]model.Journal, database.PaginationInformation) {
paginationQuery := database.PaginationQuery{Page: 1, ResultsPerPage: js.Container.Configuration.ArticlesPerPage}
paginationQuery := database.PaginationQuery{Page: 1, ResultsPerPage: js.Container.Configuration.PostsPerPage}
query := request.URL.Query()
if query["page"] != nil {
page, err := strconv.Atoi(query["page"][0])
Expand Down
4 changes: 2 additions & 2 deletions internal/app/controller/apiv1/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type statsConfigJSON struct {
Title string `json:"title"`
Description string `json:"description"`
Theme string `json:"theme"`
ArticlesPerPage int `json:"posts_per_page"`
PostsPerPage int `json:"posts_per_page"`
GoogleAnalytics bool `json:"google_analytics"`
CreateEnabled bool `json:"create_enabled"`
EditEnabled bool `json:"edit_enabled"`
Expand All @@ -58,7 +58,7 @@ func (c *Stats) Run(response http.ResponseWriter, request *http.Request) {
stats.Configuration.Title = container.Configuration.Title
stats.Configuration.Description = container.Configuration.Description
stats.Configuration.Theme = container.Configuration.Theme
stats.Configuration.ArticlesPerPage = container.Configuration.ArticlesPerPage
stats.Configuration.PostsPerPage = container.Configuration.PostsPerPage
stats.Configuration.GoogleAnalytics = container.Configuration.GoogleAnalyticsCode != ""
stats.Configuration.CreateEnabled = container.Configuration.EnableCreate
stats.Configuration.EditEnabled = container.Configuration.EnableEdit
Expand Down
4 changes: 2 additions & 2 deletions internal/app/controller/apiv1/stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
func TestStats_Run(t *testing.T) {
db := &database.MockSqlite{}
configuration := app.DefaultConfiguration()
configuration.ArticlesPerPage = 25 // Custom setting
configuration.PostsPerPage = 25 // Custom setting
configuration.GoogleAnalyticsCode = "UA-123456" // Custom GA code
container := &app.Container{Configuration: configuration, Db: db}
response := &controller.MockResponse{}
Expand All @@ -38,7 +38,7 @@ func TestStats_Run(t *testing.T) {
t.Errorf("Expected post count to be 2, got response %s", response.Content)
}
if !strings.Contains(response.Content, "posts_per_page\":25,") {
t.Errorf("Expected articles per page to be 25, got response %s", response.Content)
t.Errorf("Expected posts per page to be 25, got response %s", response.Content)
}
if !strings.Contains(response.Content, "google_analytics\":true") {
t.Error("Expected Google Analytics to be enabled")
Expand Down
2 changes: 1 addition & 1 deletion internal/app/controller/web/badrequest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestError_Run(t *testing.T) {
if response.StatusCode != 404 || !strings.Contains(response.Content, "Page Not Found") {
t.Error("Expected 404 error when journal not found")
}
if !strings.Contains(response.Content, "<title>Page Not Found - Jamie's Journal</title>") {
if !strings.Contains(response.Content, "<title>Page Not Found - A Fantastic Journal</title>") {
t.Error("Expected HTML title to be in place")
}

Expand Down
2 changes: 1 addition & 1 deletion internal/app/controller/web/edit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestEdit_Run(t *testing.T) {
if strings.Contains(response.Content, "div class=\"error\"") {
t.Error("Expected no error to be shown in form")
}
if !strings.Contains(response.Content, "<title>Edit Title - Jamie's Journal</title>") {
if !strings.Contains(response.Content, "<title>Edit Title - A Fantastic Journal</title>") {
t.Error("Expected HTML title to be in place")
}

Expand Down
6 changes: 3 additions & 3 deletions internal/app/controller/web/index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func init() {
func TestIndex_Run(t *testing.T) {
db := &database.MockSqlite{}
configuration := app.DefaultConfiguration()
configuration.ArticlesPerPage = 2
configuration.PostsPerPage = 2
configuration.SessionKey = "12345678901234567890123456789012"
container := &app.Container{Configuration: configuration, Db: db}
response := controller.NewMockResponse()
Expand All @@ -42,10 +42,10 @@ func TestIndex_Run(t *testing.T) {
if !strings.Contains(response.Content, "Title 2") {
t.Error("Expected all journals to be displayed on screen")
}
if !strings.Contains(response.Content, "<title>Jamie's Journal</title>") {
if !strings.Contains(response.Content, "<title>A Fantastic Journal</title>") {
t.Error("Expected default HTML title to be in place")
}
if !strings.Contains(response.Content, "<meta name=\"description\" content=\"A private journal") {
if !strings.Contains(response.Content, "<meta name=\"description\" content=\"A fantastic journal") {
t.Error("Expected default HTML description to be in place")
}

Expand Down
2 changes: 1 addition & 1 deletion internal/app/controller/web/new_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestNew_Run(t *testing.T) {
if !strings.Contains(response.Content, "<form") {
t.Error("Expected form to be shown")
}
if !strings.Contains(response.Content, "<title>Create New Post - Jamie's Journal</title>") {
if !strings.Contains(response.Content, "<title>Create New Post - A Fantastic Journal</title>") {
t.Error("Expected HTML title to be in place")
}

Expand Down
26 changes: 13 additions & 13 deletions internal/app/controller/web/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ type Stats struct {
}

type statsTemplateData struct {
Container *app.Container
PostCount int
FirstPostDate string
TitleSet bool
DescriptionSet bool
ThemeSet bool
ArticlesPerPage int
GACodeSet bool
CreateEnabled bool
EditEnabled bool
DailyVisits []model.DailyVisit
MonthlyVisits []model.MonthlyVisit
Container *app.Container
PostCount int
FirstPostDate string
TitleSet bool
DescriptionSet bool
ThemeSet bool
PostsPerPage int
GACodeSet bool
CreateEnabled bool
EditEnabled bool
DailyVisits []model.DailyVisit
MonthlyVisits []model.MonthlyVisit
}

// Run Stats action
Expand All @@ -52,7 +52,7 @@ func (c *Stats) Run(response http.ResponseWriter, request *http.Request) {
data.TitleSet = container.Configuration.Title != defaultConfig.Title
data.DescriptionSet = container.Configuration.Description != defaultConfig.Description
data.ThemeSet = container.Configuration.Theme != defaultConfig.Theme
data.ArticlesPerPage = container.Configuration.ArticlesPerPage
data.PostsPerPage = container.Configuration.PostsPerPage
data.GACodeSet = container.Configuration.GoogleAnalyticsCode != ""
data.CreateEnabled = container.Configuration.EnableCreate
data.EditEnabled = container.Configuration.EnableEdit
Expand Down
4 changes: 2 additions & 2 deletions internal/app/controller/web/stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
func TestStats_Run(t *testing.T) {
db := &database.MockSqlite{}
configuration := app.DefaultConfiguration()
configuration.ArticlesPerPage = 25
configuration.PostsPerPage = 25
configuration.GoogleAnalyticsCode = "UA-123456"
container := &app.Container{Configuration: configuration, Db: db}
response := controller.NewMockResponse()
Expand All @@ -39,7 +39,7 @@ func TestStats_Run(t *testing.T) {
}

if !strings.Contains(response.Content, "<dt>Posts Per Page</dt>\n <dd>25</dd>") {
t.Error("Expected custom articles per page setting to be displayed")
t.Error("Expected custom posts per page setting to be displayed")
}

if !strings.Contains(response.Content, "<dt>Google Analytics</dt>\n <dd>Enabled</dd>") {
Expand Down
2 changes: 1 addition & 1 deletion internal/app/controller/web/view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestView_Run(t *testing.T) {
if strings.Contains(response.Content, "div class=\"error\"") || !strings.Contains(response.Content, "Content") {
t.Error("Expected no error to be shown in page")
}
if !strings.Contains(response.Content, "<title>Title - Jamie's Journal</title>") {
if !strings.Contains(response.Content, "<title>Title - A Fantastic Journal</title>") {
t.Error("Expected HTML title to be in place")
}

Expand Down
Loading