feat(backend): implement task creation and admin web
This commit is contained in:
+100
-3
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -11,8 +12,13 @@ import (
|
||||
"time"
|
||||
|
||||
"cmroubao/backend-api/internal/config"
|
||||
"cmroubao/backend-api/internal/platform/assetstore"
|
||||
"cmroubao/backend-api/internal/platform/database"
|
||||
"cmroubao/backend-api/internal/platform/migration"
|
||||
repository "cmroubao/backend-api/internal/repository/sqlite"
|
||||
"cmroubao/backend-api/internal/transport/httpapi"
|
||||
"cmroubao/backend-api/internal/transport/webui"
|
||||
"cmroubao/backend-api/internal/usecase"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -43,10 +49,11 @@ func run() error {
|
||||
}
|
||||
}()
|
||||
|
||||
router, err := httpapi.NewRouter(db, func(event string) {
|
||||
log.Print(event)
|
||||
})
|
||||
router, err := buildRouter(startupContext, cfg, db)
|
||||
if err != nil {
|
||||
if errors.Is(err, errPendingMigrations) {
|
||||
return err
|
||||
}
|
||||
return errors.New("HTTP router setup failed")
|
||||
}
|
||||
server := httpapi.NewServer(cfg, router)
|
||||
@@ -111,3 +118,93 @@ func shutdownServer(
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type migrationStatusReader interface {
|
||||
Status(context.Context) ([]migration.Status, error)
|
||||
}
|
||||
|
||||
var errPendingMigrations = errors.New(
|
||||
"database migrations are pending; run migrate up",
|
||||
)
|
||||
|
||||
func buildRouter(
|
||||
ctx context.Context,
|
||||
cfg config.Config,
|
||||
db *sql.DB,
|
||||
) (http.Handler, error) {
|
||||
runner, err := migration.New(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := requireCurrentMigrations(ctx, runner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store, err := repository.New(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files, err := assetstore.New(cfg.AssetDirectory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clock := usecase.SystemClock{}
|
||||
ids := usecase.UUIDGenerator{}
|
||||
assets, err := usecase.NewAssetService(store, files, clock, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tasks, err := usecase.NewTaskService(store, clock, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
webService, err := webui.NewUsecaseAdapter(tasks, assets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
renderer, err := webui.NewRenderer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webHandler, err := webui.NewHandler(webService, renderer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
registerAdminRoutes, err := httpapi.NewAdminRouteRegistrar(
|
||||
httpapi.AdminServices{
|
||||
Assets: assets,
|
||||
Tasks: tasks,
|
||||
},
|
||||
webHandler,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return httpapi.NewRouter(httpapi.RouterDependencies{
|
||||
Database: db,
|
||||
RegisterAdminRoutes: registerAdminRoutes,
|
||||
LogEvent: func(event string) {
|
||||
log.Print(event)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func requireCurrentMigrations(
|
||||
ctx context.Context,
|
||||
reader migrationStatusReader,
|
||||
) error {
|
||||
statuses, err := reader.Status(ctx)
|
||||
if err != nil {
|
||||
return errors.New("database migration status failed")
|
||||
}
|
||||
if len(statuses) == 0 {
|
||||
return errors.New("database has no known migrations")
|
||||
}
|
||||
for _, status := range statuses {
|
||||
if !status.Applied {
|
||||
return errPendingMigrations
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user