feat: system api with profiles

pull/42/head
email 3 years ago
parent 4f88221bce
commit b3a431570c

@ -0,0 +1,38 @@
name: build-and-push-docker-image
on:
push:
branches:
# Run on pushing branches like `release/1.0.0`
- "release/v*.*.*"
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Extract build args
# Extract version from branch name
# Example: branch name `release/v1.0.0` sets up env.VERSION=1.0.0
run: |
echo "VERSION=${GITHUB_REF_NAME#release/v}" >> $GITHUB_ENV
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_NEOSMEMO_USERNAME }}
password: ${{ secrets.DOCKER_NEOSMEMO_TOKEN }}
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
- name: Build and Push
id: docker_build
uses: docker/build-push-action@v2
with:
context: ./
file: ./Dockerfile
push: true
tags: ${{ secrets.DOCKER_NEOSMEMO_USERNAME }}/memos:${{ env.VERSION }}

@ -4,40 +4,28 @@ import (
"fmt" "fmt"
"os" "os"
"memos/common"
"memos/server" "memos/server"
"memos/store" "memos/store"
) )
type Main struct { type Main struct {
profile *Profile profile *common.Profile
server *server.Server server *server.Server
db *store.DB db *store.DB
} }
func Execute() {
m := Main{}
profile := GetProfile()
m.profile = &profile
err := m.Run()
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
}
func (m *Main) Run() error { func (m *Main) Run() error {
db := store.NewDB(m.profile.dsn, m.profile.mode) db := store.NewDB(m.profile)
if err := db.Open(); err != nil { if err := db.Open(); err != nil {
return fmt.Errorf("cannot open db: %w", err) return fmt.Errorf("cannot open db: %w", err)
} }
m.db = db m.db = db
s := server.NewServer(m.profile.port, m.profile.mode) s := server.NewServer(m.profile)
s.ShortcutService = store.NewShortcutService(db) s.ShortcutService = store.NewShortcutService(db)
s.MemoService = store.NewMemoService(db) s.MemoService = store.NewMemoService(db)
@ -53,3 +41,16 @@ func (m *Main) Run() error {
return nil return nil
} }
func Execute() {
profile := common.GetProfile()
m := Main{
profile: &profile,
}
err := m.Run()
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
}

@ -1,4 +1,4 @@
package cmd package common
import ( import (
"fmt" "fmt"
@ -9,12 +9,12 @@ import (
) )
type Profile struct { type Profile struct {
// mode can be "release" or "dev" // Mode can be "release" or "dev"
mode string Mode string `json:"mode"`
// port is the binding port for server. // Port is the binding port for server.
port int Port int `json:"port"`
// dsn points to where Memos stores its own data // DSN points to where Memos stores its own data
dsn string DSN string `json:"-"`
} }
func checkDSN(dataDir string) (string, error) { func checkDSN(dataDir string) (string, error) {
@ -61,8 +61,8 @@ func GetProfile() Profile {
dsn := fmt.Sprintf("file:%s/memos_%s.db", dataDir, mode) dsn := fmt.Sprintf("file:%s/memos_%s.db", dataDir, mode)
return Profile{ return Profile{
mode: mode, Mode: mode,
port: port, Port: port,
dsn: dsn, DSN: dsn,
} }
} }

@ -3,6 +3,7 @@ package server
import ( import (
"fmt" "fmt"
"memos/api" "memos/api"
"memos/common"
"time" "time"
"github.com/gorilla/securecookie" "github.com/gorilla/securecookie"
@ -15,15 +16,15 @@ import (
type Server struct { type Server struct {
e *echo.Echo e *echo.Echo
Profile *common.Profile
UserService api.UserService UserService api.UserService
MemoService api.MemoService MemoService api.MemoService
ShortcutService api.ShortcutService ShortcutService api.ShortcutService
ResourceService api.ResourceService ResourceService api.ResourceService
port int
} }
func NewServer(port int, mode string) *Server { func NewServer(profile *common.Profile) *Server {
e := echo.New() e := echo.New()
e.Debug = true e.Debug = true
e.HideBanner = true e.HideBanner = true
@ -46,17 +47,19 @@ func NewServer(port int, mode string) *Server {
HTML5: true, HTML5: true,
})) }))
// In dev mode, set the const secret key to make login session persistence.
secret := []byte("justmemos") secret := []byte("justmemos")
if mode != "dev" { if profile.Mode == "release" {
secret = securecookie.GenerateRandomKey(16) secret = securecookie.GenerateRandomKey(16)
} }
e.Use(session.Middleware(sessions.NewCookieStore(secret))) e.Use(session.Middleware(sessions.NewCookieStore(secret)))
s := &Server{ s := &Server{
e: e, e: e,
port: port, Profile: profile,
} }
// Webhooks api skips auth checker.
webhookGroup := e.Group("/h") webhookGroup := e.Group("/h")
s.registerWebhookRoutes(webhookGroup) s.registerWebhookRoutes(webhookGroup)
@ -64,6 +67,7 @@ func NewServer(port int, mode string) *Server {
apiGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc { apiGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return BasicAuthMiddleware(s.UserService, next) return BasicAuthMiddleware(s.UserService, next)
}) })
s.registerSystemRoutes(apiGroup)
s.registerAuthRoutes(apiGroup) s.registerAuthRoutes(apiGroup)
s.registerUserRoutes(apiGroup) s.registerUserRoutes(apiGroup)
s.registerMemoRoutes(apiGroup) s.registerMemoRoutes(apiGroup)
@ -74,5 +78,5 @@ func NewServer(port int, mode string) *Server {
} }
func (server *Server) Run() error { func (server *Server) Run() error {
return server.e.Start(fmt.Sprintf(":%d", server.port)) return server.e.Start(fmt.Sprintf(":%d", server.Profile.Port))
} }

