Major refactoring for mobile app notifications

This commit is contained in:
ViacheslavKlimov 2023-12-28 12:30:41 +02:00
parent b256f3a8cd
commit 7bf58e3891
27 changed files with 154 additions and 57 deletions

View File

@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@ -41,6 +42,7 @@ import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.UserEmailInfo;
import org.thingsboard.server.common.data.UserMobileInfo;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
@ -81,6 +83,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIELD;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION;
@ -584,6 +587,20 @@ public class UserController extends BaseController {
return userSettingsService.reportUserDashboardAction(currentUser.getTenantId(), currentUser.getId(), dashboardId, action);
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping("/user/mobile/info")
public UserMobileInfo getMobileInfo(@AuthenticationPrincipal SecurityUser securityUser) {
return Optional.ofNullable(userService.findMobileInfo(securityUser.getTenantId(), securityUser.getId()))
.orElseGet(UserMobileInfo::new);
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@PostMapping("/user/mobile/info")
public void saveMobileInfo(@RequestBody UserMobileInfo mobileInfo,
@AuthenticationPrincipal SecurityUser securityUser) {
userService.saveMobileInfo(securityUser.getTenantId(), securityUser.getId(), mobileInfo);
}
private void checkNotReserved(String strType, UserSettingsType type) throws ThingsboardException {
if (type.isReserved()) {
throw new ThingsboardException("Settings with type: " + strType + " are reserved for internal use!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);

View File

@ -15,54 +15,65 @@
*/
package org.thingsboard.server.service.notification.channels;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.firebase.messaging.FirebaseMessagingException;
import com.google.firebase.messaging.MessagingErrorCode;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.notification.FirebaseService;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.UserMobileInfo;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.settings.MobileNotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.settings.MobileAppNotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.template.MobileDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.MobileAppDeliveryMethodNotificationTemplate;
import org.thingsboard.server.dao.notification.NotificationSettingsService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.service.notification.NotificationProcessingContext;
import java.util.Optional;
@Component
@RequiredArgsConstructor
public class MobileNotificationChannel implements NotificationChannel<User, MobileDeliveryMethodNotificationTemplate> {
public class MobileAppNotificationChannel implements NotificationChannel<User, MobileAppDeliveryMethodNotificationTemplate> {
private final FirebaseService firebaseService;
private final UserService userService;
private final NotificationSettingsService notificationSettingsService;
@Override
public void sendNotification(User recipient, MobileDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) throws Exception {
String fcmToken = Optional.ofNullable(recipient.getAdditionalInfo())
.map(info -> info.get("fcmToken")).filter(JsonNode::isTextual).map(JsonNode::asText)
.orElse(null);
if (StringUtils.isEmpty(fcmToken)) {
throw new RuntimeException("User doesn't have the mobile app installed");
}
public void sendNotification(User recipient, MobileAppDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) throws Exception {
UserMobileInfo mobileInfo = userService.findMobileInfo(recipient.getTenantId(), recipient.getId());
String fcmToken = Optional.ofNullable(mobileInfo)
.map(UserMobileInfo::getFcmToken)
.orElseThrow(() -> new IllegalArgumentException("User doesn't use the mobile app"));
MobileNotificationDeliveryMethodConfig config = ctx.getDeliveryMethodConfig(NotificationDeliveryMethod.MOBILE);
MobileAppNotificationDeliveryMethodConfig config = ctx.getDeliveryMethodConfig(NotificationDeliveryMethod.MOBILE_APP);
try {
firebaseService.sendMessage(ctx.getTenantId(), config.getFirebaseServiceAccountCredentials(),
fcmToken, processedTemplate.getSubject(), processedTemplate.getBody());
} catch (FirebaseMessagingException e) {
if (e.getMessagingErrorCode() == MessagingErrorCode.UNREGISTERED) {
// the token is no longer valid
mobileInfo.setFcmToken(null);
userService.saveMobileInfo(recipient.getTenantId(), recipient.getId(), mobileInfo);
throw new IllegalArgumentException("User doesn't use the mobile app");
}
throw new RuntimeException("Failed to send message via FCM: " + e.getMessage(), e);
}
}
@Override
public void check(TenantId tenantId) throws Exception {
NotificationSettings settings = notificationSettingsService.findNotificationSettings(tenantId);
if (!settings.getDeliveryMethodsConfigs().containsKey(NotificationDeliveryMethod.MOBILE)) {
if (!settings.getDeliveryMethodsConfigs().containsKey(NotificationDeliveryMethod.MOBILE_APP)) {
throw new RuntimeException("Push-notifications to mobile are not configured");
}
}
@Override
public NotificationDeliveryMethod getDeliveryMethod() {
return NotificationDeliveryMethod.MOBILE;
return NotificationDeliveryMethod.MOBILE_APP;
}
}

View File

@ -48,7 +48,7 @@ public class DefaultFirebaseService implements FirebaseService {
.build();
@Override
public void sendMessage(TenantId tenantId, String credentials, String fcmToken, String title, String body) {
public void sendMessage(TenantId tenantId, String credentials, String fcmToken, String title, String body) throws FirebaseMessagingException {
FirebaseContext firebaseContext = contexts.asMap().compute(tenantId.toString(), (key, context) -> {
if (context == null) {
return new FirebaseContext(key, credentials);
@ -65,11 +65,7 @@ public class DefaultFirebaseService implements FirebaseService {
.build())
.setToken(fcmToken)
.build();
try {
firebaseContext.getMessaging().send(message);
} catch (FirebaseMessagingException e) {
throw new RuntimeException("Failed to send message via FCM: " + e.getMessage(), e);
}
}
public static class FirebaseContext {

View File

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.user;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.UserMobileInfo;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
@ -89,4 +90,8 @@ public interface UserService extends EntityDaoService {
void setLastLoginTs(TenantId tenantId, UserId userId);
void saveMobileInfo(TenantId tenantId, UserId userId, UserMobileInfo mobileInfo);
UserMobileInfo findMobileInfo(TenantId tenantId, UserId userId);
}

View File

@ -0,0 +1,24 @@
/**
* Copyright © 2016-2023 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;
import lombok.Data;
@Data
public class UserMobileInfo {
private String fcmToken;
private long fcmTokenTimestamp;
}

View File

@ -26,9 +26,10 @@ public enum NotificationDeliveryMethod {
SMS("SMS"),
SLACK("Slack"),
MICROSOFT_TEAMS("Microsoft Teams"),
MOBILE("mobile");
MOBILE_APP("mobile app");
@Getter
private final String name;
// TODO: private final boolean allowUseSystemSettings;
}

View File

@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho
import javax.validation.constraints.NotEmpty;
@Data
public class MobileNotificationDeliveryMethodConfig implements NotificationDeliveryMethodConfig {
public class MobileAppNotificationDeliveryMethodConfig implements NotificationDeliveryMethodConfig {
private String firebaseServiceAccountCredentialsFileName;
@NotEmpty
@ -29,7 +29,7 @@ public class MobileNotificationDeliveryMethodConfig implements NotificationDeliv
@Override
public NotificationDeliveryMethod getMethod() {
return NotificationDeliveryMethod.MOBILE;
return NotificationDeliveryMethod.MOBILE_APP;
}
}

View File

@ -28,7 +28,7 @@ import java.io.Serializable;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "method")
@JsonSubTypes({
@Type(name = "SLACK", value = SlackNotificationDeliveryMethodConfig.class),
@Type(name = "MOBILE", value = MobileNotificationDeliveryMethodConfig.class)
@Type(name = "MOBILE_APP", value = MobileAppNotificationDeliveryMethodConfig.class)
})
public interface NotificationDeliveryMethodConfig extends Serializable {

View File

@ -28,7 +28,8 @@ public class NotificationSettings implements Serializable {
@NotNull
@Valid
// location on the screen, shown notifications count, timings of displaying
private Map<NotificationDeliveryMethod, NotificationDeliveryMethodConfig> deliveryMethodsConfigs;
// TODO: disable option, location on the screen, shown notifications count, timings of displaying
}

View File

@ -25,7 +25,7 @@ import java.util.Set;
@RequiredArgsConstructor
public enum NotificationTargetType {
PLATFORM_USERS(Set.of(NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS, NotificationDeliveryMethod.MOBILE)),
PLATFORM_USERS(Set.of(NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS, NotificationDeliveryMethod.MOBILE_APP)),
SLACK(Set.of(NotificationDeliveryMethod.SLACK)),
MICROSOFT_TEAMS(Set.of(NotificationDeliveryMethod.MICROSOFT_TEAMS));

View File

@ -35,7 +35,7 @@ import java.util.List;
@Type(name = "SMS", value = SmsDeliveryMethodNotificationTemplate.class),
@Type(name = "SLACK", value = SlackDeliveryMethodNotificationTemplate.class),
@Type(name = "MICROSOFT_TEAMS", value = MicrosoftTeamsDeliveryMethodNotificationTemplate.class),
@Type(name = "MOBILE", value = MobileDeliveryMethodNotificationTemplate.class)
@Type(name = "MOBILE_APP", value = MobileAppDeliveryMethodNotificationTemplate.class)
})
@Data
@NoArgsConstructor

View File

@ -28,7 +28,7 @@ import java.util.List;
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MobileDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
public class MobileAppDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
@NotEmpty
private String subject;
@ -38,19 +38,19 @@ public class MobileDeliveryMethodNotificationTemplate extends DeliveryMethodNoti
TemplatableValue.of(this::getSubject, this::setSubject)
);
public MobileDeliveryMethodNotificationTemplate(MobileDeliveryMethodNotificationTemplate other) {
public MobileAppDeliveryMethodNotificationTemplate(MobileAppDeliveryMethodNotificationTemplate other) {
super(other);
this.subject = other.subject;
}
@Override
public NotificationDeliveryMethod getMethod() {
return NotificationDeliveryMethod.MOBILE;
return NotificationDeliveryMethod.MOBILE_APP;
}
@Override
public MobileDeliveryMethodNotificationTemplate copy() {
return new MobileDeliveryMethodNotificationTemplate(this);
public MobileAppDeliveryMethodNotificationTemplate copy() {
return new MobileAppDeliveryMethodNotificationTemplate(this);
}
@Override

View File

@ -19,7 +19,14 @@ import lombok.Getter;
public enum UserSettingsType {
GENERAL, VISITED_DASHBOARDS(true), QUICK_LINKS, DOC_LINKS, DASHBOARDS, GETTING_STARTED, NOTIFICATIONS;
GENERAL,
VISITED_DASHBOARDS(true),
QUICK_LINKS,
DOC_LINKS,
DASHBOARDS,
GETTING_STARTED,
NOTIFICATIONS,
MOBILE(true);
@Getter
private final boolean reserved;

View File

@ -135,6 +135,11 @@ public class JpaUserDao extends JpaAbstractDao<UserEntity, User> implements User
DaoUtil.toPageable(pageLink)));
}
@Override
public void unassignFcmToken(TenantId tenantId, String fcmToken) {
userRepository.unassignFcmToken(fcmToken);
}
@Override
public Long countByTenantId(TenantId tenantId) {
return userRepository.countByTenantId(tenantId.getId());

View File

@ -18,8 +18,10 @@ package org.thingsboard.server.dao.sql.user;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.model.sql.UserEntity;
@ -71,4 +73,9 @@ public interface UserRepository extends JpaRepository<UserEntity, UUID> {
Long countByTenantId(UUID tenantId);
@Query(value = "UPDATE user_settings SET settings = (settings::jsonb - 'fcmToken')::text WHERE type = 'MOBILE'", nativeQuery = true)
@Modifying
@Transactional
void unassignFcmToken(@Param("fcmToken") String fcmToken);
}

View File

@ -101,4 +101,6 @@ public interface UserDao extends Dao<User>, TenantEntityDao {
PageData<User> findByAuthorityAndTenantProfilesIds(Authority authority, List<TenantProfileId> tenantProfilesIds, PageLink pageLink);
void unassignFcmToken(TenantId tenantId, String fcmToken);
}

View File

@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authentication.DisabledException;
@ -30,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.UserMobileInfo;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
@ -43,6 +45,8 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
import org.thingsboard.server.common.data.settings.UserSettings;
import org.thingsboard.server.common.data.settings.UserSettingsType;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entity.EntityCountService;
import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
@ -85,6 +89,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
private final UserDao userDao;
private final UserCredentialsDao userCredentialsDao;
private final UserAuthSettingsDao userAuthSettingsDao;
private final UserSettingsService userSettingsService;
private final DataValidator<User> userValidator;
private final DataValidator<UserCredentials> userCredentialsValidator;
private final ApplicationEventPublisher eventPublisher;
@ -391,6 +396,22 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
saveUser(tenantId, user);
}
@Override
public void saveMobileInfo(TenantId tenantId, UserId userId, UserMobileInfo mobileInfo) {
if (StringUtils.isNotEmpty(mobileInfo.getFcmToken())) {
// unassigning fcm token from other users, in case we didn't clean up it on log out or mobile app uninstall
userDao.unassignFcmToken(tenantId, mobileInfo.getFcmToken());
}
userSettingsService.updateUserSettings(tenantId, userId, UserSettingsType.MOBILE, JacksonUtil.valueToTree(mobileInfo));
}
@Override
public UserMobileInfo findMobileInfo(TenantId tenantId, UserId userId) {
return Optional.ofNullable(userSettingsService.findUserSettings(tenantId, userId, UserSettingsType.MOBILE))
.map(UserSettings::getSettings).map(settings -> JacksonUtil.treeToValue(settings, UserMobileInfo.class))
.orElse(null);
}
@Override
public int increaseFailedLoginAttempts(TenantId tenantId, UserId userId) {
log.trace("Executing onUserLoginIncorrectCredentials [{}]", userId);

View File

@ -19,6 +19,6 @@ import org.thingsboard.server.common.data.id.TenantId;
public interface FirebaseService {
void sendMessage(TenantId tenantId, String credentials, String fcmToken, String title, String body);
void sendMessage(TenantId tenantId, String credentials, String fcmToken, String title, String body) throws Exception;
}

View File

@ -75,14 +75,14 @@
<!-- <div tb-help="mobileSettings"></div>-->
</mat-card-header>
<mat-card-content>
<section formGroupName="MOBILE" style="margin-bottom: 16px;">
<section formGroupName="MOBILE_APP" style="margin-bottom: 16px;">
<tb-file-input formControlName="firebaseServiceAccountCredentials"
dropLabel="{{ 'admin.select-firebase-service-account-file' | translate }}"
label="{{ 'admin.firebase-service-account-file' | translate }}"
accept=".json,application/json"
allowedExtensions="json"
[existingFileName]="notificationSettingsForm.get('deliveryMethodsConfigs.MOBILE.firebaseServiceAccountCredentialsFileName')?.value"
(fileNameChanged)="notificationSettingsForm?.get('deliveryMethodsConfigs.MOBILE.firebaseServiceAccountCredentialsFileName').patchValue($event)">
[existingFileName]="notificationSettingsForm.get('deliveryMethodsConfigs.MOBILE_APP.firebaseServiceAccountCredentialsFileName')?.value"
(fileNameChanged)="notificationSettingsForm?.get('deliveryMethodsConfigs.MOBILE_APP.firebaseServiceAccountCredentialsFileName').patchValue($event)">
</tb-file-input>
</section>
<div fxLayout="row" fxLayoutAlign="end center" fxLayout.xs="column" fxLayoutAlign.xs="end">

View File

@ -117,7 +117,7 @@ export class SmsProviderComponent extends PageComponent implements HasConfirmFor
SLACK: this.fb.group({
botToken: ['']
}),
MOBILE: this.fb.group({
MOBILE_APP: this.fb.group({
firebaseServiceAccountCredentialsFileName: [''],
firebaseServiceAccountCredentials: ['']
})

View File

@ -446,9 +446,9 @@
</form>
</mat-step>
<mat-step *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.MOBILE.enabled').value"
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.MOBILE_APP.enabled').value"
[stepControl]="mobileTemplateForm">
<ng-template matStepLabel>{{ 'notification.delivery-method.mobile' | translate }}</ng-template>
<ng-template matStepLabel>{{ 'notification.delivery-method.mobile-app' | translate }}</ng-template>
<div class="tb-hint-available-params mat-body-2">
<span class="content">{{ 'notification.input-field-support-templatization' | translate}}</span>
<span tb-help-popup="{{ notificationTemplateTypeTranslateMap.get(notificationType.GENERAL).helpId }}"
@ -523,14 +523,14 @@
{{ preview.processedTemplates.SLACK.body }}
</div>
</section>
<section class="preview-group notification" *ngIf="preview.processedTemplates.MOBILE?.enabled">
<section class="preview-group notification" *ngIf="preview.processedTemplates.MOBILE_APP?.enabled">
<div fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<mat-icon class="tb-mat-18" svgIcon="mdi:cellphone-text"></mat-icon>
<div class="group-title" translate>notification.delivery-method.mobile-preview</div>
<div class="group-title" translate>notification.delivery-method.mobile-app-preview</div>
</div>
<div class="notification-content">
<div class="subject">{{ preview.processedTemplates.MOBILE.subject }}</div>
<div>{{ preview.processedTemplates.MOBILE.body }}</div>
<div class="subject">{{ preview.processedTemplates.MOBILE_APP.subject }}</div>
<div>{{ preview.processedTemplates.MOBILE_APP.body }}</div>
</div>
</section>
<section class="preview-group notification" *ngIf="preview.processedTemplates.MICROSOFT_TEAMS?.enabled">

View File

@ -306,7 +306,7 @@ export class SentNotificationDialogComponent extends
allowConfigureDeliveryMethod(deliveryMethod: NotificationDeliveryMethod): boolean {
const tenantAllowConfigureDeliveryMethod = new Set([
NotificationDeliveryMethod.SLACK,
NotificationDeliveryMethod.MOBILE
NotificationDeliveryMethod.MOBILE_APP
]);
if (deliveryMethod === NotificationDeliveryMethod.WEB) {
return false;
@ -329,7 +329,7 @@ export class SentNotificationDialogComponent extends
return '/settings/outgoing-mail';
case NotificationDeliveryMethod.SMS:
case NotificationDeliveryMethod.SLACK:
case NotificationDeliveryMethod.MOBILE:
case NotificationDeliveryMethod.MOBILE_APP:
return '/settings/notifications';
}
}

View File

@ -148,7 +148,7 @@ export abstract class TemplateConfiguration<T, R = any> extends DialogComponent<
[NotificationDeliveryMethod.SMS, this.smsTemplateForm],
[NotificationDeliveryMethod.SLACK, this.slackTemplateForm],
[NotificationDeliveryMethod.MICROSOFT_TEAMS, this.microsoftTeamsTemplateForm],
[NotificationDeliveryMethod.MOBILE, this.mobileTemplateForm]
[NotificationDeliveryMethod.MOBILE_APP, this.mobileTemplateForm]
]);
}

View File

@ -364,9 +364,9 @@
</div>
</form>
</mat-step>
<mat-step *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.MOBILE.enabled').value"
<mat-step *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.MOBILE_APP.enabled').value"
[stepControl]="mobileTemplateForm">
<ng-template matStepLabel>{{ 'notification.delivery-method.mobile' | translate }}</ng-template>
<ng-template matStepLabel>{{ 'notification.delivery-method.mobile-app' | translate }}</ng-template>
<div class="tb-hint-available-params mat-body-2">
<span class="content">{{ 'notification.input-field-support-templatization' | translate}}</span>
<span tb-help-popup="{{ notificationTemplateTypeTranslateMap.get(templateNotificationForm.get('notificationType').value).helpId }}"

View File

@ -380,7 +380,7 @@ export enum NotificationDeliveryMethod {
EMAIL = 'EMAIL',
SLACK = 'SLACK',
MICROSOFT_TEAMS = 'MICROSOFT_TEAMS',
MOBILE = 'MOBILE'
MOBILE_APP = 'MOBILE_APP'
}
export const NotificationDeliveryMethodTranslateMap = new Map<NotificationDeliveryMethod, string>([
@ -389,7 +389,7 @@ export const NotificationDeliveryMethodTranslateMap = new Map<NotificationDelive
[NotificationDeliveryMethod.EMAIL, 'notification.delivery-method.email'],
[NotificationDeliveryMethod.SLACK, 'notification.delivery-method.slack'],
[NotificationDeliveryMethod.MICROSOFT_TEAMS, 'notification.delivery-method.microsoft-teams'],
[NotificationDeliveryMethod.MOBILE, 'notification.delivery-method.mobile']
[NotificationDeliveryMethod.MOBILE_APP, 'notification.delivery-method.mobile-app']
]);
export enum NotificationRequestStatus {

View File

@ -3271,8 +3271,8 @@
"sms-preview": "SMS notification preview",
"web": "Web",
"web-preview": "Web notification preview",
"mobile": "Mobile",
"mobile-preview": "Mobile notification preview"
"mobile-app": "Mobile app",
"mobile-app-preview": "Mobile app notification preview"
},
"delivery-method-not-configure-click": "Delivery method is not configured. Click to setup.",
"delivery-method-not-configure-contact": "Delivery method is not configured. Contact your system administrator.",