Fix datetime parsing error in notifications (#5893)

* -fix datetime parser exception in comment thread notifications

* -resolved merge conflicts
This commit is contained in:
Nayan 2021-07-17 16:26:30 +06:00 committed by GitHub
parent 1807f6bd5a
commit ac654d754f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 17 deletions

View File

@ -3,9 +3,10 @@ package com.appsmith.server.configurations;
import com.appsmith.external.annotations.documenttype.DocumentTypeMapper;
import com.appsmith.external.annotations.encryption.EncryptionMongoEventListener;
import com.appsmith.external.models.AuthenticationDTO;
import com.appsmith.server.configurations.mongo.SoftDeleteMongoRepositoryFactoryBean;
import com.appsmith.server.repositories.BaseRepositoryImpl;
import com.appsmith.external.services.EncryptionService;
import com.appsmith.server.configurations.mongo.SoftDeleteMongoRepositoryFactoryBean;
import com.appsmith.server.converters.StringToInstantConverter;
import com.appsmith.server.repositories.BaseRepositoryImpl;
import com.github.cloudyrock.mongock.SpringBootMongock;
import com.github.cloudyrock.mongock.SpringBootMongockBuilder;
import lombok.extern.slf4j.Slf4j;
@ -21,12 +22,14 @@ import org.springframework.data.mongodb.config.EnableMongoAuditing;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.MongoTypeMapper;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import java.util.Arrays;
import java.util.Collections;
/**
* This configures the JPA Mongo repositories. The default base implementation is defined in {@link BaseRepositoryImpl}.
@ -57,7 +60,12 @@ public class MongoConfig {
@Bean
public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory, MappingMongoConverter mappingMongoConverter) {
return new MongoTemplate(mongoDbFactory, mappingMongoConverter);
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, mappingMongoConverter);
MappingMongoConverter conv = (MappingMongoConverter) mongoTemplate.getConverter();
// tell mongodb to use the custom converters
conv.setCustomConversions(mongoCustomConversions());
conv.afterPropertiesSet();
return mongoTemplate;
}
// Custom type mapper here includes our annotation based mapper that is meant to ensure correct mapping for sub-classes
@ -72,10 +80,16 @@ public class MongoConfig {
return new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Arrays.asList(typeInformationMapper, new SimpleTypeInformationMapper()));
}
@Bean
public MongoCustomConversions mongoCustomConversions() {
return new MongoCustomConversions(Collections.singletonList(new StringToInstantConverter()));
}
@Bean
public MappingMongoConverter mappingMongoConverter(DefaultTypeMapper<Bson> typeMapper, MongoMappingContext context) {
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, context);
converter.setTypeMapper((MongoTypeMapper) typeMapper);
converter.setCustomConversions(mongoCustomConversions());
return converter;
}

View File

@ -0,0 +1,22 @@
package com.appsmith.server.converters;
import org.springframework.core.convert.converter.Converter;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeParseException;
import static java.time.format.DateTimeFormatter.ISO_DATE_TIME;
public class StringToInstantConverter implements Converter<String, Instant> {
@Override
public Instant convert(String s) {
try {
LocalDateTime ldt = LocalDateTime.parse(s, ISO_DATE_TIME);
return ldt.toInstant(ZoneOffset.UTC);
} catch (DateTimeParseException e) {
return null;
}
}
}

View File

@ -222,7 +222,7 @@ public class PolicyUtils {
}
public Flux<CommentThread> updateWithApplicationPermissionsToAllItsCommentThreads(
String applicationId, Map<String, Policy> commentThreadPolicyMap, boolean addPolicyToObject) {
String applicationId, Map<String, Policy> commentThreadPolicyMap, String username, boolean addPolicyToObject) {
return
// fetch comment threads with read permissions
@ -233,6 +233,9 @@ public class PolicyUtils {
if (addPolicyToObject) {
return addPoliciesToExistingObject(commentThreadPolicyMap, thread);
} else {
if(CollectionUtils.isNotEmpty(thread.getSubscribers())) {
thread.getSubscribers().remove(username);
}
return removePoliciesFromExistingObject(commentThreadPolicyMap, thread);
}
}

View File

@ -352,12 +352,14 @@ public class CommentServiceImpl extends BaseService<CommentRepository, Comment,
if (Boolean.TRUE.equals(updatedThread.getIsPrivate())) {
return triggerBotThreadResolved(threadFromDb, user).thenReturn(updatedThread);
} else {
return emailEventHandler.publish(
Mono<Boolean> publishEmailMono = emailEventHandler.publish(
user.getUsername(),
updatedThread.getApplicationId(),
updatedThread,
originHeader
).thenReturn(updatedThread);
);
return notificationService.createNotification(updatedThread, user.getUsername())
.then(publishEmailMono).thenReturn(updatedThread);
}
}
return Mono.just(updatedThread);

View File

@ -3,14 +3,14 @@ package com.appsmith.server.services;
import com.appsmith.server.domains.Comment;
import com.appsmith.server.domains.CommentThread;
import com.appsmith.server.domains.Notification;
import com.appsmith.server.domains.User;
import com.appsmith.server.dtos.UpdateIsReadNotificationByIdDTO;
import com.appsmith.server.dtos.UpdateIsReadNotificationDTO;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface NotificationService extends CrudService<Notification, String> {
Mono<Notification> createNotification(Comment comment, String forUsername);
Mono<Notification> createNotification(CommentThread commentThread, String forUsername, User authorUser);
Flux<Notification> createNotification(CommentThread commentThread, String authorUserName);
Mono<UpdateIsReadNotificationByIdDTO> updateIsRead(UpdateIsReadNotificationByIdDTO dto);
Mono<UpdateIsReadNotificationDTO> updateIsRead(UpdateIsReadNotificationDTO dto);
Mono<Long> getUnreadCount();

View File

@ -6,7 +6,6 @@ import com.appsmith.server.domains.CommentThread;
import com.appsmith.server.domains.CommentThreadNotification;
import com.appsmith.server.domains.Notification;
import com.appsmith.server.domains.QNotification;
import com.appsmith.server.domains.User;
import com.appsmith.server.dtos.UpdateIsReadNotificationByIdDTO;
import com.appsmith.server.dtos.UpdateIsReadNotificationDTO;
import com.appsmith.server.exceptions.AppsmithError;
@ -20,6 +19,7 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -28,6 +28,8 @@ import reactor.core.scheduler.Scheduler;
import javax.validation.Validator;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
@ -117,12 +119,21 @@ public class NotificationServiceImpl
}
@Override
public Mono<Notification> createNotification(CommentThread commentThread, String forUsername, User authorUser) {
final CommentThreadNotification notification = new CommentThreadNotification();
notification.setCommentThread(commentThread);
notification.setForUsername(forUsername);
notification.setIsRead(false);
return repository.save(notification);
public Flux<Notification> createNotification(CommentThread commentThread, String authorUserName) {
if(!CollectionUtils.isEmpty(commentThread.getSubscribers())) {
List<Notification> notificationMonoList = new ArrayList<>(commentThread.getSubscribers().size());
for(String subscriberUserName: commentThread.getSubscribers()) {
if(!subscriberUserName.equals(authorUserName)) {
CommentThreadNotification commentThreadNotification = new CommentThreadNotification();
commentThreadNotification.setCommentThread(commentThread);
commentThreadNotification.setForUsername(subscriberUserName);
commentThreadNotification.setIsRead(false);
notificationMonoList.add(commentThreadNotification);
}
}
return repository.saveAll(notificationMonoList);
}
return Flux.empty();
}
@Override

View File

@ -258,7 +258,9 @@ public class UserOrganizationServiceImpl implements UserOrganizationService {
Flux<NewAction> updatedActionsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, false));
Flux<CommentThread> updatedThreadsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsCommentThreads(application.getId(), commentThreadPolicyMap, false));
.flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsCommentThreads(
application.getId(), commentThreadPolicyMap, user.getUsername(), false
));
return Mono.zip(
updatedDatasourcesFlux.collectList(),
@ -432,7 +434,9 @@ public class UserOrganizationServiceImpl implements UserOrganizationService {
Flux<NewAction> updatedActionsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, true));
Flux<CommentThread> updatedThreadsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsCommentThreads(application.getId(), commentThreadPolicyMap, true));
.flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsCommentThreads(
application.getId(), commentThreadPolicyMap, null, true
));
return Mono.when(
updatedDatasourcesFlux.collectList(),