Browse Source

Merge with main feature branch

pull/6591/head
Andrii Shvaika 4 years ago
parent
commit
f2a8832489
  1. 3
      application/src/main/data/upgrade/3.3.4/schema_update.sql
  2. 81
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  3. 46
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  4. 1
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  5. 7
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
  6. 2
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  7. 12
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  8. 1
      application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java
  9. 1
      application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java
  10. 97
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  11. 10
      application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java
  12. 55
      application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java
  13. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsService.java
  14. 19
      common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java
  15. 42
      common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java
  16. 7
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java
  17. 21
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionControlAuthMethod.java
  18. 4
      common/version-control/pom.xml
  19. 11
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java
  20. 128
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java
  21. 4
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java
  22. 4
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java
  23. 2
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  24. 9
      dao/src/main/java/org/thingsboard/server/dao/model/sql/AdminSettingsEntity.java
  25. 6
      dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsDao.java
  26. 11
      dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java
  27. 7
      dao/src/main/java/org/thingsboard/server/dao/sql/settings/AdminSettingsRepository.java
  28. 13
      dao/src/main/java/org/thingsboard/server/dao/sql/settings/JpaAdminSettingsDao.java
  29. 1
      dao/src/main/resources/sql/schema-entities.sql
  30. 5
      pom.xml

3
application/src/main/data/upgrade/3.3.4/schema_update.sql

@ -26,3 +26,6 @@ ALTER TABLE dashboard
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE customer
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE admin_settings
ADD COLUMN IF NOT EXISTS tenant_id uuid NOT NULL DEFAULT '13814000-1dd2-11b2-8080-808080808080';

81
application/src/main/java/org/thingsboard/server/controller/AdminController.java

@ -19,29 +19,30 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import org.thingsboard.server.service.update.UpdateService;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.*;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID;
@RestController
@TbCoreComponent
@ -60,6 +61,9 @@ public class AdminController extends BaseController {
@Autowired
private SystemSecurityService systemSecurityService;
@Autowired
private EntitiesVersionControlService versionControlService;
@Autowired
private UpdateService updateService;
@ -96,6 +100,7 @@ public class AdminController extends BaseController {
@RequestBody AdminSettings adminSettings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
adminSettings.setTenantId(getTenantId());
adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings));
if (adminSettings.getKey().equals("mail")) {
mailService.updateMailConfiguration();
@ -180,6 +185,68 @@ public class AdminController extends BaseController {
}
}
@ApiOperation(value = "Get version control settings (getVersionControlSettings)",
notes = "Get the version control settings object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/vcSettings")
@ResponseBody
public EntitiesVersionControlSettings getVersionControlSettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
EntitiesVersionControlSettings versionControlSettings = checkNotNull(versionControlService.getVersionControlSettings(getTenantId()));
versionControlSettings.setPassword(null);
versionControlSettings.setPrivateKey(null);
versionControlSettings.setPrivateKeyPassword(null);
return versionControlSettings;
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Creates or Updates the version control settings (saveVersionControlSettings)",
notes = "Creates or Updates the version control settings object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/vcSettings")
public void saveVersionControlSettings(@RequestBody EntitiesVersionControlSettings settings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
versionControlService.saveVersionControlSettings(getTenantId(), settings);
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Delete version control settings (deleteVersionControlSettings)",
notes = "Deletes the version control settings."
+ TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/vcSettings", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteVersionControlSettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.DELETE);
versionControlService.deleteVersionControlSettings(getTenantId());
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Check version control access (checkVersionControlAccess)",
notes = "Attempts to check version control access. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/vcSettings/checkAccess", method = RequestMethod.POST)
public void checkVersionControlAccess(
@ApiParam(value = "A JSON value representing the Entities Version Control Settings.")
@RequestBody EntitiesVersionControlSettings settings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
settings = checkNotNull(settings);
versionControlService.checkVersionControlAccess(getTenantId(), settings);
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Check for new Platform Releases (checkUpdates)",
notes = "Check notifications about new platform releases. "
+ SYSTEM_AUTHORITY_PARAGRAPH)

