diff --git a/README.md b/README.md index 0ca022a..24059da 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,7 @@ Retrieves a list of assets. ### Query arguments - **address**: string. It must be a valid polkadot address. - **id**: string +- **blockchain**: string. It must be either 'polkadot' or 'kusama' - **order**: string. It orders the results using a field. It must be `id`, `address` or `created_at`. - **ascending**: bool. It defines if the order is ascending or descendingl It's used along with `order`. - **limit**: int. The maximum number of items to return. If not specified or greater than the maximum limit, it defaults to 100. @@ -122,10 +123,11 @@ Retrieves a list of assets. "id": "asset_id", "description": "asset_description", "address": "owner", + "blockchain": "polkadot|kusama", "image": "asset_image_url", "social": { - "twitter": "twitter_handle", - "facebook": "facebook_handle" + "twitter": "twitter_handle", + "facebook": "facebook_handle" } } ] @@ -147,6 +149,7 @@ Retrieves an asset by its ID. "ok": true, "data": { "id": "asset_id", + "blockchain": "polkadot|kusama", "description": "asset_description", "image": "asset_image_url", "social": { @@ -168,6 +171,7 @@ Creates a new asset. It requires authentication. "data": { "id": "asset_id", "description": "asset_description", + "blockchain": "polkadot|kusama", "image": "asset_image_url", "social": { "twitter": "twitter_handle", @@ -189,6 +193,7 @@ Creates a new asset. It requires authentication. "data": { "id": "asset_id", "description": "asset_description", + "blockchain": "polkadot|kusama", "image": "asset_image_url", "social": { "twitter": "twitter_handle", @@ -205,7 +210,12 @@ It updates an asset. Only its owner can do it. It requires authentication. #### Request Body ```json { - "ok": true + "description": "asset_description", + "blockchain": "polkadot|kusama", + "image": "asset_image_url", + "social": { + "twitter": "twitter_handle", + "facebook": "facebook_handle" } ``` diff --git a/packages/api/pkg/adapters/assets/pg_repository.go b/packages/api/pkg/adapters/assets/pg_repository.go index 97392ae..ebb5a4a 100644 --- a/packages/api/pkg/adapters/assets/pg_repository.go +++ b/packages/api/pkg/adapters/assets/pg_repository.go @@ -50,6 +50,10 @@ func (repo *AssetsRepository) GetAssets(ctx context.Context, filters *model.GetA query = query.Where("id = ?", *filters.ID) } + if filters.Blockchain != nil { + query = query.Where("blockchain = ?", *filters.Blockchain) + } + if filters.Order.Order != nil { orderClause := fmt.Sprintf("'%s' '%s'", *filters.Order.Order, "ASC") if filters.Order.Ascending != nil && !*filters.Order.Ascending { diff --git a/packages/api/pkg/model/asset.go b/packages/api/pkg/model/asset.go index 0eedeff..224ae74 100644 --- a/packages/api/pkg/model/asset.go +++ b/packages/api/pkg/model/asset.go @@ -11,6 +11,7 @@ type Asset struct { ID_ *int `bun:"_id" json:"_id"` ID string `bun:"id" json:"id"` Address string `bun:"address" json:"address"` + Blockchain *string `bun:"blockchain" json:"blockchain"` Description *string `bun:"description" json:"description,omitempty"` Image *string `bun:"image" json:"image,omitempty"` Social *map[string]string `bun:"social" json:"social,omitempty"` diff --git a/packages/api/pkg/model/constants.go b/packages/api/pkg/model/constants.go new file mode 100644 index 0000000..b717ab3 --- /dev/null +++ b/packages/api/pkg/model/constants.go @@ -0,0 +1,4 @@ +package model + +const POLKADOT = "polkadot" +const KUSAMA = "kusama" diff --git a/packages/api/pkg/model/schema.go b/packages/api/pkg/model/schema.go index 1b3d689..cea6999 100644 --- a/packages/api/pkg/model/schema.go +++ b/packages/api/pkg/model/schema.go @@ -52,6 +52,14 @@ func validateDescription(description *string) error { } return nil } +func validateBlockchain(blockchain *string) error { + if blockchain != nil { + if *blockchain != POLKADOT && *blockchain != KUSAMA { + return errors.New("blockchain must be either 'polkadot' or 'kusama'") + } + } + return nil +} func validateSocial(social *map[string]string) error { if social != nil { @@ -87,12 +95,14 @@ type AuthHeaders struct { type NewAsset struct { ID string `json:"id"` + Blockchain string `json:"blockchain"` Description *string `json:"description"` Image *string `json:"image" validate:"nonzero"` Social *map[string]string `json:"social"` } type UpdateAsset struct { + Blockchain *string `json:"blockchain"` Description *string `json:"description"` Image *string `json:"image" validate:"nonzero"` Social *map[string]string `json:"social"` @@ -118,6 +128,10 @@ func (c *CreateAssetInput) Validate() error { if err := validateSocial(c.Social); err != nil { return err } + + if err := validateBlockchain(&c.Blockchain); err != nil { + return err + } return nil } @@ -140,6 +154,9 @@ func (c *UpdateAssetInput) Validate() error { if err := validateSocial(c.Social); err != nil { return err } + if err := validateBlockchain(c.Blockchain); err != nil { + return err + } return nil } @@ -165,8 +182,9 @@ func (c *GetAssetByIDInput) Validate() error { } type GetAssetsInput struct { - Address *string `in:"query=address"` - ID *string `in:"query=id"` + Address *string `in:"query=address"` + ID *string `in:"query=id"` + Blockchain *string `in:"query=blockchain"` Order Pagination } @@ -186,6 +204,11 @@ func (c *GetAssetsInput) Validate() error { return errors.New("address must only contain alphanumeric characters") } } + if c.Blockchain != nil { + if err := validateBlockchain(c.Blockchain); err != nil { + return err + } + } if c.Order.Order != nil { validOrders := map[string]bool{"id": true, "address": true, "created_at": true} if !validOrders[*c.Order.Order] { diff --git a/packages/api/pkg/model/schema_test.go b/packages/api/pkg/model/schema_test.go index 1d24fb0..8987968 100644 --- a/packages/api/pkg/model/schema_test.go +++ b/packages/api/pkg/model/schema_test.go @@ -17,8 +17,9 @@ func TestCreateAssetInputValidation(t *testing.T) { name: "valid input", input: model.CreateAssetInput{ NewAsset: model.NewAsset{ - ID: "1a2b3c", - Image: strPtr("https://example.com/image.jpg"), + ID: "1a2b3c", + Image: strPtr("https://example.com/image.jpg"), + Blockchain: "polkadot", }, }, wantErr: false, @@ -43,6 +44,17 @@ func TestCreateAssetInputValidation(t *testing.T) { }, wantErr: true, }, + { + name: "invalid blockchain", + input: model.CreateAssetInput{ + NewAsset: model.NewAsset{ + ID: "1a2b3c", + Image: strPtr("https://example.com/image.jpg"), + Blockchain: "invalid", + }, + }, + wantErr: true, + }, } for _, tt := range tests { @@ -90,6 +102,16 @@ func TestUpdateAssetInputValidation(t *testing.T) { }, wantErr: true, }, + { + name: "invalid blockchain", + input: model.UpdateAssetInput{ + ID: "1a2b3c", + UpdateAsset: model.UpdateAsset{ + Blockchain: strPtr("invalid"), + }, + }, + wantErr: true, + }, } for _, tt := range tests { diff --git a/packages/api/pkg/service/http.go b/packages/api/pkg/service/http.go index e1ae21a..398d179 100644 --- a/packages/api/pkg/service/http.go +++ b/packages/api/pkg/service/http.go @@ -35,6 +35,7 @@ func (srv *Service) CreateAsset(w http.ResponseWriter, r *http.Request) { Image: createAsset.Image, Social: createAsset.Social, Address: createAsset.Address, + Blockchain: &createAsset.Blockchain, } asset, err := srv.assetsApp.CreateAsset(r.Context(), asset) @@ -65,6 +66,7 @@ func (srv *Service) UpdateAsset(w http.ResponseWriter, r *http.Request) { Image: updateAsset.Image, Social: updateAsset.Social, Address: updateAsset.Address, + Blockchain: updateAsset.Blockchain, } err := srv.assetsApp.UpdateAsset(r.Context(), asset) diff --git a/packages/migrate/migrations/20250506223926_add_blockchain.down.sql b/packages/migrate/migrations/20250506223926_add_blockchain.down.sql new file mode 100644 index 0000000..55dee2d --- /dev/null +++ b/packages/migrate/migrations/20250506223926_add_blockchain.down.sql @@ -0,0 +1 @@ +ALTER TABLE assets DROP COLUMN blockchain; \ No newline at end of file diff --git a/packages/migrate/migrations/20250506223926_add_blockchain.up.sql b/packages/migrate/migrations/20250506223926_add_blockchain.up.sql new file mode 100644 index 0000000..dd36195 --- /dev/null +++ b/packages/migrate/migrations/20250506223926_add_blockchain.up.sql @@ -0,0 +1 @@ +ALTER TABLE assets ADD COLUMN blockchain TEXT NOT NULL; \ No newline at end of file