Deleting the topics module since its incomplete and additional cleanups

This commit is contained in:
Arnold Galovics
2022-05-19 18:39:44 +02:00
committed by Arnold Gálovics
parent 073b1b04b6
commit 6849f45bb8
50 changed files with 475 additions and 1561 deletions
@@ -166,6 +166,7 @@ dependencyManagement {
}
dependency 'org.owasp.esapi:esapi:2.4.0.0'
dependency 'org.awaitility:awaitility:4.2.0'
dependencySet(group: 'org.apache.poi', version: '5.2.2') {
entry 'poi'
@@ -18,6 +18,12 @@
*/
package org.apache.fineract.notification.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -28,6 +34,7 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
@@ -36,15 +43,12 @@ import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.notification.data.NotificationData;
import org.apache.fineract.notification.service.NotificationReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/notifications")
@Component
@Scope("singleton")
@Tag(name = "Notification", description = "")
@RequiredArgsConstructor
public class NotificationApiResource {
private final PlatformSecurityContext context;
@@ -52,21 +56,18 @@ public class NotificationApiResource {
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final ToApiJsonSerializer<NotificationData> toApiJsonSerializer;
@Autowired
public NotificationApiResource(PlatformSecurityContext context, NotificationReadPlatformService notificationReadPlatformService,
ApiRequestParameterHelper apiRequestParameterHelper, ToApiJsonSerializer<NotificationData> toApiJsonSerializer) {
this.context = context;
this.notificationReadPlatformService = notificationReadPlatformService;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.toApiJsonSerializer = toApiJsonSerializer;
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getAllNotifications(@Context final UriInfo uriInfo, @QueryParam("orderBy") final String orderBy,
@QueryParam("limit") final Integer limit, @QueryParam("offset") final Integer offset,
@QueryParam("sortOrder") final String sortOrder, @QueryParam("isRead") final boolean isRead) {
@Operation
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = NotificationApiResourceSwagger.GetNotificationsResponse.class))) })
public String getAllNotifications(@Context final UriInfo uriInfo,
@QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy,
@QueryParam("limit") @Parameter(description = "limit") final Integer limit,
@QueryParam("offset") @Parameter(description = "offset") final Integer offset,
@QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder,
@QueryParam("isRead") @Parameter(description = "isRead") final boolean isRead) {
this.context.authenticatedUser();
final Page<NotificationData> notificationData;
@@ -0,0 +1,68 @@
/**
* 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.api;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
final class NotificationApiResourceSwagger {
private NotificationApiResourceSwagger() {}
@Schema(description = "GetNotificationsResponse")
public static final class GetNotificationsResponse {
private GetNotificationsResponse() {}
static final class GetNotification {
private GetNotification() {}
@Schema(example = "1")
public Long id;
@Schema(example = "a")
public String objectType;
@Schema(example = "1")
public Long objectId;
@Schema(example = "a")
public String action;
@Schema(example = "1")
public Long actorId;
@Schema(example = "a")
public String content;
@Schema(example = "true")
public boolean isRead;
@Schema(example = "true")
public boolean isSystemGenerated;
@Schema(example = "a")
public String tenantIdentifier;
@Schema(example = "a")
public String createdAt;
@Schema(example = "1")
public Long officeId;
@Schema(example = "[]")
public List<Long> userIds;
}
@Schema(example = "10")
public int totalFilteredRecords;
public List<GetNotification> pageItems;
}
}
@@ -19,8 +19,10 @@
package org.apache.fineract.notification.data;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import lombok.Data;
@Data
public class NotificationData implements Serializable {
private Long id;
@@ -34,12 +36,12 @@ public class NotificationData implements Serializable {
private String tenantIdentifier;
private String createdAt;
private Long officeId;
private List<Long> userIds;
private Set<Long> userIds;
public NotificationData() {}
public NotificationData(String objectType, Long objectId, String action, Long actorId, String content, boolean isSystemGenerated,
boolean isRead, String tenantIdentifier, Long officeId, List<Long> userIds) {
boolean isRead, String tenantIdentifier, Long officeId, Set<Long> userIds) {
this.objectType = objectType;
this.objectId = objectId;
this.action = action;
@@ -51,100 +53,4 @@ public class NotificationData implements Serializable {
this.officeId = officeId;
this.userIds = userIds;
}
public Long getOfficeId() {
return officeId;
}
public void setOfficeId(Long officeId) {
this.officeId = officeId;
}
public List<Long> getUserIds() {
return userIds;
}
public void setUserId(List<Long> userIds) {
this.userIds = userIds;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public String getObjectType() {
return objectType;
}
public void setObjectType(String objectType) {
this.objectType = objectType;
}
public Long getObjectIdentfier() {
return objectId;
}
public void entifier(Long objectIdentifier) {
this.objectId = objectIdentifier;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public Long getActor() {
return actorId;
}
public void setActor(Long actorId) {
this.actorId = actorId;
}
public String getContent() {
return content;
}
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;
}
public void setSystemGenerated(boolean systemGenerated) {
isSystemGenerated = systemGenerated;
}
public String getTenantIdentifier() {
return tenantIdentifier;
}
public void setTenantIdentifier(String tenantIdentifier) {
this.tenantIdentifier = tenantIdentifier;
}
}
@@ -1,74 +0,0 @@
/**
* 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;
}
}
@@ -1,61 +0,0 @@
/**
* 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.time.LocalDate;
import org.apache.fineract.infrastructure.core.service.DateUtils;
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 = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
}
public Long getId() {
return this.id;
}
public Long getTopicId() {
return this.topicId;
}
public Long getUserId() {
return this.userId;
}
public LocalDate getSubscriptionDate() {
return this.subscriptionDate;
}
}
@@ -18,9 +18,12 @@
*/
package org.apache.fineract.notification.domain;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity
@@ -46,12 +49,13 @@ public class Notification extends AbstractPersistableCustom {
private String notificationContent;
@Column(name = "created_at")
private String createdAt;
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
public Notification() {}
public Notification(String objectType, Long objectIdentifier, String action, Long actorId, boolean isSystemGenerated,
String notificationContent, String createdAt) {
String notificationContent, Date createdAt) {
this.objectType = objectType;
this.objectIdentifier = objectIdentifier;
this.action = action;
@@ -18,11 +18,14 @@
*/
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 javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.useradministration.domain.AppUser;
@@ -42,11 +45,12 @@ public class NotificationMapper extends AbstractPersistableCustom {
private boolean isRead;
@Column(name = "created_at")
private String createdAt;
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
public NotificationMapper() {}
public NotificationMapper(Notification notification, AppUser userId, boolean isRead, String createdAt) {
public NotificationMapper(Notification notification, AppUser userId, boolean isRead, Date createdAt) {
this.notification = notification;
this.userId = userId;
this.isRead = isRead;
@@ -1,121 +0,0 @@
/**
* 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;
}
}
@@ -1,30 +0,0 @@
/**
* 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<Topic, Long>, JpaSpecificationExecutor<Topic> {
List<Topic> findByEntityId(Long entityId);
List<Topic> findByMemberType(String memberType);
}
@@ -1,77 +0,0 @@
/**
* 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;
}
}
@@ -1,29 +0,0 @@
/**
* 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<TopicSubscriber, Long>, JpaSpecificationExecutor<TopicSubscriber> {
List<TopicSubscriber> findBySubscriber(AppUser subscriber);
}
@@ -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.
*/
package org.apache.fineract.notification.eventandlistener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.notification.data.NotificationData;
import org.springframework.context.annotation.Profile;
import org.springframework.jms.listener.SessionAwareMessageListener;
import org.springframework.stereotype.Component;
@Component
@Profile("activeMqEnabled")
@RequiredArgsConstructor
public class ActiveMQNotificationEventListener implements SessionAwareMessageListener {
private final NotificationEventListener notificationEventListener;
@Override
public void onMessage(Message message, Session session) throws JMSException {
if (message instanceof ObjectMessage) {
NotificationData notificationData = (NotificationData) ((ObjectMessage) message).getObject();
notificationEventListener.receive(notificationData);
}
}
}
@@ -18,33 +18,24 @@
*/
package org.apache.fineract.notification.eventandlistener;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.Queue;
import lombok.RequiredArgsConstructor;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.fineract.notification.data.NotificationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
@Service
public class NotificationEventService {
@Profile("activeMqEnabled")
@RequiredArgsConstructor
public class ActiveMQNotificationEventPublisher implements NotificationEventPublisher {
private final JmsTemplate jmsTemplate;
@Autowired
public NotificationEventService(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);
}
});
@Override
public void broadcastNotification(NotificationData notificationData) {
Queue queue = new ActiveMQQueue("NotificationQueue");
this.jmsTemplate.send(queue, session -> session.createObjectMessage(notificationData));
}
}
@@ -21,10 +21,8 @@ package org.apache.fineract.notification.eventandlistener;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
@@ -32,57 +30,42 @@ import org.apache.fineract.notification.data.NotificationData;
import org.apache.fineract.notification.service.NotificationWritePlatformService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.AppUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.listener.SessionAwareMessageListener;
import org.springframework.stereotype.Service;
@Service
public class NotificationEventListener implements SessionAwareMessageListener {
@RequiredArgsConstructor
public class NotificationEventListener {
private final BasicAuthTenantDetailsService basicAuthTenantDetailsService;
private final NotificationWritePlatformService notificationWritePlatformService;
private final AppUserRepository appUserRepository;
@Autowired
public NotificationEventListener(BasicAuthTenantDetailsService basicAuthTenantDetailsService,
NotificationWritePlatformService notificationWritePlatformService, AppUserRepository appUserRepository) {
this.basicAuthTenantDetailsService = basicAuthTenantDetailsService;
this.notificationWritePlatformService = notificationWritePlatformService;
this.appUserRepository = appUserRepository;
}
public void receive(NotificationData notificationData) {
final FineractPlatformTenant tenant = this.basicAuthTenantDetailsService.loadTenantById(notificationData.getTenantIdentifier(),
false);
ThreadLocalContextUtil.setTenant(tenant);
@Override
public void onMessage(Message message, Session session) throws JMSException {
if (message instanceof ObjectMessage) {
NotificationData notificationData = (NotificationData) ((ObjectMessage) message).getObject();
Long appUserId = notificationData.getActorId();
final FineractPlatformTenant tenant = this.basicAuthTenantDetailsService.loadTenantById(notificationData.getTenantIdentifier(),
false);
ThreadLocalContextUtil.setTenant(tenant);
Set<Long> userIds = notificationData.getUserIds();
Long appUserId = notificationData.getActor();
List<Long> userIds = notificationData.getUserIds();
if (notificationData.getOfficeId() != null) {
List<Long> tempUserIds = new ArrayList<>(userIds);
for (Long userId : tempUserIds) {
AppUser appUser = appUserRepository.findById(userId).get();
if (!Objects.equals(appUser.getOffice().getId(), notificationData.getOfficeId())) {
userIds.remove(userId);
}
if (notificationData.getOfficeId() != null) {
List<Long> tempUserIds = new ArrayList<>(userIds);
for (Long userId : tempUserIds) {
AppUser appUser = appUserRepository.findById(userId).get();
if (!Objects.equals(appUser.getOffice().getId(), notificationData.getOfficeId())) {
userIds.remove(userId);
}
}
if (userIds.contains(appUserId)) {
userIds.remove(appUserId);
}
notificationWritePlatformService.notify(userIds, notificationData.getObjectType(), notificationData.getObjectIdentfier(),
notificationData.getAction(), notificationData.getActor(), notificationData.getContent(),
notificationData.isSystemGenerated());
}
// Don't notify the same user who triggered the event
if (userIds.contains(appUserId)) {
userIds.remove(appUserId);
}
notificationWritePlatformService.notify(userIds, notificationData.getObjectType(), notificationData.getObjectId(),
notificationData.getAction(), notificationData.getActorId(), notificationData.getContent(),
notificationData.isSystemGenerated());
}
}
@@ -16,12 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.notification.service;
package org.apache.fineract.notification.eventandlistener;
import org.apache.fineract.notification.domain.TopicSubscriber;
import org.apache.fineract.notification.data.NotificationData;
public interface TopicSubscriberWritePlatformService {
Long create(TopicSubscriber topicSubscriber);
public interface NotificationEventPublisher {
void broadcastNotification(NotificationData notificationData);
}
@@ -1,84 +0,0 @@
/**
* 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 java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
import org.apache.fineract.notification.data.NotificationData;
import org.apache.fineract.notification.service.NotificationWritePlatformService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.AppUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class SpringEventListener implements ApplicationListener<SpringEvent> {
private final BasicAuthTenantDetailsService basicAuthTenantDetailsService;
private final NotificationWritePlatformService notificationWritePlatformService;
private final AppUserRepository appUserRepository;
@Autowired
public SpringEventListener(BasicAuthTenantDetailsService basicAuthTenantDetailsService,
NotificationWritePlatformService notificationWritePlatformService, AppUserRepository appUserRepository) {
this.basicAuthTenantDetailsService = basicAuthTenantDetailsService;
this.notificationWritePlatformService = notificationWritePlatformService;
this.appUserRepository = appUserRepository;
}
@Override
public void onApplicationEvent(SpringEvent event) {
NotificationData notificationData = event.getNotificationData();
final FineractPlatformTenant tenant = this.basicAuthTenantDetailsService.loadTenantById(notificationData.getTenantIdentifier(),
false);
ThreadLocalContextUtil.setTenant(tenant);
Long appUserId = notificationData.getActor();
List<Long> userIds = notificationData.getUserIds();
if (notificationData.getOfficeId() != null) {
List<Long> tempUserIds = new ArrayList<>(userIds);
for (Long userId : tempUserIds) {
AppUser appUser = appUserRepository.findById(userId).get();
if (!Objects.equals(appUser.getOffice().getId(), notificationData.getOfficeId())) {
userIds.remove(userId);
}
}
}
if (userIds.contains(appUserId)) {
userIds.remove(appUserId);
}
notificationWritePlatformService.notify(userIds, notificationData.getObjectType(), notificationData.getObjectIdentfier(),
notificationData.getAction(), notificationData.getActor(), notificationData.getContent(),
notificationData.isSystemGenerated());
}
}
@@ -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.eventandlistener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.notification.data.NotificationData;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
@Profile("!activeMqEnabled")
@RequiredArgsConstructor
@Slf4j
public class SpringNotificationEventListener implements ApplicationListener<SpringEvent> {
private final NotificationEventListener notificationEventListener;
@Override
public void onApplicationEvent(SpringEvent event) {
log.debug("Processing Spring notification event {}", event);
NotificationData notificationData = event.getNotificationData();
notificationEventListener.receive(notificationData);
}
}
@@ -18,18 +18,24 @@
*/
package org.apache.fineract.notification.eventandlistener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.notification.data.NotificationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@Service
public class SpringEventPublisher {
@Profile("!activeMqEnabled")
@RequiredArgsConstructor
@Slf4j
public class SpringNotificationEventPublisher implements NotificationEventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
private final ApplicationEventPublisher applicationEventPublisher;
@Override
public void broadcastNotification(final NotificationData notificationData) {
log.debug("Sending Spring notification event: {}", notificationData);
SpringEvent event = new SpringEvent(this, notificationData);
applicationEventPublisher.publishEvent(event);
}
@@ -1,37 +0,0 @@
/**
* 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;
import org.springframework.dao.EmptyResultDataAccessException;
/**
* 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);
}
public TopicNotFoundException(Long id, EmptyResultDataAccessException e) {
super("error.msg.topic.id.invalid", "Topic with identifier " + id + " does not exist", id, e);
}
}
@@ -18,23 +18,19 @@
*/
package org.apache.fineract.notification.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import static java.util.stream.Collectors.toSet;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.jms.Queue;
import lombok.RequiredArgsConstructor;
import org.apache.activemq.command.ActiveMQQueue;
import lombok.extern.slf4j.Slf4j;
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.data.TopicSubscriberData;
import org.apache.fineract.notification.eventandlistener.NotificationEventService;
import org.apache.fineract.notification.eventandlistener.SpringEventPublisher;
import org.apache.fineract.organisation.office.domain.OfficeRepository;
import org.apache.fineract.notification.eventandlistener.NotificationEventPublisher;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants;
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BusinessEntity;
@@ -49,21 +45,19 @@ import org.apache.fineract.portfolio.savings.domain.RecurringDepositAccount;
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.Role;
import org.apache.fineract.useradministration.domain.RoleRepository;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.AppUserRepository;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
@Slf4j
public class NotificationDomainServiceImpl implements NotificationDomainService {
private final BusinessEventNotifierService businessEventNotifierService;
private final PlatformSecurityContext context;
private final RoleRepository roleRepository;
private final OfficeRepository officeRepository;
private final TopicSubscriberReadPlatformService topicSubscriberReadPlatformService;
private final NotificationEventService notificationEvent;
private final SpringEventPublisher springEventPublisher;
private final NotificationEventPublisher notificationEventPublisher;
private final AppUserRepository appUserRepository;
@PostConstruct
public void addListeners() {
@@ -387,39 +381,20 @@ public class NotificationDomainServiceImpl implements NotificationDomainService
String eventType, Long appUserId, Long officeId) {
String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
Queue queue = new ActiveMQQueue("NotificationQueue");
List<Long> userIds = retrieveSubscribers(officeId, permission);
Set<Long> userIds = getNotifiableUserIds(officeId, permission);
NotificationData notificationData = new NotificationData(objectType, objectIdentifier, eventType, appUserId, notificationContent,
false, false, tenantIdentifier, officeId, userIds);
try {
this.notificationEvent.broadcastNotification(queue, notificationData);
notificationEventPublisher.broadcastNotification(notificationData);
} catch (Exception e) {
this.springEventPublisher.broadcastNotification(notificationData);
// We want to avoid rethrowing the exception to stop the business transaction from rolling back
log.error("Error while broadcasting notification event", e);
}
}
private List<Long> retrieveSubscribers(Long officeId, String permission) {
Set<TopicSubscriberData> topicSubscribers = new HashSet<>();
List<Long> subscriberIds = new ArrayList<>();
Long entityId = officeId;
String entityType = "";
if (officeRepository.findById(entityId).get().getParent() == null) {
entityType = "OFFICE";
} else {
entityType = "BRANCH";
}
List<Role> allRoles = roleRepository.findAll();
for (Role curRole : allRoles) {
if (curRole.hasPermissionTo(permission) || curRole.hasPermissionTo("ALL_FUNCTIONS")) {
String memberType = curRole.getName();
topicSubscribers.addAll(topicSubscriberReadPlatformService.getSubscribers(entityId, entityType, memberType));
}
}
for (TopicSubscriberData topicSubscriber : topicSubscribers) {
subscriberIds.add(topicSubscriber.getUserId());
}
return subscriberIds;
private Set<Long> getNotifiableUserIds(Long officeId, String permission) {
Collection<AppUser> users = appUserRepository.findByOfficeId(officeId);
Collection<AppUser> usersWithPermission = users.stream().filter(aU -> aU.hasAnyPermission(permission, "ALL_FUNCTIONS")).toList();
return usersWithPermission.stream().map(AppUser::getId).collect(toSet());
}
}
@@ -18,21 +18,17 @@
*/
package org.apache.fineract.notification.service;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.notification.domain.Notification;
import org.apache.fineract.notification.domain.NotificationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class NotificationGeneratorWritePlatformServiceImpl implements NotificationGeneratorWritePlatformService {
private final NotificationRepository notificationRepository;
@Autowired
public NotificationGeneratorWritePlatformServiceImpl(NotificationRepository notificationRepository) {
this.notificationRepository = notificationRepository;
}
@Override
public Long create(Notification notification) {
this.notificationRepository.saveAndFlush(notification);
@@ -22,6 +22,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
@@ -32,32 +33,24 @@ import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.notification.cache.CacheNotificationResponseHeader;
import org.apache.fineract.notification.data.NotificationData;
import org.apache.fineract.notification.data.NotificationMapperData;
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
@RequiredArgsConstructor
public class NotificationReadPlatformServiceImpl implements NotificationReadPlatformService {
private HashMap<Long, HashMap<Long, CacheNotificationResponseHeader>> tenantNotificationResponseHeaderCache = new HashMap<>();
private final NotificationDataRow notificationDataRow = new NotificationDataRow();
private final NotificationMapperRow notificationMapperRow = new NotificationMapperRow();
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final ColumnValidator columnValidator;
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final NotificationDataRow notificationDataRow = new NotificationDataRow();
private final NotificationMapperRow notificationMapperRow = new NotificationMapperRow();
private HashMap<Long, HashMap<Long, CacheNotificationResponseHeader>> tenantNotificationResponseHeaderCache = new HashMap<>();
@Autowired
public NotificationReadPlatformServiceImpl(final JdbcTemplate jdbcTemplate, final PlatformSecurityContext context,
final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = jdbcTemplate;
this.context = context;
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
public boolean hasUnreadNotifications(Long appUserId) {
@@ -204,10 +197,10 @@ public class NotificationReadPlatformServiceImpl implements NotificationReadPlat
notificationData.setObjectType(objectType);
final Long objectId = rs.getLong("objectId");
notificationData.entifier(objectId);
notificationData.setObjectId(objectId);
final Long actorId = rs.getLong("actor");
notificationData.setActor(actorId);
notificationData.setActorId(actorId);
final String action = rs.getString("action");
notificationData.setAction(action);
@@ -18,13 +18,13 @@
*/
package org.apache.fineract.notification.service;
import java.util.List;
import java.util.Collection;
public interface NotificationWritePlatformService {
Long notify(Long userId, String objectType, Long objectId, String action, Long actorId, String notificationContent,
boolean isSystemGenerated);
Long notify(List<Long> userIds, String objectType, Long objectId, String action, Long actorId, String notificationContent,
Long notify(Collection<Long> userIds, String objectType, Long objectId, String action, Long actorId, String notificationContent,
boolean isSystemGenerated);
}
@@ -18,39 +18,28 @@
*/
package org.apache.fineract.notification.service;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Collection;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.notification.domain.Notification;
import org.apache.fineract.notification.domain.NotificationMapper;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.AppUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
@RequiredArgsConstructor
public class NotificationWritePlatformServiceImpl implements NotificationWritePlatformService {
private final NotificationGeneratorWritePlatformService notificationGeneratorWritePlatformService;
private final NotificationGeneratorReadRepositoryWrapper notificationGeneratorReadRepositoryWrapper;
private final AppUserRepository appUserRepository;
private final NotificationMapperWritePlatformService notificationMapperWritePlatformService;
@Autowired
public NotificationWritePlatformServiceImpl(final NotificationGeneratorWritePlatformService notificationGeneratorWritePlatformService,
final NotificationGeneratorReadRepositoryWrapper notificationGeneratorReadRepositoryWrapper,
final AppUserRepository appUserRepository,
final NotificationMapperWritePlatformService notificationMapperWritePlatformService) {
this.notificationGeneratorWritePlatformService = notificationGeneratorWritePlatformService;
this.notificationGeneratorReadRepositoryWrapper = notificationGeneratorReadRepositoryWrapper;
this.appUserRepository = appUserRepository;
this.notificationMapperWritePlatformService = notificationMapperWritePlatformService;
}
@Override
public Long notify(Long userId, String objectType, Long objectIdentifier, String action, Long actorId, String notificationContent,
boolean isSystemGenerated) {
@@ -64,7 +53,8 @@ public class NotificationWritePlatformServiceImpl implements NotificationWritePl
private Long insertIntoNotificationMapper(Long userId, Long generatedNotificationId) {
AppUser appUser = this.appUserRepository.findById(userId).orElse(null);
NotificationMapper notificationMapper = new NotificationMapper(
this.notificationGeneratorReadRepositoryWrapper.findById(generatedNotificationId), appUser, false, getCurrentDateTime());
this.notificationGeneratorReadRepositoryWrapper.findById(generatedNotificationId), appUser, false,
DateUtils.getDateOfTenant());
this.notificationMapperWritePlatformService.create(notificationMapper);
return notificationMapper.getId();
@@ -74,13 +64,13 @@ public class NotificationWritePlatformServiceImpl implements NotificationWritePl
String notificationContent, boolean isSystemGenerated) {
Notification notification = new Notification(objectType, objectIdentifier, action, actorId, isSystemGenerated, notificationContent,
getCurrentDateTime());
DateUtils.getDateOfTenant());
return this.notificationGeneratorWritePlatformService.create(notification);
}
@Override
public Long notify(List<Long> userIds, String objectType, Long objectId, String action, Long actorId, String notificationContent,
public Long notify(Collection<Long> userIds, String objectType, Long objectId, String action, Long actorId, String notificationContent,
boolean isSystemGenerated) {
Long generatedNotificationId = insertIntoNotificationGenerator(objectType, objectId, action, actorId, notificationContent,
@@ -90,22 +80,16 @@ public class NotificationWritePlatformServiceImpl implements NotificationWritePl
return generatedNotificationId;
}
private List<Long> insertIntoNotificationMapper(List<Long> userIds, Long generatedNotificationId) {
private List<Long> insertIntoNotificationMapper(Collection<Long> userIds, Long generatedNotificationId) {
List<Long> mappedIds = new ArrayList<>();
for (Long userId : userIds) {
AppUser appUser = this.appUserRepository.findById(userId).get();
NotificationMapper notificationMapper = new NotificationMapper(
this.notificationGeneratorReadRepositoryWrapper.findById(generatedNotificationId), appUser, false,
getCurrentDateTime());
DateUtils.getDateOfTenant());
this.notificationMapperWritePlatformService.create(notificationMapper);
mappedIds.add(notificationMapper.getId());
}
return mappedIds;
}
private String getCurrentDateTime() {
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return formatter.format(date);
}
}
@@ -1,44 +0,0 @@
/**
* 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.Map;
import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.Role;
public interface TopicDomainService {
void createTopic(Office newOffice);
void createTopic(Role newRole);
void updateTopic(Office updatedOffice, Map<String, Object> changes);
void updateTopic(String previousRolename, Role updatedRole, Map<String, Object> changes);
void deleteTopic(Role role);
void subscribeUserToTopic(AppUser newUser);
void updateUserSubscription(AppUser userToUpdate, Map<String, Object> changes);
void unsubcribeUserFromTopic(AppUser user);
}
@@ -1,248 +0,0 @@
/**
* 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.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.OfficeRepository;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.Role;
import org.apache.fineract.useradministration.domain.RoleRepository;
import org.apache.fineract.useradministration.exception.RoleNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
@Service
@Transactional
public class TopicDomainServiceImpl implements TopicDomainService {
private final RoleRepository roleRepository;
private final TopicRepository topicRepository;
private final OfficeRepository officeRepository;
private final TopicSubscriberRepository topicSubscriberRepository;
@Autowired
public TopicDomainServiceImpl(RoleRepository roleRepository, TopicRepository topicRepository, OfficeRepository officeRepository,
TopicSubscriberRepository topicSubscriberRepository) {
this.roleRepository = roleRepository;
this.topicRepository = topicRepository;
this.officeRepository = officeRepository;
this.topicSubscriberRepository = topicSubscriberRepository;
}
@Override
public void createTopic(Office newOffice) {
Long entityId = newOffice.getId();
String entityType = this.getEntityType(newOffice);
List<Role> allRoles = roleRepository.findAll();
for (Role role : allRoles) {
String memberType = role.getName().toUpperCase();
String title = role.getName() + " of " + newOffice.getName();
Topic newTopic = new Topic(title, true, entityId, entityType, memberType);
topicRepository.save(newTopic);
}
}
@Override
public void createTopic(Role newRole) {
List<Office> offices = officeRepository.findAll();
for (Office office : offices) {
String entityType = this.getEntityType(office);
String title = newRole.getName() + " of " + office.getName();
Topic newTopic = new Topic(title, true, office.getId(), entityType, newRole.getName().toUpperCase());
topicRepository.save(newTopic);
}
}
@Override
public void updateTopic(Office updatedOffice, Map<String, Object> changes) {
List<Topic> entityTopics = topicRepository.findByEntityId(updatedOffice.getId());
if (changes.containsKey("parentId")) {
String entityType = this.getEntityType(updatedOffice);
for (Topic topic : entityTopics) {
topic.setEntityType(entityType);
topicRepository.save(topic);
}
}
if (changes.containsKey("name")) {
for (Topic topic : entityTopics) {
Role role = roleRepository.getRoleByName(topic.getMemberType());
String title = role.getName() + " of " + updatedOffice.getName();
topic.setTitle(title);
topicRepository.save(topic);
}
}
}
@Override
public void updateTopic(String previousRolename, Role updatedRole, Map<String, Object> changes) {
if (changes.containsKey("name")) {
List<Topic> entityTopics = topicRepository.findByMemberType(previousRolename);
for (Topic topic : entityTopics) {
Office office = officeRepository.findById(topic.getEntityId()).get();
String title = updatedRole.getName() + " of " + office.getName();
topic.setTitle(title);
topic.setMemberType(updatedRole.getName().toUpperCase());
topicRepository.save(topic);
}
}
}
@Override
public void deleteTopic(Role role) {
List<Topic> topics = topicRepository.findByMemberType(role.getName().toUpperCase());
for (Topic topic : topics) {
topicRepository.delete(topic);
}
}
@Override
public void subscribeUserToTopic(AppUser newUser) {
List<Topic> possibleTopics = topicRepository.findByEntityId(newUser.getOffice().getId());
if (!possibleTopics.isEmpty()) {
Set<Role> userRoles = newUser.getRoles();
for (Role role : userRoles) {
for (Topic topic : possibleTopics) {
if (role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) {
TopicSubscriber topicSubscriber = new TopicSubscriber(topic, newUser, new Date());
topicSubscriberRepository.save(topicSubscriber);
}
}
}
}
}
@Override
public void updateUserSubscription(AppUser userToUpdate, Map<String, Object> changes) {
List<TopicSubscriber> oldSubscriptions = topicSubscriberRepository.findBySubscriber(userToUpdate);
if (changes.containsKey("officeId")) {
final Long oldOfficeId = userToUpdate.getOffice().getId();
final Long newOfficeId = (Long) changes.get("officeId");
List<Topic> oldTopics = topicRepository.findByEntityId(oldOfficeId);
List<Topic> newTopics = topicRepository.findByEntityId(newOfficeId);
for (TopicSubscriber subscriber : oldSubscriptions) {
for (Topic topic : oldTopics) {
if (subscriber.getTopic().getId().equals(topic.getId())) {
topicSubscriberRepository.delete(subscriber);
}
}
}
Set<Role> userRoles = userToUpdate.getRoles();
for (Role role : userRoles) {
for (Topic topic : newTopics) {
if (role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) {
TopicSubscriber newSubscription = new TopicSubscriber(topic, userToUpdate, new Date());
topicSubscriberRepository.save(newSubscription);
}
}
}
}
if (changes.containsKey("roles")) {
final Set<Role> oldRoles = userToUpdate.getRoles();
final Set<Role> tempOldRoles = new HashSet<>(oldRoles);
final String[] roleIds = (String[]) changes.get("roles");
final Set<Role> updatedRoles = assembleSetOfRoles(roleIds);
final Set<Role> tempUpdatedRoles = new HashSet<>(updatedRoles);
tempOldRoles.removeAll(updatedRoles);
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<Topic> 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);
}
}
}
}
}
@Override
public void unsubcribeUserFromTopic(AppUser user) {
List<TopicSubscriber> subscriptions = topicSubscriberRepository.findBySubscriber(user);
for (TopicSubscriber subscription : subscriptions) {
topicSubscriberRepository.delete(subscription);
}
}
private String getEntityType(Office office) {
if (office.getParent() == null) {
return "OFFICE";
} else {
return "BRANCH";
}
}
private Set<Role> assembleSetOfRoles(final String[] rolesArray) {
final Set<Role> allRoles = new HashSet<>();
if (!ObjectUtils.isEmpty(rolesArray)) {
for (final String roleId : rolesArray) {
final Long id = Long.valueOf(roleId);
final Role role = this.roleRepository.findById(id).orElseThrow(() -> new RoleNotFoundException(id));
allRoles.add(role);
}
}
return allRoles;
}
}
@@ -1,32 +0,0 @@
/**
* 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<TopicData> getAllTopics();
Collection<TopicData> getAllEnabledTopics();
TopicData findById(Long id);
}
@@ -1,96 +0,0 @@
/**
* 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.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 JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
private static final class TopicMapper implements RowMapper<TopicData> {
private final String schema;
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<TopicData> getAllTopics() {
final TopicMapper tm = new TopicMapper();
String sql = "select " + tm.schema();
return this.jdbcTemplate.query(sql, tm); // NOSONAR
}
@Override
public Collection<TopicData> 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 }); // NOSONAR
}
@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 }); // NOSONAR
} catch (final EmptyResultDataAccessException e) {
throw new TopicNotFoundException(topicId, e);
}
}
}
@@ -1,28 +0,0 @@
/**
* 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<TopicSubscriberData> getSubscribers(Long entityId, String entityType, String memberType);
}
@@ -1,77 +0,0 @@
/**
* 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.time.LocalDate;
import java.util.Collection;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.notification.data.TopicSubscriberData;
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 JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
private static final class TopicSubscriberMapper implements RowMapper<TopicSubscriberData> {
private final String schema;
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<TopicSubscriberData> getSubscribers(Long entityId, String entityType, String memberType) {
final TopicSubscriberMapper tsm = new TopicSubscriberMapper();
final String sql = "SELECT " + tsm.schema();
return this.jdbcTemplate.query(sql, tsm, new Object[] { entityId, entityType, memberType }); // NOSONAR
}
}
@@ -1,42 +0,0 @@
/**
* 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.saveAndFlush(topicSubscriber);
return topicSubscriber.getId();
}
}
@@ -1,27 +0,0 @@
/**
* 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);
}
@@ -1,42 +0,0 @@
/**
* 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.saveAndFlush(topic);
return topic.getId();
}
}
@@ -20,6 +20,8 @@ package org.apache.fineract.organisation.office.service;
import java.util.Map;
import javax.persistence.PersistenceException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
@@ -27,7 +29,6 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild
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.service.TopicDomainService;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
@@ -39,9 +40,6 @@ import org.apache.fineract.organisation.office.domain.OfficeTransactionRepositor
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.dao.DataIntegrityViolationException;
@@ -50,32 +48,16 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Slf4j
@RequiredArgsConstructor
public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWritePlatformService {
private static final Logger LOG = LoggerFactory.getLogger(OfficeWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final OfficeCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final OfficeTransactionCommandFromApiJsonDeserializer moneyTransferCommandFromApiJsonDeserializer;
private final OfficeRepositoryWrapper officeRepositoryWrapper;
private final OfficeTransactionRepository officeTransactionRepository;
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
private final TopicDomainService topicDomainService;
@Autowired
public OfficeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final OfficeCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final OfficeTransactionCommandFromApiJsonDeserializer moneyTransferCommandFromApiJsonDeserializer,
final OfficeRepositoryWrapper officeRepositoryWrapper, final OfficeTransactionRepository officeMonetaryTransferRepository,
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, final TopicDomainService topicDomainService) {
this.context = context;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.moneyTransferCommandFromApiJsonDeserializer = moneyTransferCommandFromApiJsonDeserializer;
this.officeRepositoryWrapper = officeRepositoryWrapper;
this.officeTransactionRepository = officeMonetaryTransferRepository;
this.applicationCurrencyRepository = applicationCurrencyRepository;
this.topicDomainService = topicDomainService;
}
@Transactional
@Override
@@ -104,8 +86,6 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
this.officeRepositoryWrapper.save(office);
this.topicDomainService.createTopic(office);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(office.getId()) //
@@ -150,8 +130,6 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
if (!changes.isEmpty()) {
this.officeRepositoryWrapper.saveAndFlush(office);
this.topicDomainService.updateTopic(office, changes);
}
return new CommandProcessingResultBuilder() //
@@ -239,7 +217,7 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
"name", name);
}
LOG.error("Error occured.", dve);
log.error("Error occured.", dve);
throw new PlatformDataIntegrityException("error.msg.office.unknown.data.integrity.issue",
"Unknown data integrity issue with resource.");
}
@@ -20,6 +20,7 @@ package org.apache.fineract.useradministration.api;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Collection;
import java.util.List;
import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.useradministration.data.RoleData;
@@ -111,6 +112,10 @@ final class UsersApiResourceSwagger {
@Schema(example = "newuser")
public String username;
@Schema(example = "password")
public String password;
@Schema(example = "repeatPassword")
public String repeatPassword;
@Schema(example = "Test")
public String firstname;
@Schema(example = "User")
@@ -122,7 +127,7 @@ final class UsersApiResourceSwagger {
@Schema(example = "1")
public Long staffId;
@Schema(example = "[2,3]")
public String roles;
public List<String> roles;
@Schema(example = "true")
public Boolean sendPasswordToEmail;
@Schema(example = "true")
@@ -19,6 +19,7 @@
package org.apache.fineract.useradministration.domain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
@@ -598,7 +599,11 @@ public class AppUser extends AbstractPersistableCustom implements PlatformUser {
return !hasAnyPermission(permissions);
}
private boolean hasAnyPermission(final List<String> permissions) {
public boolean hasAnyPermission(String... permissions) {
return hasAnyPermission(Arrays.asList(permissions));
}
public boolean hasAnyPermission(final List<String> permissions) {
boolean hasAtLeastOneOf = false;
for (final String permissionCode : permissions) {
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.useradministration.domain;
import java.util.Collection;
import org.apache.fineract.infrastructure.security.domain.PlatformUserRepository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -28,4 +29,6 @@ public interface AppUserRepository extends JpaRepository<AppUser, Long>, JpaSpec
@Query("Select appUser from AppUser appUser where appUser.username = :username")
AppUser findAppUserByName(@Param("username") String username);
Collection<AppUser> findByOfficeId(Long officeId);
}
@@ -26,6 +26,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.PersistenceException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -37,7 +39,6 @@ import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityEx
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.service.TopicDomainService;
import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
import org.apache.fineract.organisation.staff.domain.Staff;
@@ -55,9 +56,6 @@ import org.apache.fineract.useradministration.domain.UserDomainService;
import org.apache.fineract.useradministration.exception.PasswordPreviouslyUsedException;
import org.apache.fineract.useradministration.exception.RoleNotFoundException;
import org.apache.fineract.useradministration.exception.UserNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.dao.DataIntegrityViolationException;
@@ -70,10 +68,10 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
@Service
@Slf4j
@RequiredArgsConstructor
public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWritePlatformService {
private static final Logger LOG = LoggerFactory.getLogger(AppUserWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final UserDomainService userDomainService;
private final PlatformPasswordEncoder platformPasswordEncoder;
@@ -84,27 +82,6 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
private final AppUserPreviousPasswordRepository appUserPreviewPasswordRepository;
private final StaffRepositoryWrapper staffRepositoryWrapper;
private final ClientRepositoryWrapper clientRepositoryWrapper;
private final TopicDomainService topicDomainService;
@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 TopicDomainService topicDomainService) {
this.context = context;
this.appUserRepository = appUserRepository;
this.userDomainService = userDomainService;
this.officeRepositoryWrapper = officeRepositoryWrapper;
this.roleRepository = roleRepository;
this.platformPasswordEncoder = platformPasswordEncoder;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.appUserPreviewPasswordRepository = appUserPreviewPasswordRepository;
this.staffRepositoryWrapper = staffRepositoryWrapper;
this.clientRepositoryWrapper = clientRepositoryWrapper;
this.topicDomainService = topicDomainService;
}
@Override
@Transactional
@@ -152,8 +129,6 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
final Boolean sendPasswordToEmail = command.booleanObjectValueOfParameterNamed("sendPasswordToEmail");
this.userDomainService.create(appUser, sendPasswordToEmail);
this.topicDomainService.subscribeUserToTopic(appUser);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(appUser.getId()) //
@@ -162,11 +137,11 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
} catch (final DataIntegrityViolationException dve) {
throw handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
LOG.error("createUser: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
log.error("createUser: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
throw handleDataIntegrityIssues(command, throwable, dve);
} catch (final PlatformEmailSendException e) {
LOG.error("createUser: PlatformEmailSendException", e);
log.error("createUser: PlatformEmailSendException", e);
final String email = command.stringValueOfParameterNamed("email");
final ApiParameterError error = ApiParameterError.parameterError("error.msg.user.email.invalid",
@@ -208,7 +183,6 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
final Map<String, Object> changes = userToUpdate.update(command, this.platformPasswordEncoder, clients);
this.topicDomainService.updateUserSubscription(userToUpdate, changes);
if (changes.containsKey("officeId")) {
final Long officeId = (Long) changes.get("officeId");
final Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
@@ -248,7 +222,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
} catch (final DataIntegrityViolationException dve) {
throw handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
LOG.error("updateUser: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
log.error("updateUser: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
throw handleDataIntegrityIssues(command, throwable, dve);
}
@@ -303,7 +277,6 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
}
user.delete();
this.topicDomainService.unsubcribeUserFromTopic(user);
this.appUserRepository.save(user);
return new CommandProcessingResultBuilder().withEntityId(userId).withOfficeId(user.getOffice().getId()).build();
@@ -333,7 +306,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
"Self Service User Id is already created. Go to Admin->Users to edit or delete the self-service user.");
}
LOG.error("handleDataIntegrityIssues: Neither duplicate username nor existing user; unknown error occured", dve);
log.error("handleDataIntegrityIssues: Neither duplicate username nor existing user; unknown error occured", dve);
return new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
}
}
@@ -22,13 +22,14 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.PersistenceException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
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.service.TopicDomainService;
import org.apache.fineract.useradministration.command.PermissionsCommand;
import org.apache.fineract.useradministration.domain.Permission;
import org.apache.fineract.useradministration.domain.PermissionRepository;
@@ -38,9 +39,6 @@ import org.apache.fineract.useradministration.exception.PermissionNotFoundExcept
import org.apache.fineract.useradministration.exception.RoleAssociatedException;
import org.apache.fineract.useradministration.exception.RoleNotFoundException;
import org.apache.fineract.useradministration.serialization.PermissionsCommandFromApiJsonDeserializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.dao.DataIntegrityViolationException;
@@ -49,27 +47,15 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Slf4j
@RequiredArgsConstructor
public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatformService {
private static final Logger LOG = LoggerFactory.getLogger(RoleWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final RoleRepository roleRepository;
private final PermissionRepository permissionRepository;
private final RoleDataValidator roleCommandFromApiJsonDeserializer;
private final PermissionsCommandFromApiJsonDeserializer permissionsFromApiJsonDeserializer;
private final TopicDomainService topicDomainService;
@Autowired
public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository,
final PermissionRepository permissionRepository, final RoleDataValidator roleCommandFromApiJsonDeserializer,
final PermissionsCommandFromApiJsonDeserializer fromApiJsonDeserializer, final TopicDomainService topicDomainService) {
this.context = context;
this.roleRepository = roleRepository;
this.permissionRepository = permissionRepository;
this.roleCommandFromApiJsonDeserializer = roleCommandFromApiJsonDeserializer;
this.permissionsFromApiJsonDeserializer = fromApiJsonDeserializer;
this.topicDomainService = topicDomainService;
}
@Transactional
@Override
@@ -81,9 +67,7 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
this.roleCommandFromApiJsonDeserializer.validateForCreate(command.json());
final Role entity = Role.fromJson(command);
this.roleRepository.save(entity);
this.topicDomainService.createTopic(entity);
this.roleRepository.saveAndFlush(entity);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(entity.getId()).build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -118,7 +102,7 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
}
private void logAsErrorUnexpectedDataIntegrityException(final Exception dve) {
LOG.error("Error occured.", dve);
log.error("Error occured.", dve);
}
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
@@ -136,9 +120,6 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
final Map<String, Object> changes = role.update(command);
if (!changes.isEmpty()) {
this.roleRepository.saveAndFlush(role);
if (changes.containsKey("name")) {
this.topicDomainService.updateTopic(previousRoleName, role, changes);
}
}
return new CommandProcessingResultBuilder() //
@@ -230,8 +211,6 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
throw new RoleAssociatedException("error.msg.role.associated.with.users.deleted", roleId);
}
this.topicDomainService.deleteTopic(role);
this.roleRepository.delete(role);
return new CommandProcessingResultBuilder().withEntityId(roleId).build();
} catch (final JpaSystemException | DataIntegrityViolationException e) {
@@ -32,4 +32,5 @@
<include file="parts/0010_lien_allowed_on_savings_account_products.xml" relativeToChangelogFile="true"/>
<include file="parts/0011_add_credit_balance_refund_permission.xml" relativeToChangelogFile="true"/>
<include file="parts/0012_add_merchantissuedrefund_payoutrefund_goodwillcredit_permissions.xml" relativeToChangelogFile="true"/>
<include file="parts/0013_remove_topics.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet author="fineract" id="1">
<dropTable tableName="topic_subscriber"/>
<dropTable tableName="topic"/>
</changeSet>
</databaseChangeLog>
+2 -2
View File
@@ -29,7 +29,7 @@ configurations {
apply from: 'dependencies.gradle'
// enable when all tests are migrated
tasks.cucumber.onlyIf {false}
tasks.cucumber.onlyIf { false }
// Allow external drivers to be used for the tests without packaging it
// mainly due to license incompatibilities
@@ -92,7 +92,7 @@ cargoStartLocal.dependsOn ':fineract-war:war'
cargoStartLocal.mustRunAfter 'testClasses'
test {
dependsOn (cargoStartLocal)
dependsOn(cargoStartLocal)
finalizedBy cargoStopLocal
}
+1
View File
@@ -38,6 +38,7 @@ dependencies {
exclude group: 'org.apache.sling'
exclude group: 'com.sun.xml.bind'
}
testImplementation 'org.awaitility:awaitility'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
@@ -18,40 +18,93 @@
*/
package org.apache.fineract.integrationtests;
import static org.apache.fineract.integrationtests.useradministration.roles.RolesHelper.SUPER_USER_ROLE_ID;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.util.HashMap;
import java.util.List;
import org.apache.fineract.client.models.GetNotification;
import org.apache.fineract.client.models.GetNotificationsResponse;
import org.apache.fineract.client.models.GetOfficesResponse;
import org.apache.fineract.client.models.PostClientsRequest;
import org.apache.fineract.client.models.PostUsersRequest;
import org.apache.fineract.client.models.PostUsersResponse;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.NotificationHelper;
import org.apache.fineract.integrationtests.common.OfficeHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.useradministration.users.UserHelper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NotificationApiTest {
private static final Logger LOG = LoggerFactory.getLogger(NotificationApiTest.class);
private ResponseSpecification responseSpec;
public static final int SUPER_USER_ID = 1;
public static final String CLIENT_OBJECT_TYPE = "client";
public static final String CREATED_ACTION_TYPE = "created";
private RequestSpecification requestSpec;
private ResponseSpecification responseSpec;
private RequestSpecification newUserRequestSpec;
private ResponseSpecification newUserResponseSpec;
@BeforeEach
public void setUp() {
Utils.initializeRESTAssured();
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
GetOfficesResponse headOffice = OfficeHelper.getHeadOffice(requestSpec, responseSpec);
String username = Utils.randomNameGenerator("NotificationUser", 4);
String password = Utils.randomStringGenerator("aA1", 10); // prefix is to conform with the password rules
PostUsersRequest createUserRequest = new PostUsersRequest().username(username)
.firstname(Utils.randomNameGenerator("NotificationFN", 4)).lastname(Utils.randomNameGenerator("NotificationLN", 4))
.email("whatever@mifos.org").password(password).repeatPassword(password).sendPasswordToEmail(false)
.roles(List.of(Long.toString(SUPER_USER_ROLE_ID))).officeId(headOffice.getId());
PostUsersResponse userCreationResponse = UserHelper.createUser(requestSpec, responseSpec, createUserRequest);
Assertions.assertNotNull(userCreationResponse.getResourceId());
newUserRequestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
newUserRequestSpec.header("Authorization",
"Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(username, password));
newUserResponseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
}
@Test
@SuppressWarnings("unchecked")
public void testNotificationRetrieval() {
HashMap<String, Object> response = (HashMap<String, Object>) NotificationHelper.getNotifications(this.requestSpec,
this.responseSpec, "");
LOG.info("Response : {}", response.toString());
public void testNotificationRetrievalWorksWhenNoNotificationsAreAvailable() {
// given
// when
GetNotificationsResponse response = NotificationHelper.getNotifications(requestSpec, responseSpec);
// then
Assertions.assertNotNull(response);
}
@Test
public void testNotificationRetrievalWorksWhenOneNotificationIsAvailable() {
// given
PostClientsRequest clientRequest = ClientHelper.defaultClientCreationRequest();
Integer clientId = ClientHelper.createClient(requestSpec, responseSpec, clientRequest);
Assertions.assertNotNull(clientId);
// when
NotificationHelper.waitUntilNotificationsAreAvailable(newUserRequestSpec, newUserResponseSpec);
GetNotificationsResponse response = NotificationHelper.getNotifications(newUserRequestSpec, newUserResponseSpec);
// then
Assertions.assertNotNull(response);
List<GetNotification> pageItems = response.getPageItems();
Assertions.assertEquals(1, pageItems.size());
GetNotification firstNotification = pageItems.get(0);
Assertions.assertEquals(SUPER_USER_ID, firstNotification.getActorId());
Assertions.assertEquals(false, firstNotification.getIsRead());
Assertions.assertEquals(CREATED_ACTION_TYPE, firstNotification.getAction());
Assertions.assertEquals(clientId.longValue(), firstNotification.getObjectId());
Assertions.assertEquals(CLIENT_OBJECT_TYPE, firstNotification.getObjectType());
}
}
@@ -18,28 +18,40 @@
*/
package org.apache.fineract.integrationtests.common;
import static org.awaitility.Awaitility.await;
import com.google.gson.Gson;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.client.models.GetNotificationsResponse;
import org.apache.fineract.client.util.JSON;
public class NotificationHelper {
private static final Logger LOG = LoggerFactory.getLogger(NotificationHelper.class);
private final RequestSpecification requestSpec;
private final ResponseSpecification responseSpec;
@Slf4j
public final class NotificationHelper {
private static final String NOTIFICATION_API_URL = "/fineract-provider/api/v1/notifications?" + Utils.TENANT_IDENTIFIER;
private static final Gson GSON = new JSON().getGson();
public NotificationHelper(RequestSpecification requestSpec, ResponseSpecification responseSpec) {
this.requestSpec = requestSpec;
this.responseSpec = responseSpec;
private NotificationHelper() {}
public static GetNotificationsResponse getNotifications(final RequestSpecification requestSpec,
final ResponseSpecification responseSpec) {
final String GET_NOTIFICATIONS_URL = NOTIFICATION_API_URL;
log.info("-----------------------------GET NOTIFICATIONS-----------------------------------");
String response = Utils.performServerGet(requestSpec, responseSpec, GET_NOTIFICATIONS_URL);
return GSON.fromJson(response, GetNotificationsResponse.class);
}
public static Object getNotifications(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
final String jsonReturn) {
final String GET_NOTIFICATIONS_URL = NOTIFICATION_API_URL;
LOG.info("-----------------------------GET NOTIFICATIONS-----------------------------------");
return Utils.performServerGet(requestSpec, responseSpec, GET_NOTIFICATIONS_URL, "");
public static boolean areNotificationsAvailable(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
return getNotifications(requestSpec, responseSpec).getPageItems().size() > 0;
}
// Waiting for notifications to be available is needed due to the asynchronous event processing
public static void waitUntilNotificationsAreAvailable(final RequestSpecification requestSpec,
final ResponseSpecification responseSpec) {
await().atMost(Duration.ofSeconds(30)).pollInterval(Duration.ofMillis(250))
.until(() -> NotificationHelper.areNotificationsAvailable(requestSpec, responseSpec));
}
}
@@ -29,6 +29,8 @@ import java.io.InputStream;
import java.util.HashMap;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.apache.fineract.client.models.GetOfficesResponse;
import org.apache.fineract.client.util.JSON;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
@@ -36,8 +38,11 @@ import org.slf4j.LoggerFactory;
public class OfficeHelper {
public static final long HEAD_OFFICE_ID = 1L; // The ID is hardcoded in the initial Liquibase migration script
private static final Logger LOG = LoggerFactory.getLogger(OfficeHelper.class);
private static final String OFFICE_URL = "/fineract-provider/api/v1/offices";
private static final Gson GSON = new JSON().getGson();
private final RequestSpecification requestSpec;
private final ResponseSpecification responseSpec;
@@ -52,6 +57,12 @@ public class OfficeHelper {
return new Gson().fromJson(json, new TypeToken<OfficeDomain>() {}.getType());
}
public static GetOfficesResponse getHeadOffice(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
String response = Utils.performServerGet(requestSpec, responseSpec,
OFFICE_URL + "/" + HEAD_OFFICE_ID + "?" + Utils.TENANT_IDENTIFIER);
return GSON.fromJson(response, GetOfficesResponse.class);
}
public Integer createOffice(final String openingDate) {
String json = getAsJSON(openingDate);
return Utils.performServerPost(this.requestSpec, this.responseSpec, OFFICE_URL + "?" + Utils.TENANT_IDENTIFIER, json,
@@ -118,12 +118,17 @@ public final class Utils {
}
public static String loginIntoServerAndGetBase64EncodedAuthenticationKey() {
return loginIntoServerAndGetBase64EncodedAuthenticationKey("mifos", "password");
}
public static String loginIntoServerAndGetBase64EncodedAuthenticationKey(String username, String password) {
awaitSpringBootActuatorHealthyUp();
try {
LOG.info("Logging in, for integration test...");
// system.out.println("-----------------------------------LOGIN-----------------------------------------");
String json = RestAssured.given().contentType(ContentType.JSON).body("{\"username\":\"mifos\", \"password\":\"password\"}")
.expect().log().ifError().when().post(LOGIN_URL).asString();
String json = RestAssured.given().contentType(ContentType.JSON)
.body("{\"username\":\"" + username + "\", \"password\":\"" + password + "\"}").expect().log().ifError().when()
.post(LOGIN_URL).asString();
assertThat("Failed to login into fineract platform", StringUtils.isBlank(json), is(false));
String key = JsonPath.with(json).get("base64EncodedAuthenticationKey");
assertThat("Failed to obtain key: " + json, StringUtils.isBlank(key), is(false));
@@ -26,6 +26,8 @@ import org.apache.fineract.integrationtests.common.Utils;
public final class RolesHelper {
public static final long SUPER_USER_ROLE_ID = 1L; // This is hardcoded into the initial Liquibase migration
private RolesHelper() {
}
@@ -18,22 +18,25 @@
*/
package org.apache.fineract.integrationtests.useradministration.users;
import com.google.gson.Gson;
import io.restassured.path.json.JsonPath;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.util.HashMap;
import java.util.List;
import org.apache.fineract.client.models.PostUsersRequest;
import org.apache.fineract.client.models.PostUsersResponse;
import org.apache.fineract.client.util.JSON;
import org.apache.fineract.integrationtests.common.Utils;
import org.junit.jupiter.api.Assertions;
public final class UserHelper {
private UserHelper() {
}
private static final String CREATE_USER_URL = "/fineract-provider/api/v1/users?" + Utils.TENANT_IDENTIFIER;
private static final String USER_URL = "/fineract-provider/api/v1/users";
private static final Gson GSON = new JSON().getGson();
private UserHelper() {}
public static Integer createUser(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, int roleId,
int staffId) {
@@ -46,6 +49,13 @@ public final class UserHelper {
attribute);
}
public static PostUsersResponse createUser(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
PostUsersRequest request) {
String requestBody = GSON.toJson(request);
String response = Utils.performServerPost(requestSpec, responseSpec, CREATE_USER_URL, requestBody);
return GSON.fromJson(response, PostUsersResponse.class);
}
public static Object createUserForSelfService(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
int roleId, int staffId, int clientId, String attribute) {
return Utils.performServerPost(requestSpec, responseSpec, CREATE_USER_URL,