46
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -18,21 +18,15 @@ package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
@ -263,7 +257,7 @@ public class EntitiesVersionControlController extends BaseController {
List<String> remoteBranches = versionControlService.listBranches(getTenantId());
List<BranchInfo> infos = new ArrayList<>();
String defaultBranch = getSettings().getDefaultBranch();
String defaultBranch = versionControlService.getVersionControlSettings(getTenantId()).getDefaultBranch();
if (StringUtils.isNotEmpty(defaultBranch)) {
remoteBranches.remove(defaultBranch);
infos.add(new BranchInfo(defaultBranch, true));
@ -276,40 +270,6 @@ public class EntitiesVersionControlController extends BaseController {
}
}
@ApiOperation(value = "", notes = "" +
"```\n{\n" +
" \"repositoryUri\": \"https://github.com/User/repo.git\",\n" +
" \"username\": \"User\",\n" +
" \"password\": \"api_key\",\n" +
" \"defaultBranch\": \"master\"\n" +
"}\n```")
@GetMapping("/settings")
public EntitiesVersionControlSettings getSettings() throws ThingsboardException {
try {
return versionControlService.getSettings(getTenantId());
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "", notes = "" +
"```\n{\n" +
" \"repositoryUri\": \"https://github.com/User/repo.git\",\n" +
" \"username\": \"User\",\n" +
" \"password\": \"api_key\",\n" +
" \"defaultBranch\": \"master\"\n" +
"}\n```")
@PostMapping("/settings")
public void saveSettings(@RequestBody EntitiesVersionControlSettings settings) throws ThingsboardException {
try {
versionControlService.saveSettings(getTenantId(), settings);
} catch (Exception e) {
throw handleException(e);
}
}
@Data
public static class BranchInfo {
private final String name;

1
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -219,6 +219,7 @@ public class ThingsboardInstallService {
databaseEntitiesUpgradeService.upgradeDatabase("3.3.3");
case "3.3.4":
log.info("Upgrading ThingsBoard from version 3.3.4 to 3.4.0 ...");
databaseEntitiesUpgradeService.upgradeDatabase("3.3.4");
log.info("Updating system data...");
systemDataLoaderService.updateSystemWidgets();
break;

7
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java

@ -83,7 +83,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings)));
AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
AdminSettings tenantMailSettings = convertToTenantAdminSettings(tenantId, systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings)));
@ -91,7 +91,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates)));
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(tenantId, systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates)));
@ -151,8 +151,9 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
}
}
private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) {
private AdminSettings convertToTenantAdminSettings(TenantId tenantId, String key, ObjectNode jsonValue) {
AdminSettings tenantMailSettings = new AdminSettings();
tenantMailSettings.setTenantId(tenantId);
jsonValue.put("useSystemMailSettings", true);
tenantMailSettings.setJsonValue(jsonValue);
tenantMailSettings.setKey(key);

2
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -231,6 +231,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
@Override
public void createAdminSettings() throws Exception {
AdminSettings generalSettings = new AdminSettings();
generalSettings.setTenantId(TenantId.SYS_TENANT_ID);
generalSettings.setKey("general");
ObjectNode node = objectMapper.createObjectNode();
node.put("baseUrl", "http://localhost:8080");
@ -239,6 +240,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, generalSettings);
AdminSettings mailSettings = new AdminSettings();
mailSettings.setTenantId(TenantId.SYS_TENANT_ID);
mailSettings.setKey("mail");
node = objectMapper.createObjectNode();
node.put("mailFrom", "ThingsBoard <sysadmin@localhost.localdomain>");

12
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -534,6 +534,18 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
log.error("Failed updating schema!!!", e);
}
break;
case "3.3.4":
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
log.info("Updating schema ...");
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.4", SCHEMA_UPDATE_SQL);
loadSql(schemaUpdateFile, conn);
log.info("Updating schema settings...");
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004000;");
log.info("Schema updated.");
} catch (Exception e) {
log.error("Failed updating schema!!!", e);
}
break;
default:
throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
}

1
application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java

