Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions backend/cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1713,6 +1713,19 @@ func main() {
// must be registered BEFORE /assets/:id, or "statistics" is parsed as an
// asset UUID and the route answers 400 for a request that is perfectly valid.
protected.Get("/assets/statistics", assetRead, assetHandler.GetAssetStatistics)
// #861 — CSV import of the inventory: every row or none, one transaction,
// and the plan cap checked against the whole file.
assetImportHandler := handlers.NewAssetImportHandler(
assetapp.NewImportAssetsUseCase(repository.RunAssetTx(database.DB), repository.ListAssetNames(database.DB)).
WithActivation(activationRecorder).
WithCapacity(func(ctx context.Context, tenant uuid.UUID) (int, error) {
_, limit, used, _, err := entitlementService.Capacity(ctx, tenant, ent.LimitAssets)
if err != nil || limit == ent.Unlimited || used < 0 {
return -1, err
}
return max(limit-used, 0), nil
}))
protected.Post("/assets/import", assetCreate, capAssets, assetImportHandler.ImportAssets)
protected.Get("/asset-dependencies", assetRead, assetDepHandler.ListAssetDependencies)
protected.Post("/asset-dependencies", assetUpdate, assetDepHandler.CreateAssetDependency)
protected.Delete("/asset-dependencies/:id", assetUpdate, assetDepHandler.DeleteAssetDependency)
Expand Down
9 changes: 8 additions & 1 deletion backend/internal/application/asset/create_asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type CreateAssetInput struct {
// Attributes is the raw, unvalidated bag from the client. It is only ever
// persisted after AttributeValidator has checked and coerced it.
Attributes map[string]any
// Source records how the asset entered the inventory. Empty means MANUAL.
Source string
}

// AttributeValidator validates a raw attribute bag against the tenant's schema
Expand Down Expand Up @@ -97,14 +99,19 @@ func (uc *CreateAssetUseCase) Execute(ctx context.Context, tenantID uuid.UUID, i
return nil, domain.NewValidationError("attributes require an asset category — pick one so the values can be validated against its schema")
}

source := input.Source
if source == "" {
source = "MANUAL"
}

assetEntity := &domain.Asset{
ID: uuid.New(),
TenantID: tenantID,
Name: input.Name,
Type: input.Type,
Criticality: criticality,
Owner: input.Owner,
Source: "MANUAL",
Source: source,
Category: category,
Attributes: attrs,
}
Expand Down
Loading
Loading