Copilot commented on code in PR #12144:
URL: https://github.com/apache/cloudstack/pull/12144#discussion_r3959254726


##########
engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql:
##########
@@ -19,6 +19,22 @@
 -- Schema upgrade from 4.22.1.0 to 4.23.0.0
 --;
 
+CREATE TABLE IF NOT EXISTS `cloud`.`service_offering_category` (
+ `id` bigint unsigned NOT NULL auto_increment,
+ `name` varchar(255) NOT NULL,
+ `uuid` varchar(40) NOT NULL,
+ `sort_key` int NOT NULL DEFAULT 0,
+ PRIMARY KEY  (`id`),
+ CONSTRAINT `uc_service_offering_category__uuid` UNIQUE (`uuid`),
+ CONSTRAINT `uc_service_offering_category__name` UNIQUE (`name`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
+
+INSERT IGNORE INTO `cloud`.`service_offering_category` (id, name, uuid) VALUES 
(1, 'Default', UUID());
+
+CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.service_offering', 'category_id', 
'bigint unsigned NOT NULL DEFAULT 1');
+CALL `cloud`.`IDEMPOTENT_DROP_FOREIGN_KEY`('cloud.service_offering', 
'fk_service_offering__category_id');
+ALTER TABLE `cloud`.`service_offering` ADD CONSTRAINT 
`fk_service_offering__category_id` FOREIGN KEY (`category_id`) REFERENCES 
`cloud`.`service_offering_category` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

Review Comment:
   The migration uses a raw `ALTER TABLE ... ADD CONSTRAINT` which is not 
idempotent; re-running the upgrade (or running on a partially-upgraded DB) can 
fail if the FK already exists. Prefer using the project’s idempotent helper 
(e.g., `IDEMPOTENT_ADD_FOREIGN_KEY`) or an `IF NOT EXISTS`-style mechanism 
consistent with other schema migrations.



##########
api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java:
##########
@@ -286,6 +286,14 @@ public class ServiceOfferingResponse extends 
BaseResponseWithAnnotations {
     @Param(description = "Action to be taken once lease is over", since = 
"4.21.0")
     private String leaseExpiryAction;
 
+    @SerializedName("categoryid")
+    @Param(description = "the ID of the service offering category", since = 
"24.0")
+    private String categoryId;
+
+    @SerializedName("category")
+    @Param(description = "the name of the service offering category", since = 
"24.0")

Review Comment:
   The `since = "24.0"` metadata looks inconsistent with the existing 
versioning scheme in the codebase (e.g., many params use `"4.xx.x"`). If the 
project expects CloudStack-style `4.x` versions, this `since` value should be 
updated to the correct release version for this feature to avoid inaccurate API 
documentation and client generation artifacts.



##########
server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java:
##########
@@ -9555,4 +9590,97 @@ public void setScope(String scope) {
             this.scope = scope;
         }
     }
+
+    @Override
+    @ActionEvent(eventType = 
EventTypes.EVENT_SERVICE_OFFERING_CATEGORY_CREATE, eventDescription = "creating 
service offering category")
+    public ServiceOfferingCategory 
createServiceOfferingCategory(CreateServiceOfferingCategoryCmd cmd) {
+        String name = cmd.getName();
+        Integer sortKey = cmd.getSortKey();
+
+        // Check if category with same name already exists
+        ServiceOfferingCategoryVO existingCategory = 
_serviceOfferingCategoryDao.findByName(name);
+        if (existingCategory != null) {
+            throw new InvalidParameterValueException("Service offering 
category with name " + name + " already exists");
+        }
+
+        ServiceOfferingCategoryVO category = new 
ServiceOfferingCategoryVO(name);
+        if (sortKey != null) {
+            category.setSortKey(sortKey);
+        }
+
+        category = _serviceOfferingCategoryDao.persist(category);
+        CallContext.current().setEventDetails("Service offering category id=" 
+ category.getId());
+        return category;
+    }
+
+    @Override
+    @ActionEvent(eventType = 
EventTypes.EVENT_SERVICE_OFFERING_CATEGORY_DELETE, eventDescription = "deleting 
service offering category")
+    public boolean 
deleteServiceOfferingCategory(DeleteServiceOfferingCategoryCmd cmd) {
+        Long categoryId = cmd.getId();
+
+        ServiceOfferingCategoryVO category = 
_serviceOfferingCategoryDao.findById(categoryId);
+        if (category == null) {
+            throw new InvalidParameterValueException("Unable to find service 
offering category with id " + categoryId);
+        }
+
+        // Check if any service offering is using this category
+        // For now we'll just check if it's the default category (id=1)
+        if (categoryId == 1L) {
+            throw new InvalidParameterValueException("Cannot delete the 
default service offering category");
+        }

Review Comment:
   The hard-coded default category ID (`1L`) is a fragile “magic number” that 
tightly couples runtime behavior to an assumption about DB contents. If the 
default row’s ID ever differs (e.g., different seed strategy or pre-existing 
table), deletion protection will be incorrect. A more robust approach is to 
explicitly model “default” (e.g., `is_default` column), or resolve the 
protected category by a stable attribute (like reserved UUID/name) and enforce 
that at the DB/application level.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to