package api import ( "database/sql" "log/slog" "net/http" "atlas9.dev/c/core" "atlas9.dev/c/core/dbi" "atlas9.dev/c/demo/bots" ) type BotKeysImpl struct { DB *sql.DB KeyStore dbi.Factory[bots.KeyStore] } func (k *BotKeysImpl) Create(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // Read, prepare, and validate the request. var req BotKeys_CreateReq if read(w, r, &req) { return } // Create new key key, secret, err := bots.NewKey(req.Tenant, req.Bot) if writeErr(ctx, w, err) { return } // Save the key err = dbi.ReadWrite(ctx, k.DB, func(tx dbi.DBI) error { return k.KeyStore(tx).Create(ctx, key) }) // Write the response res := BotKeys_CreateRes{ ID: key.ID, Tenant: key.Tenant, Bot: key.Bot, Secret: secret, CreatedAt: key.CreatedAt, ExpiresAt: key.ExpiresAt, } if write(ctx, w, err, res) { return } // Audit logging. // TODO should be in the store? But then it would need to participate in the transaction. slog.Info("bot key created", "ID", key.ID, "Tenant", key.Tenant.String(), "Bot", key.Bot, ) } func (k *BotKeysImpl) Get(w http.ResponseWriter, r *http.Request) { var req BotKeys_GetReq if read(w, r, &req) { return } ctx := r.Context() var key bots.Key err := dbi.ReadOnly(ctx, k.DB, func(tx dbi.DBI) error { return k.KeyStore(tx).Get(ctx, req.Tenant, req.ID, &key) }) res := BotKeys_GetRes{ ID: key.ID, Tenant: key.Tenant, Bot: key.Bot, CreatedAt: key.CreatedAt, ExpiresAt: key.ExpiresAt, } write(ctx, w, err, res) } func (k *BotKeysImpl) List(w http.ResponseWriter, r *http.Request) { var req BotKeys_ListReq if read(w, r, &req) { return } ctx := r.Context() var page core.Page[bots.Key] err := dbi.ReadOnly(ctx, k.DB, func(tx dbi.DBI) error { return k.KeyStore(tx).List(ctx, req.Tenant, &page) }) // Convert to metadata var res BotKeys_ListRes res.Page.Cursor = page.Cursor for _, it := range page.Items { res.Page.Items = append(res.Page.Items, BotKeys_ListItem{ ID: it.ID, Tenant: it.Tenant, Bot: it.Bot, CreatedAt: it.CreatedAt, ExpiresAt: it.ExpiresAt, }) } write(ctx, w, err, res) } func (k *BotKeysImpl) SetExpiration(w http.ResponseWriter, r *http.Request) { var req BotKeys_SetExpirationReq if read(w, r, &req) { return } ctx := r.Context() err := dbi.ReadWrite(ctx, k.DB, func(tx dbi.DBI) error { return k.KeyStore(tx).SetExpiration(ctx, req.Tenant, req.ID, req.ExpiresAt) }) if write(ctx, w, err, BotKeys_SetExpirationRes{}) { return } slog.Info("api key set expiration", "ID", req.ID) }