diff --git a/application/src/main/java/org/thingsboard/server/controller/AiSettingsController.java b/application/src/main/java/org/thingsboard/server/controller/AiSettingsController.java index 2f7aa1dd43..530fc1e56a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AiSettingsController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AiSettingsController.java @@ -63,9 +63,10 @@ public class AiSettingsController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @PostMapping public AiSettings saveAiSettings(@RequestBody AiSettings aiSettings) throws ThingsboardException { - aiSettings.setTenantId(getTenantId()); + var user = getCurrentUser(); + aiSettings.setTenantId(user.getTenantId()); checkEntity(aiSettings.getId(), aiSettings, Resource.AI_SETTINGS); - return aiSettingsService.save(aiSettings); + return tbAiSettingsService.save(aiSettings, user); } @ApiOperation( @@ -143,7 +144,7 @@ public class AiSettingsController extends BaseController { return false; } accessControlService.checkPermission(user, Resource.AI_SETTINGS, Operation.DELETE, aiSettingsId, aiSettingsOpt.get()); - return aiSettingsService.deleteByTenantIdAndId(user.getTenantId(), aiSettingsId); + return tbAiSettingsService.delete(aiSettingsOpt.get(), user); } } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index ef50a6552c..26ff7c1a94 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -177,6 +177,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.action.EntityActionService; import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.entitiy.TbLogEntityActionService; +import org.thingsboard.server.service.entitiy.ai.TbAiSettingsService; import org.thingsboard.server.service.entitiy.user.TbUserSettingsService; import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.profile.TbAssetProfileCache; @@ -379,6 +380,9 @@ public abstract class BaseController { @Autowired protected AiSettingsService aiSettingsService; + @Autowired + protected TbAiSettingsService tbAiSettingsService; + @Value("${server.log_controller_error_stack_trace}") @Getter private boolean logControllerErrorStackTrace; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiSettingsService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiSettingsService.java new file mode 100644 index 0000000000..08e663633d --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiSettingsService.java @@ -0,0 +1,79 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.entitiy.ai; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.ai.AiSettings; +import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.dao.ai.AiSettingsService; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entitiy.AbstractTbEntityService; + +import static java.util.Objects.requireNonNullElseGet; + +@Service +@TbCoreComponent +@RequiredArgsConstructor +class DefaultTbAiSettingsService extends AbstractTbEntityService implements TbAiSettingsService { + + private final AiSettingsService aiSettingsService; + + @Override + public AiSettings save(AiSettings aiSettings, User user) { + var actionType = aiSettings.getId() == null ? ActionType.ADDED : ActionType.UPDATED; + + var tenantId = user.getTenantId(); + aiSettings.setTenantId(tenantId); + + AiSettings savedSettings; + try { + savedSettings = aiSettingsService.save(aiSettings); + } catch (Exception e) { + logEntityActionService.logEntityAction(tenantId, requireNonNullElseGet(aiSettings.getId(), () -> emptyId(EntityType.AI_SETTINGS)), aiSettings, actionType, user, e); + throw e; + } + + logEntityActionService.logEntityAction(tenantId, savedSettings.getId(), savedSettings, actionType, user); + + return savedSettings; + } + + @Override + public boolean delete(AiSettings aiSettings, User user) { + var actionType = ActionType.DELETED; + + var tenantId = user.getTenantId(); + var aiSettingsId = aiSettings.getId(); + + boolean deleted; + try { + deleted = aiSettingsService.deleteByTenantIdAndId(tenantId, aiSettingsId); + } catch (Exception e) { + logEntityActionService.logEntityAction(tenantId, aiSettingsId, aiSettings, actionType, user, e, aiSettingsId.toString()); + throw e; + } + + if (deleted) { + logEntityActionService.logEntityAction(tenantId, aiSettingsId, aiSettings, actionType, user, aiSettingsId.toString()); + } + + return deleted; + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/ai/TbAiSettingsService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/ai/TbAiSettingsService.java new file mode 100644 index 0000000000..399a3b2bdd --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/ai/TbAiSettingsService.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.entitiy.ai; + +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.ai.AiSettings; + +public interface TbAiSettingsService { + + AiSettings save(AiSettings aiSettings, User user); + + boolean delete(AiSettings aiSettings, User user); + +} diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index d7dbc0d6ac..5104f2e264 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -846,22 +846,23 @@ audit-log: # Allowed values: OFF (disable), W (log write operations), RW (log read and write operations) logging-level: mask: - "device": "${AUDIT_LOG_MASK_DEVICE:W}" # Device logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "asset": "${AUDIT_LOG_MASK_ASSET:W}" # Asset logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "dashboard": "${AUDIT_LOG_MASK_DASHBOARD:W}" # Dashboard logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "widget_type": "${AUDIT_LOG_MASK_WIDGET_TYPE:W}" # Widget type logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "widgets_bundle": "${AUDIT_LOG_MASK_WIDGETS_BUNDLE:W}" # Widget bundles logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "customer": "${AUDIT_LOG_MASK_CUSTOMER:W}" # Customer logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "user": "${AUDIT_LOG_MASK_USER:W}" # User logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}" # Rule chain logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "alarm": "${AUDIT_LOG_MASK_ALARM:W}" # Alarm logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "entity_view": "${AUDIT_LOG_MASK_ENTITY_VIEW:W}" # Entity view logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "device_profile": "${AUDIT_LOG_MASK_DEVICE_PROFILE:W}" # Device profile logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "asset_profile": "${AUDIT_LOG_MASK_ASSET_PROFILE:W}" # Asset profile logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "edge": "${AUDIT_LOG_MASK_EDGE:W}" # Edge logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "tb_resource": "${AUDIT_LOG_MASK_RESOURCE:W}" # TB resource logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "ota_package": "${AUDIT_LOG_MASK_OTA_PACKAGE:W}" # Ota package logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation - "calculated_field": "${AUDIT_LOG_MASK_CALCULATED_FIELD:W}" # Calculated field logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "device": "${AUDIT_LOG_MASK_DEVICE:W}" # Device logging levels. + "asset": "${AUDIT_LOG_MASK_ASSET:W}" # Asset logging levels. + "dashboard": "${AUDIT_LOG_MASK_DASHBOARD:W}" # Dashboard logging levels. + "widget_type": "${AUDIT_LOG_MASK_WIDGET_TYPE:W}" # Widget type logging levels. + "widgets_bundle": "${AUDIT_LOG_MASK_WIDGETS_BUNDLE:W}" # Widget bundles logging levels. + "customer": "${AUDIT_LOG_MASK_CUSTOMER:W}" # Customer logging levels. + "user": "${AUDIT_LOG_MASK_USER:W}" # User logging levels. + "rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}" # Rule chain logging levels. + "alarm": "${AUDIT_LOG_MASK_ALARM:W}" # Alarm logging levels. + "entity_view": "${AUDIT_LOG_MASK_ENTITY_VIEW:W}" # Entity view logging levels. + "device_profile": "${AUDIT_LOG_MASK_DEVICE_PROFILE:W}" # Device profile logging levels. + "asset_profile": "${AUDIT_LOG_MASK_ASSET_PROFILE:W}" # Asset profile logging levels. + "edge": "${AUDIT_LOG_MASK_EDGE:W}" # Edge logging levels. + "tb_resource": "${AUDIT_LOG_MASK_RESOURCE:W}" # TB resource logging levels. + "ota_package": "${AUDIT_LOG_MASK_OTA_PACKAGE:W}" # Ota package logging levels. + "calculated_field": "${AUDIT_LOG_MASK_CALCULATED_FIELD:W}" # Calculated field logging levels. + "ai_settings": "${AUDIT_LOG_MASK_AI_SETTINGS:W}" # AI settings logging levels. sink: # Type of external sink. possible options: none, elasticsearch type: "${AUDIT_LOG_SINK_TYPE:none}" diff --git a/ui-ngx/src/app/shared/models/entity-type.models.ts b/ui-ngx/src/app/shared/models/entity-type.models.ts index 48cad42e7b..0c7b6ca152 100644 --- a/ui-ngx/src/app/shared/models/entity-type.models.ts +++ b/ui-ngx/src/app/shared/models/entity-type.models.ts @@ -51,6 +51,7 @@ export enum EntityType { MOBILE_APP_BUNDLE = 'MOBILE_APP_BUNDLE', MOBILE_APP = 'MOBILE_APP', CALCULATED_FIELD = 'CALCULATED_FIELD', + AI_SETTINGS = 'AI_SETTINGS', } export enum AliasEntityType { @@ -491,6 +492,13 @@ export const entityTypeTranslations = new Map