use of io.lumeer.api.model.UserNotification in project engine by Lumeer.
the class UserNotificationFacade method createResourceSharedNotifications.
private List<UserNotification> createResourceSharedNotifications(final Resource resource, final java.util.Collection<String> newUsers) {
if (workspaceKeeper.getOrganization().isEmpty() && resource.getType() != ResourceType.ORGANIZATION) {
return Collections.emptyList();
}
final DataDocument data = getResourceDescription(resource);
final List<UserNotification> notifications = newUsers.stream().map(userId -> createNotification(userId, getNotificationTypeByResource(resource), data)).collect(Collectors.toList());
return dao.createNotificationsBatch(notifications);
}
use of io.lumeer.api.model.UserNotification in project engine by Lumeer.
the class UserNotificationCodec method decode.
@Override
public UserNotification decode(final BsonReader reader, final DecoderContext decoderContext) {
final Document bson = documentCodec.decode(reader, decoderContext);
final String id = bson.getObjectId(ID).toHexString();
final String userId = bson.getString(USER_ID);
final boolean read = bson.getBoolean(READ);
final NotificationType type = NotificationType.values()[bson.getInteger(TYPE)];
final org.bson.Document data = bson.get(DATA, org.bson.Document.class);
ZonedDateTime createdAt = null;
if (bson.getDate(CREATED_AT) != null) {
createdAt = ZonedDateTime.ofInstant(bson.getDate(CREATED_AT).toInstant(), ZoneOffset.UTC);
}
ZonedDateTime firstReadAt = null;
if (bson.getDate(FIRST_READ_AT) != null) {
firstReadAt = ZonedDateTime.ofInstant(bson.getDate(FIRST_READ_AT).toInstant(), ZoneOffset.UTC);
}
final UserNotification notification = new UserNotification(userId, createdAt, read, firstReadAt, type, new DataDocument(data != null ? data : new org.bson.Document()));
notification.setId(id);
return notification;
}
use of io.lumeer.api.model.UserNotification in project engine by Lumeer.
the class MongoUserNotificationDao method removeNotifications.
@Override
public void removeNotifications(final String searchField, final String searchId, final Set<String> users) {
Bson filter = createRemoveNotificationsFilter(searchField, searchId, users);
final List<UserNotification> deletedNotifications = databaseCollection().find(filter).into(new ArrayList<>());
final DeleteResult result = databaseCollection().deleteMany(filter);
if (result.getDeletedCount() > 0 && removeUserNotificationEvent != null) {
deletedNotifications.forEach(notification -> removeUserNotificationEvent.fire(new RemoveUserNotification(notification)));
}
}
use of io.lumeer.api.model.UserNotification in project engine by Lumeer.
the class MongoUserNotificationDao method updateNotifications.
@Override
public void updateNotifications(final String searchField, final String searchId, final Map<String, String> updates) {
final List<Bson> sets = updates.entrySet().stream().map(e -> Updates.set(e.getKey(), e.getValue())).collect(Collectors.toList());
final UpdateResult result = databaseCollection().updateMany(Filters.eq(searchField, searchId), Updates.combine(sets));
if (result.getModifiedCount() > 0 && createOrUpdateUserNotificationEvent != null) {
final List<UserNotification> updatedNotifications = databaseCollection().find(Filters.eq(searchField, searchId)).into(new ArrayList<>());
updatedNotifications.forEach(notification -> createOrUpdateUserNotificationEvent.fire(new CreateOrUpdateUserNotification(notification)));
}
}
use of io.lumeer.api.model.UserNotification in project engine by Lumeer.
the class DelayedActionIT method testAssignment.
@Test
public void testAssignment() {
List<UserNotification> notifications = userNotificationDao.getRecentNotifications(user2.getId());
assertThat(notifications.size()).isEqualTo(0);
Document doc = createDocument("My cool task", List.of("evžen@vystrčil.cz", user2.getEmail()), new Date(ZonedDateTime.now().minus(DelayedActionDao.PROCESSING_DELAY_MINUTES, ChronoUnit.MINUTES).toInstant().toEpochMilli()), "To Do", List.of(), "so just another task");
List<DelayedAction> actions = delayedActionDao.getActions();
// now we should have:
// evžen@vystrčil.cz - PAST_DUE_DATE x 3 channels
// rspath@lumeerio.com (USER2 - observer) - PAST_DUE_DATE x 3 channels
// evžen@vystrčil.cz - TASK_ASSIGNED x 3 channels
// rspath@lumeerio.com (USER2 - observer) - TASK_ASSIGNED x 3 channels
// evžen@vystrčil.cz - STATE_UPDATE x 3 channels
// rspath@lumeerio.com (USER2 - observer) - STATE_UPDATE x 3 channels
var types = countOccurrences(actions, DelayedAction::getNotificationType);
assertThat(types.get(NotificationType.STATE_UPDATE)).isEqualTo(6);
assertThat(types.get(NotificationType.TASK_ASSIGNED)).isEqualTo(6);
assertThat(types.get(NotificationType.PAST_DUE_DATE)).isEqualTo(6);
assertThat(countOccurrences(actions, DelayedAction::getStartedProcessing).get(null)).isEqualTo(18);
assertThat(countOccurrences(actions, DelayedAction::getCompleted).get(null)).isEqualTo(18);
assertThat(countOccurrences(actions, (action) -> action.getCheckAfter().isBefore(ZonedDateTime.now())).get(true)).isEqualTo(18);
var channels = countOccurrences(actions, DelayedAction::getNotificationChannel);
assertThat(channels.get(NotificationChannel.Email)).isEqualTo(6);
assertThat(channels.get(NotificationChannel.Internal)).isEqualTo(6);
assertThat(channels.get(NotificationChannel.Slack)).isEqualTo(6);
assertThat(countOccurrences(actions, DelayedAction::getInitiator).get(user.getEmail())).isEqualTo(18);
assertThat(countOccurrences(actions, DelayedAction::getReceiver).get(user2.getEmail())).isEqualTo(9);
delayedActionProcessor.process();
notifications = userNotificationDao.getRecentNotifications(user2.getId());
// now TASK_ASSIGNED and STATE_UPDATE got aggregated to TASK_ASSIGNED
// each user receives 2 internal notifications - aggregated TASK_ASSIGNED and PAST_DUE_DATE
assertThat(notifications.size()).isEqualTo(2);
types = countOccurrences(notifications, UserNotification::getType);
assertThat(types.get(NotificationType.PAST_DUE_DATE)).isEqualTo(1);
assertThat(types.get(NotificationType.TASK_ASSIGNED)).isEqualTo(1);
actions = delayedActionDao.getActions();
// each user (2) has 3 channels and one PAST_DUE_DATE message scheduled for future = 6
assertThat(countOccurrences(actions, DelayedAction::getStartedProcessing).getOrDefault(null, 0)).isEqualTo(6);
assertThat(countOccurrences(actions, DelayedAction::getCompleted).getOrDefault(null, 0)).isEqualTo(6);
// Removing USER2 user from assignees
Document patched = documentFacade.patchDocumentData(collection.getId(), doc.getId(), new DataDocument("a1", List.of("evžen@vystrčil.cz")));
delayedActionProcessor.process();
actions = delayedActionDao.getActions();
// USER2 has TASK_UNASSIGNED for each channel (3) = 3
// evžen@vystrčil.cz has previous PAST_DUE_DATE on each channel = 3
types = countOccurrences(actions, DelayedAction::getNotificationType);
assertThat(types.getOrDefault(NotificationType.STATE_UPDATE, 0)).isEqualTo(0);
assertThat(types.getOrDefault(NotificationType.TASK_ASSIGNED, 0)).isEqualTo(0);
assertThat(types.getOrDefault(NotificationType.TASK_UNASSIGNED, 0)).isEqualTo(3);
assertThat(types.getOrDefault(NotificationType.PAST_DUE_DATE, 0)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getStartedProcessing).getOrDefault(null, 0)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getCompleted).getOrDefault(null, 0)).isEqualTo(3);
assertThat(countOccurrences(actions, (action) -> action.getCheckAfter().isBefore(ZonedDateTime.now())).get(true)).isEqualTo(3);
// Adding USER2 user back to assignees
patched = documentFacade.patchDocumentData(collection.getId(), doc.getId(), new DataDocument("a1", List.of(user2.getEmail())));
delayedActionProcessor.process();
actions = delayedActionDao.getActions();
types = countOccurrences(actions, DelayedAction::getNotificationType);
assertThat(types.get(NotificationType.PAST_DUE_DATE)).isEqualTo(3);
assertThat(types.get(NotificationType.TASK_ASSIGNED)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getReceiver).get(user2.getEmail())).isEqualTo(6);
notifications = userNotificationDao.getRecentNotifications(user2.getId());
// there should be three additional notifications - TASK_UNASSIGNED, TASK_ASSIGNED, PAST_DUE_DATE
assertThat(notifications.size()).isEqualTo(2 + 3);
types = countOccurrences(notifications, UserNotification::getType);
// this was aggregated under ASSIGNED
assertThat(types.containsKey(NotificationType.STATE_UPDATE)).isFalse();
assertThat(types.get(NotificationType.PAST_DUE_DATE)).isEqualTo(1 + 1);
assertThat(types.get(NotificationType.TASK_ASSIGNED)).isEqualTo(1 + 1);
assertThat(types.get(NotificationType.TASK_UNASSIGNED)).isEqualTo(1);
// three previously processed actions are removed
assertThat(actions.size()).isEqualTo(9);
assertThat(countOccurrences(actions, DelayedAction::getStartedProcessing).getOrDefault(null, 0)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.PAST_DUE_DATE)).isEqualTo(3);
// Setting state to completed
patched = documentFacade.patchDocumentData(collection.getId(), doc.getId(), new DataDocument("a3", "Done"));
actions = delayedActionDao.getActions();
var newActions = actions.stream().filter(action -> action.getStartedProcessing() == null).collect(Collectors.toList());
// past due date actions were replaced with state update
assertThat(newActions.size()).isEqualTo(3);
assertThat(countOccurrences(newActions, DelayedAction::getNotificationType).get(NotificationType.STATE_UPDATE)).isEqualTo(3);
delayedActionProcessor.process();
// Setting due date in future, but the task is completed
patched = documentFacade.patchDocumentData(collection.getId(), doc.getId(), new DataDocument("a2", new Date(ZonedDateTime.now().plus(1, ChronoUnit.DAYS).toInstant().toEpochMilli())));
actions = delayedActionDao.getActions();
assertThat(actions.stream().filter(action -> action.getStartedProcessing() == null).count()).isEqualTo(0);
// not assigned to user, nothing has changed, except for the fact that the actions were processed
assertThat(actions.size()).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.STATE_UPDATE)).isEqualTo(3);
delayedActionProcessor.process();
// Setting state as incomplete
patched = documentFacade.patchDocumentData(collection.getId(), doc.getId(), new DataDocument("a3", "New"));
actions = delayedActionDao.getActions();
// assignment and past due actions are back
assertThat(actions.stream().filter(action -> action.getStartedProcessing() == null).count()).isEqualTo(9);
assertThat(actions.size()).isEqualTo(9);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.STATE_UPDATE)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.TASK_REOPENED)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.PAST_DUE_DATE)).isEqualTo(3);
// Setting due date in the future again so expecting new notifications
patched = documentFacade.patchDocumentData(collection.getId(), doc.getId(), new DataDocument("a2", new Date(ZonedDateTime.now().plus(4, ChronoUnit.DAYS).toInstant().toEpochMilli())));
actions = delayedActionDao.getActions();
// we can even have due soon + due date changed
assertThat(actions.stream().filter(action -> action.getStartedProcessing() == null).count()).isEqualTo(15);
assertThat(actions.size()).isEqualTo(15);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.STATE_UPDATE)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.TASK_REOPENED)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.PAST_DUE_DATE)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.DUE_DATE_SOON)).isEqualTo(3);
assertThat(countOccurrences(actions, DelayedAction::getNotificationType).get(NotificationType.DUE_DATE_CHANGED)).isEqualTo(3);
notifications = userNotificationDao.getRecentNotifications(user2.getId());
assertThat(countOccurrences(notifications, UserNotification::getType).getOrDefault(NotificationType.TASK_CHANGED, 0)).isEqualTo(0);
delayedActionProcessor.process();
notifications = userNotificationDao.getRecentNotifications(user2.getId());
assertThat(countOccurrences(notifications, UserNotification::getType).getOrDefault(NotificationType.TASK_CHANGED, 0)).isEqualTo(1);
delayedActionDao.deleteAllScheduledActions(organizationId);
actions = delayedActionDao.getActions();
assertThat(actions.size()).isEqualTo(0);
}
Aggregations