@ -28,6 +28,7 @@ public class TenantAdminPermissions extends AbstractPermissions {
public TenantAdminPermissions() {
super();
put(Resource.ADMIN_SETTINGS, PermissionChecker.allowAllPermissionChecker);
put(Resource.ALARM, tenantEntityPermissionChecker);
put(Resource.ASSET, tenantEntityPermissionChecker);
put(Resource.DEVICE, tenantEntityPermissionChecker);

1
application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java

@ -107,6 +107,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, "securitySettings");
if (adminSettings == null) {
adminSettings = new AdminSettings();
adminSettings.setTenantId(tenantId);
adminSettings.setKey("securitySettings");
}
adminSettings.setJsonValue(JacksonUtil.valueToTree(securitySettings));

97
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -16,39 +16,35 @@
package org.thingsboard.server.service.sync.vc;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.sync.vc.*;
import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadConfig;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.ie.EntitiesExportImportService;
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.ComplexVersionCreateRequest;
import org.thingsboard.server.common.data.sync.vc.request.create.SingleEntityVersionCreateRequest;
import org.thingsboard.server.common.data.sync.vc.request.create.SyncStrategy;
@ -79,12 +75,10 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
private final GitVersionControlService gitService;
private final EntitiesExportImportService exportImportService;
private final ExportableEntitiesService exportableEntitiesService;
private final AttributesService attributesService;
private final AdminSettingsService adminSettingsService;
private final EntityService entityService;
private final TransactionTemplate transactionTemplate;
public static final String SETTINGS_KEY = "vc";
@Override
public VersionCreationResult saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception {
var commit = gitService.prepareCommit(user.getTenantId(), request);
@ -208,7 +202,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
List<EntityExportData<?>> entityDataList;
do {
entityDataList = gitService.getEntities(user.getTenantId(), request.getBranch(), request.getVersionId(), entityType, offset, limit);
for (EntityExportData<?> entityData : entityDataList) {
for (EntityExportData entityData : entityDataList) {
EntityImportResult<?> importResult = exportImportService.importEntity(user, entityData, EntityImportSettings.builder()
.updateRelations(config.isLoadRelations())
.findExistingByName(config.isFindExistingEntityByName())
@ -282,18 +276,77 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
return gitService.listBranches(tenantId);
}
@SneakyThrows
@Override
public void saveSettings(TenantId tenantId, EntitiesVersionControlSettings settings) {
attributesService.save(tenantId, tenantId, DataConstants.SERVER_SCOPE, List.of(
new BaseAttributeKvEntry(System.currentTimeMillis(), new JsonDataEntry(SETTINGS_KEY, JacksonUtil.toString(settings)))
)).get();
public EntitiesVersionControlSettings getVersionControlSettings(TenantId tenantId) {
AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, SETTINGS_KEY);
if (adminSettings != null) {
try {
return JacksonUtil.convertValue(adminSettings.getJsonValue(), EntitiesVersionControlSettings.class);
} catch (Exception e) {
throw new RuntimeException("Failed to load version control settings!", e);
}
}
return null;
}
@Override
public EntitiesVersionControlSettings saveVersionControlSettings(TenantId tenantId, EntitiesVersionControlSettings versionControlSettings) {
EntitiesVersionControlSettings storedSettings = getVersionControlSettings(tenantId);
versionControlSettings = this.restoreCredentials(versionControlSettings, storedSettings);
AdminSettings adminSettings = new AdminSettings();
adminSettings.setTenantId(tenantId);
adminSettings.setKey(SETTINGS_KEY);
adminSettings.setJsonValue(JacksonUtil.valueToTree(versionControlSettings));
AdminSettings savedAdminSettings = adminSettingsService.saveAdminSettings(tenantId, adminSettings);
EntitiesVersionControlSettings savedVersionControlSettings;
try {
savedVersionControlSettings = JacksonUtil.convertValue(savedAdminSettings.getJsonValue(), EntitiesVersionControlSettings.class);
} catch (Exception e) {
throw new RuntimeException("Failed to load version control settings!", e);
}
try {
gitService.clearRepository(tenantId);
gitService.initRepository(tenantId, savedVersionControlSettings);
} catch (Exception e) {
throw new RuntimeException("Failed to init repository!", e);
}
return savedVersionControlSettings;
}
gitService.initRepository(tenantId, settings);
@Override
public void deleteVersionControlSettings(TenantId tenantId) {
if (adminSettingsService.deleteAdminSettings(tenantId, SETTINGS_KEY)) {
gitService.clearRepository(tenantId);
}
}
@Override
public EntitiesVersionControlSettings getSettings(TenantId tenantId) {
return gitService.getSettings(tenantId);
public void checkVersionControlAccess(TenantId tenantId, EntitiesVersionControlSettings settings) throws ThingsboardException {
EntitiesVersionControlSettings storedSettings = getVersionControlSettings(tenantId);
settings = this.restoreCredentials(settings, storedSettings);
try {
gitService.testRepository(tenantId, settings);
} catch (Exception e) {
throw new ThingsboardException(String.format("Unable to access repository: %s", e.getMessage()),
ThingsboardErrorCode.GENERAL);
}
}
private EntitiesVersionControlSettings restoreCredentials(EntitiesVersionControlSettings settings, EntitiesVersionControlSettings storedSettings) {
VersionControlAuthMethod authMethod = settings.getAuthMethod();
if (VersionControlAuthMethod.USERNAME_PASSWORD.equals(authMethod) && settings.getPassword() == null) {
if (storedSettings != null) {
settings.setPassword(storedSettings.getPassword());
}
} else if (VersionControlAuthMethod.PRIVATE_KEY.equals(authMethod) && settings.getPrivateKey() == null) {
if (storedSettings != null) {
settings.setPrivateKey(storedSettings.getPrivateKey());
if (StringUtils.isEmpty(settings.getPrivateKeyPassword()) &&
StringUtils.isNotEmpty(storedSettings.getPrivateKeyPassword())) {
settings.setPrivateKeyPassword(storedSettings.getPrivateKeyPassword());
}
}
}
return settings;
}
}

10
application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.sync.vc;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -31,6 +32,8 @@ import java.util.List;
public interface EntitiesVersionControlService {
String SETTINGS_KEY = "entitiesVersionControl";
VersionCreationResult saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception;
@ -51,9 +54,12 @@ public interface EntitiesVersionControlService {
List<String> listBranches(TenantId tenantId) throws Exception;
EntitiesVersionControlSettings getVersionControlSettings(TenantId tenantId);
EntitiesVersionControlSettings saveVersionControlSettings(TenantId tenantId, EntitiesVersionControlSettings versionControlSettings);
void saveSettings(TenantId tenantId, EntitiesVersionControlSettings settings);
void deleteVersionControlSettings(TenantId tenantId);
EntitiesVersionControlSettings getSettings(TenantId tenantId);
void checkVersionControlAccess(TenantId tenantId, EntitiesVersionControlSettings settings) throws ThingsboardException;
}

55
application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java

@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
@ -38,6 +39,7 @@ import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.dao.tenant.TenantDao;
import org.thingsboard.server.queue.util.AfterStartUp;
@ -63,14 +65,14 @@ public class LocalGitVersionControlService implements GitVersionControlService {
private final ObjectWriter jsonWriter = new ObjectMapper().writer(SerializationFeature.INDENT_OUTPUT);
private final GitRepositoryService gitRepositoryService;
private final TenantDao tenantDao;
private final AttributesService attributesService;
private final AdminSettingsService adminSettingsService;
private final ConcurrentMap<TenantId, Lock> tenantRepoLocks = new ConcurrentHashMap<>();
private final Map<TenantId, PendingCommit> pendingCommitMap = new HashMap<>();
@AfterStartUp
public void init() {
DaoUtil.processInBatches(tenantDao::findTenantsIds, 100, tenantId -> {
EntitiesVersionControlSettings settings = getSettings(tenantId);
EntitiesVersionControlSettings settings = getVersionControlSettings(tenantId);
if (settings != null) {
try {
gitRepositoryService.initRepository(tenantId, settings);
@ -82,18 +84,17 @@ public class LocalGitVersionControlService implements GitVersionControlService {
}
@Override
@SneakyThrows
public EntitiesVersionControlSettings getSettings(TenantId tenantId) {
return attributesService.find(tenantId, tenantId, DataConstants.SERVER_SCOPE, DefaultEntitiesVersionControlService.SETTINGS_KEY).get()
.flatMap(KvEntry::getJsonValue)
.map(json -> {
try {
return JacksonUtil.fromString(json, EntitiesVersionControlSettings.class);
} catch (IllegalArgumentException e) {
return null;
}
})
.orElse(null);
public void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) {
var lock = getRepoLock(tenantId);
lock.lock();
try {
gitRepositoryService.testRepository(tenantId, settings);
} catch (Exception e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
@Override
@ -110,6 +111,20 @@ public class LocalGitVersionControlService implements GitVersionControlService {
}
}
@Override
public void clearRepository(TenantId tenantId) {
var lock = getRepoLock(tenantId);
lock.lock();
try {
gitRepositoryService.clearRepository(tenantId);
} catch (Exception e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
@Override
public PendingCommit prepareCommit(TenantId tenantId, VersionCreateRequest request) {
var lock = getRepoLock(tenantId);
@ -214,6 +229,18 @@ public class LocalGitVersionControlService implements GitVersionControlService {
}
}
private EntitiesVersionControlSettings getVersionControlSettings(TenantId tenantId) {
AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, EntitiesVersionControlService.SETTINGS_KEY);
if (adminSettings != null) {
try {
return JacksonUtil.convertValue(adminSettings.getJsonValue(), EntitiesVersionControlSettings.class);
} catch (Exception e) {
throw new RuntimeException("Failed to load version control settings!", e);
}
}
return null;
}
private List<EntityVersion> listVersions(TenantId tenantId, String branch, String path) {
try {
return gitRepositoryService.listVersions(tenantId, branch, path);

2
common/dao-api/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsService.java

@ -27,4 +27,6 @@ public interface AdminSettingsService {
AdminSettings saveAdminSettings(TenantId tenantId, AdminSettings adminSettings);
boolean deleteAdminSettings(TenantId tenantId, String key);
}

19
common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java

@ -21,14 +21,17 @@ import org.thingsboard.server.common.data.id.AdminSettingsId;
import com.fasterxml.jackson.databind.JsonNode;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@ApiModel
public class AdminSettings extends BaseData<AdminSettingsId> {
public class AdminSettings extends BaseData<AdminSettingsId> implements HasTenantId {
private static final long serialVersionUID = -7670322981725511892L;
private TenantId tenantId;
@NoXss
@Length(fieldName = "key")
private String key;
@ -44,6 +47,7 @@ public class AdminSettings extends BaseData<AdminSettingsId> {
public AdminSettings(AdminSettings adminSettings) {
super(adminSettings);
this.tenantId = adminSettings.getTenantId();
this.key = adminSettings.getKey();
this.jsonValue = adminSettings.getJsonValue();
}
@ -60,7 +64,16 @@ public class AdminSettings extends BaseData<AdminSettingsId> {
return super.getCreatedTime();
}
@ApiModelProperty(position = 3, value = "The Administration Settings key, (e.g. 'general' or 'mail')", example = "mail")
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", readOnly = true)
public TenantId getTenantId() {
return tenantId;
}
public void setTenantId(TenantId tenantId) {
this.tenantId = tenantId;
}
@ApiModelProperty(position = 4, value = "The Administration Settings key, (e.g. 'general' or 'mail')", example = "mail")
public String getKey() {
return key;
}
@ -69,7 +82,7 @@ public class AdminSettings extends BaseData<AdminSettingsId> {
this.key = key;
}
@ApiModelProperty(position = 4, value = "JSON representation of the Administration Settings value")
@ApiModelProperty(position = 5, value = "JSON representation of the Administration Settings value")
public JsonNode getJsonValue() {
return jsonValue;
}

42
common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java

@ -17,6 +17,10 @@ package org.thingsboard.server.common.data;
public class StringUtils {
public static final String EMPTY = "";
public static final int INDEX_NOT_FOUND = -1;
public static boolean isEmpty(String source) {
return source == null || source.isEmpty();
}
@ -32,4 +36,42 @@ public class StringUtils {
public static boolean isNotBlank(String source) {
return source != null && !source.isEmpty() && !source.trim().isEmpty();
}
public static String removeStart(final String str, final String remove) {
if (isEmpty(str) || isEmpty(remove)) {
return str;
}
if (str.startsWith(remove)){
return str.substring(remove.length());
}
return str;
}
public static String substringBefore(final String str, final String separator) {
if (isEmpty(str) || separator == null) {
return str;
}
if (separator.isEmpty()) {
return EMPTY;
}
final int pos = str.indexOf(separator);
if (pos == INDEX_NOT_FOUND) {
return str;
}
return str.substring(0, pos);
}
public static String substringBetween(final String str, final String open, final String close) {
if (str == null || open == null || close == null) {
return null;
}
final int start = str.indexOf(open);
if (start != INDEX_NOT_FOUND) {
final int end = str.indexOf(close, start + open.length());
if (end != INDEX_NOT_FOUND) {
return str.substring(start + open.length(), end);
}
}
return null;
}
}

7
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java

@ -16,11 +16,14 @@
package org.thingsboard.server.common.data.sync.vc;
import lombok.Data;
@Data
public class EntitiesVersionControlSettings {
private String repositoryUri;
private VersionControlAuthMethod authMethod;
private String username;
private String password;
private String privateKeyFileName;
private String privateKey;
private String privateKeyPassword;
private String defaultBranch;
}
}

21
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionControlAuthMethod.java

@ -0,0 +1,21 @@
/**
* Copyright © 2016-2022 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.common.data.sync.vc;
public enum VersionControlAuthMethod {
USERNAME_PASSWORD,
PRIVATE_KEY
}

4
common/version-control/pom.xml

@ -101,6 +101,10 @@
<artifactId>grpc-stub</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ssh.apache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

11
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java

@ -205,6 +205,12 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
.collect(Collectors.toList());
}
@Override
public void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception {
Path repositoryDirectory = Path.of(repositoriesFolder, tenantId.getId().toString());
GitRepository.test(settings, repositoryDirectory.toFile());
}
@Override
public void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception {
Path repositoryDirectory = Path.of(repositoriesFolder, tenantId.getId().toString());
@ -214,11 +220,12 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
}
Files.createDirectories(repositoryDirectory);
repository = GitRepository.clone(settings.getRepositoryUri(), settings.getUsername(), settings.getPassword(), repositoryDirectory.toFile());
repository = GitRepository.clone(settings, repositoryDirectory.toFile());
repositories.put(tenantId, repository);
}
private void clearRepository(TenantId tenantId) throws IOException {
@Override
public void clearRepository(TenantId tenantId) throws IOException {
GitRepository repository = repositories.get(tenantId);
if (repository != null) {
FileUtils.deleteDirectory(new File(repository.getDirectory()));

128
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java

@ -18,13 +18,8 @@ package org.thingsboard.server.service.sync.vc;
import com.google.common.collect.Streams;
import lombok.Data;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.LogCommand;
import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.TransportCommand;
import org.apache.sshd.common.util.security.SecurityUtils;
import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@ -33,14 +28,27 @@ import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.SshTransport;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.transport.sshd.JGitKeyCache;
import org.eclipse.jgit.transport.sshd.ServerKeyDatabase;
import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
import org.eclipse.jgit.transport.sshd.SshdSessionFactoryBuilder;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.data.sync.vc.VersionControlAuthMethod;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -49,32 +57,59 @@ public class GitRepository {
private final Git git;
private final CredentialsProvider credentialsProvider;
private final SshdSessionFactory sshSessionFactory;
@Getter
private final String directory;
private GitRepository(Git git, CredentialsProvider credentialsProvider, String directory) {
private GitRepository(Git git, CredentialsProvider credentialsProvider, SshdSessionFactory sshSessionFactory, String directory) {
this.git = git;
this.credentialsProvider = credentialsProvider;
this.sshSessionFactory = sshSessionFactory;
this.directory = directory;
}
public static GitRepository clone(String uri, String username, String password, File directory) throws GitAPIException {
CredentialsProvider credentialsProvider = newCredentialsProvider(username, password);
Git git = Git.cloneRepository()
.setURI(uri)
public static GitRepository clone(EntitiesVersionControlSettings settings, File directory) throws GitAPIException {
CredentialsProvider credentialsProvider = null;
SshdSessionFactory sshSessionFactory = null;
if (VersionControlAuthMethod.USERNAME_PASSWORD.equals(settings.getAuthMethod())) {
credentialsProvider = newCredentialsProvider(settings.getUsername(), settings.getPassword());
} else if (VersionControlAuthMethod.PRIVATE_KEY.equals(settings.getAuthMethod())) {
sshSessionFactory = newSshdSessionFactory(settings.getPrivateKey(), settings.getPrivateKeyPassword(), directory);
}
CloneCommand cloneCommand = Git.cloneRepository()
.setURI(settings.getRepositoryUri())
.setDirectory(directory)
.setNoCheckout(true)
.setCredentialsProvider(credentialsProvider)
.call();
return new GitRepository(git, credentialsProvider, directory.getAbsolutePath());
.setNoCheckout(true);
configureTransportCommand(cloneCommand, credentialsProvider, sshSessionFactory);
Git git = cloneCommand.call();
return new GitRepository(git, credentialsProvider, sshSessionFactory, directory.getAbsolutePath());
}
public static GitRepository open(File directory, String username, String password) throws IOException {
public static GitRepository open(File directory, EntitiesVersionControlSettings settings) throws IOException {
Git git = Git.open(directory);
return new GitRepository(git, newCredentialsProvider(username, password), directory.getAbsolutePath());
CredentialsProvider credentialsProvider = null;
SshdSessionFactory sshSessionFactory = null;
if (VersionControlAuthMethod.USERNAME_PASSWORD.equals(settings.getAuthMethod())) {
credentialsProvider = newCredentialsProvider(settings.getUsername(), settings.getPassword());
} else if (VersionControlAuthMethod.PRIVATE_KEY.equals(settings.getAuthMethod())) {
sshSessionFactory = newSshdSessionFactory(settings.getPrivateKey(), settings.getPrivateKeyPassword(), directory);
}
return new GitRepository(git, credentialsProvider, sshSessionFactory, directory.getAbsolutePath());
}
public static void test(EntitiesVersionControlSettings settings, File directory) throws GitAPIException {
CredentialsProvider credentialsProvider = null;
SshdSessionFactory sshSessionFactory = null;
if (VersionControlAuthMethod.USERNAME_PASSWORD.equals(settings.getAuthMethod())) {
credentialsProvider = newCredentialsProvider(settings.getUsername(), settings.getPassword());
} else if (VersionControlAuthMethod.PRIVATE_KEY.equals(settings.getAuthMethod())) {
sshSessionFactory = newSshdSessionFactory(settings.getPrivateKey(), settings.getPrivateKeyPassword(), directory);
}
LsRemoteCommand lsRemoteCommand = Git.lsRemoteRepository().setRemote(settings.getRepositoryUri());
configureTransportCommand(lsRemoteCommand, credentialsProvider, sshSessionFactory);
lsRemoteCommand.call();
}
public void fetch() throws GitAPIException {
execute(git.fetch()
@ -111,7 +146,6 @@ public class GitRepository {
.distinct().collect(Collectors.toList());
}
public List<Commit> listCommits(String branch, int limit) throws IOException, GitAPIException {
return listCommits(branch, null, limit);
}
@ -250,16 +284,66 @@ public class GitRepository {
}
private <C extends GitCommand<T>, T> T execute(C command) throws GitAPIException {
if (command instanceof TransportCommand && credentialsProvider != null) {
((TransportCommand<?, ?>) command).setCredentialsProvider(credentialsProvider);
if (command instanceof TransportCommand) {
configureTransportCommand((TransportCommand) command, credentialsProvider, sshSessionFactory);
}
return command.call();
}
private static void configureTransportCommand(TransportCommand transportCommand, CredentialsProvider credentialsProvider, SshdSessionFactory sshSessionFactory) {
if (credentialsProvider != null) {
transportCommand.setCredentialsProvider(credentialsProvider);
}
if (sshSessionFactory != null) {
transportCommand.setTransportConfigCallback(transport -> {
if (transport instanceof SshTransport) {
SshTransport sshTransport = (SshTransport) transport;
sshTransport.setSshSessionFactory(sshSessionFactory);
}
});
}
}
private static CredentialsProvider newCredentialsProvider(String username, String password) {
return new UsernamePasswordCredentialsProvider(username, password);
return new UsernamePasswordCredentialsProvider(username, password == null ? "" : password);
}
private static SshdSessionFactory newSshdSessionFactory(String privateKey, String password, File directory) {
SshdSessionFactory sshSessionFactory = null;
if (StringUtils.isNotBlank(privateKey)) {
Iterable<KeyPair> keyPairs = loadKeyPairs(privateKey, password);
sshSessionFactory = new SshdSessionFactoryBuilder()
.setPreferredAuthentications("publickey")
.setDefaultKeysProvider(file -> keyPairs)
.setHomeDirectory(directory)
.setSshDirectory(directory)
.setServerKeyDatabase((file, file2) -> new ServerKeyDatabase() {
@Override
public List<PublicKey> lookup(String connectAddress, InetSocketAddress remoteAddress, Configuration config) {
return Collections.emptyList();
}
@Override
public boolean accept(String connectAddress, InetSocketAddress remoteAddress, PublicKey serverKey, Configuration config, CredentialsProvider provider) {
return true;
}
})
.build(new JGitKeyCache());
}
return sshSessionFactory;
}
private static Iterable<KeyPair> loadKeyPairs(String privateKeyContent, String password) {
Iterable<KeyPair> keyPairs = null;
try {
keyPairs = SecurityUtils.loadKeyPairIdentities(null,
null, new ByteArrayInputStream(privateKeyContent.getBytes()), (session, resourceKey, retryIndex) -> password);
} catch (Exception e) {}
if (keyPairs == null) {
throw new IllegalArgumentException("Failed to load ssh private key");
}
return keyPairs;
}
@Data
public static class Commit {

4
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java

@ -32,8 +32,12 @@ public interface GitRepositoryService {
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, String path) throws Exception;
void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception;
void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception;
void clearRepository(TenantId tenantId) throws IOException;
void add(PendingCommit commit, String relativePath, String entityDataJson) throws IOException;
void deleteFolderContent(PendingCommit commit, String relativePath) throws IOException;

4
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java

@ -30,10 +30,12 @@ import java.util.List;
public interface GitVersionControlService {
EntitiesVersionControlSettings getSettings(TenantId tenantId);
void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings);
void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings);
void clearRepository(TenantId tenantId);
PendingCommit prepareCommit(TenantId tenantId, VersionCreateRequest request);
void addToCommit(PendingCommit commit, EntityExportData<ExportableEntity<EntityId>> entityData);

2
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -90,6 +90,8 @@ public class ModelConstants {
* Cassandra admin_settings constants.
*/
public static final String ADMIN_SETTINGS_COLUMN_FAMILY_NAME = "admin_settings";
public static final String ADMIN_SETTINGS_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String ADMIN_SETTINGS_KEY_PROPERTY = "key";
public static final String ADMIN_SETTINGS_JSON_VALUE_PROPERTY = "json_value";

9
dao/src/main/java/org/thingsboard/server/dao/model/sql/AdminSettingsEntity.java

@ -22,14 +22,18 @@ import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.id.AdminSettingsId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.ADMIN_SETTINGS_COLUMN_FAMILY_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.ADMIN_SETTINGS_JSON_VALUE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ADMIN_SETTINGS_KEY_PROPERTY;
@ -41,6 +45,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.ADMIN_SETTINGS_KEY
@Table(name = ADMIN_SETTINGS_COLUMN_FAMILY_NAME)
public final class AdminSettingsEntity extends BaseSqlEntity<AdminSettings> implements BaseEntity<AdminSettings> {
@Column(name = ModelConstants.ADMIN_SETTINGS_TENANT_ID_PROPERTY)
private UUID tenantId;
@Column(name = ADMIN_SETTINGS_KEY_PROPERTY)
private String key;
@ -57,6 +64,7 @@ public final class AdminSettingsEntity extends BaseSqlEntity<AdminSettings> impl
this.setUuid(adminSettings.getId().getId());
}
this.setCreatedTime(adminSettings.getCreatedTime());
this.tenantId = adminSettings.getTenantId().getId();
this.key = adminSettings.getKey();
this.jsonValue = adminSettings.getJsonValue();
}
@ -65,6 +73,7 @@ public final class AdminSettingsEntity extends BaseSqlEntity<AdminSettings> impl
public AdminSettings toData() {
AdminSettings adminSettings = new AdminSettings(new AdminSettingsId(id));
adminSettings.setCreatedTime(createdTime);
adminSettings.setTenantId(TenantId.fromUUID(tenantId));
adminSettings.setKey(key);
adminSettings.setJsonValue(jsonValue);
return adminSettings;

6
dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsDao.java

@ -19,6 +19,8 @@ import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.Dao;
import java.util.UUID;
public interface AdminSettingsDao extends Dao<AdminSettings> {
/**
@ -35,6 +37,8 @@ public interface AdminSettingsDao extends Dao<AdminSettings> {
* @param key the key
* @return the admin settings object
*/
AdminSettings findByKey(TenantId tenantId, String key);
AdminSettings findByTenantIdAndKey(UUID tenantId, String key);
boolean removeByTenantIdAndKey(UUID tenantId, String key);
}

11
dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java

@ -46,21 +46,26 @@ public class AdminSettingsServiceImpl implements AdminSettingsService {
public AdminSettings findAdminSettingsByKey(TenantId tenantId, String key) {
log.trace("Executing findAdminSettingsByKey [{}]", key);
Validator.validateString(key, "Incorrect key " + key);
return adminSettingsDao.findByKey(tenantId, key);
return adminSettingsDao.findByTenantIdAndKey(tenantId.getId(), key);
}
@Override
public AdminSettings saveAdminSettings(TenantId tenantId, AdminSettings adminSettings) {
log.trace("Executing saveAdminSettings [{}]", adminSettings);
adminSettingsValidator.validate(adminSettings, data -> tenantId);
if(adminSettings.getKey().equals("mail") && !adminSettings.getJsonValue().has("password")) {
if (adminSettings.getKey().equals("mail") && !adminSettings.getJsonValue().has("password")) {
AdminSettings mailSettings = findAdminSettingsByKey(tenantId, "mail");
if (mailSettings != null) {
((ObjectNode) adminSettings.getJsonValue()).put("password", mailSettings.getJsonValue().get("password").asText());
}
}
return adminSettingsDao.save(tenantId, adminSettings);
}
@Override
public boolean deleteAdminSettings(TenantId tenantId, String key) {
log.trace("Executing deleteAdminSettings, tenantId [{}], key [{}]", tenantId, key);
Validator.validateString(key, "Incorrect key " + key);
return adminSettingsDao.removeByTenantIdAndKey(tenantId.getId(), key);
}
}

7
dao/src/main/java/org/thingsboard/server/dao/sql/settings/AdminSettingsRepository.java

@ -25,5 +25,10 @@ import java.util.UUID;
*/
public interface AdminSettingsRepository extends JpaRepository<AdminSettingsEntity, UUID> {
AdminSettingsEntity findByKey(String key);
AdminSettingsEntity findByTenantIdAndKey(UUID tenantId, String key);
void deleteByTenantIdAndKey(UUID tenantId, String key);
boolean existsByTenantIdAndKey(UUID tenantId, String key);
}

13
dao/src/main/java/org/thingsboard/server/dao/sql/settings/JpaAdminSettingsDao.java

@ -46,7 +46,16 @@ public class JpaAdminSettingsDao extends JpaAbstractDao<AdminSettingsEntity, Adm
}
@Override
public AdminSettings findByKey(TenantId tenantId, String key) {
return DaoUtil.getData(adminSettingsRepository.findByKey(key));
public AdminSettings findByTenantIdAndKey(UUID tenantId, String key) {
return DaoUtil.getData(adminSettingsRepository.findByTenantIdAndKey(tenantId, key));
}
@Override
public boolean removeByTenantIdAndKey(UUID tenantId, String key) {
if (adminSettingsRepository.existsByTenantIdAndKey(tenantId, key)) {
adminSettingsRepository.deleteByTenantIdAndKey(tenantId, key);
return true;
}
return false;
}
}

1
dao/src/main/resources/sql/schema-entities.sql

@ -34,6 +34,7 @@ call insert_tb_schema_settings();
CREATE TABLE IF NOT EXISTS admin_settings (
id uuid NOT NULL CONSTRAINT admin_settings_pkey PRIMARY KEY,
tenant_id uuid NOT NULL,
created_time bigint NOT NULL,
json_value varchar,
key varchar(255)

5
pom.xml

@ -1892,6 +1892,11 @@
<artifactId>org.eclipse.jgit</artifactId>
<version>${jgit.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ssh.apache</artifactId>
<version>${jgit.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

Loading…
Cancel
Save