package main import ( "context" "flag" "html" "html/template" "log" "path/filepath" "strings" "time" "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/extractors" "github.com/gofiber/fiber/v3/middleware/session" "github.com/gofiber/fiber/v3/middleware/static" "github.com/gofiber/storage/sqlite3/v2" fiber_html "github.com/gofiber/template/html/v3" "github.com/gofiber/utils/v2" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" "lmika.dev/lmika/weiro/config" "lmika.dev/lmika/weiro/handlers" "lmika.dev/lmika/weiro/handlers/middleware" "lmika.dev/lmika/weiro/providers/db" "lmika.dev/lmika/weiro/services/auth" "lmika.dev/lmika/weiro/services/posts" "lmika.dev/lmika/weiro/services/publisher" "lmika.dev/lmika/weiro/services/sites" _ "modernc.org/sqlite" ) func main() { flagUser := flag.String("user", "", "select user to perform operation on") flagPasswd := flag.String("passwd", "", "change password for user") flag.Parse() cfg, err := config.LoadConfig() if err != nil { log.Fatal(err) } dbp, err := db.New(filepath.Join(cfg.DataDir, "weiro.db")) if err != nil { log.Fatal(err) } defer dbp.Close() authSvc := auth.New(dbp) publisherSvc := publisher.New(dbp) publisherQueue := publisher.NewQueue(publisherSvc) postService := posts.New(dbp, publisherQueue) siteService := sites.New(dbp) // CLI tools if *flagPasswd != "" && *flagUser != "" { user, err := authSvc.SetPassword(context.Background(), *flagUser, *flagPasswd) if err != nil { log.Fatal(err) } log.Printf("Password changed for user %s\n", user.Username) return } publisherQueue.Start(context.Background()) fiberTemplate := fiber_html.New("./views", ".html") fiberTemplate.Funcmap["sub"] = func(x, y int) int { return x - y } fiberTemplate.Funcmap["markdown"] = func() func(s string) template.HTML { mdParser := goldmark.New( goldmark.WithExtensions(extension.GFM), ) return func(s string) template.HTML { var sb strings.Builder if err := mdParser.Convert([]byte(s), &sb); err != nil { return template.HTML("Markdown error: " + html.EscapeString(err.Error())) } return template.HTML(sb.String()) } }() // Initialize custom config store := sqlite3.New(sqlite3.Config{ Database: filepath.Join(cfg.DataDir, "./fiber.db"), Table: "fiber_storage", Reset: false, GCInterval: 10 * time.Second, MaxOpenConns: 100, MaxIdleConns: 100, ConnMaxLifetime: 1 * time.Second, }) app := fiber.New(fiber.Config{ Views: fiberTemplate, ViewsLayout: "layouts/main", PassLocalsToViews: true, }) app.Use(session.New(session.Config{ // Storage Storage: store, // Security CookieSecure: cfg.IsProd(), CookieSameSite: "Lax", // Session Management IdleTimeout: 24 * time.Hour, // Inactivity timeout AbsoluteTimeout: 7 * 24 * time.Hour, // Maximum session duration // Cookie Settings CookiePath: "/", CookieDomain: cfg.SiteDomain, CookieSessionOnly: false, // Persist across browser restarts // Session ID Extractor: extractors.FromCookie("__wro-session_id"), KeyGenerator: utils.SecureToken, // Error Handling ErrorHandler: func(c fiber.Ctx, err error) { log.Printf("Session error: %v", err) }, })) ih := handlers.IndexHandler{SiteService: siteService} lh := handlers.LoginHandler{Config: cfg, AuthService: authSvc} ph := handlers.PostsHandler{PostService: postService} app.Get("/login", lh.Login) app.Post("/login", lh.DoLogin) app.Post("/logout", lh.Logout) siteGroup := app.Group("/sites/:siteID", middleware.RequireUser(authSvc), middleware.RequiresSite(dbp)) siteGroup.Get("/posts", ph.Index) siteGroup.Get("/posts/new", ph.New) siteGroup.Get("/posts/:postID", ph.Edit) siteGroup.Post("/posts", ph.Update) siteGroup.Patch("/posts/:postID", ph.Patch) siteGroup.Delete("/posts/:postID", ph.Delete) app.Get("/", middleware.OptionalUser(authSvc), ih.Index) app.Get("/first-run", ih.FirstRun) app.Post("/first-run", ih.FirstRunSubmit) app.Get("/static/*", static.New("./static")) // TEMP // /* dbp.SaveUser(context.Background(), &models.User{Username: "testuser"}) ctx := models.WithUser(context.Background(), models.User{ID: 1}) site, err := importer.New(dbp).Import(ctx, "_test-site") if err != nil { log.Fatal(err) } target := models.SitePublishTarget{ SiteID: site.ID, BaseURL: "https://jolly-boba-9e2486.netlify.app", TargetType: "netlify", TargetRef: "55c878a7-189e-42cf-aa02-5c60908143f3", TargetKey: os.Getenv("NETLIFY_AUTH_TOKEN"), } if err := dbp.SavePublishTarget(ctx, &target); err != nil { log.Fatal(err) } */ //if err := publisherSvc.Publish(ctx, site.ID); err != nil { // log.Fatal(err) //} log.Fatal(app.Listen(":3000")) }