Merge pull request #13667 from AndriiLandiak/add-admin-settings-entity-type

Add entity type for admin settings
This commit is contained in:
Viacheslav Klimov 2025-07-16 18:33:27 +03:00 committed by GitHub
commit 4ff470088f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 266 additions and 378 deletions

View File

@ -37,14 +37,13 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
@ -125,14 +124,13 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Get the Administration Settings object using key (getAdminSettings)",
notes = "Get the Administration Settings object using specified string key. Referencing non-existing key will cause an error." + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/settings/{key}", method = RequestMethod.GET)
@ResponseBody
@GetMapping(value = "/settings/{key}")
public AdminSettings getAdminSettings(
@Parameter(description = "A string value of the key (e.g. 'general' or 'mail').")
@PathVariable("key") String key) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key), "No Administration settings found for key: " + key);
if (adminSettings.getKey().equals("mail")) {
if (adminSettings.getKey().equals(MAIL_SETTINGS_KEY)) {
((ObjectNode) adminSettings.getJsonValue()).remove("password");
((ObjectNode) adminSettings.getJsonValue()).remove("refreshToken");
}
@ -144,15 +142,14 @@ public class AdminController extends BaseController {
"The Administration Settings Id will be present in the response. Specify the Administration Settings Id when you would like to update the Administration Settings. " +
"Referencing non-existing Administration Settings Id will cause an error." + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/settings", method = RequestMethod.POST)
@ResponseBody
@PostMapping(value = "/settings")
public AdminSettings saveAdminSettings(
@Parameter(description = "A JSON value representing the Administration Settings.")
@RequestBody AdminSettings adminSettings) throws ThingsboardException {
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")) {
if (adminSettings.getKey().equals(MAIL_SETTINGS_KEY)) {
mailService.updateMailConfiguration();
((ObjectNode) adminSettings.getJsonValue()).remove("password");
((ObjectNode) adminSettings.getJsonValue()).remove("refreshToken");
@ -165,8 +162,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Get the Security Settings object (getSecuritySettings)",
notes = "Get the Security Settings object that contains password policy, etc." + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/securitySettings", method = RequestMethod.GET)
@ResponseBody
@GetMapping(value = "/securitySettings")
public SecuritySettings getSecuritySettings() throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
return checkNotNull(securitySettingsService.getSecuritySettings());
@ -175,8 +171,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Update Security Settings (saveSecuritySettings)",
notes = "Updates the Security Settings object that contains password policy, etc." + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/securitySettings", method = RequestMethod.POST)
@ResponseBody
@PostMapping(value = "/securitySettings")
public SecuritySettings saveSecuritySettings(
@Parameter(description = "A JSON value representing the Security Settings.")
@RequestBody SecuritySettings securitySettings) throws ThingsboardException {
@ -188,8 +183,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Get the JWT Settings object (getJwtSettings)",
notes = "Get the JWT Settings object that contains JWT token policy, etc. " + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/jwtSettings", method = RequestMethod.GET)
@ResponseBody
@GetMapping(value = "/jwtSettings")
public JwtSettings getJwtSettings() throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
return checkNotNull(jwtSettingsService.getJwtSettings());
@ -198,8 +192,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Update JWT Settings (saveJwtSettings)",
notes = "Updates the JWT Settings object that contains JWT token policy, etc. The tokenSigningKey field is a Base64 encoded string." + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/jwtSettings", method = RequestMethod.POST)
@ResponseBody
@PostMapping(value = "/jwtSettings")
public JwtPair saveJwtSettings(
@Parameter(description = "A JSON value representing the JWT Settings.")
@RequestBody JwtSettings jwtSettings) throws ThingsboardException {
@ -213,15 +206,15 @@ public class AdminController extends BaseController {
notes = "Attempts to send test email to the System Administrator User using Mail Settings provided as a parameter. " +
"You may change the 'To' email in the user profile of the System Administrator. " + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/settings/testMail", method = RequestMethod.POST)
@PostMapping(value = "/settings/testMail")
public void sendTestMail(
@Parameter(description = "A JSON value representing the Mail Settings.")
@RequestBody AdminSettings adminSettings) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
adminSettings = checkNotNull(adminSettings);
if (adminSettings.getKey().equals("mail")) {
if (adminSettings.getKey().equals(MAIL_SETTINGS_KEY)) {
if (adminSettings.getJsonValue().has("enableOauth2") && adminSettings.getJsonValue().get("enableOauth2").asBoolean()) {
AdminSettings mailSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"));
AdminSettings mailSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, MAIL_SETTINGS_KEY));
JsonNode refreshToken = mailSettings.getJsonValue().get("refreshToken");
if (refreshToken == null) {
throw new ThingsboardException("Refresh token was not generated. Please, generate refresh token.", ThingsboardErrorCode.GENERAL);
@ -230,7 +223,7 @@ public class AdminController extends BaseController {
settings.put("refreshToken", refreshToken.asText());
} else {
if (!adminSettings.getJsonValue().has("password")) {
AdminSettings mailSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"));
AdminSettings mailSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, MAIL_SETTINGS_KEY));
((ObjectNode) adminSettings.getJsonValue()).put("password", mailSettings.getJsonValue().get("password").asText());
}
}
@ -251,7 +244,7 @@ public class AdminController extends BaseController {
notes = "Attempts to send test sms to the System Administrator User using SMS Settings and phone number provided as a parameters of the request. "
+ SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/settings/testSms", method = RequestMethod.POST)
@PostMapping(value = "/settings/testSms")
public void sendTestSms(
@Parameter(description = "A JSON value representing the Test SMS request.")
@RequestBody TestSmsRequest testSmsRequest) throws ThingsboardException {
@ -325,7 +318,7 @@ public class AdminController extends BaseController {
notes = "Deletes the repository settings."
+ TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/repositorySettings", method = RequestMethod.DELETE)
@DeleteMapping(value = "/repositorySettings")
@ResponseStatus(value = HttpStatus.OK)
public DeferredResult<Void> deleteRepositorySettings() throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.DELETE);
@ -335,7 +328,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Check repository access (checkRepositoryAccess)",
notes = "Attempts to check repository access. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/repositorySettings/checkAccess", method = RequestMethod.POST)
@PostMapping(value = "/repositorySettings/checkAccess")
public DeferredResult<Void> checkRepositoryAccess(
@Parameter(description = "A JSON value representing the Repository Settings.")
@RequestBody RepositorySettings settings) throws Exception {
@ -376,7 +369,7 @@ public class AdminController extends BaseController {
notes = "Deletes the auto commit settings."
+ TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/autoCommitSettings", method = RequestMethod.DELETE)
@DeleteMapping(value = "/autoCommitSettings")
@ResponseStatus(value = HttpStatus.OK)
public void deleteAutoCommitSettings() throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.DELETE);
@ -387,9 +380,8 @@ public class AdminController extends BaseController {
notes = "Check notifications about new platform releases. "
+ SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/updates", method = RequestMethod.GET)
@ResponseBody
public UpdateMessage checkUpdates() throws ThingsboardException {
@GetMapping(value = "/updates")
public UpdateMessage checkUpdates() {
return updateService.checkUpdates();
}
@ -397,9 +389,8 @@ public class AdminController extends BaseController {
notes = "Get main information about system. "
+ SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/systemInfo", method = RequestMethod.GET)
@ResponseBody
public SystemInfo getSystemInfo() throws ThingsboardException {
@GetMapping(value = "/systemInfo")
public SystemInfo getSystemInfo() {
return systemInfoService.getSystemInfo();
}
@ -407,8 +398,7 @@ public class AdminController extends BaseController {
notes = "Get information about enabled/disabled features. "
+ SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/featuresInfo", method = RequestMethod.GET)
@ResponseBody
@GetMapping(value = "/featuresInfo")
public FeaturesInfo getFeaturesInfo() {
return systemInfoService.getFeaturesInfo();
}
@ -417,8 +407,7 @@ public class AdminController extends BaseController {
"double quotes. After successful authentication with OAuth2 provider and user consent for requested scope, it makes a redirect to this path so that the platform can do " +
"further log in processing and generating access tokens. " + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/mail/oauth2/loginProcessingUrl", method = RequestMethod.GET)
@ResponseBody
@GetMapping(value = "/mail/oauth2/loginProcessingUrl")
public String getMailProcessingUrl() throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
return "\"/api/admin/mail/oauth2/code\"";
@ -427,7 +416,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Redirect user to mail provider login page. ", notes = "After user logged in and provided access" +
"provider sends authorization code to specified redirect uri.)")
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/mail/oauth2/authorize", method = RequestMethod.GET, produces = "application/text")
@GetMapping(value = "/mail/oauth2/authorize", produces = "application/text")
public String getAuthorizationUrl(HttpServletRequest request, HttpServletResponse response) throws ThingsboardException {
String state = StringUtils.generateSafeToken();
if (request.getParameter(PREV_URI_PATH_PARAMETER) != null) {
@ -452,7 +441,7 @@ public class AdminController extends BaseController {
.build() + "\"";
}
@RequestMapping(value = "/mail/oauth2/code", params = {"code", "state"}, method = RequestMethod.GET)
@GetMapping(value = "/mail/oauth2/code", params = {"code", "state"})
public void codeProcessingUrl(
@RequestParam(value = "code") String code, @RequestParam(value = "state") String state,
HttpServletRequest request, HttpServletResponse response) throws ThingsboardException, IOException {

View File

@ -22,9 +22,9 @@ import freemarker.template.Template;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Lazy;
@ -64,55 +64,37 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@Service
@Slf4j
@Service
@RequiredArgsConstructor
public class DefaultMailService implements MailService {
public static final String TARGET_EMAIL = "targetEmail";
public static final String UTF_8 = "UTF-8";
private static final String TARGET_EMAIL = "targetEmail";
private static final String UTF_8 = "UTF-8";
private static final long DEFAULT_TIMEOUT = 10_000;
private final ScheduledExecutorService timeoutScheduler = ThingsBoardExecutors.newSingleThreadScheduledExecutor("mail-service-watchdog");
private final MessageSource messages;
private final Configuration freemarkerConfig;
private final AdminSettingsService adminSettingsService;
private final TbApiUsageReportClient apiUsageClient;
private static final long DEFAULT_TIMEOUT = 10_000;
@Lazy
@Autowired
private TbApiUsageStateService apiUsageStateService;
@Autowired
private MailSenderInternalExecutorService mailExecutorService;
@Autowired
private PasswordResetExecutorService passwordResetExecutorService;
@Autowired
private TbMailContextComponent ctx;
@Autowired
private RateLimitService rateLimitService;
private final TbApiUsageStateService apiUsageStateService;
private final MailSenderInternalExecutorService mailExecutorService;
private final PasswordResetExecutorService passwordResetExecutorService;
private final TbMailContextComponent ctx;
private final RateLimitService rateLimitService;
@Value("${mail.per_tenant_rate_limits:}")
private String perTenantRateLimitConfig;
private final ScheduledExecutorService timeoutScheduler;
private TbMailSender mailSender;
private String mailFrom;
private long timeout;
public DefaultMailService(MessageSource messages, Configuration freemarkerConfig, AdminSettingsService adminSettingsService, TbApiUsageReportClient apiUsageClient) {
this.messages = messages;
this.freemarkerConfig = freemarkerConfig;
this.adminSettingsService = adminSettingsService;
this.apiUsageClient = apiUsageClient;
this.timeoutScheduler = ThingsBoardExecutors.newSingleThreadScheduledExecutor("mail-service-watchdog");
}
@PostConstruct
private void init() {
updateMailConfiguration();
@ -120,9 +102,7 @@ public class DefaultMailService implements MailService {
@PreDestroy
public void destroy() {
if (timeoutScheduler != null) {
timeoutScheduler.shutdownNow();
}
timeoutScheduler.shutdownNow();
}
@Override
@ -311,22 +291,21 @@ public class DefaultMailService implements MailService {
model.put("apiFeature", apiFeature.getLabel());
model.put(TARGET_EMAIL, email);
String message = null;
switch (stateValue) {
case ENABLED:
String message = switch (stateValue) {
case ENABLED -> {
model.put("apiLabel", toEnabledValueLabel(apiFeature));
message = mergeTemplateIntoString("state.enabled.ftl", model);
break;
case WARNING:
yield mergeTemplateIntoString("state.enabled.ftl", model);
}
case WARNING -> {
model.put("apiValueLabel", toDisabledValueLabel(apiFeature) + " " + toWarningValueLabel(recordState));
message = mergeTemplateIntoString("state.warning.ftl", model);
break;
case DISABLED:
yield mergeTemplateIntoString("state.warning.ftl", model);
}
case DISABLED -> {
model.put("apiLimitValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(recordState));
message = mergeTemplateIntoString("state.disabled.ftl", model);
break;
}
yield mergeTemplateIntoString("state.disabled.ftl", model);
}
};
sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@ -341,89 +320,55 @@ public class DefaultMailService implements MailService {
}
private String toEnabledValueLabel(ApiFeature apiFeature) {
switch (apiFeature) {
case DB:
return "save";
case TRANSPORT:
return "receive";
case JS:
return "invoke";
case RE:
return "process";
case EMAIL:
case SMS:
return "send";
case ALARM:
return "create";
default:
throw new RuntimeException("Not implemented!");
}
return switch (apiFeature) {
case DB -> "save";
case TRANSPORT -> "receive";
case JS -> "invoke";
case RE -> "process";
case EMAIL, SMS -> "send";
case ALARM -> "create";
default -> throw new RuntimeException("Not implemented!");
};
}
private String toDisabledValueLabel(ApiFeature apiFeature) {
switch (apiFeature) {
case DB:
return "saved";
case TRANSPORT:
return "received";
case JS:
return "invoked";
case RE:
return "processed";
case EMAIL:
case SMS:
return "sent";
case ALARM:
return "created";
default:
throw new RuntimeException("Not implemented!");
}
return switch (apiFeature) {
case DB -> "saved";
case TRANSPORT -> "received";
case JS -> "invoked";
case RE -> "processed";
case EMAIL, SMS -> "sent";
case ALARM -> "created";
default -> throw new RuntimeException("Not implemented!");
};
}
private String toWarningValueLabel(ApiUsageRecordState recordState) {
String valueInM = recordState.getValueAsString();
String thresholdInM = recordState.getThresholdAsString();
switch (recordState.getKey()) {
case STORAGE_DP_COUNT:
case TRANSPORT_DP_COUNT:
return valueInM + " out of " + thresholdInM + " allowed data points";
case TRANSPORT_MSG_COUNT:
return valueInM + " out of " + thresholdInM + " allowed messages";
case JS_EXEC_COUNT:
return valueInM + " out of " + thresholdInM + " allowed JavaScript functions";
case TBEL_EXEC_COUNT:
return valueInM + " out of " + thresholdInM + " allowed Tbel functions";
case RE_EXEC_COUNT:
return valueInM + " out of " + thresholdInM + " allowed Rule Engine messages";
case EMAIL_EXEC_COUNT:
return valueInM + " out of " + thresholdInM + " allowed Email messages";
case SMS_EXEC_COUNT:
return valueInM + " out of " + thresholdInM + " allowed SMS messages";
default:
throw new RuntimeException("Not implemented!");
}
return switch (recordState.getKey()) {
case STORAGE_DP_COUNT, TRANSPORT_DP_COUNT -> valueInM + " out of " + thresholdInM + " allowed data points";
case TRANSPORT_MSG_COUNT -> valueInM + " out of " + thresholdInM + " allowed messages";
case JS_EXEC_COUNT -> valueInM + " out of " + thresholdInM + " allowed JavaScript functions";
case TBEL_EXEC_COUNT -> valueInM + " out of " + thresholdInM + " allowed Tbel functions";
case RE_EXEC_COUNT -> valueInM + " out of " + thresholdInM + " allowed Rule Engine messages";
case EMAIL_EXEC_COUNT -> valueInM + " out of " + thresholdInM + " allowed Email messages";
case SMS_EXEC_COUNT -> valueInM + " out of " + thresholdInM + " allowed SMS messages";
default -> throw new RuntimeException("Not implemented!");
};
}
private String toDisabledValueLabel(ApiUsageRecordState recordState) {
switch (recordState.getKey()) {
case STORAGE_DP_COUNT:
case TRANSPORT_DP_COUNT:
return recordState.getValueAsString() + " data points";
case TRANSPORT_MSG_COUNT:
return recordState.getValueAsString() + " messages";
case JS_EXEC_COUNT:
return "JavaScript functions " + recordState.getValueAsString() + " times";
case TBEL_EXEC_COUNT:
return "TBEL functions " + recordState.getValueAsString() + " times";
case RE_EXEC_COUNT:
return recordState.getValueAsString() + " Rule Engine messages";
case EMAIL_EXEC_COUNT:
return recordState.getValueAsString() + " Email messages";
case SMS_EXEC_COUNT:
return recordState.getValueAsString() + " SMS messages";
default:
throw new RuntimeException("Not implemented!");
}
return switch (recordState.getKey()) {
case STORAGE_DP_COUNT, TRANSPORT_DP_COUNT -> recordState.getValueAsString() + " data points";
case TRANSPORT_MSG_COUNT -> recordState.getValueAsString() + " messages";
case JS_EXEC_COUNT -> "JavaScript functions " + recordState.getValueAsString() + " times";
case TBEL_EXEC_COUNT -> "TBEL functions " + recordState.getValueAsString() + " times";
case RE_EXEC_COUNT -> recordState.getValueAsString() + " Rule Engine messages";
case EMAIL_EXEC_COUNT -> recordState.getValueAsString() + " Email messages";
case SMS_EXEC_COUNT -> recordState.getValueAsString() + " SMS messages";
default -> throw new RuntimeException("Not implemented!");
};
}
private void sendMail(JavaMailSenderImpl mailSender, String mailFrom, String email,

View File

@ -25,6 +25,7 @@ import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.mail.MailException;
@ -50,8 +51,10 @@ public class TbMailSender extends JavaMailSenderImpl {
private final TbMailContextComponent ctx;
private final Lock lock;
@Getter
private final Boolean oauth2Enabled;
private volatile String accessToken;
@Getter
private volatile long tokenExpires;
public TbMailSender(TbMailContextComponent ctx, JsonNode jsonConfig) {
@ -70,14 +73,6 @@ public class TbMailSender extends JavaMailSenderImpl {
setJavaMailProperties(createJavaMailProperties(jsonConfig));
}
public Boolean getOauth2Enabled() {
return oauth2Enabled;
}
public long getTokenExpires() {
return tokenExpires;
}
@Override
protected void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) throws MailException {
updateOauth2PasswordIfExpired();
@ -98,8 +93,8 @@ public class TbMailSender extends JavaMailSenderImpl {
super.testConnection();
}
public void updateOauth2PasswordIfExpired() {
if (getOauth2Enabled() && (System.currentTimeMillis() > getTokenExpires())){
public void updateOauth2PasswordIfExpired() {
if (getOauth2Enabled() && (System.currentTimeMillis() > getTokenExpires())) {
refreshAccessToken();
setPassword(accessToken);
}
@ -168,8 +163,8 @@ public class TbMailSender extends JavaMailSenderImpl {
.setClientAuthentication(new ClientParametersAuthentication(clientId, clientSecret))
.execute();
if (MailOauth2Provider.OFFICE_365.name().equals(providerId)) {
((ObjectNode)jsonValue).put("refreshToken", tokenResponse.getRefreshToken());
((ObjectNode)jsonValue).put("refreshTokenExpires", Instant.now().plus(Duration.ofDays(AZURE_DEFAULT_REFRESH_TOKEN_LIFETIME_IN_DAYS)).toEpochMilli());
((ObjectNode) jsonValue).put("refreshToken", tokenResponse.getRefreshToken());
((ObjectNode) jsonValue).put("refreshTokenExpires", Instant.now().plus(Duration.ofDays(AZURE_DEFAULT_REFRESH_TOKEN_LIFETIME_IN_DAYS)).toEpochMilli());
ctx.getAdminSettingsService().saveAdminSettings(TenantId.SYS_TENANT_ID, settings);
}
accessToken = tokenResponse.getAccessToken();
@ -190,4 +185,5 @@ public class TbMailSender extends JavaMailSenderImpl {
throw new IncorrectParameterException(String.format("Invalid smtp port value: %s", strPort));
}
}
}
}

View File

@ -121,7 +121,7 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
errorPrefix = "/login?loginError=";
}
getRedirectStrategy().sendRedirect(request, response, baseUrl + errorPrefix +
URLEncoder.encode(e.getMessage(), StandardCharsets.UTF_8.toString()));
URLEncoder.encode(e.getMessage(), StandardCharsets.UTF_8));
}
}
@ -138,4 +138,5 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
}
return baseUrl + "accessToken=" + tokenPair.getToken() + "&refreshToken=" + tokenPair.getRefreshToken();
}
}

View File

@ -21,7 +21,7 @@ import java.util.Collections;
import java.util.Set;
public enum Resource {
ADMIN_SETTINGS(),
ADMIN_SETTINGS(EntityType.ADMIN_SETTINGS),
ALARM(EntityType.ALARM),
DEVICE(EntityType.DEVICE),
ASSET(EntityType.ASSET),

View File

@ -31,16 +31,12 @@ public class DefaultSmsSenderFactory implements SmsSenderFactory {
@Override
public SmsSender createSmsSender(SmsProviderConfiguration config) {
switch (config.getType()) {
case AWS_SNS:
return new AwsSmsSender((AwsSnsSmsProviderConfiguration)config);
case TWILIO:
return new TwilioSmsSender((TwilioSmsProviderConfiguration)config);
case SMPP:
return new SmppSmsSender((SmppSmsProviderConfiguration) config);
default:
throw new RuntimeException("Unknown SMS provider type " + config.getType());
}
return switch (config.getType()) {
case AWS_SNS -> new AwsSmsSender((AwsSnsSmsProviderConfiguration) config);
case TWILIO -> new TwilioSmsSender((TwilioSmsProviderConfiguration) config);
case SMPP -> new SmppSmsSender((SmppSmsProviderConfiguration) config);
default -> throw new RuntimeException("Unknown SMS provider type " + config.getType());
};
}
}

View File

@ -18,6 +18,7 @@ package org.thingsboard.server.service.sms;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.NestedRuntimeException;
import org.springframework.stereotype.Service;
@ -37,8 +38,9 @@ import org.thingsboard.server.common.stats.TbApiUsageReportClient;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
@Service
@Slf4j
@Service
@RequiredArgsConstructor
public class DefaultSmsService implements SmsService {
private final SmsSenderFactory smsSenderFactory;
@ -48,13 +50,6 @@ public class DefaultSmsService implements SmsService {
private SmsSender smsSender;
public DefaultSmsService(SmsSenderFactory smsSenderFactory, AdminSettingsService adminSettingsService, TbApiUsageStateService apiUsageStateService, TbApiUsageReportClient apiUsageClient) {
this.smsSenderFactory = smsSenderFactory;
this.adminSettingsService = adminSettingsService;
this.apiUsageStateService = apiUsageStateService;
this.apiUsageClient = apiUsageClient;
}
@PostConstruct
private void init() {
updateSmsConfiguration();
@ -148,4 +143,5 @@ public class DefaultSmsService implements SmsService {
return new ThingsboardException(String.format("Unable to send SMS: %s", message),
ThingsboardErrorCode.GENERAL);
}
}

View File

@ -18,8 +18,9 @@ package org.thingsboard.server.dao.settings;
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.entity.EntityDaoService;
public interface AdminSettingsService {
public interface AdminSettingsService extends EntityDaoService {
AdminSettings findAdminSettingsById(TenantId tenantId, AdminSettingsId adminSettingsId);
@ -31,6 +32,4 @@ public interface AdminSettingsService {
boolean deleteAdminSettingsByTenantIdAndKey(TenantId tenantId, String key);
void deleteAdminSettingsByTenantId(TenantId tenantId);
}

View File

@ -22,9 +22,6 @@ import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
/**
* @author Andrew Shvayka
*/
public enum EntityType {
TENANT(1),
CUSTOMER(2),
@ -65,7 +62,8 @@ public enum EntityType {
MOBILE_APP_BUNDLE(38),
CALCULATED_FIELD(39),
CALCULATED_FIELD_LINK(40),
JOB(41);
JOB(41),
ADMIN_SETTINGS(42);
@Getter
private final int protoNumber; // Corresponds to EntityTypeProto

View File

@ -17,14 +17,26 @@ package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
public class AdminSettingsId extends UUIDBased {
public class AdminSettingsId extends UUIDBased implements EntityId {
@Serial
private static final long serialVersionUID = -4208011957475806567L;
@JsonCreator
public AdminSettingsId(@JsonProperty("id") UUID id){
public AdminSettingsId(@JsonProperty("id") UUID id) {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "ADMIN_SETTINGS", allowableValues = "ADMIN_SETTINGS")
@Override
public EntityType getEntityType() {
return EntityType.ADMIN_SETTINGS;
}
}

View File

@ -23,10 +23,12 @@ import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
public class EdgeId extends UUIDBased implements EntityId {
@Serial
private static final long serialVersionUID = 1L;
@JsonIgnore
@ -51,4 +53,5 @@ public class EdgeId extends UUIDBased implements EntityId {
public static EdgeId fromUUID(@JsonProperty("id") UUID id) {
return edges.computeIfAbsent(id, EdgeId::new);
}
}

View File

@ -24,10 +24,6 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serializable;
import java.util.UUID;
/**
* @author Andrew Shvayka
*/
@JsonDeserialize(using = EntityIdDeserializer.class)
@JsonSerialize(using = EntityIdSerializer.class)
@Schema

View File

@ -20,9 +20,6 @@ import org.thingsboard.server.common.data.edge.EdgeEventType;
import java.util.UUID;
/**
* Created by ashvayka on 25.04.17.
*/
public class EntityIdFactory {
public static EntityId getByTypeAndUuid(int type, String uuid) {
@ -50,131 +47,74 @@ public class EntityIdFactory {
}
public static EntityId getByTypeAndUuid(EntityType type, UUID uuid) {
switch (type) {
case TENANT:
return TenantId.fromUUID(uuid);
case CUSTOMER:
return new CustomerId(uuid);
case USER:
return new UserId(uuid);
case DASHBOARD:
return new DashboardId(uuid);
case DEVICE:
return new DeviceId(uuid);
case ASSET:
return new AssetId(uuid);
case ALARM:
return new AlarmId(uuid);
case RULE_CHAIN:
return new RuleChainId(uuid);
case RULE_NODE:
return new RuleNodeId(uuid);
case ENTITY_VIEW:
return new EntityViewId(uuid);
case WIDGETS_BUNDLE:
return new WidgetsBundleId(uuid);
case WIDGET_TYPE:
return new WidgetTypeId(uuid);
case DEVICE_PROFILE:
return new DeviceProfileId(uuid);
case ASSET_PROFILE:
return new AssetProfileId(uuid);
case TENANT_PROFILE:
return new TenantProfileId(uuid);
case API_USAGE_STATE:
return new ApiUsageStateId(uuid);
case TB_RESOURCE:
return new TbResourceId(uuid);
case OTA_PACKAGE:
return new OtaPackageId(uuid);
case EDGE:
return new EdgeId(uuid);
case RPC:
return new RpcId(uuid);
case QUEUE:
return new QueueId(uuid);
case NOTIFICATION_TARGET:
return new NotificationTargetId(uuid);
case NOTIFICATION_REQUEST:
return new NotificationRequestId(uuid);
case NOTIFICATION_RULE:
return new NotificationRuleId(uuid);
case NOTIFICATION_TEMPLATE:
return new NotificationTemplateId(uuid);
case NOTIFICATION:
return new NotificationId(uuid);
case QUEUE_STATS:
return new QueueStatsId(uuid);
case OAUTH2_CLIENT:
return new OAuth2ClientId(uuid);
case MOBILE_APP:
return new MobileAppId(uuid);
case DOMAIN:
return new DomainId(uuid);
case MOBILE_APP_BUNDLE:
return new MobileAppBundleId(uuid);
case CALCULATED_FIELD:
return new CalculatedFieldId(uuid);
case CALCULATED_FIELD_LINK:
return new CalculatedFieldLinkId(uuid);
case JOB:
return new JobId(uuid);
}
throw new IllegalArgumentException("EntityType " + type + " is not supported!");
return switch (type) {
case TENANT -> TenantId.fromUUID(uuid);
case CUSTOMER -> new CustomerId(uuid);
case USER -> new UserId(uuid);
case DASHBOARD -> new DashboardId(uuid);
case DEVICE -> new DeviceId(uuid);
case ASSET -> new AssetId(uuid);
case ALARM -> new AlarmId(uuid);
case RULE_CHAIN -> new RuleChainId(uuid);
case RULE_NODE -> new RuleNodeId(uuid);
case ENTITY_VIEW -> new EntityViewId(uuid);
case WIDGETS_BUNDLE -> new WidgetsBundleId(uuid);
case WIDGET_TYPE -> new WidgetTypeId(uuid);
case DEVICE_PROFILE -> new DeviceProfileId(uuid);
case ASSET_PROFILE -> new AssetProfileId(uuid);
case TENANT_PROFILE -> new TenantProfileId(uuid);
case API_USAGE_STATE -> new ApiUsageStateId(uuid);
case TB_RESOURCE -> new TbResourceId(uuid);
case OTA_PACKAGE -> new OtaPackageId(uuid);
case EDGE -> EdgeId.fromUUID(uuid);
case RPC -> new RpcId(uuid);
case QUEUE -> new QueueId(uuid);
case NOTIFICATION_TARGET -> new NotificationTargetId(uuid);
case NOTIFICATION_REQUEST -> new NotificationRequestId(uuid);
case NOTIFICATION_RULE -> new NotificationRuleId(uuid);
case NOTIFICATION_TEMPLATE -> new NotificationTemplateId(uuid);
case NOTIFICATION -> new NotificationId(uuid);
case QUEUE_STATS -> new QueueStatsId(uuid);
case OAUTH2_CLIENT -> new OAuth2ClientId(uuid);
case MOBILE_APP -> new MobileAppId(uuid);
case DOMAIN -> new DomainId(uuid);
case MOBILE_APP_BUNDLE -> new MobileAppBundleId(uuid);
case CALCULATED_FIELD -> new CalculatedFieldId(uuid);
case CALCULATED_FIELD_LINK -> new CalculatedFieldLinkId(uuid);
case JOB -> new JobId(uuid);
case ADMIN_SETTINGS -> new AdminSettingsId(uuid);
default -> throw new IllegalArgumentException("EntityType " + type + " is not supported!");
};
}
public static EntityId getByEdgeEventTypeAndUuid(EdgeEventType edgeEventType, UUID uuid) {
switch (edgeEventType) {
case TENANT:
return TenantId.fromUUID(uuid);
case CUSTOMER:
return new CustomerId(uuid);
case USER:
return new UserId(uuid);
case DASHBOARD:
return new DashboardId(uuid);
case DEVICE:
return new DeviceId(uuid);
case ASSET:
return new AssetId(uuid);
case ALARM:
return new AlarmId(uuid);
case RULE_CHAIN:
return new RuleChainId(uuid);
case ENTITY_VIEW:
return new EntityViewId(uuid);
case WIDGETS_BUNDLE:
return new WidgetsBundleId(uuid);
case WIDGET_TYPE:
return new WidgetTypeId(uuid);
case DEVICE_PROFILE:
return new DeviceProfileId(uuid);
case ASSET_PROFILE:
return new AssetProfileId(uuid);
case TENANT_PROFILE:
return new TenantProfileId(uuid);
case OTA_PACKAGE:
return new OtaPackageId(uuid);
case EDGE:
return new EdgeId(uuid);
case QUEUE:
return new QueueId(uuid);
case TB_RESOURCE:
return new TbResourceId(uuid);
case NOTIFICATION_RULE:
return new NotificationRuleId(uuid);
case NOTIFICATION_TARGET:
return new NotificationTargetId(uuid);
case NOTIFICATION_TEMPLATE:
return new NotificationTemplateId(uuid);
case OAUTH2_CLIENT:
return new OAuth2ClientId(uuid);
case DOMAIN:
return new DomainId(uuid);
case CALCULATED_FIELD:
return new CalculatedFieldId(uuid);
}
throw new IllegalArgumentException("EdgeEventType " + edgeEventType + " is not supported!");
return switch (edgeEventType) {
case TENANT -> TenantId.fromUUID(uuid);
case CUSTOMER -> new CustomerId(uuid);
case USER -> new UserId(uuid);
case DASHBOARD -> new DashboardId(uuid);
case DEVICE -> new DeviceId(uuid);
case ASSET -> new AssetId(uuid);
case ALARM -> new AlarmId(uuid);
case RULE_CHAIN -> new RuleChainId(uuid);
case ENTITY_VIEW -> new EntityViewId(uuid);
case WIDGETS_BUNDLE -> new WidgetsBundleId(uuid);
case WIDGET_TYPE -> new WidgetTypeId(uuid);
case DEVICE_PROFILE -> new DeviceProfileId(uuid);
case ASSET_PROFILE -> new AssetProfileId(uuid);
case TENANT_PROFILE -> new TenantProfileId(uuid);
case OTA_PACKAGE -> new OtaPackageId(uuid);
case EDGE -> EdgeId.fromUUID(uuid);
case QUEUE -> new QueueId(uuid);
case TB_RESOURCE -> new TbResourceId(uuid);
case NOTIFICATION_RULE -> new NotificationRuleId(uuid);
case NOTIFICATION_TARGET -> new NotificationTargetId(uuid);
case NOTIFICATION_TEMPLATE -> new NotificationTemplateId(uuid);
case OAUTH2_CLIENT -> new OAuth2ClientId(uuid);
case DOMAIN -> new DomainId(uuid);
case CALCULATED_FIELD -> new CalculatedFieldId(uuid);
default -> throw new IllegalArgumentException("EdgeEventType " + edgeEventType + " is not supported!");
};
}
}

View File

@ -20,10 +20,14 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
public class JobId extends UUIDBased implements EntityId {
@Serial
private static final long serialVersionUID = -2225072123132918395L;
@JsonCreator
public JobId(@JsonProperty("id") UUID id) {
super(id);

View File

@ -23,6 +23,7 @@ import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
public final class TenantId extends UUIDBased implements EntityId {
@ -33,6 +34,7 @@ public final class TenantId extends UUIDBased implements EntityId {
@JsonIgnore
public static final TenantId SYS_TENANT_ID = TenantId.fromUUID(EntityId.NULL_UUID);
@Serial
private static final long serialVersionUID = 1L;
@JsonCreator

View File

@ -252,7 +252,7 @@ public class ProtoUtils {
public static EdgeEvent fromProto(TransportProtos.EdgeEventMsgProto proto) {
EdgeEvent edgeEvent = new EdgeEvent();
TenantId tenantId = new TenantId(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB()));
TenantId tenantId = TenantId.fromUUID(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB()));
edgeEvent.setTenantId(tenantId);
edgeEvent.setType(EdgeEventType.valueOf(proto.getEntityType()));
edgeEvent.setAction(EdgeEventActionType.valueOf(proto.getAction()));
@ -845,7 +845,7 @@ public class ProtoUtils {
public static Device fromProto(TransportProtos.DeviceProto proto) {
Device device = new Device(getEntityId(proto.getDeviceIdMSB(), proto.getDeviceIdLSB(), DeviceId::new));
device.setCreatedTime(proto.getCreatedTime());
device.setTenantId(getEntityId(proto.getTenantIdMSB(), proto.getTenantIdLSB(), TenantId::new));
device.setTenantId(getEntityId(proto.getTenantIdMSB(), proto.getTenantIdLSB(), TenantId::fromUUID));
device.setName(proto.getDeviceName());
device.setType(proto.getDeviceType());
device.setDeviceProfileId(getEntityId(proto.getDeviceProfileIdMSB(), proto.getDeviceProfileIdLSB(), DeviceProfileId::new));
@ -937,7 +937,7 @@ public class ProtoUtils {
public static DeviceProfile fromProto(TransportProtos.DeviceProfileProto proto) {
DeviceProfile deviceProfile = new DeviceProfile(getEntityId(proto.getDeviceProfileIdMSB(), proto.getDeviceProfileIdLSB(), DeviceProfileId::new));
deviceProfile.setCreatedTime(proto.getCreatedTime());
deviceProfile.setTenantId(getEntityId(proto.getTenantIdMSB(), proto.getTenantIdLSB(), TenantId::new));
deviceProfile.setTenantId(getEntityId(proto.getTenantIdMSB(), proto.getTenantIdLSB(), TenantId::fromUUID));
deviceProfile.setName(proto.getName());
deviceProfile.setDefault(proto.getIsDefault());
deviceProfile.setType(DeviceProfileType.valueOf(proto.getType()));
@ -1028,7 +1028,7 @@ public class ProtoUtils {
}
public static Tenant fromProto(TransportProtos.TenantProto proto) {
Tenant tenant = new Tenant(getEntityId(proto.getTenantIdMSB(), proto.getTenantIdLSB(), TenantId::new));
Tenant tenant = new Tenant(getEntityId(proto.getTenantIdMSB(), proto.getTenantIdLSB(), TenantId::fromUUID));
tenant.setCreatedTime(proto.getCreatedTime());
tenant.setTenantProfileId(getEntityId(proto.getTenantProfileIdMSB(), proto.getTenantProfileIdLSB(), TenantProfileId::new));
tenant.setTitle(proto.getTitle());
@ -1142,7 +1142,7 @@ public class ProtoUtils {
public static TbResource fromProto(TransportProtos.TbResourceProto proto) {
TbResource resource = new TbResource(getEntityId(proto.getResourceIdMSB(), proto.getResourceIdLSB(), TbResourceId::new));
resource.setTenantId(getEntityId(proto.getTenantIdMSB(), proto.getTenantIdLSB(), TenantId::new));
resource.setTenantId(getEntityId(proto.getTenantIdMSB(), proto.getTenantIdLSB(), TenantId::fromUUID));
resource.setCreatedTime(proto.getCreatedTime());
resource.setTitle(proto.getTitle());
resource.setResourceType(ResourceType.valueOf(proto.getResourceType()));
@ -1198,7 +1198,7 @@ public class ProtoUtils {
public static ApiUsageState fromProto(TransportProtos.ApiUsageStateProto proto) {
ApiUsageState apiUsageState = new ApiUsageState(getEntityId(proto.getApiUsageStateIdMSB(), proto.getApiUsageStateIdLSB(), ApiUsageStateId::new));
apiUsageState.setTenantId(getEntityId(proto.getTenantProfileIdMSB(), proto.getTenantProfileIdLSB(), TenantId::new));
apiUsageState.setTenantId(getEntityId(proto.getTenantProfileIdMSB(), proto.getTenantProfileIdLSB(), TenantId::fromUUID));
apiUsageState.setCreatedTime(proto.getCreatedTime());
apiUsageState.setEntityId(EntityIdFactory.getByTypeAndUuid(fromProto(proto.getEntityType()), new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB())));
apiUsageState.setTransportState(ApiUsageStateValue.valueOf(proto.getTransportState()));

View File

@ -64,6 +64,7 @@ enum EntityTypeProto {
CALCULATED_FIELD = 39;
CALCULATED_FIELD_LINK = 40;
JOB = 41;
ADMIN_SETTINGS = 42;
}
enum ApiUsageRecordKeyProto {

View File

@ -29,6 +29,7 @@ import java.util.UUID;
@Component
public class HybridClientRegistrationRepository implements ClientRegistrationRepository {
private static final String defaultRedirectUriTemplate = "{baseUrl}/login/oauth2/code/{registrationId}";
@Autowired
@ -37,11 +38,13 @@ public class HybridClientRegistrationRepository implements ClientRegistrationRep
@Override
public ClientRegistration findByRegistrationId(String registrationId) {
OAuth2Client oAuth2Client = oAuth2ClientService.findOAuth2ClientById(TenantId.SYS_TENANT_ID, new OAuth2ClientId(UUID.fromString(registrationId)));
return oAuth2Client == null ?
null : toSpringClientRegistration(oAuth2Client);
if (oAuth2Client == null) {
return null;
}
return toSpringClientRegistration(oAuth2Client);
}
private ClientRegistration toSpringClientRegistration(OAuth2Client oAuth2Client){
private ClientRegistration toSpringClientRegistration(OAuth2Client oAuth2Client) {
String registrationId = oAuth2Client.getUuidId().toString();
// NONE is used if we need pkce-based code challenge
@ -67,4 +70,5 @@ public class HybridClientRegistrationRepository implements ClientRegistrationRep
.redirectUri(defaultRedirectUriTemplate)
.build();
}
}

View File

@ -23,20 +23,8 @@ import java.util.UUID;
public interface AdminSettingsDao extends Dao<AdminSettings> {
/**
* Save or update admin settings object
*
* @param adminSettings the admin settings object
* @return saved admin settings object
*/
AdminSettings save(TenantId tenantId, AdminSettings adminSettings);
/**
* Find admin settings by key.
*
* @param key the key
* @return the admin settings object
*/
AdminSettings findByTenantIdAndKey(UUID tenantId, String key);
boolean removeByTenantIdAndKey(UUID tenantId, String key);

View File

@ -21,11 +21,16 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.AdminSettingsId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.Validator;
import java.util.Optional;
@Service
@Slf4j
public class AdminSettingsServiceImpl implements AdminSettingsService {
@ -87,10 +92,25 @@ public class AdminSettingsServiceImpl implements AdminSettingsService {
}
@Override
public void deleteAdminSettingsByTenantId(TenantId tenantId) {
public void deleteByTenantId(TenantId tenantId) {
adminSettingsDao.removeByTenantId(tenantId.getId());
}
@Override
public void deleteEntity(TenantId tenantId, EntityId id, boolean force) {
adminSettingsDao.removeById(tenantId, id.getId());
}
@Override
public Optional<HasId<?>> findEntity(TenantId tenantId, EntityId entityId) {
return Optional.ofNullable(adminSettingsDao.findById(tenantId, entityId.getId()));
}
@Override
public EntityType getEntityType() {
return EntityType.ADMIN_SETTINGS;
}
private void dropTokenIfProviderInfoChanged(JsonNode newJsonValue, JsonNode oldJsonValue) {
if (newJsonValue.has("enableOauth2") && newJsonValue.get("enableOauth2").asBoolean()) {
if (!newJsonValue.get("providerId").equals(oldJsonValue.get("providerId")) ||

View File

@ -22,9 +22,6 @@ import org.thingsboard.server.dao.model.sql.AdminSettingsEntity;
import java.util.UUID;
/**
* Created by Valerii Sosliuk on 5/6/2017.
*/
public interface AdminSettingsRepository extends JpaRepository<AdminSettingsEntity, UUID> {
AdminSettingsEntity findByTenantIdAndKey(UUID tenantId, String key);

View File

@ -15,12 +15,12 @@
*/
package org.thingsboard.server.dao.sql.settings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.RequiredArgsConstructor;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -35,21 +35,10 @@ import java.util.UUID;
@Component
@SqlDao
@Slf4j
@RequiredArgsConstructor
public class JpaAdminSettingsDao extends JpaAbstractDao<AdminSettingsEntity, AdminSettings> implements AdminSettingsDao, TenantEntityDao<AdminSettings> {
@Autowired
private AdminSettingsRepository adminSettingsRepository;
@Override
protected Class<AdminSettingsEntity> getEntityClass() {
return AdminSettingsEntity.class;
}
@Override
protected JpaRepository<AdminSettingsEntity, UUID> getRepository() {
return adminSettingsRepository;
}
private final AdminSettingsRepository adminSettingsRepository;
@Override
public AdminSettings findByTenantIdAndKey(UUID tenantId, String key) {
@ -77,4 +66,19 @@ public class JpaAdminSettingsDao extends JpaAbstractDao<AdminSettingsEntity, Adm
return DaoUtil.toPageData(adminSettingsRepository.findByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink)));
}
@Override
protected Class<AdminSettingsEntity> getEntityClass() {
return AdminSettingsEntity.class;
}
@Override
protected JpaRepository<AdminSettingsEntity, UUID> getRepository() {
return adminSettingsRepository;
}
@Override
public EntityType getEntityType() {
return EntityType.ADMIN_SETTINGS;
}
}

View File

@ -43,7 +43,6 @@ import org.thingsboard.server.dao.notification.NotificationSettingsService;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.service.validator.TenantDataValidator;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.dao.trendz.TrendzSettingsService;
import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
import org.thingsboard.server.dao.user.UserService;
@ -76,8 +75,6 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
@Autowired
private ApiUsageStateService apiUsageStateService;
@Autowired
private AdminSettingsService adminSettingsService;
@Autowired
private NotificationSettingsService notificationSettingsService;
@Autowired
private QrCodeSettingService qrCodeSettingService;
@ -168,7 +165,6 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
userService.deleteAllByTenantId(tenantId);
notificationSettingsService.deleteNotificationSettings(tenantId);
trendzSettingsService.deleteTrendzSettings(tenantId);
adminSettingsService.deleteAdminSettingsByTenantId(tenantId);
qrCodeSettingService.deleteByTenantId(tenantId);
tenantDao.removeById(tenantId, tenantId.getId());
@ -176,7 +172,7 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(tenantId).entity(tenant).build());
cleanUpService.removeTenantEntities(tenantId, // don't forget to implement deleteEntity from EntityDaoService when adding entity type to this list
EntityType.JOB, EntityType.ENTITY_VIEW, EntityType.WIDGETS_BUNDLE, EntityType.WIDGET_TYPE,
EntityType.ADMIN_SETTINGS, EntityType.JOB, EntityType.ENTITY_VIEW, EntityType.WIDGETS_BUNDLE, EntityType.WIDGET_TYPE,
EntityType.ASSET, EntityType.ASSET_PROFILE, EntityType.DEVICE, EntityType.DEVICE_PROFILE,
EntityType.DASHBOARD, EntityType.EDGE, EntityType.RULE_CHAIN, EntityType.API_USAGE_STATE,
EntityType.TB_RESOURCE, EntityType.OTA_PACKAGE, EntityType.RPC, EntityType.QUEUE,
@ -230,7 +226,7 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
return existsTenantCache.getAndPutInTransaction(tenantId, () -> tenantDao.existsById(tenantId, tenantId.getId()), false);
}
private PaginatedRemover<TenantId, Tenant> tenantsRemover = new PaginatedRemover<>() {
private final PaginatedRemover<TenantId, Tenant> tenantsRemover = new PaginatedRemover<>() {
@Override
protected PageData<Tenant> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {

View File

@ -146,6 +146,7 @@ public class TenantIdLoader {
tenantEntity = ctx.getNotificationRequestService().findNotificationRequestById(ctxTenantId, new NotificationRequestId(id));
break;
case NOTIFICATION:
case ADMIN_SETTINGS:
return ctxTenantId;
case NOTIFICATION_RULE:
tenantEntity = ctx.getNotificationRuleService().findNotificationRuleById(ctxTenantId, new NotificationRuleId(id));

View File

@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.api.RuleEngineAssetProfileCache;
import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache;
import org.thingsboard.rule.engine.api.RuleEngineRpcService;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
@ -167,7 +168,6 @@ public class TenantIdLoaderTest {
private TenantId tenantId;
private TenantProfileId tenantProfileId;
private NotificationId notificationId;
private AbstractListeningExecutor dbExecutor;
@BeforeEach
@ -179,9 +179,8 @@ public class TenantIdLoaderTest {
}
};
dbExecutor.init();
this.tenantId = new TenantId(UUID.randomUUID());
this.tenantId = TenantId.fromUUID(UUID.randomUUID());
this.tenantProfileId = new TenantProfileId(UUID.randomUUID());
this.notificationId = new NotificationId(UUID.randomUUID());
when(ctx.getTenantId()).thenReturn(tenantId);
@ -199,6 +198,7 @@ public class TenantIdLoaderTest {
switch (entityType) {
case TENANT:
case NOTIFICATION:
case ADMIN_SETTINGS:
break;
case CUSTOMER:
Customer customer = new Customer();
@ -465,7 +465,7 @@ public class TenantIdLoaderTest {
@Test
public void test_findEntityIdAsync_other_tenant() {
checkTenant(new TenantId(UUID.randomUUID()), false);
checkTenant(TenantId.fromUUID(UUID.randomUUID()), false);
}
}