Skip to content

Commit

Permalink
update character API spec
Browse files Browse the repository at this point in the history
  • Loading branch information
totegamma committed Feb 25, 2024
1 parent 22a67b6 commit 9550586
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 18 deletions.
1 change: 1 addition & 0 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ func main() {
// character
apiV1.PUT("/character", characterHandler.Put, auth.Restrict(auth.ISLOCAL))
apiV1.GET("/characters", characterHandler.Get)
apiV1.DELETE("/character/:id", characterHandler.Delete, auth.Restrict(auth.ISLOCAL))

// stream
apiV1.POST("/stream", streamHandler.Create, auth.Restrict(auth.ISLOCAL))
Expand Down
55 changes: 52 additions & 3 deletions x/character/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ package character

import (
"errors"
"net/http"

"github.com/labstack/echo/v4"
"go.opentelemetry.io/otel"
"gorm.io/gorm"
"net/http"

"github.com/totegamma/concurrent/x/core"
)

var tracer = otel.Tracer("character")
Expand All @@ -15,6 +18,7 @@ var tracer = otel.Tracer("character")
type Handler interface {
Get(c echo.Context) error
Put(c echo.Context) error
Delete(c echo.Context) error
}

type handler struct {
Expand All @@ -33,13 +37,27 @@ func (h handler) Get(c echo.Context) error {

author := c.QueryParam("author")
schema := c.QueryParam("schema")
characters, err := h.service.GetCharacters(ctx, author, schema)

var err error
var characters []core.Character

if author != "" && schema != "" {
characters, err = h.service.GetByAuthorAndSchema(ctx, author, schema)
} else if author != "" {
characters, err = h.service.GetByAuthor(ctx, author)
} else if schema != "" {
characters, err = h.service.GetBySchema(ctx, schema)
} else {
return c.JSON(http.StatusBadRequest, echo.Map{"error": "Invalid request", "message": "author or schema is required"})
}

if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return c.JSON(http.StatusNotFound, echo.Map{"error": "Character not found"})
}
return err
}

return c.JSON(http.StatusOK, echo.Map{"status": "ok", "content": characters})
}

Expand All @@ -54,9 +72,40 @@ func (h handler) Put(c echo.Context) error {
return c.JSON(http.StatusBadRequest, echo.Map{"error": "Invalid request", "message": err.Error()})
}

updated, err := h.service.PutCharacter(ctx, request.SignedObject, request.Signature, request.ID)
updated, err := h.service.Put(ctx, request.SignedObject, request.Signature, request.ID)
if err != nil {
return c.JSON(http.StatusBadRequest, echo.Map{"error": "Invalid request", "message": err.Error()})
}
return c.JSON(http.StatusOK, echo.Map{"status": "ok", "content": updated})
}

func (h handler) Delete(c echo.Context) error {
ctx, span := tracer.Start(c.Request().Context(), "HandlerDelete")
defer span.End()

id := c.Param("id")
if id == "" {
return c.JSON(http.StatusBadRequest, echo.Map{"error": "Invalid request", "message": "id is required"})
}

requester, ok := c.Get(core.RequesterIdCtxKey).(string)
if !ok {
return c.JSON(http.StatusForbidden, echo.Map{"status": "error", "message": "requester not found"})
}

target, err := h.service.Get(ctx, id)
if err != nil {
return c.JSON(http.StatusNotFound, echo.Map{"error": "Character not found"})
}

if target.Author != requester {
return c.JSON(http.StatusForbidden, echo.Map{"error": "you are not authorized to perform this action"})
}

deleted, err := h.service.Delete(ctx, id)
if err != nil {
return c.JSON(http.StatusBadRequest, echo.Map{"error": "Invalid request", "message": err.Error()})
}

return c.JSON(http.StatusOK, echo.Map{"status": "ok", "content": deleted})
}
61 changes: 58 additions & 3 deletions x/character/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import (
// Repository is the interface for character repository
type Repository interface {
Upsert(ctx context.Context, character core.Character) error
Get(ctx context.Context, owner string, schema string) ([]core.Character, error)
Get(ctx context.Context, id string) (core.Character, error)
GetByAuthorAndSchema(ctx context.Context, owner string, schema string) ([]core.Character, error)
GetByAuthor(ctx context.Context, owner string) ([]core.Character, error)
GetBySchema(ctx context.Context, schema string) ([]core.Character, error)
Delete(ctx context.Context, id string) (core.Character, error)
Count(ctx context.Context) (int64, error)
}

Expand Down Expand Up @@ -83,8 +87,8 @@ func (r *repository) Upsert(ctx context.Context, character core.Character) error
}

