Skip to content
Draft
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
64 changes: 53 additions & 11 deletions cmd/leafwiki/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"flag"
"fmt"
"log"
"log/slog"
"os"
"strings"
"time"
Expand All @@ -20,6 +20,7 @@ func printUsage() {
leafwiki --jwt-secret <SECRET> --admin-password <PASSWORD> [--host <HOST>] [--port <PORT>] [--data-dir <DIR>]
leafwiki --disable-auth [--host <HOST>] [--port <PORT>] [--data-dir <DIR>]
leafwiki reset-admin-password
leafwiki [--data-dir <DIR>] reconstruct-tree
leafwiki --help

Options:
Expand All @@ -42,6 +43,7 @@ func printUsage() {
LEAFWIKI_PORT
LEAFWIKI_DATA_DIR
LEAFWIKI_JWT_SECRET
LEAFWIKI_LOG_LEVEL
LEAFWIKI_ADMIN_PASSWORD
LEAFWIKI_PUBLIC_ACCESS
LEAFWIKI_ALLOW_INSECURE
Expand All @@ -53,7 +55,31 @@ func printUsage() {
`)
}

func setupLogger() {
level := slog.LevelInfo
if os.Getenv("LEAFWIKI_LOG_LEVEL") == "debug" {
level = slog.LevelDebug
} else if (os.Getenv("LEAFWIKI_LOG_LEVEL")) == "error" {
level = slog.LevelError
} else if (os.Getenv("LEAFWIKI_LOG_LEVEL")) == "warn" {
level = slog.LevelWarn
}

handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: level,
AddSource: true,
})

slog.SetDefault(slog.New(handler))
}

func fail(msg string, args ...any) {
slog.Default().Error(msg, args...)
os.Exit(1)
}

func main() {
setupLogger()

// flags
hostFlag := flag.String("host", "", "host/IP address to bind the server to (e.g. 127.0.0.1 or 0.0.0.0)")
Expand Down Expand Up @@ -94,12 +120,28 @@ func main() {
case "reset-admin-password":
user, err := tools.ResetAdminPassword(dataDir)
if err != nil {
log.Fatalf("Password reset failed: %v", err)
fail("Password reset failed", "error", err)
}

fmt.Println("Admin password reset successfully.")
fmt.Printf("New password for user %s: %s\n", user.Username, user.Password)
return
case "reconstruct-tree":
// Ensure data directory exists before reconstruction
if _, err := os.Stat(dataDir); err != nil {
if os.IsNotExist(err) {
if err := os.MkdirAll(dataDir, 0755); err != nil {
fail("Failed to create data directory", "error", err)
}
} else {
fail("Failed to access data directory", "error", err)
}
}
if err := tools.ReconstructTreeFromFS(dataDir); err != nil {
fail("Tree reconstruction failed", "error", err)
}
fmt.Println("Tree reconstructed successfully from filesystem.")
return
case "--help", "-h", "help":
printUsage()
return
Expand All @@ -112,27 +154,27 @@ func main() {

if disableAuth {
publicAccess = true
log.Printf("WARNING: Authentication disabled. Wiki is publicly accessible without authentication.")
slog.Default().Warn("Authentication disabled. Wiki is publicly accessible without authentication.")
}

if allowInsecure {
log.Printf("WARNING: allow-insecure enabled. Auth cookies may be transmitted over plain HTTP (INSECURE).")
slog.Default().Warn("allow-insecure enabled. Auth cookies may be transmitted over plain HTTP (INSECURE).")
}

// Check if data directory exists
if _, err := os.Stat(dataDir); os.IsNotExist(err) {
if err := os.MkdirAll(dataDir, 0755); err != nil {
log.Fatalf("Failed to create data directory: %v", err)
fail("Failed to create data directory", "error", err)
}
}

if !disableAuth {
if jwtSecret == "" {
log.Fatal("JWT secret is required. Set it using --jwt-secret or LEAFWIKI_JWT_SECRET environment variable.")
fail("JWT secret is required. Set it using --jwt-secret or LEAFWIKI_JWT_SECRET environment variable.")
}

if adminPassword == "" {
log.Fatalf("admin password is required. Set it using --admin-password or LEAFWIKI_ADMIN_PASSWORD environment variable.")
fail("admin password is required. Set it using --admin-password or LEAFWIKI_ADMIN_PASSWORD environment variable.")
}
}

Expand All @@ -145,7 +187,7 @@ func main() {
AuthDisabled: disableAuth,
})
if err != nil {
log.Fatalf("Failed to initialize Wiki: %v", err)
fail("Failed to initialize Wiki", "error", err)
}
defer w.Close()

Expand All @@ -164,7 +206,7 @@ func main() {

// Start server
if err := router.Run(listenAddr); err != nil {
log.Fatalf("Failed to start server: %v", err)
fail("Failed to start server", "error", err)
}
}

Expand Down Expand Up @@ -192,7 +234,7 @@ func resolveBool(flagName string, flagVal bool, visited map[string]bool, envVar
return b
}
// If env var is set but invalid, fail fast (helps operators)
log.Fatalf("Invalid value for %s: %q (expected true/false/1/0/yes/no)", envVar, env)
fail("Invalid environment variable value", "variable", envVar, "value", env, "expected", "true/false/1/0/yes/no")
}
return flagVal // default from flag
}
Expand All @@ -206,7 +248,7 @@ func resolveDuration(flagName string, flagVal time.Duration, visited map[string]
return d
}
// If env var is set but invalid, fail fast (helps operators)
log.Fatalf("Invalid value for %s: %q (expected duration like 24h, 15m)", envVar, env)
fail("Invalid environment variable value", "variable", envVar, "value", env, "expected", "duration like 24h, 15m")
}
return flagVal // default from flag
}
Expand Down
15 changes: 13 additions & 2 deletions e2e/pages/TreeView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,13 @@ export default class TreeView {
await nodeRow.scrollIntoViewIfNeeded();
await nodeRow.hover(); // oder mouse.move, s.u.

const sortButton = nodeRow.locator('button[data-testid="tree-view-action-button-sort"]');
// open more actions menu
const moreActionsButton = nodeRow.locator(
'button[data-testid="tree-view-action-button-open-more-actions"]',
);
await moreActionsButton.click({ force: true });

const sortButton = this.page.locator('div[data-testid="tree-view-action-button-sort"]');
await sortButton.click({ force: true });

const sortPageDialog = new SortPageDialog(this.page);
Expand All @@ -111,7 +117,12 @@ export default class TreeView {
await nodeRow.scrollIntoViewIfNeeded();
await nodeRow.hover(); // oder mouse.move, s.u.

const moveButton = nodeRow.locator('button[data-testid="tree-view-action-button-move"]');
const moreActionsButton = nodeRow.locator(
'button[data-testid="tree-view-action-button-open-more-actions"]',
);
await moreActionsButton.click({ force: true });

const moveButton = this.page.locator('div[data-testid="tree-view-action-button-move"]');
await moveButton.click({ force: true });

const movePageDialog = new MovePageDialog(this.page);
Expand Down
5 changes: 4 additions & 1 deletion e2e/tests/page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import DeletePageDialog from '../pages/DeletePageDialog';
import EditPage from '../pages/EditPage';
import LoginPage from '../pages/LoginPage';
import NotFoundPage from '../pages/NotFoundPage';
import SearchView from '../pages/SearchView';
import TreeView from '../pages/TreeView';
import ViewPage from '../pages/ViewPage';

Expand Down Expand Up @@ -368,6 +367,9 @@ graph TD;
test.expect(await deletePageDialog.dialogTextVisible()).toBeFalsy();
});

// disable this test cases, because it is flaky
// TODO: fix the flakiness
/*
test('search-page', async ({ page }) => {
const title = `Page To Search ${Date.now()}`;
const content = `This is the content of the page to search, created at ${new Date().toISOString()}`;
Expand Down Expand Up @@ -404,6 +406,7 @@ graph TD;
// clear search
await searchView.clearSearch();
});
*/

test('test-asset-upload-and-use-in-page', async ({ page }) => {
const title = `Page With Asset ${Date.now()}`;
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569
github.com/yuin/goldmark v1.7.16
golang.org/x/crypto v0.47.0
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.44.2
)

Expand All @@ -33,6 +34,7 @@ require (
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand Down
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZw
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down Expand Up @@ -52,6 +53,10 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
Expand All @@ -75,6 +80,8 @@ github.com/quic-go/quic-go v0.57.0 h1:AsSSrrMs4qI/hLrKlTH/TGQeTMY0ib1pAOX7vA3Adq
github.com/quic-go/quic-go v0.57.0/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down Expand Up @@ -120,6 +127,8 @@ golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
5 changes: 5 additions & 0 deletions internal/core/markdown/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package markdown

import "errors"

var ErrFrontmatterParse = errors.New("frontmatter parse error")
Loading