@ -0,0 +1,19 @@
package server
import (
"encoding/json"
"net/http"
"github.com/labstack/echo/v4"
)
func (s *Server) registerSystemRoutes(g *echo.Group) {
g.GET("/ping", func(c echo.Context) error {
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(s.Profile)); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to compose system profile").SetInternal(err)
}
return nil
})
}

@ -36,7 +36,7 @@ CREATE TABLE memo (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
-- allowed row status are 'NORMAL', 'HIDDEN'. -- allowed row status are 'NORMAL', 'PINNED', 'HIDDEN'.
row_status TEXT NOT NULL DEFAULT 'NORMAL', row_status TEXT NOT NULL DEFAULT 'NORMAL',
content TEXT NOT NULL DEFAULT '', content TEXT NOT NULL DEFAULT '',
creator_id INTEGER NOT NULL, creator_id INTEGER NOT NULL,
@ -69,7 +69,7 @@ CREATE TABLE shortcut (
title TEXT NOT NULL DEFAULT '', title TEXT NOT NULL DEFAULT '',
payload TEXT NOT NULL DEFAULT '', payload TEXT NOT NULL DEFAULT '',
creator_id INTEGER NOT NULL, creator_id INTEGER NOT NULL,
-- allowed row status are 'NORMAL', 'ARCHIVED'. -- allowed row status are 'NORMAL', 'PINNED'.
row_status TEXT NOT NULL DEFAULT 'NORMAL', row_status TEXT NOT NULL DEFAULT 'NORMAL',
FOREIGN KEY(creator_id) REFERENCES users(id) FOREIGN KEY(creator_id) REFERENCES users(id)
); );

@ -1,4 +1,10 @@
INSERT INTO memo INSERT INTO
(`content`, `creator_id`) memo (
`content`,
`creator_id`
)
VALUES VALUES
('👋 Welcome to memos', 101); (
'#memos 👋 Welcome to memos',
101
);

@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/fs" "io/fs"
"memos/common"
"sort" "sort"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
@ -19,18 +20,17 @@ var seedFS embed.FS
type DB struct { type DB struct {
Db *sql.DB Db *sql.DB
// datasource name // datasource name
DSN string DSN string
// mode: release or dev // mode should be release or dev
mode string mode string
} }
// NewDB returns a new instance of DB associated with the given datasource name. // NewDB returns a new instance of DB associated with the given datasource name.
func NewDB(dsn string, mode string) *DB { func NewDB(profile *common.Profile) *DB {
db := &DB{ db := &DB{
DSN: dsn, DSN: profile.DSN,
mode: mode, mode: profile.Mode,
} }
return db return db
} }

Loading…
Cancel
Save