mirror of
https://github.com/rjNemo/rentease.git
synced 2026-06-11 21:26:50 +00:00
Some checks are pending
CI / checks (push) Waiting to run
Introduce backend and frontend support for generating Stripe payment links for outstanding booking balances. Adds a new POST endpoint to create payment links, updates booking view to include a Stripe button, and integrates error handling and feedback for payment link creation. Refactors view models and templates to support the new feature.
106 lines
2.7 KiB
Go
106 lines
2.7 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"embed"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"time"
|
|
|
|
"github.com/getsentry/sentry-go"
|
|
sentryecho "github.com/getsentry/sentry-go/echo"
|
|
"github.com/gorilla/sessions"
|
|
"github.com/labstack/echo-contrib/session"
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/labstack/echo/v4/middleware"
|
|
|
|
"github.com/rjNemo/rentease/internal/config"
|
|
"github.com/rjNemo/rentease/internal/service/auth"
|
|
"github.com/rjNemo/rentease/internal/service/booking"
|
|
)
|
|
|
|
type Server struct {
|
|
Router *echo.Echo
|
|
bs *booking.Service
|
|
as *auth.Service
|
|
hc *config.Host
|
|
addr string
|
|
stripeWebhookSecret string
|
|
}
|
|
|
|
func New(bs *booking.Service, as *auth.Service, hc *config.Host, opts ...Option) (*Server, error) {
|
|
option := new(options)
|
|
for _, opt := range opts {
|
|
err := opt(option)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
s := &Server{
|
|
Router: NewRouter(*option.fs, *option.debug, *option.secretKey, option.origins),
|
|
bs: bs,
|
|
as: as,
|
|
hc: hc,
|
|
addr: fmt.Sprintf("0.0.0.0:%d", *option.port),
|
|
stripeWebhookSecret: "",
|
|
}
|
|
|
|
if option.stripeWebhookSecret != nil {
|
|
s.stripeWebhookSecret = *option.stripeWebhookSecret
|
|
}
|
|
|
|
s.MountHandlers()
|
|
return s, nil
|
|
}
|
|
|
|
func (s Server) Start(c context.Context) {
|
|
go func() {
|
|
if err := s.Router.Start(s.addr); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
s.Router.Logger.Fatalf("shutting down the server: %s", err)
|
|
}
|
|
}()
|
|
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, os.Interrupt)
|
|
<-quit
|
|
ctx, cancel := context.WithTimeout(c, 10*time.Second)
|
|
defer cancel()
|
|
if err := s.Router.Shutdown(ctx); err != nil {
|
|
s.Router.Logger.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func NewRouter(fs embed.FS, debug bool, secret string, origins []string) *echo.Echo {
|
|
e := echo.New()
|
|
// config
|
|
e.HideBanner = !debug
|
|
e.Debug = debug
|
|
// middlewares
|
|
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
|
Format: "${time_rfc3339} [${method}: ${status}] ${uri}; ip=${remote_ip}; ${latency_human}; ${user_agent}\n",
|
|
}))
|
|
e.Use(middleware.Recover())
|
|
e.Use(middleware.Secure())
|
|
e.Use(middleware.Gzip())
|
|
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{AllowOrigins: origins}))
|
|
e.Use(sentryecho.New(sentryecho.Options{}))
|
|
e.Use(SentryTracingMiddleware)
|
|
e.Use(CachingMiddleware(0, "js", "css", "png", "ico"))
|
|
e.Use(session.Middleware(sessions.NewCookieStore([]byte(secret))))
|
|
// static assets
|
|
e.StaticFS("/static", echo.MustSubFS(fs, "assets"))
|
|
|
|
return e
|
|
}
|
|
|
|
func captureError(c echo.Context, err error) {
|
|
if hub := sentryecho.GetHubFromContext(c); hub != nil {
|
|
hub.WithScope(func(s *sentry.Scope) {
|
|
hub.CaptureMessage(err.Error())
|
|
})
|
|
}
|
|
}
|