Skip to content

Commit 13881a4

Browse files
committed
Maintenance mode
1 parent 7599423 commit 13881a4

File tree

10 files changed

+279
-56
lines changed

10 files changed

+279
-56
lines changed

.env.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ DBMATE_MIGRATIONS_DIR="./sql/migrations"
55
DBMATE_SCHEMA_FILE="./sql/schema.sql"
66
INVITATION_CODE="CODE123"
77
COOKIE_SECRET="dev_secret"
8+
MAINTENANCE_MODE=false
89
SMTP_HOST="localhost"
910
SMTP_PORT=1025
1011
SMTP_USERNAME=""

app/app.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,32 @@ func Run(ctx context.Context, distFS embed.FS, pragmasSQL string, localesFS embe
3939
return err
4040
}
4141

42-
sqlDB, err := db.InitDB(ctx, cfg.DatabasePath(), pragmasSQL)
42+
sessionStore := session.InitStore(cfg.CookieSecret, cfg.IsDev)
43+
44+
i18nBundle, err := intl.NewBundle(localesFS)
4345
if err != nil {
44-
return fmt.Errorf("failed to initialize database: %w", err)
46+
return err
4547
}
46-
queries := db.New(sqlDB)
4748

48-
sessionStore := session.InitStore(cfg.CookieSecret, cfg.IsDev)
49+
if cfg.IsMaintenanceMode {
50+
s := server.NewMaintenance(cfg, logger, vite, sessionStore, i18nBundle)
4951

50-
email, err := email.New(cfg)
52+
return server.Run(ctx, s, logger, cfg.Port)
53+
}
54+
55+
intl.SetupZogI18n()
56+
57+
sqlDB, err := db.InitDB(ctx, cfg.DatabasePath(), pragmasSQL)
5158
if err != nil {
52-
return err
59+
return fmt.Errorf("failed to initialize database: %w", err)
5360
}
61+
queries := db.New(sqlDB)
5462

55-
i18nBundle, err := intl.NewBundle(localesFS)
63+
email, err := email.New(cfg)
5664
if err != nil {
5765
return err
5866
}
5967

60-
intl.SetupZogI18n()
61-
6268
s := server.New(cfg, logger, sqlDB, queries, vite, sessionStore, email, i18nBundle)
6369

6470
return server.Run(ctx, s, logger, cfg.Port)

app/config/config.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@ import (
1010
)
1111

1212
type Config struct {
13-
Port int `env:"PORT" envDefault:"3000"`
14-
IsDev bool `env:"DEV" envDefault:"false"`
15-
DatabaseURL string `env:"DATABASE_URL" envDefault:"sqlite:data/app.sqlite"`
16-
InvitationCode string `env:"INVITATION_CODE"`
17-
CookieSecret string `env:"COOKIE_SECRET,required"`
18-
SMTPHost string `env:"SMTP_HOST" envDefault:"localhost"`
19-
SMTPPort int `env:"SMTP_PORT" envDefault:"1025"`
20-
SMTPUsername string `env:"SMTP_USERNAME"`
21-
SMTPPassword string `env:"SMTP_PASSWORD"`
22-
EmailFrom string `env:"EMAIL_FROM" envDefault:"Simply Shared Notes <noreply@local.test>"`
13+
Port int `env:"PORT" envDefault:"3000"`
14+
IsDev bool `env:"DEV" envDefault:"false"`
15+
DatabaseURL string `env:"DATABASE_URL" envDefault:"sqlite:data/app.sqlite"`
16+
InvitationCode string `env:"INVITATION_CODE"`
17+
CookieSecret string `env:"COOKIE_SECRET,required"`
18+
IsMaintenanceMode bool `env:"MAINTENANCE_MODE" envDefault:"false"`
19+
SMTPHost string `env:"SMTP_HOST" envDefault:"localhost"`
20+
SMTPPort int `env:"SMTP_PORT" envDefault:"1025"`
21+
SMTPUsername string `env:"SMTP_USERNAME"`
22+
SMTPPassword string `env:"SMTP_PASSWORD"`
23+
EmailFrom string `env:"EMAIL_FROM" envDefault:"Simply Shared Notes <noreply@local.test>"`
2324
}
2425

