Push-notifications to mobile
This commit is contained in:
		
							parent
							
								
									25c4f309a7
								
							
						
					
					
						commit
						9add2962a6
					
				@ -354,6 +354,10 @@
 | 
			
		||||
            <groupId>com.slack.api</groupId>
 | 
			
		||||
            <artifactId>slack-api-client</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.google.firebase</groupId>
 | 
			
		||||
            <artifactId>firebase-admin</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 | 
			
		||||
@ -149,7 +149,7 @@ public class SystemInfoController extends BaseController {
 | 
			
		||||
            infoObject.put("artifact", buildProperties.getArtifact());
 | 
			
		||||
            infoObject.put("name", buildProperties.getName());
 | 
			
		||||
        } else {
 | 
			
		||||
            infoObject.put("version", "unknown");
 | 
			
		||||
            infoObject.put("version", "3.5.5");
 | 
			
		||||
        }
 | 
			
		||||
        return infoObject;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,109 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.service.notification.channels;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.databind.JsonNode;
 | 
			
		||||
import com.google.auth.oauth2.GoogleCredentials;
 | 
			
		||||
import com.google.common.util.concurrent.Futures;
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import com.google.firebase.FirebaseApp;
 | 
			
		||||
import com.google.firebase.FirebaseOptions;
 | 
			
		||||
import com.google.firebase.messaging.FirebaseMessaging;
 | 
			
		||||
import com.google.firebase.messaging.Message;
 | 
			
		||||
import com.google.firebase.messaging.Notification;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.apache.commons.io.IOUtils;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.thingsboard.server.common.data.User;
 | 
			
		||||
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.NotificationSettings;
 | 
			
		||||
import org.thingsboard.server.common.data.notification.template.MobileDeliveryMethodNotificationTemplate;
 | 
			
		||||
import org.thingsboard.server.dao.notification.NotificationSettingsService;
 | 
			
		||||
import org.thingsboard.server.service.executors.ExternalCallExecutorService;
 | 
			
		||||
import org.thingsboard.server.service.notification.NotificationProcessingContext;
 | 
			
		||||
 | 
			
		||||
import java.nio.charset.StandardCharsets;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
public class MobileNotificationChannel implements NotificationChannel<User, MobileDeliveryMethodNotificationTemplate> {
 | 
			
		||||
 | 
			
		||||
    private final ExternalCallExecutorService executor;
 | 
			
