Skip to content

Commit

Permalink
Merge branch 'master' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixDz committed Apr 14, 2021
2 parents 12f9ad4 + 620271b commit ca19c59
Show file tree
Hide file tree
Showing 76 changed files with 4,070 additions and 1,379 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: goreleaser

on:
push:
tags:
- "v*" # Will trigger only if tag is pushed matching pattern `v*` (Eg: `v0.1.0`)

jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.16

- name: Login to Docker Registry
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Prepare Dependencies
run: |
make deps
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: --parallelism 1 --rm-dist --skip-validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dockers:
-
goos: linux
goarch: amd64
binaries:
ids:
- listmonk
image_templates:
- "listmonk/listmonk:latest"
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ COPY listmonk .
COPY config.toml.sample config.toml
COPY config-demo.toml .
CMD ["./listmonk"]
EXPOSE 9000
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ deps:
# Build the backend to ./listmonk.
.PHONY: build
build:
go build -o ${BIN} -ldflags="-s -w -X 'main.buildString=${BUILDSTR}' -X 'main.versionString=${VERSION}'" cmd/*.go
CGO_ENABLED=0 go build -o ${BIN} -ldflags="-s -w -X 'main.buildString=${BUILDSTR}' -X 'main.versionString=${VERSION}'" cmd/*.go

# Run the backend.
.PHONY: run
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ Visit [listmonk.app](https://listmonk.app)
The latest image is available on DockerHub at `listmonk/listmonk:latest`. Use the sample [docker-compose.yml](https://github.com/knadh/listmonk/blob/master/docker-compose.yml) to run listmonk and Postgres DB with docker-compose as follows:

#### Demo
`docker-compose up -d demo-db demo-app`

```bash
mkdir listmonk-demo
sh -c "$(curl -sSL https://raw.githubusercontent.com/knadh/listmonk/master/install-demo.sh)"
```

The demo does not persist Postgres after the containers are removed. DO NOT use this demo setup in production.

Expand Down
48 changes: 12 additions & 36 deletions cmd/admin.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"sort"
Expand All @@ -13,41 +11,29 @@ import (
"github.com/labstack/echo"
)

type configScript struct {
RootURL string `json:"rootURL"`
FromEmail string `json:"fromEmail"`
Messengers []string `json:"messengers"`
MediaProvider string `json:"mediaProvider"`
NeedsRestart bool `json:"needsRestart"`
Update *AppUpdate `json:"update"`
Langs []i18nLang `json:"langs"`
EnablePublicSubPage bool `json:"enablePublicSubscriptionPage"`
Lang json.RawMessage `json:"lang"`
type serverConfig struct {
Messengers []string `json:"messengers"`
Langs []i18nLang `json:"langs"`
Lang string `json:"lang"`
Update *AppUpdate `json:"update"`
NeedsRestart bool `json:"needs_restart"`
}

// handleGetConfigScript returns general configuration as a Javascript
// variable that can be included in an HTML page directly.
func handleGetConfigScript(c echo.Context) error {
// handleGetServerConfig returns general server config.
func handleGetServerConfig(c echo.Context) error {
var (
app = c.Get("app").(*App)
out = configScript{
RootURL: app.constants.RootURL,
FromEmail: app.constants.FromEmail,
MediaProvider: app.constants.MediaProvider,
EnablePublicSubPage: app.constants.EnablePublicSubPage,
}
out = serverConfig{}
)

// Language list.
langList, err := geti18nLangList(app.constants.Lang, app)
langList, err := getI18nLangList(app.constants.Lang, app)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError,
fmt.Sprintf("Error loading language list: %v", err))
}
out.Langs = langList

// Current language.
out.Lang = json.RawMessage(app.i18n.JSON())
out.Lang = app.constants.Lang

// Sort messenger names with `email` always as the first item.
var names []string
Expand All @@ -66,17 +52,7 @@ func handleGetConfigScript(c echo.Context) error {
out.Update = app.update
app.Unlock()

// Write the Javascript variable opening;
b := bytes.Buffer{}
b.Write([]byte(`var CONFIG = `))

// Encode the config payload as JSON and write as the variable's value assignment.
j := json.NewEncoder(&b)
if err := j.Encode(out); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError,
app.i18n.Ts("admin.errorMarshallingConfig", "error", err.Error()))
}
return c.Blob(http.StatusOK, "application/javascript; charset=utf-8", b.Bytes())
return c.JSON(http.StatusOK, okResp{out})
}

// handleGetDashboardCharts returns chart data points to render ont he dashboard.
Expand Down
21 changes: 10 additions & 11 deletions cmd/campaigns.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,14 @@ func handlePreviewCampaign(c echo.Context) error {
var (
app = c.Get("app").(*App)
id, _ = strconv.Atoi(c.Param("id"))
body = c.FormValue("body")

camp = &models.Campaign{}
)

if id < 1 {
return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("globals.messages.invalidID"))
}

err := app.queries.GetCampaignForPreview.Get(camp, id)
var camp models.Campaign
err := app.queries.GetCampaignForPreview.Get(&camp, id)
if err != nil {
if err == sql.ErrNoRows {
return echo.NewHTTPError(http.StatusBadRequest,
Expand All @@ -177,6 +175,12 @@ func handlePreviewCampaign(c echo.Context) error {
"name", "{globals.terms.campaign}", "error", pqErrMsg(err)))
}

// There's a body in the request to preview instead of the body in the DB.
if c.Request().Method == http.MethodPost {
camp.ContentType = c.FormValue("content_type")
camp.Body = c.FormValue("body")
}

var sub models.Subscriber
// Get a random subscriber from the campaign.
if err := app.queries.GetOneCampaignSubscriber.Get(&sub, camp.ID); err != nil {
Expand All @@ -191,19 +195,14 @@ func handlePreviewCampaign(c echo.Context) error {
}
}

// Compile the template.
if body != "" {
camp.Body = body
}

if err := camp.CompileTemplate(app.manager.TemplateFuncs(camp)); err != nil {
if err := camp.CompileTemplate(app.manager.TemplateFuncs(&camp)); err != nil {
app.log.Printf("error compiling template: %v", err)
return echo.NewHTTPError(http.StatusBadRequest,
app.i18n.Ts("templates.errorCompiling", "error", err.Error()))
}

// Render the message body.
m := app.manager.NewCampaignMessage(camp, sub)
m := app.manager.NewCampaignMessage(&camp, sub)
if err := m.Render(); err != nil {
app.log.Printf("error rendering message: %v", err)
return echo.NewHTTPError(http.StatusBadRequest,
Expand Down
35 changes: 12 additions & 23 deletions cmd/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package main

import (
"crypto/subtle"
"encoding/json"
"fmt"
"net/http"
"net/url"
"regexp"
Expand Down Expand Up @@ -39,13 +37,21 @@ var (
)

// registerHandlers registers HTTP handlers.
func registerHTTPHandlers(e *echo.Echo) {
func registerHTTPHandlers(e *echo.Echo, app *App) {
// Group of private handlers with BasicAuth.
g := e.Group("", middleware.BasicAuth(basicAuth))
var g *echo.Group

if len(app.constants.AdminUsername) == 0 ||
len(app.constants.AdminPassword) == 0 {
g = e.Group("")
} else {
g = e.Group("", middleware.BasicAuth(basicAuth))
}

g.GET("/", handleIndexPage)
g.GET("/api/health", handleHealthCheck)
g.GET("/api/config.js", handleGetConfigScript)
g.GET("/api/lang/:lang", handleLoadLanguage)
g.GET("/api/config", handleGetServerConfig)
g.GET("/api/lang/:lang", handleGetI18nLang)
g.GET("/api/dashboard/charts", handleGetDashboardCharts)
g.GET("/api/dashboard/counts", handleGetDashboardCounts)

Expand Down Expand Up @@ -164,23 +170,6 @@ func handleHealthCheck(c echo.Context) error {
return c.JSON(http.StatusOK, okResp{true})
}

// handleLoadLanguage returns the JSON language pack given the language code.
func handleLoadLanguage(c echo.Context) error {
app := c.Get("app").(*App)

lang := c.Param("lang")
if len(lang) > 6 || reLangCode.MatchString(lang) {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid language code.")
}

b, err := app.fs.Read(fmt.Sprintf("/lang/%s.json", lang))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Unknown language.")
}

return c.JSON(http.StatusOK, okResp{json.RawMessage(b)})
}

// basicAuth middleware does an HTTP BasicAuth authentication for admin handlers.
func basicAuth(username, password string, c echo.Context) (bool, error) {
app := c.Get("app").(*App)
Expand Down
53 changes: 51 additions & 2 deletions cmd/i18n.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package main
import (
"encoding/json"
"fmt"
"net/http"

"github.com/knadh/listmonk/internal/i18n"
"github.com/knadh/stuffbin"
"github.com/labstack/echo"
)

type i18nLang struct {
Expand All @@ -15,8 +20,25 @@ type i18nLangRaw struct {
Name string `json:"_.name"`
}

// geti18nLangList returns the list of available i18n languages.
func geti18nLangList(lang string, app *App) ([]i18nLang, error) {
// handleGetI18nLang returns the JSON language pack given the language code.
func handleGetI18nLang(c echo.Context) error {
app := c.Get("app").(*App)

lang := c.Param("lang")
if len(lang) > 6 || reLangCode.MatchString(lang) {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid language code.")
}

i, err := getI18nLang(lang, app.fs)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Unknown language.")
}

return c.JSON(http.StatusOK, okResp{json.RawMessage(i.JSON())})
}

// getI18nLangList returns the list of available i18n languages.
func getI18nLangList(lang string, app *App) ([]i18nLang, error) {
list, err := app.fs.Glob("/i18n/*.json")
if err != nil {
return nil, err
Expand All @@ -42,3 +64,30 @@ func geti18nLangList(lang string, app *App) ([]i18nLang, error) {

return out, nil
}

func getI18nLang(lang string, fs stuffbin.FileSystem) (*i18n.I18n, error) {
const def = "en"

b, err := fs.Read(fmt.Sprintf("/i18n/%s.json", def))
if err != nil {
return nil, fmt.Errorf("error reading default i18n language file: %s: %v", def, err)
}

// Initialize with the default language.
i, err := i18n.New(b)
if err != nil {
return nil, fmt.Errorf("error unmarshalling i18n language: %v", err)
}

// Load the selected language on top of it.
b, err = fs.Read(fmt.Sprintf("/i18n/%s.json", lang))
if err != nil {
return nil, fmt.Errorf("error reading i18n language file: %v", err)
}

if err := i.Load(b); err != nil {
return nil, fmt.Errorf("error loading i18n language file: %v", err)
}

return i, nil
}
24 changes: 3 additions & 21 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,28 +262,10 @@ func initConstants() *constants {
// and then the selected language is loaded on top of it so that if there are
// missing translations in it, the default English translations show up.
func initI18n(lang string, fs stuffbin.FileSystem) *i18n.I18n {
const def = "en"

b, err := fs.Read(fmt.Sprintf("/i18n/%s.json", def))
i, err := getI18nLang(lang, fs)
if err != nil {
lo.Fatalf("error reading default i18n language file: %s: %v", def, err)
lo.Fatal(err)
}

// Initialize with the default language.
i, err := i18n.New(b)
if err != nil {
lo.Fatalf("error unmarshalling i18n language: %v", err)
}

// Load the selected language on top of it.
b, err = fs.Read(fmt.Sprintf("/i18n/%s.json", lang))
if err != nil {
lo.Fatalf("error reading i18n language file: %v", err)
}
if err := i.Load(b); err != nil {
lo.Fatalf("error loading i18n language file: %v", err)
}

return i
}

Expand Down Expand Up @@ -505,7 +487,7 @@ func initHTTPServer(app *App) *echo.Echo {
}

// Register all HTTP handlers.
registerHTTPHandlers(srv)
registerHTTPHandlers(srv, app)

// Start the server.
go func() {
Expand Down
Loading

0 comments on commit ca19c59

Please sign in to comment.