// Get returns a character by owner and schema
func (r *repository) Get(ctx context.Context, owner string, schema string) ([]core.Character, error) {
ctx, span := tracer.Start(ctx, "RepositoryGet")
func (r *repository) GetByAuthorAndSchema(ctx context.Context, owner string, schema string) ([]core.Character, error) {
ctx, span := tracer.Start(ctx, "RepositoryGetByAuthorAndSchema")
defer span.End()

var characters []core.Character
Expand All @@ -96,3 +100,54 @@ func (r *repository) Get(ctx context.Context, owner string, schema string) ([]co
}
return characters, nil
}

func (r *repository) GetByAuthor(ctx context.Context, owner string) ([]core.Character, error) {
ctx, span := tracer.Start(ctx, "RepositoryGetByAuthor")
defer span.End()

var characters []core.Character
if err := r.db.WithContext(ctx).Preload("Associations").Where("author = $1", owner).Find(&characters).Error; err != nil {
return []core.Character{}, err
}
if characters == nil {
return []core.Character{}, nil
}
return characters, nil
}

func (r *repository) GetBySchema(ctx context.Context, schema string) ([]core.Character, error) {
ctx, span := tracer.Start(ctx, "RepositoryGetBySchema")
defer span.End()

var characters []core.Character
if err := r.db.WithContext(ctx).Preload("Associations").Where("schema = $1", schema).Find(&characters).Error; err != nil {
return []core.Character{}, err
}
if characters == nil {
return []core.Character{}, nil
}
return characters, nil
}

func (r *repository) Delete(ctx context.Context, id string) (core.Character, error) {
ctx, span := tracer.Start(ctx, "RepositoryDelete")
defer span.End()

var character core.Character
if err := r.db.WithContext(ctx).Where("id = $1", id).Delete(&character).Error; err != nil {
return core.Character{}, err
}

return character, nil
}

func (r *repository) Get(ctx context.Context, id string) (core.Character, error) {
ctx, span := tracer.Start(ctx, "RepositoryGet")
defer span.End()

var character core.Character
if err := r.db.WithContext(ctx).Preload("Associations").Where("id = $1", id).First(&character).Error; err != nil {
return core.Character{}, err
}
return character, nil
}
54 changes: 42 additions & 12 deletions x/character/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import (

// Service is the interface for character service
type Service interface {
GetCharacters(ctx context.Context, owner string, schema string) ([]core.Character, error)
PutCharacter(ctx context.Context, objectStr string, signature string, id string) (core.Character, error)
Put(ctx context.Context, objectStr string, signature string, id string) (core.Character, error)
Count(ctx context.Context) (int64, error)
Get(ctx context.Context, id string) (core.Character, error)
GetByAuthorAndSchema(ctx context.Context, owner string, schema string) ([]core.Character, error)
GetByAuthor(ctx context.Context, owner string) ([]core.Character, error)
GetBySchema(ctx context.Context, schema string) ([]core.Character, error)
Delete(ctx context.Context, id string) (core.Character, error)
}

type service struct {
Expand All @@ -32,21 +36,32 @@ func (s *service) Count(ctx context.Context) (int64, error) {
return s.repo.Count(ctx)
}

// GetCharacters returns characters by owner and schema
func (s *service) GetCharacters(ctx context.Context, owner string, schema string) ([]core.Character, error) {
ctx, span := tracer.Start(ctx, "ServiceGetCharacters")
// GetByAuthorAndSchema returns characters by owner and schema
func (s *service) GetByAuthorAndSchema(ctx context.Context, owner string, schema string) ([]core.Character, error) {
ctx, span := tracer.Start(ctx, "ServiceGetByAuthorAndSchema")
defer span.End()

characters, err := s.repo.Get(ctx, owner, schema)
if err != nil {
span.RecordError(err)
return []core.Character{}, err
}
return characters, nil
return s.repo.GetByAuthorAndSchema(ctx, owner, schema)
}

// GetByAuthor returns characters by owner
func (s *service) GetByAuthor(ctx context.Context, owner string) ([]core.Character, error) {
ctx, span := tracer.Start(ctx, "ServiceGetByAuthor")
defer span.End()

return s.repo.GetByAuthor(ctx, owner)
}

// GetBySchema returns characters by schema
func (s *service) GetBySchema(ctx context.Context, schema string) ([]core.Character, error) {
ctx, span := tracer.Start(ctx, "ServiceGetBySchema")
defer span.End()

return s.repo.GetBySchema(ctx, schema)
}

// PutCharacter creates new character if the signature is valid
func (s *service) PutCharacter(ctx context.Context, objectStr string, signature string, id string) (core.Character, error) {
func (s *service) Put(ctx context.Context, objectStr string, signature string, id string) (core.Character, error) {
ctx, span := tracer.Start(ctx, "ServicePutCharacter")
defer span.End()

Expand Down Expand Up @@ -79,3 +94,18 @@ func (s *service) PutCharacter(ctx context.Context, objectStr string, signature

return character, nil
}

// Delete deletes character
func (s *service) Delete(ctx context.Context, id string) (core.Character, error) {
ctx, span := tracer.Start(ctx, "ServiceDelete")
defer span.End()

return s.repo.Delete(ctx, id)
}

func (s *service) Get(ctx context.Context, id string) (core.Character, error) {
ctx, span := tracer.Start(ctx, "ServiceGet")
defer span.End()

return s.repo.Get(ctx, id)
}

0 comments on commit 9550586

Please sign in to comment.