package acl import ( "errors" "fmt" "strings" "gorm.io/gorm" ) // GetResources returns all resources. // May return [ErrNotInitialized] or db error. func (s *Service) GetResources() ([]Resource, error) { if !s.isInitialized() { return nil, ErrNotInitialized } var resources []Resource if err := s.db.Order("id").Find(&resources).Error; err != nil { return nil, fmt.Errorf("db error: %w", err) } return resources, nil } // CreateResource creates a new resource with the given key or returns existing one. // Returns ID of created resource. // May return [ErrNotInitialized], [ErrInvalidResourceKey], [ErrResourceAlreadyExists] or db error. func (s *Service) CreateResource(key string) (uint, error) { if !s.isInitialized() { return 0, ErrNotInitialized } key = strings.TrimSpace(key) if key == "" { return 0, ErrInvalidResourceKey } var res Resource if err := s.db.Where("key = ?", key).First(&res).Error; err == nil { // already exists return res.ID, ErrResourceAlreadyExists } else if !errors.Is(err, gorm.ErrRecordNotFound) { // other db error return 0, fmt.Errorf("db error: %w", err) } res = Resource{Key: key} if err := s.db.Create(&res).Error; err != nil { return 0, fmt.Errorf("db error: %w", err) } return res.ID, nil } // GetResourceByID returns the resource with the given ID. // May return [ErrNotInitialized], [ErrResourceNotFound] or db error. func (s *Service) GetResourceByID(resourceID uint) (*Resource, error) { if !s.isInitialized() { return nil, ErrNotInitialized } var res Resource if err := s.db.First(&res, resourceID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrResourceNotFound } return nil, fmt.Errorf("db error: %w", err) } return &res, nil } // UpdateResource updates the key of a resource. // May return [ErrNotInitialized], [ErrInvalidResourceKey], [ErrResourceNotFound], [ErrSameResourceKey] or db error. func (s *Service) UpdateResource(resourceID uint, newKey string) error { if !s.isInitialized() { return ErrNotInitialized } newKey = strings.TrimSpace(newKey) if newKey == "" { return ErrInvalidResourceKey } var res Resource if err := s.db.First(&res, resourceID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return ErrResourceNotFound } return fmt.Errorf("db error: %w", err) } // same key? if res.Key == newKey { return ErrSameResourceKey } // check if key used by another resource var count int64 if err := s.db.Model(&Resource{}). Where("key = ? AND id != ?", newKey, resourceID). Count(&count).Error; err != nil { return fmt.Errorf("db error: %w", err) } if count > 0 { return ErrSameResourceKey } res.Key = newKey if err := s.db.Save(&res).Error; err != nil { return fmt.Errorf("failed to update resource: %w", err) } return nil } // DeleteResource deletes a resource. // May return [ErrNotInitialized], [ErrResourceNotFound], [ErrResourceInUse] or db error. func (s *Service) DeleteResource(resourceID uint) error { if !s.isInitialized() { return ErrNotInitialized } result := s.db.Delete(&Resource{}, resourceID) if err := result.Error; err != nil { if strings.Contains(err.Error(), "FOREIGN KEY constraint failed") { return ErrResourceInUse } return fmt.Errorf("db error: %w", err) } if result.RowsAffected == 0 { return ErrResourceNotFound } return nil }