2526
func New() (*Config, error) {

app/server/maintenance.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package server
2+
3+
import (
4+
"log/slog"
5+
"net/http"
6+
7+
"github.com/go-chi/chi/v5"
8+
"github.com/go-chi/chi/v5/middleware"
9+
"github.com/gorilla/sessions"
10+
"github.com/nicksnyder/go-i18n/v2/i18n"
11+
"github.com/nicolashery/simply-shared-notes/app/config"
12+
"github.com/nicolashery/simply-shared-notes/app/rctx"
13+
"github.com/nicolashery/simply-shared-notes/app/views/pages"
14+
"github.com/nicolashery/simply-shared-notes/app/vite"
15+
)
16+
17+
func NewMaintenance(
18+
cfg *config.Config,
19+
logger *slog.Logger,
20+
vite *vite.Vite,
21+
sessionStore *sessions.CookieStore,
22+
i18nBundle *i18n.Bundle,
23+
) http.Handler {
24+
logger.Warn("running in maintenance mode")
25+
26+
r := chi.NewRouter()
27+
28+
r.Use(
29+
middleware.Logger,
30+
middleware.Recoverer,
31+
)
32+
33+
StaticDir(r, "/assets", vite.AssetsFS)
34+
StaticFile(r, "/robots.txt", vite.PublicFS)
35+
36+
r.Group(func(r chi.Router) {
37+
r.Use(rctx.ViteCtxMiddleware(vite))
38+
r.Use(rctx.SessionCtxMiddleware(logger, sessionStore))
39+
r.Use(rctx.ThemeCtxMiddleware())
40+
r.Use(rctx.IntlCtxMiddleware(logger, i18nBundle))
41+
42+
r.Get("/", handleMaintenance(logger))
43+
r.Get("/*", func(w http.ResponseWriter, r *http.Request) {
44+
http.Redirect(w, r, "/", http.StatusFound)
45+
})
46+
})
47+
48+
return r
49+
}
50+
51+
func handleMaintenance(logger *slog.Logger) http.HandlerFunc {
52+
return func(w http.ResponseWriter, r *http.Request) {
53+
w.WriteHeader(http.StatusServiceUnavailable)
54+
55+
err := pages.Maintenance().Render(r.Context(), w)
56+
if err != nil {
57+
logger.Error(
58+
"failed to render template",
59+
slog.Any("error", err),
60+
slog.String("template", "Maintenance"),
61+
)
62+
http.Error(w, "internal server error", http.StatusInternalServerError)
63+
}
64+
}
65+
}

app/views/pages/home.page.templ

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,7 @@ templ Home() {
1818
<div class="hero-content text-center">
1919
<div class="max-w-md">
2020
<h1 class="text-4xl font-bold">
21-
{ intl.Localize(&i18n.LocalizeConfig{
22-
DefaultMessage: &i18n.Message{
23-
ID: "Home.Hero.Title",
24-
Other: "Simply Shared Notes",
25-
},
26-
}) }
21+
Simply Shared Notes
2722
</h1>
2823
<p class="py-6">
2924
{ intl.Localize(&i18n.LocalizeConfig{

app/views/pages/home.page_templ.go

Lines changed: 8 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package pages
2+
3+
import (
4+
"github.com/nicksnyder/go-i18n/v2/i18n"
5+
"github.com/nicolashery/simply-shared-notes/app/rctx"
6+
"github.com/nicolashery/simply-shared-notes/app/views/layouts"
7+
)
8+
9+
templ Maintenance() {
10+
{{ intl := rctx.GetIntl(ctx) }}
11+
@layouts.Base(intl.Localize(&i18n.LocalizeConfig{
12+
DefaultMessage: &i18n.Message{
13+
ID: "Maintenance.PageTitle",
14+
Other: "Maintenance",
15+
},
16+
}), nil) {
17+
<div class="hero">
18+
<div class="hero-content">
19+
<div class="max-w-md py-6 flex flex-col gap-6 items-center">
20+
<svg
21+
class="size-12 text-warning"
22+
xmlns="http://www.w3.org/2000/svg"
23+
viewBox="0 0 24 24"
24+
fill="none"
25+
stroke="currentColor"
26+
stroke-width="2"
27+
stroke-linecap="round"
28+
stroke-linejoin="round"
29+
class="lucide lucide-construction-icon lucide-construction"
30+
>
31+
<rect x="2" y="6" width="20" height="8" rx="1"></rect>
32+
<path d="M17 14v7"></path><path d="M7 14v7"></path><path d="M17 3v3"></path><path d="M7 3v3"></path><path d="M10 14 2.3 6.3"></path><path d="m14 6 7.7 7.7"></path><path d="m8 6 8 8"></path>
33+
</svg>
34+
<h1 class="text-4xl font-bold text-center">
35+
{ intl.Localize(&i18n.LocalizeConfig{
36+
DefaultMessage: &i18n.Message{
37+
ID: "Maintenance.Title",
38+
Other: "Under Maintenance",
39+
},
40+
}) }
41+
</h1>
42+
<p class="text-center">
43+
{ intl.Localize(&i18n.LocalizeConfig{
44+
DefaultMessage: &i18n.Message{
45+
ID: "Maintenance.Message",
46+
Other: "We're currently performing scheduled maintenance to improve our service. We'll be back up and running shortly. Thank you for your patience!",
47+
},
48+
}) }
49+
</p>
50+
<p class="text-center italic opacity-60">
51+
- Simply Shared Notes -
52+
</p>
53+
</div>
54+
</div>
55+
</div>
56+
}
57+
}

app/views/pages/maintenance.page_templ.go

Lines changed: 106 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)