From 5a3c2322f9e8d302a59eb2d9c48055d3f186a576 Mon Sep 17 00:00:00 2001 From: Anh3h Date: Wed, 23 Aug 2017 07:27:57 +0100 Subject: [PATCH] Notification sub-system --- fineract-provider/dependencies.gradle | 1 - .../integrationtests/NotificationApiTest.java | 5 +- .../common/NotificationHelper.java | 3 +- .../TenantAwareBasicAuthenticationFilter.java | 8 + .../api/NotificationApiResource.java | 2 +- .../CacheNotificationResponseHeader.java | 1 - .../notification/data/NotificationData.java | 12 +- .../fineract/notification/data/TopicData.java | 76 ++ .../data/TopicSubscriberData.java | 60 + .../notification/domain/Notification.java | 6 +- .../domain/NotificationMapper.java | 1 - .../domain/NotificationMapperRepository.java | 1 - .../domain/NotificationRepository.java | 1 - .../fineract/notification/domain/Topic.java | 122 ++ .../notification/domain/TopicRepository.java | 29 + .../notification/domain/TopicSubscriber.java | 80 ++ .../domain/TopicSubscriberRepository.java | 29 + .../eventandlistener/NotificationEvent.java | 51 + .../exception/TopicNotFoundException.java | 32 + .../NotificationDomainServiceImpl.java | 1085 +++++++++-------- ...otificationMapperWritePlatformService.java | 1 - .../NotificationReadPlatformServiceImpl.java | 10 +- .../NotificationWritePlatformService.java | 1 + .../service/TopicReadPlatformService.java | 32 + .../service/TopicReadPlatformServiceImpl.java | 98 ++ .../TopicSubscriberReadPlatformService.java | 29 + ...opicSubscriberReadPlatformServiceImpl.java | 78 ++ .../TopicSubscriberWritePlatformService.java | 27 + ...WritePlatformServiceJpaRepositoryImpl.java | 42 + .../service/TopicWritePlatformService.java | 27 + ...WritePlatformServiceJpaRepositoryImpl.java | 42 + .../organisation/office/domain/Office.java | 4 + ...WritePlatformServiceJpaRepositoryImpl.java | 49 +- .../BusinessEventNotificationConstants.java | 1 + ...WritePlatformServiceJpaRepositoryImpl.java | 2 + ...WritePlatformServiceJpaRepositoryImpl.java | 5 + ...WritePlatformServiceJpaRepositoryImpl.java | 6 + ...WritePlatformServiceJpaRepositoryImpl.java | 8 +- .../useradministration/domain/Role.java | 4 + ...WritePlatformServiceJpaRepositoryImpl.java | 91 +- ...WritePlatformServiceJpaRepositoryImpl.java | 50 +- .../resources/META-INF/spring/appContext.xml | 1 - .../META-INF/spring/notificationContext.xml | 1 + .../core_db/V336__topic_module_table.sql | 45 + .../fineract/notification/Listener.java | 3 +- .../fineract/notification/ListenerTest.java | 3 +- .../fineract/notification/SenderTest.java | 4 +- .../fineract/notification/StorageTest.java | 6 +- .../fineract/notification/TopicTest.java | 109 ++ 49 files changed, 1795 insertions(+), 589 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicData.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicSubscriberData.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/domain/Topic.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicRepository.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriber.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriberRepository.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/exception/TopicNotFoundException.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformService.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformServiceImpl.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberReadPlatformService.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberReadPlatformServiceImpl.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberWritePlatformService.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberWritePlatformServiceJpaRepositoryImpl.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicWritePlatformService.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicWritePlatformServiceJpaRepositoryImpl.java create mode 100644 fineract-provider/src/main/resources/sql/migrations/core_db/V336__topic_module_table.sql create mode 100644 fineract-provider/src/test/java/org/apache/fineract/notification/TopicTest.java diff --git a/fineract-provider/dependencies.gradle b/fineract-provider/dependencies.gradle index 562e7678447..5d5bc88218e 100644 --- a/fineract-provider/dependencies.gradle +++ b/fineract-provider/dependencies.gradle @@ -93,7 +93,6 @@ dependencies { //[group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.0'] [group: 'org.springframework', name:'spring-jms'], [group: 'org.apache.activemq', name: 'activemq-broker'] - ) testCompile 'junit:junit:4.11', 'junit:junit-dep:4.11', diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java index c516502fa59..b052649c345 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java @@ -1,5 +1,3 @@ -package org.apache.fineract.integrationtests; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +package org.apache.fineract.integrationtests; import com.jayway.restassured.builder.RequestSpecBuilder; import com.jayway.restassured.builder.ResponseSpecBuilder; @@ -54,4 +52,5 @@ public void testNotificationRetrieval() { System.out.println("Response : " + response.toString()); Assert.assertNotNull(response); } + } diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java index efac104a620..a2674bac69f 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java @@ -1,5 +1,3 @@ -package org.apache.fineract.integrationtests.common; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.fineract.integrationtests.common; import com.jayway.restassured.specification.RequestSpecification; import com.jayway.restassured.specification.ResponseSpecification; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java index a36079da6be..ccd71cb469d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java @@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.time.StopWatch; +import org.apache.fineract.notification.service.NotificationReadPlatformService; import org.apache.fineract.infrastructure.cache.domain.CacheType; import org.apache.fineract.infrastructure.cache.service.CacheWritePlatformService; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; @@ -78,6 +79,7 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil private final ToApiJsonSerializer toApiJsonSerializer; private final ConfigurationDomainService configurationDomainService; private final CacheWritePlatformService cacheWritePlatformService; + private final NotificationReadPlatformService notificationReadPlatformService; private final String tenantRequestHeader = "Fineract-Platform-TenantId"; private final boolean exceptionIfHeaderMissing = true; @@ -177,6 +179,12 @@ protected void onSuccessfulAuthentication(HttpServletRequest request, response.addHeader("X-Notification-Refresh", "false"); } + if(notificationReadPlatformService.hasUnreadNotifications(user.getId())) { + response.addHeader("X-Notification-Refresh", "true"); + } else { + response.addHeader("X-Notification-Refresh", "false"); + } + String pathURL = request.getRequestURI(); boolean isSelfServiceRequest = (pathURL != null && pathURL.contains("/self/")); diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java index 065d7cbb766..860c74f0b9d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.notification.api; - import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; @@ -86,4 +85,5 @@ public void update() { this.context.authenticatedUser(); this.notificationReadPlatformService.updateNotificationReadStatus(); } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java b/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java index 205050b786f..3b5a6e1a16f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.notification.cache; - public class CacheNotificationResponseHeader { private boolean hasNotifications; diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java b/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java index 63dab1ad8f4..865447cac1c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java @@ -29,6 +29,7 @@ public class NotificationData implements Serializable { private String action; private Long actorId; private String content; + private boolean isRead; private boolean isSystemGenerated; private String tenantIdentifier; private String createdAt; @@ -40,12 +41,13 @@ public NotificationData() { } public NotificationData(String objectType, Long objectId, String action, Long actorId, String content, boolean isSystemGenerated, - String tenantIdentifier, Long officeId, List userIds) { + boolean isRead, String tenantIdentifier, Long officeId, List userIds) { this.objectType = objectType; this.objectId = objectId; this.action = action; this.actorId = actorId; this.content = content; + this.isRead = isRead; this.isSystemGenerated = isSystemGenerated; this.tenantIdentifier = tenantIdentifier; this.officeId = officeId; @@ -123,6 +125,14 @@ public String getContent() { public void setContent(String content) { this.content = content; } + + public boolean isRead() { + return this.isRead; + } + + public void setRead(boolean isRead) { + this.isRead = isRead; + } public boolean isSystemGenerated() { return isSystemGenerated; diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicData.java b/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicData.java new file mode 100644 index 00000000000..9e070fbd2df --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicData.java @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.data; + +import java.io.Serializable; + +public class TopicData implements Serializable { + + private final Long id; + private final String title; + private final boolean enabled; + private final Long entityId; + private final String entityType; + private final String memberType; + + public TopicData(Long id, String title, boolean enabled, Long entityId, String entityType, + String memberType) { + this.id = id; + this.title = title; + this.enabled = enabled; + this.entityId = entityId; + this.entityType = entityType; + this.memberType = memberType; + } + + public TopicData(Long id, String title, Long entityId, String entityType, + String memberType) { + this.id = id; + this.title = title; + this.enabled = true; + this.entityId = entityId; + this.entityType = entityType; + this.memberType = memberType; + } + + public Long getId() { + return this.id; + } + + public String getTitle() { + return this.title; + } + + public boolean isEnabled() { + return this.enabled; + } + + public Long getEntityId() { + return this.entityId; + } + + public String getEntityType() { + return this.entityType; + } + + public String getMemberType() { + return this.memberType; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicSubscriberData.java b/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicSubscriberData.java new file mode 100644 index 00000000000..76916947214 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicSubscriberData.java @@ -0,0 +1,60 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.data; + +import org.joda.time.LocalDate; + +public class TopicSubscriberData { + + private final Long id; + private final Long topicId; + private final Long userId; + private final LocalDate subscriptionDate; + + public TopicSubscriberData(Long id, Long topicId, Long userId, LocalDate subscriptionDate) { + this.id = id; + this.topicId = topicId; + this.userId = userId; + this.subscriptionDate = subscriptionDate; + } + + public TopicSubscriberData(Long id, Long topicId, Long userId) { + this.id = id; + this.topicId = topicId; + this.userId = userId; + this.subscriptionDate = new LocalDate(); + } + + public Long getId() { + return this.id; + } + + public Long getTopicId() { + return this.topicId; + } + + public Long getUserId() { + return this.userId; + } + + public LocalDate getSubscriptionDate() { + return this.subscriptionDate; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java index cf7d41e2d11..4985f253ff4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java @@ -20,9 +20,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Table; +import javax.persistence.*; @Entity @Table(name = "notification_generator") @@ -90,7 +88,7 @@ public Long getActor() { return actorId; } - public void setActor(Long actor) { + public void setActor(Long actorId) { this.actorId = actorId; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java index 5297d231713..970b4472708 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.notification.domain; - import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import org.apache.fineract.useradministration.domain.AppUser; diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java index fb88509d138..5caabf1cd93 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java @@ -20,5 +20,4 @@ import org.springframework.data.jpa.repository.JpaRepository; - public interface NotificationMapperRepository extends JpaRepository {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java index ed0675d73be..6b9160ffd4e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java @@ -20,5 +20,4 @@ import org.springframework.data.jpa.repository.JpaRepository; - public interface NotificationRepository extends JpaRepository {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Topic.java b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Topic.java new file mode 100644 index 00000000000..62f1a568186 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Topic.java @@ -0,0 +1,122 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; + +@Entity +@Table(name = "topic") +public class Topic extends AbstractPersistableCustom { + + @Column(name = "title", unique = true, nullable = false, length = 100) + private String title; + + @Column(name = "enabled", nullable = false) + private Boolean enabled; + + @Column(name = "entity_id", nullable = false) + private Long entityId; + + @Column(name = "entity_type") + private String entityType; + + @Column(name = "member_type") + private String memberType; + + public Topic() { + } + + public Topic(String title, Boolean enabled, Long entityId, String entityType, String memberType) { + this.title = title.trim(); + this.enabled = enabled; + this.entityId = entityId; + this.entityType = entityType.trim(); + this.memberType = memberType.trim(); + } + + public static Topic fromJson(final JsonCommand command) { + String title = ""; + Boolean enabled = null; + Long entityId = 0L; + String entityType = ""; + String memberType = ""; + + if (command.hasParameter("title")) { + title = command.stringValueOfParameterNamed("title"); + } + if (command.hasParameter("enabled")) { + enabled = command.booleanPrimitiveValueOfParameterNamed("enabled"); + } + if (command.hasParameter("entityId")) { + entityId = command.longValueOfParameterNamed("entityId"); + } + if (command.hasParameter("entityType")) { + entityType = command.stringValueOfParameterNamed("entityType"); + } + if (command.hasParameter("memberType")) { + memberType = command.stringValueOfParameterNamed("memberType"); + } + return new Topic(title, enabled, entityId, entityType, memberType); + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Boolean getEnabled() { + return this.enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Long getEntityId() { + return this.entityId; + } + + public void setEntityId(Long entityId) { + this.entityId = entityId; + } + + public String getEntityType() { + return this.entityType; + } + + public void setEntityType(String entityType) { + this.entityType = entityType; + } + + public String getMemberType() { + return this.memberType; + } + + public void setMemberType(String memberType) { + this.memberType = memberType; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicRepository.java b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicRepository.java new file mode 100644 index 00000000000..c01bb7be097 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicRepository.java @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.domain; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface TopicRepository extends JpaRepository, JpaSpecificationExecutor { + List findByEntityId(Long entityId); + List findByMemberType(String memberType); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriber.java b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriber.java new file mode 100644 index 00000000000..74ef96021f6 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriber.java @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.domain; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; +import org.apache.fineract.useradministration.domain.AppUser; + +@Entity +@Table(name = "topic_subscriber") +public class TopicSubscriber extends AbstractPersistableCustom { + + @ManyToOne + @JoinColumn(name = "topic_id") + private Topic topic; + + @ManyToOne + @JoinColumn(name = "user_id") + private AppUser subscriber; + + @Column(name = "subscription_date") + private Date subscriptionDate; + + public TopicSubscriber() { + } + + public TopicSubscriber(Topic topic, AppUser subscriber, Date subscriptionDate) { + this.topic = topic; + this.subscriber = subscriber; + this.subscriptionDate = subscriptionDate; + } + + public Topic getTopic() { + return this.topic; + } + + public void setTopic(Topic topic) { + this.topic = topic; + } + + public AppUser getSubscriber() { + return this.subscriber; + } + + public void setSubscriber(AppUser subscriber) { + this.subscriber = subscriber; + } + + public Date getSubscriptionDate() { + return this.subscriptionDate; + } + + public void setSubscriptionDate(Date subscriptionDate) { + this.subscriptionDate = subscriptionDate; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriberRepository.java b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriberRepository.java new file mode 100644 index 00000000000..cd67fb9426c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriberRepository.java @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.domain; + +import java.util.List; + +import org.apache.fineract.useradministration.domain.AppUser; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface TopicSubscriberRepository extends JpaRepository, JpaSpecificationExecutor { + List findBySubscriber(AppUser subscriber); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java new file mode 100644 index 00000000000..9df5215cd31 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.eventandlistener; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; + +import org.apache.fineract.notification.data.NotificationData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.MessageCreator; +import org.springframework.stereotype.Service; + +@Service +public class NotificationEvent { + + private final JmsTemplate jmsTemplate; + + @Autowired + public NotificationEvent(JmsTemplate jmsTemplate) { + this.jmsTemplate = jmsTemplate; + } + + public void broadcastNotification(final Destination destination, final NotificationData notificationData) { + this.jmsTemplate.send(destination, new MessageCreator() { + @Override + public Message createMessage(Session session) throws JMSException { + return session.createObjectMessage(notificationData); + } + }); + } + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/exception/TopicNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/notification/exception/TopicNotFoundException.java new file mode 100644 index 00000000000..857ef4c4fa4 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/exception/TopicNotFoundException.java @@ -0,0 +1,32 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when topic resources are not found. + */ +public class TopicNotFoundException extends AbstractPlatformResourceNotFoundException { + + public TopicNotFoundException(final Long id) { + super("error.msg.topic.id.invalid", "Topic with identifier " + id + " does not exist", id); + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java index e8becbeef95..1744bd3749c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java @@ -18,13 +18,14 @@ */ package org.apache.fineract.notification.service; - import org.apache.activemq.command.ActiveMQQueue; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.notification.data.NotificationData; -import org.apache.fineract.notification.eventandlistener.NotificationEventService; +import org.apache.fineract.notification.data.TopicSubscriberData; +import org.apache.fineract.notification.eventandlistener.NotificationEvent; +import org.apache.fineract.organisation.office.domain.OfficeRepository; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; @@ -39,552 +40,562 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction; import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount; -import org.apache.fineract.useradministration.domain.AppUser; -import org.apache.fineract.useradministration.domain.AppUserRepository; import org.apache.fineract.useradministration.domain.Role; +import org.apache.fineract.useradministration.domain.RoleRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.jms.Queue; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; @Service public class NotificationDomainServiceImpl implements NotificationDomainService { - private final BusinessEventNotifierService businessEventNotifierService; - private final NotificationEventService notificationEventService; - private final AppUserRepository appUserRepository; - private final PlatformSecurityContext context; - - - @Autowired - public NotificationDomainServiceImpl(final BusinessEventNotifierService businessEventNotifierService, - final NotificationEventService notificationEventService, - final AppUserRepository appUserRepository, - final PlatformSecurityContext context) { - this.businessEventNotifierService = businessEventNotifierService; - this.notificationEventService = notificationEventService; - this.appUserRepository = appUserRepository; - this.context = context; - } - - @PostConstruct - public void addListeners() { - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CLIENTS_CREATE, - new ClientCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_APPROVE, - new SavingsAccountApprovedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CENTERS_CREATE, - new CenterCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.GROUPS_CREATE, - new GroupCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_DEPOSIT, - new SavingsAccountDepositListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_PRODUCT_DIVIDENDS_CREATE, - new ShareProductDividendCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.FIXED_DEPOSIT_ACCOUNT_CREATE, - new FixedDepositAccountCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.RECURRING_DEPOSIT_ACCOUNT_CREATE, - new RecurringDepositAccountCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_POST_INTEREST, - new SavingsPostInterestListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CREATE, - new LoanCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_APPROVED, - new LoanApprovedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CLOSE, - new LoanClosedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CLOSE_AS_RESCHEDULE, - new LoanCloseAsRescheduledListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_MAKE_REPAYMENT, - new LoanMakeRepaymentListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_PRODUCT_CREATE, - new LoanProductCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_CREATE, - new SavingsAccountCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_CLOSE, - new SavingsAccountClosedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_ACCOUNT_CREATE, - new ShareAccountCreatedListener()); - businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_ACCOUNT_APPROVE, - new ShareAccountApprovedListener()); - } - - private abstract class NotificationBusinessEventAdapter implements BusinessEventListner { - - @Override - public void businessEventToBeExecuted(Map businessEventEntity) { - //Nothing to do - } - } - - private class ClientCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - Client client; - Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.CLIENT); - if (entity != null) { - client = (Client) entity; - buildNotification( - "ACTIVATE_CLIENT", - "client", - client.getId(), - "New client created", - "created", - context.authenticatedUser().getId(), - client.getOffice().getId() - ); - } - } - } - - private class CenterCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - CommandProcessingResult commandProcessingResult; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.GROUP); - if (entity != null) { - commandProcessingResult = (CommandProcessingResult) entity; - buildNotification( - "ACTIVATE_CENTER", - "center", - commandProcessingResult.getGroupId(), - "New center created", - "created", - context.authenticatedUser().getId(), - commandProcessingResult.getOfficeId() - ); - } - } - } - - private class GroupCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - CommandProcessingResult commandProcessingResult; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.GROUP); - if (entity != null) { - commandProcessingResult = (CommandProcessingResult) entity; - buildNotification( - "ACTIVATE_GROUP", - "group", - commandProcessingResult.getGroupId(), - "New group created", - "created", - context.authenticatedUser().getId(), - commandProcessingResult.getOfficeId() - ); - } - } - } - - private class SavingsAccountDepositListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - SavingsAccountTransaction savingsAccountTransaction; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVINGS_TRANSACTION); - if (entity != null) { - savingsAccountTransaction = (SavingsAccountTransaction) entity; - buildNotification( - "READ_SAVINGSACCOUNT", - "savingsAccount", - savingsAccountTransaction.getSavingsAccount().getId(), - "Deposit made", - "depositMade", - context.authenticatedUser().getId(), - savingsAccountTransaction.getSavingsAccount().officeId() - ); - } - } - } - - private class ShareProductDividendCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - Long shareProductId; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.SHARE_PRODUCT); - if (entity != null) { - shareProductId = (Long) entity; - buildNotification( - "READ_DIVIDEND_SHAREPRODUCT", - "shareProduct", - shareProductId, - "Dividend posted to account", - "dividendPosted", - context.authenticatedUser().getId(), - context.authenticatedUser().getOffice().getId() - ); - } - } - } - - private class FixedDepositAccountCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - FixedDepositAccount fixedDepositAccount; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.DEPOSIT_ACCOUNT); - if (entity != null) { - fixedDepositAccount = (FixedDepositAccount) entity; - buildNotification( - "APPROVE_FIXEDDEPOSITACCOUNT", - "fixedDeposit", - fixedDepositAccount.getId(), - "New fixed deposit account created", - "created", - context.authenticatedUser().getId(), - fixedDepositAccount.officeId() - ); - } - } - } - - private class RecurringDepositAccountCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - RecurringDepositAccount recurringDepositAccount; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.DEPOSIT_ACCOUNT); - if (entity != null) { - recurringDepositAccount = (RecurringDepositAccount) entity; - buildNotification( - "APPROVE_RECURRINGDEPOSITACCOUNT", - "recurringDepositAccount", - recurringDepositAccount.getId(), - "New recurring deposit account created", - "created", - context.authenticatedUser().getId(), - recurringDepositAccount.officeId() - ); - } - } - } - - - private class SavingsAccountApprovedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - SavingsAccount savingsAccount; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING); - if (entity != null) { - savingsAccount = (SavingsAccount) entity; - if (savingsAccount.depositAccountType().equals(DepositAccountType.FIXED_DEPOSIT)) { - - buildNotification( - "ACTIVATE_FIXEDDEPOSITACCOUNT", - "fixedDeposit", - savingsAccount.getId(), - "Fixed deposit account approved", - "approved", - context.authenticatedUser().getId(), - savingsAccount.officeId() - ); - - } else if (savingsAccount.depositAccountType().equals(DepositAccountType.RECURRING_DEPOSIT)) { - - buildNotification( - "ACTIVATE_RECURRINGDEPOSITACCOUNT", - "recurringDepositAccount", - savingsAccount.getId(), - "Recurring deposit account approved", - "approved", - context.authenticatedUser().getId(), - savingsAccount.officeId() - ); - - } else if (savingsAccount.depositAccountType().equals(DepositAccountType.SAVINGS_DEPOSIT)) { - - buildNotification( - "ACTIVATE_SAVINGSACCOUNT", - "savingsAccount", - savingsAccount.getId(), - "Savings account approved", - "approved", - context.authenticatedUser().getId(), - savingsAccount.officeId() - ); - } - } - } - } - - private class SavingsPostInterestListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - SavingsAccount savingsAccount; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING); - if (entity != null) { - savingsAccount = (SavingsAccount) entity; - buildNotification( - "READ_SAVINGSACCOUNT", - "savingsAccount", - savingsAccount.getId(), - "Interest posted to account", - "interestPosted", - context.authenticatedUser().getId(), - savingsAccount.officeId() - ); - } - } - } - - private class LoanCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - Loan loan; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); - if (entity != null) { - loan = (Loan) entity; - buildNotification( - "APPROVE_LOAN", - "loan", - loan.getId(), - "New loan created", - "created", - context.authenticatedUser().getId(), - loan.getOfficeId() - ); - } - } - } - - private class LoanApprovedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - Loan loan; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); - if (entity != null) { - loan = (Loan) entity; - buildNotification( - "DISBURSE_LOAN", - "loan", - loan.getId(), - "New loan approved", - "approved", - context.authenticatedUser().getId(), - loan.getOfficeId() - ); - } - } - } - - private class LoanClosedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - Loan loan; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); - if (entity != null) { - loan = (Loan) entity; - buildNotification( - "READ_LOAN", - "loan", - loan.getId(), - "Loan closed", - "loanClosed", - context.authenticatedUser().getId(), - loan.getOfficeId() - ); - } - } - } - - private class LoanCloseAsRescheduledListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - Loan loan; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); - if (entity != null) { - loan = (Loan) entity; - buildNotification( - "READ_Rescheduled Loans", - "loan", - loan.getId(), - "Loan has been rescheduled", - "loanRescheduled", - context.authenticatedUser().getId(), - loan.getOfficeId() - ); - } - } - } - - private class LoanMakeRepaymentListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - Loan loan; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); - if (entity != null) { - loan = (Loan) entity; - buildNotification( - "READ_LOAN", - "loan", - loan.getId(), - "Repayment made", - "repaymentMade", - context.authenticatedUser().getId(), - loan.getOfficeId() - ); - } - } - } - - private class LoanProductCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - - LoanProduct loanProduct; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN_PRODUCT); - if (entity != null) { - loanProduct = (LoanProduct) entity; - buildNotification( - "READ_LOANPRODUCT", - "loanProduct", - loanProduct.getId(), - "New loan product created", - "created", - context.authenticatedUser().getId(), - context.authenticatedUser().getOffice().getId() - ); - } - } - } - - private class SavingsAccountCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - SavingsAccount savingsAccount; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING); - if (entity != null) { - savingsAccount = (SavingsAccount) entity; - buildNotification( - "APPROVE_SAVINGSACCOUNT", - "savingsAccount", - savingsAccount.getId(), - "New savings account created", - "created", - context.authenticatedUser().getId(), - savingsAccount.officeId() - ); - } - } - } - - private class SavingsAccountClosedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - SavingsAccount savingsAccount; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING); - if (entity != null) { - savingsAccount = (SavingsAccount) entity; - buildNotification( - "READ_SAVINGSACCOUNT", - "savingsAccount", - savingsAccount.getId(), - "Savings has gone into dormant", - "closed", - context.authenticatedUser().getId(), - savingsAccount.officeId() - ); - } - } - } - - private class ShareAccountCreatedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - ShareAccount shareAccount; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.SHARE_ACCOUNT); - if (entity != null) { - shareAccount = (ShareAccount) entity; - buildNotification( - "APPROVE_SHAREACCOUNT", - "shareAccount", - shareAccount.getId(), - "New share account created", - "created", - context.authenticatedUser().getId(), - shareAccount.getOfficeId() - ); - } - } - } - - private class ShareAccountApprovedListener extends NotificationBusinessEventAdapter { - - @Override - public void businessEventWasExecuted(Map businessEventEntity) { - ShareAccount shareAccount; - Object entity = businessEventEntity.get(BUSINESS_ENTITY.SHARE_ACCOUNT); - if (entity != null) { - shareAccount = (ShareAccount) entity; - buildNotification( - "ACTIVATE_SHAREACCOUNT", - "shareAccount", - shareAccount.getId(), - "Share account approved", - "approved", - context.authenticatedUser().getId(), - shareAccount.getOfficeId() - ); - } - } - } - - private void buildNotification(String permission, String objectType, - Long objectIdentifier, String notificationContent, String eventType, - Long appUserId, Long officeId) { - - String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier(); - Queue queue = new ActiveMQQueue("NotificationQueue"); - List userIds = retrieveUsersWithSpecificPermission(permission); - NotificationData notificationData = new NotificationData( - objectType, - objectIdentifier, - eventType, - appUserId, - notificationContent, - false, - tenantIdentifier, - officeId, - userIds - ); - notificationEventService.broadcastNotification(queue, notificationData); - - } - - private List retrieveUsersWithSpecificPermission(String permission) { - List appUsers = appUserRepository.findAll(); - List userIds = new ArrayList<>(); - for (AppUser appUser : appUsers) { - Set roles = appUser.getRoles(); - for (Role role : roles) { - if (role.hasPermissionTo(permission)) { - if (!(userIds.contains(appUser.getId()))) { - userIds.add(appUser.getId()); - } - } - } - } - return userIds; - } + private final BusinessEventNotifierService businessEventNotifierService; + private final NotificationEvent notificationEvent; + private final PlatformSecurityContext context; + private final RoleRepository roleRepository; + private final OfficeRepository officeRepository; + private final TopicSubscriberReadPlatformService topicSubscriberReadPlatformService; + + @Autowired + public NotificationDomainServiceImpl(final BusinessEventNotifierService businessEventNotifierService, + final NotificationEvent notificationEvent, + final PlatformSecurityContext context, final RoleRepository roleRepository, + final TopicSubscriberReadPlatformService topicSubscriberReadPlatformService, + final OfficeRepository officeRepository) { + + this.businessEventNotifierService = businessEventNotifierService; + this.notificationEvent = notificationEvent; + this.context = context; + this.roleRepository = roleRepository; + this.topicSubscriberReadPlatformService = topicSubscriberReadPlatformService; + this.officeRepository = officeRepository; + } + + @PostConstruct + public void addListeners() { + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CLIENTS_CREATE, + new ClientCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_APPROVE, + new SavingsAccountApprovedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CENTERS_CREATE, + new CenterCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.GROUPS_CREATE, + new GroupCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_DEPOSIT, + new SavingsAccountDepositListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_PRODUCT_DIVIDENDS_CREATE, + new ShareProductDividendCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.FIXED_DEPOSIT_ACCOUNT_CREATE, + new FixedDepositAccountCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.RECURRING_DEPOSIT_ACCOUNT_CREATE, + new RecurringDepositAccountCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_POST_INTEREST, + new SavingsPostInterestListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CREATE, + new LoanCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_APPROVED, + new LoanApprovedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CLOSE, + new LoanClosedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CLOSE_AS_RESCHEDULE, + new LoanCloseAsRescheduledListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_MAKE_REPAYMENT, + new LoanMakeRepaymentListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_PRODUCT_CREATE, + new LoanProductCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_CREATE, + new SavingsAccountCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_CLOSE, + new SavingsAccountClosedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_ACCOUNT_CREATE, + new ShareAccountCreatedListener()); + businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_ACCOUNT_APPROVE, + new ShareAccountApprovedListener()); + } + + private abstract class NotificationBusinessEventAdapter implements BusinessEventListner { + @Override + public void businessEventToBeExecuted(Map businessEventEntity) { + } + } + + private class ClientCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + Client client; + Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.CLIENT); + if (entity != null) { + client = (Client) entity; + buildNotification( + "ACTIVATE_CLIENT", + "client", + client.getId(), + "New client created", + "created", + context.authenticatedUser().getId(), + client.getOffice().getId() + ); + } + } + } + + private class CenterCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + CommandProcessingResult commandProcessingResult; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.GROUP); + if (entity != null) { + commandProcessingResult = (CommandProcessingResult) entity; + buildNotification( + "ACTIVATE_CENTER", + "center", + commandProcessingResult.getGroupId(), + "New center created", + "created", + context.authenticatedUser().getId(), + commandProcessingResult.getOfficeId() + ); + } + } + } + + private class GroupCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + CommandProcessingResult commandProcessingResult; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.GROUP); + if (entity != null) { + commandProcessingResult = (CommandProcessingResult) entity; + buildNotification( + "ACTIVATE_GROUP", + "group", + commandProcessingResult.getGroupId(), + "New group created", + "created", + context.authenticatedUser().getId(), + commandProcessingResult.getOfficeId() + ); + } + } + } + + private class SavingsAccountDepositListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + SavingsAccountTransaction savingsAccountTransaction; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVINGS_TRANSACTION); + if (entity != null) { + savingsAccountTransaction = (SavingsAccountTransaction) entity; + buildNotification( + "READ_SAVINGSACCOUNT", + "savingsAccount", + savingsAccountTransaction.getSavingsAccount().getId(), + "Deposit made", + "depositMade", + context.authenticatedUser().getId(), + savingsAccountTransaction.getSavingsAccount().officeId() + ); + } + } + } + + private class ShareProductDividendCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + Long shareProductId; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.SHARE_PRODUCT); + if (entity != null) { + shareProductId = (Long) entity; + buildNotification( + "READ_DIVIDEND_SHAREPRODUCT", + "shareProduct", + shareProductId, + "Dividend posted to account", + "dividendPosted", + context.authenticatedUser().getId(), + context.authenticatedUser().getOffice().getId() + ); + } + } + } + + private class FixedDepositAccountCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + FixedDepositAccount fixedDepositAccount; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.DEPOSIT_ACCOUNT); + if (entity != null) { + fixedDepositAccount = (FixedDepositAccount) entity; + buildNotification( + "APPROVE_FIXEDDEPOSITACCOUNT", + "fixedDeposit", + fixedDepositAccount.getId(), + "New fixed deposit account created", + "created", + context.authenticatedUser().getId(), + fixedDepositAccount.officeId() + ); + } + } + } + + private class RecurringDepositAccountCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + RecurringDepositAccount recurringDepositAccount; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.DEPOSIT_ACCOUNT); + if (entity != null) { + recurringDepositAccount = (RecurringDepositAccount) entity; + buildNotification( + "APPROVE_RECURRINGDEPOSITACCOUNT", + "recurringDepositAccount", + recurringDepositAccount.getId(), + "New recurring deposit account created", + "created", + context.authenticatedUser().getId(), + recurringDepositAccount.officeId() + ); + } + } + } + + private class SavingsAccountApprovedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + SavingsAccount savingsAccount; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING); + if (entity != null) { + savingsAccount = (SavingsAccount) entity; + if (savingsAccount.depositAccountType().equals(DepositAccountType.FIXED_DEPOSIT)) { + + buildNotification( + "ACTIVATE_FIXEDDEPOSITACCOUNT", + "fixedDeposit", + savingsAccount.getId(), + "Fixed deposit account approved", + "approved", + context.authenticatedUser().getId(), + savingsAccount.officeId() + ); + } else if (savingsAccount.depositAccountType().equals(DepositAccountType.RECURRING_DEPOSIT)) { + + buildNotification( + "ACTIVATE_RECURRINGDEPOSITACCOUNT", + "recurringDepositAccount", + savingsAccount.getId(), + "Recurring deposit account approved", + "approved", + context.authenticatedUser().getId(), + savingsAccount.officeId() + ); + } else if (savingsAccount.depositAccountType().equals(DepositAccountType.SAVINGS_DEPOSIT)) { + + buildNotification( + "ACTIVATE_SAVINGSACCOUNT", + "savingsAccount", + savingsAccount.getId(), + "Savings account approved", + "approved", + context.authenticatedUser().getId(), + savingsAccount.officeId() + ); + } + } + } + } + + private class SavingsPostInterestListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + SavingsAccount savingsAccount; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING); + if (entity != null) { + savingsAccount = (SavingsAccount) entity; + buildNotification( + "READ_SAVINGSACCOUNT", + "savingsAccount", + savingsAccount.getId(), + "Interest posted to account", + "interestPosted", + context.authenticatedUser().getId(), + savingsAccount.officeId() + ); + } + } + } + + private class LoanCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + Loan loan; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); + if (entity != null) { + loan = (Loan) entity; + buildNotification( + "APPROVE_LOAN", + "loan", + loan.getId(), + "New loan created", + "created", + context.authenticatedUser().getId(), + loan.getOfficeId() + ); + } + + } + } + + private class LoanApprovedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + Loan loan; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); + if (entity != null) { + loan = (Loan) entity; + buildNotification( + "DISBURSE_LOAN", + "loan", + loan.getId(), + "New loan approved", + "approved", + context.authenticatedUser().getId(), + loan.getOfficeId() + ); + } + } + } + + private class LoanClosedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + + Loan loan; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); + if (entity != null) { + loan = (Loan) entity; + buildNotification( + "READ_LOAN", + "loan", + loan.getId(), + "Loan closed", + "loanClosed", + context.authenticatedUser().getId(), + loan.getOfficeId() + ); + } + } + } + + private class LoanCloseAsRescheduledListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + Loan loan; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); + if (entity != null) { + loan = (Loan) entity; + buildNotification( + "READ_Rescheduled Loans", + "loan", + loan.getId(), + "Loan has been rescheduled", + "loanRescheduled", + context.authenticatedUser().getId(), + loan.getOfficeId() + ); + } + } + } + + private class LoanMakeRepaymentListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + Loan loan; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN); + if (entity != null) { + loan = (Loan) entity; + buildNotification( + "READ_LOAN", + "loan", + loan.getId(), + "Repayment made", + "repaymentMade", + context.authenticatedUser().getId(), + loan.getOfficeId() + ); + } + } + } + + private class LoanProductCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + + LoanProduct loanProduct; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN_PRODUCT); + if (entity != null) { + loanProduct = (LoanProduct) entity; + buildNotification( + "READ_LOANPRODUCT", + "loanProduct", + loanProduct.getId(), + "New loan product created", + "created", + context.authenticatedUser().getId(), + context.authenticatedUser().getOffice().getId() + ); + } + } + } + + private class SavingsAccountCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + SavingsAccount savingsAccount; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING); + if (entity != null) { + savingsAccount = (SavingsAccount) entity; + buildNotification( + "APPROVE_SAVINGSACCOUNT", + "savingsAccount", + savingsAccount.getId(), + "New savings account created", + "created", + context.authenticatedUser().getId(), + savingsAccount.officeId() + ); + } + } + } + + private class SavingsAccountClosedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + SavingsAccount savingsAccount; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING); + if (entity != null) { + savingsAccount = (SavingsAccount) entity; + buildNotification( + "READ_SAVINGSACCOUNT", + "savingsAccount", + savingsAccount.getId(), + "Savings has gone into dormant", + "closed", + context.authenticatedUser().getId(), + savingsAccount.officeId() + ); + } + } + } + + private class ShareAccountCreatedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + ShareAccount shareAccount; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.SHARE_ACCOUNT); + if (entity != null) { + shareAccount = (ShareAccount) entity; + buildNotification( + "APPROVE_SHAREACCOUNT", + "shareAccount", + shareAccount.getId(), + "New share account created", + "created", + context.authenticatedUser().getId(), + shareAccount.getOfficeId() + ); + } + } + } + + private class ShareAccountApprovedListener extends NotificationBusinessEventAdapter { + + @Override + public void businessEventWasExecuted(Map businessEventEntity) { + ShareAccount shareAccount; + Object entity = businessEventEntity.get(BUSINESS_ENTITY.SHARE_ACCOUNT); + if (entity != null) { + shareAccount = (ShareAccount) entity; + buildNotification( + "ACTIVATE_SHAREACCOUNT", + "shareAccount", + shareAccount.getId(), + "Share account approved", + "approved", + context.authenticatedUser().getId(), + shareAccount.getOfficeId() + ); + } + } + } + + private void buildNotification(String permission, String objectType, Long objectIdentifier, + String notificationContent, String eventType, Long appUserId, Long officeId) { + + String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier(); + Queue queue = new ActiveMQQueue("NotificationQueue"); + List userIds = retrieveSubscribers(officeId, permission); + NotificationData notificationData = new NotificationData( + objectType, + objectIdentifier, + eventType, + appUserId, + notificationContent, + false, + false, + tenantIdentifier, + officeId, + userIds + ); + notificationEvent.broadcastNotification(queue, notificationData); + } + + private List retrieveSubscribers(Long officeId, String permission) { + + Collection topicSubscribers = new ArrayList<>(); + List subscriberIds = new ArrayList<>(); + Long entityId = officeId; + String entityType= ""; + if (officeRepository.findOne(entityId).getParent() == null) { + entityType = "OFFICE"; + } else { + entityType = "BRANCH"; + } + List allRoles = roleRepository.findAll(); + for (Role curRole : allRoles) { + if (curRole.hasPermissionTo(permission) || curRole.hasPermissionTo("ALL_FUNCTIONS")) { + System.out.println(curRole + " Role has permission"); + String memberType = curRole.getName(); + topicSubscribers = topicSubscriberReadPlatformService.getSubscribers(entityId, entityType, memberType); + } + } + + for (TopicSubscriberData topicSubscriber : topicSubscribers) { + subscriberIds.add(topicSubscriber.getUserId()); + } + return subscriberIds; + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java index 72c2ded9e15..fe8b13aba4c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java @@ -20,7 +20,6 @@ import org.apache.fineract.notification.domain.NotificationMapper; - public interface NotificationMapperWritePlatformService { Long create(NotificationMapper notificationMapper); diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java index c701be259f4..1c53d4ecdd1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java @@ -61,16 +61,12 @@ public boolean hasUnreadNotifications(Long appUserId) { Long lastFetch = notificationResponseHeaderCache.get(appUserId).getLastFetch(); if ((now - lastFetch) > 1) { return this.createUpdateCacheValue(appUserId, now, notificationResponseHeaderCache); - } else { - return notificationResponseHeaderCache.get(appUserId).hasNotifications(); } - } else { - return this.createUpdateCacheValue(appUserId, now, notificationResponseHeaderCache); + return notificationResponseHeaderCache.get(appUserId).hasNotifications(); } - } else { - return this.initializeTenantNotificationResponseHeaderCache(tenantId, now, appUserId); - + return this.createUpdateCacheValue(appUserId, now, notificationResponseHeaderCache); } + return this.initializeTenantNotificationResponseHeaderCache(tenantId, now, appUserId); } private boolean initializeTenantNotificationResponseHeaderCache(Long tenantId, Long now, Long appUserId) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java index 703cf8e18e6..cb760700187 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java @@ -26,4 +26,5 @@ Long notify(Long userId, String objectType, Long objectId, String action, Long notify(List userIds, String objectType, Long objectId, String action, Long actorId, String notificationContent, boolean isSystemGenerated); + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformService.java new file mode 100644 index 00000000000..e6c9ea5f827 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformService.java @@ -0,0 +1,32 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.service; + +import java.util.Collection; +import org.apache.fineract.notification.data.TopicData; + +public interface TopicReadPlatformService { + + Collection getAllTopics(); + + Collection getAllEnabledTopics(); + + TopicData findById(Long id); + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformServiceImpl.java new file mode 100644 index 00000000000..948f9310d1e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformServiceImpl.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +import org.apache.fineract.infrastructure.core.service.RoutingDataSource; +import org.apache.fineract.notification.data.TopicData; +import org.apache.fineract.notification.exception.TopicNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class TopicReadPlatformServiceImpl implements TopicReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public TopicReadPlatformServiceImpl(final RoutingDataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + private static final class TopicMapper implements RowMapper { + + private final String schema; + + public TopicMapper() { + final StringBuilder sqlBuilder = new StringBuilder(200); + sqlBuilder.append("t.id as id, t.title as title, t.enabled as enabled, "); + sqlBuilder.append("t.entity_id as entityId, t.entity_type as entityType, "); + sqlBuilder.append("t.member_type as memberType, from topic t"); + this.schema = sqlBuilder.toString(); + } + + public String schema() { + return this.schema; + } + + @Override + public TopicData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + final Long id = rs.getLong("id"); + final String title = rs.getString("title"); + final Boolean enabled = rs.getBoolean("enabled"); + final Long entityId = rs.getLong("entityId"); + final String entityType = rs.getString("entityType"); + final String memberType = rs.getString("memberType"); + + return new TopicData(id, title, enabled, entityId, entityType, memberType); + } + + } + + @Override + public Collection getAllTopics() { + final TopicMapper tm = new TopicMapper(); + String sql = "select " + tm.schema(); + return this.jdbcTemplate.query(sql, tm, new Object[] {}); + } + + @Override + public Collection getAllEnabledTopics() { + final TopicMapper tm = new TopicMapper(); + final String sql = "select " + tm.schema() + " where t.is_active = ?"; + return this.jdbcTemplate.query(sql, tm, new Object[] { true }); + } + + @Override + public TopicData findById(Long topicId) { + try { + final TopicMapper tm = new TopicMapper(); + final String sql = "select " + tm.schema() + " where t.id = ?"; + return this.jdbcTemplate.queryForObject(sql, tm, new Object[] { topicId }); + } catch (final EmptyResultDataAccessException e) { + throw new TopicNotFoundException(topicId); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberReadPlatformService.java new file mode 100644 index 00000000000..834b5747965 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberReadPlatformService.java @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.service; + +import java.util.Collection; + +import org.apache.fineract.notification.data.TopicSubscriberData; + +public interface TopicSubscriberReadPlatformService { + + Collection getSubscribers(Long entityId, String entityType, String memberType); + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberReadPlatformServiceImpl.java new file mode 100644 index 00000000000..4d597a015f7 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberReadPlatformServiceImpl.java @@ -0,0 +1,78 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.apache.fineract.infrastructure.core.service.RoutingDataSource; +import org.apache.fineract.notification.data.TopicSubscriberData; +import org.joda.time.LocalDate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class TopicSubscriberReadPlatformServiceImpl implements TopicSubscriberReadPlatformService{ + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public TopicSubscriberReadPlatformServiceImpl(final RoutingDataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + private static final class TopicSubscriberMapper implements RowMapper { + + private final String schema; + + public TopicSubscriberMapper() { + final StringBuilder sqlBuilder = new StringBuilder(200); + sqlBuilder.append("ts.id as id, ts.topic_id as topicId, ts.user_id as userId, "); + sqlBuilder.append("ts.subscription_date as subscriptionDate from topic_subscriber ts "); + sqlBuilder.append("WHERE ts.topic_id = ( SELECT id from topic WHERE entity_id = ? "); + sqlBuilder.append("AND entity_type = ? AND member_type = ? )"); + this.schema = sqlBuilder.toString(); + } + + public String schema() { + return this.schema; + } + + @Override + public TopicSubscriberData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + final Long id = rs.getLong("id"); + final Long topicId = rs.getLong("topicId"); + final Long userId = rs.getLong("userId"); + final LocalDate subscriptionDate = JdbcSupport.getLocalDate(rs, "subscriptionDate"); + + return new TopicSubscriberData(id, topicId, userId, subscriptionDate); + } + + } + + @Override + public Collection getSubscribers(Long entityId, String entityType, String memberType) { + final TopicSubscriberMapper tsm = new TopicSubscriberMapper(); + String sql = "SELECT " + tsm.schema(); + return this.jdbcTemplate.query(sql, tsm, new Object[] { entityId, entityType, memberType }); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberWritePlatformService.java new file mode 100644 index 00000000000..95cbd9fc859 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberWritePlatformService.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.service; + +import org.apache.fineract.notification.domain.TopicSubscriber; + +public interface TopicSubscriberWritePlatformService { + + Long create(TopicSubscriber topicSubscriber); + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberWritePlatformServiceJpaRepositoryImpl.java new file mode 100644 index 00000000000..541fd1ad4f9 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicSubscriberWritePlatformServiceJpaRepositoryImpl.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.service; + +import org.apache.fineract.notification.domain.TopicSubscriber; +import org.apache.fineract.notification.domain.TopicSubscriberRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class TopicSubscriberWritePlatformServiceJpaRepositoryImpl implements TopicSubscriberWritePlatformService { + +private final TopicSubscriberRepository topicSubscriberRepository; + + @Autowired + public TopicSubscriberWritePlatformServiceJpaRepositoryImpl(TopicSubscriberRepository topicSubscriberRepository) { + this.topicSubscriberRepository = topicSubscriberRepository; + } + + @Override + public Long create(TopicSubscriber topicSubscriber) { + topicSubscriberRepository.save(topicSubscriber); + return topicSubscriber.getId(); + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicWritePlatformService.java new file mode 100644 index 00000000000..d48206319df --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicWritePlatformService.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.service; + +import org.apache.fineract.notification.domain.Topic; + +public interface TopicWritePlatformService { + + Long create(Topic topic); + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicWritePlatformServiceJpaRepositoryImpl.java new file mode 100644 index 00000000000..63cb911af2d --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicWritePlatformServiceJpaRepositoryImpl.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification.service; + +import org.apache.fineract.notification.domain.Topic; +import org.apache.fineract.notification.domain.TopicRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class TopicWritePlatformServiceJpaRepositoryImpl implements TopicWritePlatformService { + + private final TopicRepository topicRepository; + + @Autowired + public TopicWritePlatformServiceJpaRepositoryImpl(TopicRepository topicRepository) { + this.topicRepository = topicRepository; + } + + @Override + public Long create(Topic topic) { + topicRepository.save(topic); + return topic.getId(); + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/domain/Office.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/domain/Office.java index c64e856ce63..23b6fa11f1d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/domain/Office.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/domain/Office.java @@ -205,6 +205,10 @@ public String getHierarchy() { return this.hierarchy; } + public Office getParent() { + return this.parent; + } + public boolean hasParentOf(final Office office) { boolean isParent = false; if (this.parent != null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java index ba12c4131c0..9da65f6e22e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.organisation.office.service; +import java.util.List; import java.util.Map; import javax.persistence.PersistenceException; @@ -29,6 +30,8 @@ import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.security.exception.NoAuthorizationException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.notification.domain.Topic; +import org.apache.fineract.notification.domain.TopicRepository; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; @@ -40,6 +43,8 @@ import org.apache.fineract.organisation.office.serialization.OfficeCommandFromApiJsonDeserializer; import org.apache.fineract.organisation.office.serialization.OfficeTransactionCommandFromApiJsonDeserializer; import org.apache.fineract.useradministration.domain.AppUser; +import org.apache.fineract.useradministration.domain.Role; +import org.apache.fineract.useradministration.domain.RoleRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -60,19 +65,23 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP private final OfficeRepositoryWrapper officeRepositoryWrapper; private final OfficeTransactionRepository officeTransactionRepository; private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository; + private final RoleRepository roleRepository; + private final TopicRepository topicRepository; @Autowired public OfficeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final OfficeCommandFromApiJsonDeserializer fromApiJsonDeserializer, final OfficeTransactionCommandFromApiJsonDeserializer moneyTransferCommandFromApiJsonDeserializer, final OfficeRepositoryWrapper officeRepositoryWrapper, final OfficeTransactionRepository officeMonetaryTransferRepository, - final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository) { + final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, RoleRepository roleRepository, TopicRepository topicRepository) { this.context = context; this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.moneyTransferCommandFromApiJsonDeserializer = moneyTransferCommandFromApiJsonDeserializer; this.officeRepositoryWrapper = officeRepositoryWrapper; this.officeTransactionRepository = officeMonetaryTransferRepository; this.applicationCurrencyRepository = applicationCurrencyRepository; + this.roleRepository = roleRepository; + this.topicRepository = topicRepository; } @Transactional @@ -101,6 +110,23 @@ public CommandProcessingResult createOffice(final JsonCommand command) { office.generateHierarchy(); this.officeRepositoryWrapper.save(office); + + Long entityId = office.getId(); + String entityType = ""; + if (office.getParent() == null) { + entityType = "OFFICE"; + } else { + entityType = "BRANCH"; + } + + List allRoles = roleRepository.findAll(); + for(Role curRole : allRoles) { + String memberType = curRole.getName().toUpperCase(); + String title = curRole.getName() + " of " + office.getName(); + Topic newTopic = new Topic(title, true, entityId, entityType, memberType); + topicRepository.save(newTopic); + } + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // @@ -142,6 +168,27 @@ public CommandProcessingResult updateOffice(final Long officeId, final JsonComma if (changes.containsKey("parentId")) { final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, parentId); office.update(parent); + String entityType = ""; + if (office.getParent() == null) { + entityType = "OFFICE"; + } else { + entityType = "BRANCH"; + } + List entityTopics = topicRepository.findByEntityId(office.getId()); + for (Topic topic : entityTopics) { + topic.setEntityType(entityType); + topicRepository.save(topic); + } + } + + if (changes.containsKey("name")) { + List entityTopics = topicRepository.findByEntityId(office.getId()); + for (Topic topic: entityTopics) { + Role role = roleRepository.getRoleByName(topic.getMemberType()); + String title = role.getName() + " of " + office.getName(); + topic.setTitle(title); + topicRepository.save(topic); + } } if (!changes.isEmpty()) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java index 4a11d022363..4e8966a250f 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java @@ -67,6 +67,7 @@ public static enum BUSINESS_ENTITY { "loan_adjusted_transaction"), SAVING("saving"), CLIENT("client"), SAVINGS_TRANSACTION("Savings Transaction"), GROUP("group"), SHARE_ACCOUNT("share_account"), SHARE_PRODUCT("share_product"), DEPOSIT_ACCOUNT("deposit_account"), LOAN_PRODUCT("loan_product"); + private final String value; private BUSINESS_ENTITY(final String value) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java index 2616c27cb3e..55cfce6c834 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java @@ -53,6 +53,8 @@ import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.service.LoanStatusMapper; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants; +import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; +import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS; import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; import org.apache.fineract.portfolio.group.domain.*; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java index a21fe5204b0..adfb9cda597 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java @@ -37,6 +37,8 @@ import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants; +import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; +import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS; import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate; import org.apache.fineract.portfolio.floatingrates.domain.FloatingRateRepositoryWrapper; @@ -151,6 +153,9 @@ public CommandProcessingResult createLoanProduct(final JsonCommand command) { this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_PRODUCT_CREATE, constructEntityMap(BUSINESS_ENTITY.LOAN_PRODUCT, loanproduct)); + this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_PRODUCT_CREATE, + constructEntityMap(BUSINESS_ENTITY.LOAN_PRODUCT, loanproduct)); + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withEntityId(loanproduct.getId()) // diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java index cedcfdda8fc..0833d83c27a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java @@ -62,6 +62,8 @@ import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants; +import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; +import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.group.domain.Group; @@ -229,6 +231,8 @@ public CommandProcessingResult submitFDApplication(final JsonCommand command) { } final Long savingsId = account.getId(); + this.businessEventNotifierService.notifyBusinessEventWasExecuted( BUSINESS_EVENTS.FIXED_DEPOSIT_ACCOUNT_CREATE, + constructEntityMap(BUSINESS_ENTITY.DEPOSIT_ACCOUNT, account)); this.businessEventNotifierService.notifyBusinessEventWasExecuted( BUSINESS_EVENTS.FIXED_DEPOSIT_ACCOUNT_CREATE, constructEntityMap(BUSINESS_ENTITY.DEPOSIT_ACCOUNT, account)); @@ -290,6 +294,8 @@ public CommandProcessingResult submitRDApplication(final JsonCommand command) { financialYearBeginningMonth); account.validateApplicableInterestRate(); this.savingAccountRepository.save(account); + this.businessEventNotifierService.notifyBusinessEventWasExecuted( BUSINESS_EVENTS.RECURRING_DEPOSIT_ACCOUNT_CREATE, + constructEntityMap(BUSINESS_ENTITY.DEPOSIT_ACCOUNT, account)); this.businessEventNotifierService.notifyBusinessEventWasExecuted( BUSINESS_EVENTS.RECURRING_DEPOSIT_ACCOUNT_CREATE, constructEntityMap(BUSINESS_ENTITY.DEPOSIT_ACCOUNT, account)); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java index 1a4ff23e1da..463ec621a32 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java @@ -215,11 +215,11 @@ private void handleDataIntegrityIssues(final JsonCommand command, final Throwabl throw new PlatformDataIntegrityException("error.msg.shareproduct.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); } - + private Map constructEntityMap(final BusinessEventNotificationConstants.BUSINESS_ENTITY entityEvent, Object entity) { - Map map = new HashMap<>(1); - map.put(entityEvent, entity); - return map; + Map map = new HashMap<>(1); + map.put(entityEvent, entity); + return map; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/Role.java b/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/Role.java index 19b3d98dff1..bc0970e5496 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/Role.java +++ b/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/Role.java @@ -129,6 +129,10 @@ public RoleData toData() { return new RoleData(getId(), this.name, this.description, this.disabled); } + public String getName() { + return this.name; + } + public void disableRole() { this.disabled = true; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java index acda463e8c9..7fefedcda9c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java @@ -20,12 +20,12 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import javax.persistence.EntityExistsException; import javax.persistence.PersistenceException; import org.apache.commons.lang.exception.ExceptionUtils; @@ -39,6 +39,10 @@ import org.apache.fineract.infrastructure.core.service.PlatformEmailSendException; import org.apache.fineract.infrastructure.security.service.PlatformPasswordEncoder; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.notification.domain.Topic; +import org.apache.fineract.notification.domain.TopicRepository; +import org.apache.fineract.notification.domain.TopicSubscriber; +import org.apache.fineract.notification.domain.TopicSubscriberRepository; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; import org.apache.fineract.organisation.staff.domain.Staff; @@ -87,13 +91,16 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit private final AppUserPreviousPasswordRepository appUserPreviewPasswordRepository; private final StaffRepositoryWrapper staffRepositoryWrapper; private final ClientRepositoryWrapper clientRepositoryWrapper; + private final TopicRepository topicRepository; + private final TopicSubscriberRepository topicSubscriberRepository; @Autowired public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final AppUserRepository appUserRepository, final UserDomainService userDomainService, final OfficeRepositoryWrapper officeRepositoryWrapper, final RoleRepository roleRepository, final PlatformPasswordEncoder platformPasswordEncoder, final UserDataValidator fromApiJsonDeserializer, final AppUserPreviousPasswordRepository appUserPreviewPasswordRepository, final StaffRepositoryWrapper staffRepositoryWrapper, - final ClientRepositoryWrapper clientRepositoryWrapper) { + final ClientRepositoryWrapper clientRepositoryWrapper, final TopicRepository topicRepository, + final TopicSubscriberRepository topicSubscriberRepository) { this.context = context; this.appUserRepository = appUserRepository; this.userDomainService = userDomainService; @@ -104,6 +111,8 @@ public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContex this.appUserPreviewPasswordRepository = appUserPreviewPasswordRepository; this.staffRepositoryWrapper = staffRepositoryWrapper; this.clientRepositoryWrapper = clientRepositoryWrapper; + this.topicRepository = topicRepository; + this.topicSubscriberRepository = topicSubscriberRepository; } @Transactional @@ -150,6 +159,19 @@ public CommandProcessingResult createUser(final JsonCommand command) { final Boolean sendPasswordToEmail = command.booleanObjectValueOfParameterNamed("sendPasswordToEmail"); this.userDomainService.create(appUser, sendPasswordToEmail); + List possibleTopics = topicRepository.findByEntityId(appUser.getOffice().getId()); + + if (!possibleTopics.isEmpty()) { + Set userRoles = appUser.getRoles(); + for (Role curRole : userRoles) { + for (Topic curTopic : possibleTopics) { + if(curRole.getName().compareToIgnoreCase(curTopic.getMemberType()) == 0) { + TopicSubscriber topicSubscriber = new TopicSubscriber(curTopic, appUser, new Date()); + topicSubscriberRepository.save(topicSubscriber); + } + } + } + } return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // @@ -201,8 +223,7 @@ public CommandProcessingResult updateUser(final Long userId, final JsonCommand c isSelfServiceUser = command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER); } - if(isSelfServiceUser - && command.hasParameter(AppUserConstants.CLIENTS)){ + if(isSelfServiceUser && command.hasParameter(AppUserConstants.CLIENTS)){ JsonArray clientsArray = command.arrayOfParameterNamed(AppUserConstants.CLIENTS); Collection clientIds = new HashSet<>(); for(JsonElement clientElement : clientsArray){ @@ -214,9 +235,32 @@ public CommandProcessingResult updateUser(final Long userId, final JsonCommand c final Map changes = userToUpdate.update(command, this.platformPasswordEncoder, clients); if (changes.containsKey("officeId")) { - final Long officeId = (Long) changes.get("officeId"); - final Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId); + final Long oldOfficeId = userToUpdate.getOffice().getId(); + final Long newOfficeId = (Long) changes.get("officeId"); + final Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(newOfficeId); userToUpdate.changeOffice(office); + + List oldTopics = topicRepository.findByEntityId(oldOfficeId); + List newTopics = topicRepository.findByEntityId(newOfficeId); + + List oldSubscriptions = topicSubscriberRepository.findBySubscriber(userToUpdate); + for (TopicSubscriber subscriber : oldSubscriptions) { + for (Topic topic : oldTopics) { + if (subscriber.getTopic().getId() == topic.getId()) { + topicSubscriberRepository.delete(subscriber); + } + } + } + + Set userRoles = userToUpdate.getRoles(); + for (Role curRole : userRoles) { + for (Topic curTopic : newTopics) { + if (curRole.getName().compareToIgnoreCase(curTopic.getMemberType()) == 0) { + TopicSubscriber newSubscription = new TopicSubscriber(curTopic, userToUpdate, new Date()); + topicSubscriberRepository.save(newSubscription); + } + } + } } if (changes.containsKey("staffId")) { @@ -230,9 +274,34 @@ public CommandProcessingResult updateUser(final Long userId, final JsonCommand c if (changes.containsKey("roles")) { final String[] roleIds = (String[]) changes.get("roles"); - final Set allRoles = assembleSetOfRoles(roleIds); - - userToUpdate.updateRoles(allRoles); + final Set oldRoles = userToUpdate.getRoles() ; + final Set tempOldRoles = new HashSet<>(oldRoles); + final Set updatedRoles = assembleSetOfRoles(roleIds); + final Set tempUpdatedRoles = new HashSet<>(updatedRoles); + + tempOldRoles.removeAll(updatedRoles); + List oldSubscriptions = topicSubscriberRepository.findBySubscriber(userToUpdate); + for (TopicSubscriber subscriber : oldSubscriptions) { + Topic topic = subscriber.getTopic(); + for (Role role : tempOldRoles) { + if (role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) { + topicSubscriberRepository.delete(subscriber); + } + } + } + + tempUpdatedRoles.removeAll(oldRoles); + List newTopics = topicRepository.findByEntityId(userToUpdate.getOffice().getId()); + for (Topic topic : newTopics) { + for (Role role : tempUpdatedRoles) { + if (role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) { + TopicSubscriber topicSubscriber = new TopicSubscriber(topic, userToUpdate, new Date()); + topicSubscriberRepository.save(topicSubscriber); + } + } + } + + userToUpdate.updateRoles(updatedRoles); } if (!changes.isEmpty()) { @@ -324,6 +393,10 @@ public CommandProcessingResult deleteUser(final Long userId) { if (user == null || user.isDeleted()) { throw new UserNotFoundException(userId); } user.delete(); + List subscriptions = topicSubscriberRepository.findBySubscriber(user); + for (TopicSubscriber subscription : subscriptions) { + topicSubscriberRepository.delete(subscription); + } this.appUserRepository.save(user); return new CommandProcessingResultBuilder().withEntityId(userId).withOfficeId(user.getOffice().getId()).build(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java index 7b473328473..83f30af5bae 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.persistence.PersistenceException; @@ -30,6 +31,10 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.notification.domain.Topic; +import org.apache.fineract.notification.domain.TopicRepository; +import org.apache.fineract.organisation.office.domain.Office; +import org.apache.fineract.organisation.office.domain.OfficeRepository; import org.apache.fineract.useradministration.command.PermissionsCommand; import org.apache.fineract.useradministration.domain.Permission; import org.apache.fineract.useradministration.domain.PermissionRepository; @@ -55,18 +60,23 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf private final PlatformSecurityContext context; private final RoleRepository roleRepository; private final PermissionRepository permissionRepository; + private final TopicRepository topicRepository; + private final OfficeRepository officeRepository; private final RoleDataValidator roleCommandFromApiJsonDeserializer; private final PermissionsCommandFromApiJsonDeserializer permissionsFromApiJsonDeserializer; @Autowired public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository, final PermissionRepository permissionRepository, final RoleDataValidator roleCommandFromApiJsonDeserializer, - final PermissionsCommandFromApiJsonDeserializer fromApiJsonDeserializer) { + final PermissionsCommandFromApiJsonDeserializer fromApiJsonDeserializer, TopicRepository topicRepository, + final OfficeRepository officeRepository) { this.context = context; this.roleRepository = roleRepository; this.permissionRepository = permissionRepository; this.roleCommandFromApiJsonDeserializer = roleCommandFromApiJsonDeserializer; this.permissionsFromApiJsonDeserializer = fromApiJsonDeserializer; + this.topicRepository = topicRepository; + this.officeRepository = officeRepository; } @Transactional @@ -78,10 +88,22 @@ public CommandProcessingResult createRole(final JsonCommand command) { this.roleCommandFromApiJsonDeserializer.validateForCreate(command.json()); - final Role entity = Role.fromJson(command); - this.roleRepository.save(entity); + final Role role = Role.fromJson(command); + List offices = officeRepository.findAll(); + for (Office office : offices) { + String entityType = ""; + if (office.getParent() == null) { + entityType = "OFFICE"; + } else { + entityType = "BRANCH"; + } + String title = role.getName() + " of " + office.getName(); + Topic newTopic = new Topic(title, true, office.getId(), entityType, role.getName().toUpperCase()); + topicRepository.save(newTopic); + } + this.roleRepository.save(role); - return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(entity.getId()).build(); + return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(role.getId()).build(); } catch (final DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve); return new CommandProcessingResultBuilder() // @@ -129,8 +151,22 @@ public CommandProcessingResult updateRole(final Long roleId, final JsonCommand c final Role role = this.roleRepository.findOne(roleId); if (role == null) { throw new RoleNotFoundException(roleId); } - + + String oldMemberType = role.getName().toUpperCase(); final Map changes = role.update(command); + + if (changes.containsKey("name")) { + String newMemberType = (String) changes.get("name"); + List entityTopics = topicRepository.findByMemberType(oldMemberType); + for (Topic topic : entityTopics) { + Office office = officeRepository.findOne(topic.getEntityId()); + String title = role.getName() + " of " + office.getName(); + topic.setTitle(title); + topic.setMemberType(newMemberType.toUpperCase()); + topicRepository.save(topic); + } + } + if (!changes.isEmpty()) { this.roleRepository.saveAndFlush(role); } @@ -222,6 +258,10 @@ public CommandProcessingResult deleteRole(Long roleId) { final Integer count = this.roleRepository.getCountOfRolesAssociatedWithUsers(roleId); if (count > 0) { throw new RoleAssociatedException("error.msg.role.associated.with.users.deleted", roleId); } + List topics = topicRepository.findByMemberType(role.getName().toUpperCase()); + for (Topic topic : topics) { + topicRepository.delete(topic); + } this.roleRepository.delete(role); return new CommandProcessingResultBuilder().withEntityId(roleId).build(); } catch (final DataIntegrityViolationException e) { diff --git a/fineract-provider/src/main/resources/META-INF/spring/appContext.xml b/fineract-provider/src/main/resources/META-INF/spring/appContext.xml index e348d8aeff1..90ee5a5fa85 100644 --- a/fineract-provider/src/main/resources/META-INF/spring/appContext.xml +++ b/fineract-provider/src/main/resources/META-INF/spring/appContext.xml @@ -98,6 +98,5 @@ - diff --git a/fineract-provider/src/main/resources/META-INF/spring/notificationContext.xml b/fineract-provider/src/main/resources/META-INF/spring/notificationContext.xml index 5ca57e740a7..2883481c5d9 100644 --- a/fineract-provider/src/main/resources/META-INF/spring/notificationContext.xml +++ b/fineract-provider/src/main/resources/META-INF/spring/notificationContext.xml @@ -41,4 +41,5 @@ + \ No newline at end of file diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V336__topic_module_table.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V336__topic_module_table.sql new file mode 100644 index 00000000000..92562ef0543 --- /dev/null +++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V336__topic_module_table.sql @@ -0,0 +1,45 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you 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. +-- + +CREATE TABLE IF NOT EXISTS `topic` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `title` VARCHAR(100) NOT NULL, + `enabled` TINYINT(1) NULL, + `entity_id` BIGINT(20) NOT NULL, + `entity_type` TEXT NOT NULL, + `member_type` TEXT NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `title_UNIQUE` (`title` ASC) +)ENGINE = InnoDB; + +CREATE TABLE IF NOT EXISTS `topic_subscriber` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `topic_id` BIGINT(20) NOT NULL, + `user_id` BIGINT(20) NOT NULL, + `subscription_date` DATE NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_topic_has_m_appuser_topic` FOREIGN KEY (`topic_id`) REFERENCES `topic` (`id`), + CONSTRAINT `fk_topic_has_m_appuser_m_appuser1` FOREIGN KEY (`user_id`) REFERENCES `m_appuser` (`id`) +) ENGINE = InnoDB; + +INSERT INTO topic (enabled, entity_type, entity_id, member_type, title) SELECT true, 'OFFICE', o.id as entity_id, UPPER(r.name) as member_type, CONCAT(r.name, ' of ', o.name) as title FROM m_office o, m_role r WHERE o.parent_id IS NULL AND CONCAT(r.name, ' of ', o.name) NOT IN (SELECT title FROM topic); + +INSERT INTO topic (enabled, entity_type, entity_id, member_type, title) SELECT true, 'BRANCH', o.id as entity_id, UPPER(r.name) as member_type, CONCAT(r.name, ' of ', o.name) as title FROM m_office o, m_role r WHERE o.parent_id IS NOT NULL AND CONCAT(r.name, ' of ', o.name) NOT IN (SELECT title FROM topic); + +INSERT INTO topic_subscriber( user_id, topic_id, subscription_date ) SELECT u.id AS user_id, t.id AS topic_id, NOW() FROM topic t, m_appuser u, m_appuser_role ur, m_role r WHERE u.office_id = t.entity_id AND u.id = ur.appuser_id AND ur.role_id = r.id AND r.name = t.member_type AND NOT EXISTS (SELECT user_id, topic_id FROM topic_subscriber WHERE user_id = u.id AND topic_id = t.id); diff --git a/fineract-provider/src/test/java/org/apache/fineract/notification/Listener.java b/fineract-provider/src/test/java/org/apache/fineract/notification/Listener.java index 866eaddb913..e4276244bdb 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/notification/Listener.java +++ b/fineract-provider/src/test/java/org/apache/fineract/notification/Listener.java @@ -1,5 +1,3 @@ -package org.apache.fineract.notification; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.fineract.notification; import org.springframework.jms.listener.SessionAwareMessageListener; diff --git a/fineract-provider/src/test/java/org/apache/fineract/notification/ListenerTest.java b/fineract-provider/src/test/java/org/apache/fineract/notification/ListenerTest.java index 7f943792089..90ea998bd92 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/notification/ListenerTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/notification/ListenerTest.java @@ -1,5 +1,3 @@ -package org.apache.fineract.notification; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.fineract.notification; import org.junit.Before; import org.junit.Test; diff --git a/fineract-provider/src/test/java/org/apache/fineract/notification/SenderTest.java b/fineract-provider/src/test/java/org/apache/fineract/notification/SenderTest.java index 1a7e09182be..455b49069fd 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/notification/SenderTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/notification/SenderTest.java @@ -1,5 +1,3 @@ -package org.apache.fineract.notification; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.fineract.notification; import com.mockrunner.mock.jms.MockQueue; import org.apache.fineract.notification.data.NotificationData; @@ -61,6 +60,7 @@ public void notificationCreation() { actorId, notificationContent, false, + false, null, null, null diff --git a/fineract-provider/src/test/java/org/apache/fineract/notification/StorageTest.java b/fineract-provider/src/test/java/org/apache/fineract/notification/StorageTest.java index 59ae708f115..ef554e0caa3 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/notification/StorageTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/notification/StorageTest.java @@ -1,5 +1,3 @@ -package org.apache.fineract.notification; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -19,9 +17,12 @@ * under the License. */ +package org.apache.fineract.notification; + import org.apache.fineract.notification.domain.Notification; import org.apache.fineract.notification.domain.NotificationMapper; import org.apache.fineract.notification.service.NotificationGeneratorReadRepositoryWrapper; + import org.apache.fineract.notification.service.NotificationGeneratorWritePlatformService; import org.apache.fineract.notification.service.NotificationMapperWritePlatformService; import org.apache.fineract.notification.service.NotificationWritePlatformServiceImpl; @@ -127,4 +128,5 @@ private String getCurrentDateTime() { SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return formatter.format(date); } + } diff --git a/fineract-provider/src/test/java/org/apache/fineract/notification/TopicTest.java b/fineract-provider/src/test/java/org/apache/fineract/notification/TopicTest.java new file mode 100644 index 00000000000..6c17a1a5eb3 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/notification/TopicTest.java @@ -0,0 +1,109 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.fineract.notification; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.refEq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Date; + +import org.apache.fineract.notification.domain.Topic; +import org.apache.fineract.notification.domain.TopicRepository; +import org.apache.fineract.notification.domain.TopicSubscriber; +import org.apache.fineract.notification.service.TopicSubscriberWritePlatformService; +import org.apache.fineract.notification.service.TopicWritePlatformService; +import org.apache.fineract.organisation.office.domain.Office; +import org.apache.fineract.organisation.office.domain.OfficeRepository; +import org.apache.fineract.useradministration.domain.AppUser; +import org.apache.fineract.useradministration.domain.AppUserRepository; +import org.apache.fineract.useradministration.domain.Role; +import org.apache.fineract.useradministration.domain.RoleRepository; +import org.junit.Test; +import org.mockito.Mock; + +public class TopicTest { + + @Mock + private OfficeRepository officeRepository; + + @Mock + private RoleRepository roleRepository; + + @Mock + private TopicWritePlatformService topicWritePltfService; + + @Mock + private TopicRepository topicRepository; + + @Mock + private TopicSubscriberWritePlatformService topicSubscriberWritePltfService; + + @Mock + private AppUserRepository appUserRepository; + + @Test + public void testTopicStorage() { + Office office = officeRepository.getOne(1L); + Role role = new Role("New Member_Type", "Testing topic creation"); + + String title = role.getName() + " of " + office.getName(); + Long entityId = office.getId(); + String entityType = ""; + if (office.getParent() == null) { + entityType = "OFFICE"; + } else { + entityType = "BRANCH"; + } + Topic topic = new Topic(title, true, entityId, entityType, role.getName().toUpperCase()); + + when(this.officeRepository.getOne(1L)).thenReturn(office); + when(this.roleRepository.save(role)).thenReturn(role); + when(this.topicWritePltfService.create(refEq(topic))).thenReturn(1L); + + this.roleRepository.save(role); + Long topicId = this.topicWritePltfService.create(topic); + + verify(this.roleRepository, times(1)).save(role); + verify(this.topicWritePltfService, times(1)).create(refEq(topic)); + assertEquals(topicId, new Long(1)); + + } + + @Test + public void testTopicSubscriberStorage() { + AppUser user = appUserRepository.findOne(1L); + Topic topic = topicRepository.findOne(1L); + + TopicSubscriber topicSubscriber = new TopicSubscriber(topic, user, new Date()); + + when(this.appUserRepository.getOne(1L)).thenReturn(user); + when(this.topicRepository.getOne(1L)).thenReturn(topic); + when(this.topicSubscriberWritePltfService.create(refEq(topicSubscriber))).thenReturn(1L); + + Long subscriberId = this.topicSubscriberWritePltfService.create(topicSubscriber); + + verify(this.topicSubscriberWritePltfService, times(1)).create(refEq(topicSubscriber)); + assertEquals(subscriberId, new Long(1)); + + } + +}