		||||
    private final NotificationSettingsService notificationSettingsService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<Void> sendNotification(User recipient, MobileDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) {
 | 
			
		||||
        String fcmToken = Optional.ofNullable(recipient.getAdditionalInfo())
 | 
			
		||||
                .map(info -> info.get("fcmToken")).filter(JsonNode::isTextual).map(JsonNode::asText)
 | 
			
		||||
                .orElse(null);
 | 
			
		||||
        if (StringUtils.isEmpty(fcmToken)) {
 | 
			
		||||
            return Futures.immediateFailedFuture(new RuntimeException("User doesn't have the mobile app installed"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MobileNotificationDeliveryMethodConfig config = ctx.getDeliveryMethodConfig(NotificationDeliveryMethod.MOBILE);
 | 
			
		||||
        return executor.submit(() -> {
 | 
			
		||||
            FirebaseOptions firebaseOptions = FirebaseOptions.builder()
 | 
			
		||||
                    .setCredentials(GoogleCredentials.fromStream(IOUtils.toInputStream(config.getFirebaseServiceAccountCredentials(), StandardCharsets.UTF_8)))
 | 
			
		||||
                    .build();
 | 
			
		||||
            String appName = ctx.getTenantId().toString();
 | 
			
		||||
 | 
			
		||||
            FirebaseApp firebaseApp = FirebaseApp.getApps().stream()
 | 
			
		||||
                    .filter(app -> app.getName().equals(appName))
 | 
			
		||||
                    .findFirst().orElseGet(() -> {
 | 
			
		||||
                        try {
 | 
			
		||||
                            return FirebaseApp.initializeApp(firebaseOptions, appName);
 | 
			
		||||
                        } catch (IllegalStateException e) {
 | 
			
		||||
                            return FirebaseApp.getInstance(appName);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
            FirebaseMessaging firebaseMessaging;
 | 
			
		||||
            try {
 | 
			
		||||
                firebaseMessaging = FirebaseMessaging.getInstance(firebaseApp);
 | 
			
		||||
            } catch (IllegalArgumentException e) {
 | 
			
		||||
                // because of concurrency issues: FirebaseMessaging.getInstance lazily loads FirebaseMessagingService
 | 
			
		||||
                firebaseMessaging = FirebaseMessaging.getInstance(firebaseApp);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Message message = Message.builder()
 | 
			
		||||
                    .setNotification(Notification.builder()
 | 
			
		||||
                            .setTitle(processedTemplate.getSubject())
 | 
			
		||||
                            .setBody(processedTemplate.getBody())
 | 
			
		||||
                            .build())
 | 
			
		||||
                    .setToken(fcmToken)
 | 
			
		||||
                    .build();
 | 
			
		||||
            firebaseMessaging.send(message);
 | 
			
		||||
            return null;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void check(TenantId tenantId) throws Exception {
 | 
			
		||||
        NotificationSettings settings = notificationSettingsService.findNotificationSettings(tenantId);
 | 
			
		||||
        if (!settings.getDeliveryMethodsConfigs().containsKey(NotificationDeliveryMethod.MOBILE)) {
 | 
			
		||||
            throw new RuntimeException("Push-notifications to mobile are not configured");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public NotificationDeliveryMethod getDeliveryMethod() {
 | 
			
		||||
        return NotificationDeliveryMethod.MOBILE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -24,7 +24,8 @@ public enum NotificationDeliveryMethod {
 | 
			
		||||
    WEB("web"),
 | 
			
		||||
    EMAIL("email"),
 | 
			
		||||
    SMS("SMS"),
 | 
			
		||||
    SLACK("Slack");
 | 
			
		||||
    SLACK("Slack"),
 | 
			
		||||
    MOBILE("mobile");
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
    private final String name;
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,35 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.notification.settings;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
 | 
			
		||||
 | 
			
		||||
import javax.validation.constraints.NotEmpty;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class MobileNotificationDeliveryMethodConfig implements NotificationDeliveryMethodConfig {
 | 
			
		||||
 | 
			
		||||
    private String firebaseServiceAccountCredentialsFileName;
 | 
			
		||||
    @NotEmpty
 | 
			
		||||
    private String firebaseServiceAccountCredentials;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public NotificationDeliveryMethod getMethod() {
 | 
			
		||||
        return NotificationDeliveryMethod.MOBILE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -27,7 +27,8 @@ import java.io.Serializable;
 | 
			
		||||
@JsonIgnoreProperties(ignoreUnknown = true)
 | 
			
		||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "method")
 | 
			
		||||
@JsonSubTypes({
 | 
			
		||||
        @Type(name = "SLACK", value = SlackNotificationDeliveryMethodConfig.class)
 | 
			
		||||
        @Type(name = "SLACK", value = SlackNotificationDeliveryMethodConfig.class),
 | 
			
		||||
        @Type(name = "MOBILE", value = MobileNotificationDeliveryMethodConfig.class)
 | 
			
		||||
})
 | 
			
		||||
public interface NotificationDeliveryMethodConfig extends Serializable {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ import java.util.Set;
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
public enum NotificationTargetType {
 | 
			
		||||
 | 
			
		||||
    PLATFORM_USERS(Set.of(NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS)),
 | 
			
		||||
    PLATFORM_USERS(Set.of(NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS, NotificationDeliveryMethod.MOBILE)),
 | 
			
		||||
    SLACK(Set.of(NotificationDeliveryMethod.SLACK));
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,8 @@ import javax.validation.constraints.NotEmpty;
 | 
			
		||||
        @Type(name = "WEB", value = WebDeliveryMethodNotificationTemplate.class),
 | 
			
		||||
        @Type(name = "EMAIL", value = EmailDeliveryMethodNotificationTemplate.class),
 | 
			
		||||
        @Type(name = "SMS", value = SmsDeliveryMethodNotificationTemplate.class),
 | 
			
		||||
        @Type(name = "SLACK", value = SlackDeliveryMethodNotificationTemplate.class)
 | 
			
		||||
        @Type(name = "SLACK", value = SlackDeliveryMethodNotificationTemplate.class),
 | 
			
		||||
        @Type(name = "MOBILE", value = MobileDeliveryMethodNotificationTemplate.class)
 | 
			
		||||
})
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,56 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.notification.template;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.ToString;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
 | 
			
		||||
 | 
			
		||||
import javax.validation.constraints.NotEmpty;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@ToString(callSuper = true)
 | 
			
		||||
public class MobileDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
 | 
			
		||||
 | 
			
		||||
    @NotEmpty
 | 
			
		||||
    private String subject;
 | 
			
		||||
 | 
			
		||||
    public MobileDeliveryMethodNotificationTemplate(MobileDeliveryMethodNotificationTemplate other) {
 | 
			
		||||
        super(other);
 | 
			
		||||
        this.subject = other.subject;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public NotificationDeliveryMethod getMethod() {
 | 
			
		||||
        return NotificationDeliveryMethod.MOBILE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MobileDeliveryMethodNotificationTemplate copy() {
 | 
			
		||||
        return new MobileDeliveryMethodNotificationTemplate(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean containsAny(String... params) {
 | 
			
		||||
        return super.containsAny(params) || StringUtils.containsAny(subject, params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							@ -150,6 +150,7 @@
 | 
			
		||||
        <allure-testng.version>2.21.0</allure-testng.version>
 | 
			
		||||
        <allure-maven.version>2.12.0</allure-maven.version>
 | 
			
		||||
        <slack-api.version>1.12.1</slack-api.version>
 | 
			
		||||
        <firebase-admin.version>8.0.1</firebase-admin.version>
 | 
			
		||||
        <oshi.version>3.4.0</oshi.version>
 | 
			
		||||
    </properties>
 | 
			
		||||
 | 
			
		||||
@ -1987,6 +1988,11 @@
 | 
			
		||||
                <artifactId>slack-api-client</artifactId>
 | 
			
		||||
                <version>${slack-api.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.google.firebase</groupId>
 | 
			
		||||
                <artifactId>firebase-admin</artifactId>
 | 
			
		||||
                <version>${firebase-admin.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.eclipse.jgit</groupId>
 | 
			
		||||
                <artifactId>org.eclipse.jgit</artifactId>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user