Search in sources :

Example 1 with UserNotification

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);
}
Also used : UserDao(io.lumeer.storage.api.dao.UserDao) NotificationType(io.lumeer.api.model.NotificationType) NotificationChannel(io.lumeer.api.model.NotificationChannel) UserNotification(io.lumeer.api.model.UserNotification) ZonedDateTime(java.time.ZonedDateTime) User(io.lumeer.api.model.User) AuthenticatedUser(io.lumeer.core.auth.AuthenticatedUser) RemoveResource(io.lumeer.engine.api.event.RemoveResource) StringUtils(org.apache.commons.lang3.StringUtils) Function(java.util.function.Function) CreateResource(io.lumeer.engine.api.event.CreateResource) ArrayList(java.util.ArrayList) Level(java.util.logging.Level) WorkspaceKeeper(io.lumeer.core.WorkspaceKeeper) HashSet(java.util.HashSet) Inject(javax.inject.Inject) Language(io.lumeer.api.model.Language) RolesDifference(io.lumeer.api.model.RolesDifference) ResourceType(io.lumeer.api.model.ResourceType) QueryStem(io.lumeer.api.model.QueryStem) Resource(io.lumeer.api.model.common.Resource) Map(java.util.Map) Observes(javax.enterprise.event.Observes) Query(io.lumeer.api.model.Query) Organization(io.lumeer.api.model.Organization) View(io.lumeer.api.model.View) DataDocument(io.lumeer.engine.api.data.DataDocument) Permissions(io.lumeer.api.model.Permissions) Collection(java.util.Collection) Set(java.util.Set) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Project(io.lumeer.api.model.Project) List(java.util.List) AccessForbiddenException(io.lumeer.core.exception.AccessForbiddenException) UserNotificationDao(io.lumeer.storage.api.dao.UserNotificationDao) RequestScoped(javax.enterprise.context.RequestScoped) UpdateResource(io.lumeer.engine.api.event.UpdateResource) Utils(io.lumeer.core.util.Utils) Collections(java.util.Collections) DataDocument(io.lumeer.engine.api.data.DataDocument) UserNotification(io.lumeer.api.model.UserNotification)

Example 2 with UserNotification

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;
}
Also used : Document(org.bson.Document) DataDocument(io.lumeer.engine.api.data.DataDocument) ZonedDateTime(java.time.ZonedDateTime) NotificationType(io.lumeer.api.model.NotificationType) UserNotification(io.lumeer.api.model.UserNotification) Document(org.bson.Document) DataDocument(io.lumeer.engine.api.data.DataDocument)

Example 3 with UserNotification

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)));
    }
}
Also used : RemoveUserNotification(io.lumeer.engine.api.event.RemoveUserNotification) UserNotification(io.lumeer.api.model.UserNotification) CreateOrUpdateUserNotification(io.lumeer.engine.api.event.CreateOrUpdateUserNotification) RemoveUserNotification(io.lumeer.engine.api.event.RemoveUserNotification) DeleteResult(com.mongodb.client.result.DeleteResult) Bson(org.bson.conversions.Bson)

Example 4 with UserNotification

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)));
    }
}
Also used : Document(org.bson.Document) MongoCollection(com.mongodb.client.MongoCollection) UserNotification(io.lumeer.api.model.UserNotification) StringUtils(org.apache.commons.lang3.StringUtils) ArrayList(java.util.ArrayList) Filters(com.mongodb.client.model.Filters) Bson(org.bson.conversions.Bson) Inject(javax.inject.Inject) UpdateResult(com.mongodb.client.result.UpdateResult) Map(java.util.Map) Event(javax.enterprise.event.Event) UserNotificationCodec(io.lumeer.storage.mongodb.codecs.UserNotificationCodec) MongoException(com.mongodb.MongoException) ReturnDocument(com.mongodb.client.model.ReturnDocument) Updates(com.mongodb.client.model.Updates) Set(java.util.Set) IndexOptions(com.mongodb.client.model.IndexOptions) Collectors(java.util.stream.Collectors) CreateOrUpdateUserNotification(io.lumeer.engine.api.event.CreateOrUpdateUserNotification) Indexes(com.mongodb.client.model.Indexes) StorageException(io.lumeer.storage.api.exception.StorageException) List(java.util.List) MongoFilters.idFilter(io.lumeer.storage.mongodb.util.MongoFilters.idFilter) Sorts(com.mongodb.client.model.Sorts) RemoveUserNotification(io.lumeer.engine.api.event.RemoveUserNotification) UserNotificationDao(io.lumeer.storage.api.dao.UserNotificationDao) PostConstruct(javax.annotation.PostConstruct) DeleteResult(com.mongodb.client.result.DeleteResult) ObjectId(org.bson.types.ObjectId) FindOneAndReplaceOptions(com.mongodb.client.model.FindOneAndReplaceOptions) ApplicationScoped(javax.enterprise.context.ApplicationScoped) UserNotification(io.lumeer.api.model.UserNotification) CreateOrUpdateUserNotification(io.lumeer.engine.api.event.CreateOrUpdateUserNotification) RemoveUserNotification(io.lumeer.engine.api.event.RemoveUserNotification) CreateOrUpdateUserNotification(io.lumeer.engine.api.event.CreateOrUpdateUserNotification) UpdateResult(com.mongodb.client.result.UpdateResult) Bson(org.bson.conversions.Bson)

Example 5 with UserNotification

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);
}
Also used : NotificationSetting(io.lumeer.api.model.NotificationSetting) UserDao(io.lumeer.storage.api.dao.UserDao) NotificationType(io.lumeer.api.model.NotificationType) NotificationChannel(io.lumeer.api.model.NotificationChannel) ProjectDao(io.lumeer.storage.api.dao.ProjectDao) Arquillian(org.jboss.arquillian.junit.Arquillian) UserNotification(io.lumeer.api.model.UserNotification) Date(java.util.Date) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) ZonedDateTime(java.time.ZonedDateTime) User(io.lumeer.api.model.User) AuthenticatedUser(io.lumeer.core.auth.AuthenticatedUser) RunWith(org.junit.runner.RunWith) HashMap(java.util.HashMap) Function(java.util.function.Function) CollectionPurpose(io.lumeer.api.model.CollectionPurpose) WorkspaceKeeper(io.lumeer.core.WorkspaceKeeper) Inject(javax.inject.Inject) OrganizationDao(io.lumeer.storage.api.dao.OrganizationDao) CollectionDao(io.lumeer.storage.api.dao.CollectionDao) DelayedActionProcessor(io.lumeer.core.action.DelayedActionProcessor) Map(java.util.Map) DelayedAction(io.lumeer.api.model.DelayedAction) Organization(io.lumeer.api.model.Organization) Before(org.junit.Before) Permission(io.lumeer.api.model.Permission) DataDocument(io.lumeer.engine.api.data.DataDocument) Permissions(io.lumeer.api.model.Permissions) Document(io.lumeer.api.model.Document) Set(java.util.Set) Test(org.junit.Test) CollectionPurposeType(io.lumeer.api.model.CollectionPurposeType) Constraint(io.lumeer.api.model.Constraint) NotificationFrequency(io.lumeer.api.model.NotificationFrequency) Collectors(java.util.stream.Collectors) Project(io.lumeer.api.model.Project) List(java.util.List) IntegrationTestBase(io.lumeer.engine.IntegrationTestBase) ChronoUnit(java.time.temporal.ChronoUnit) DelayedActionDao(io.lumeer.storage.api.dao.DelayedActionDao) UserNotificationDao(io.lumeer.storage.api.dao.UserNotificationDao) NotificationsSettings(io.lumeer.api.model.NotificationsSettings) Attribute(io.lumeer.api.model.Attribute) Collection(io.lumeer.api.model.Collection) ConstraintType(io.lumeer.api.model.ConstraintType) DataDocument(io.lumeer.engine.api.data.DataDocument) UserNotification(io.lumeer.api.model.UserNotification) DataDocument(io.lumeer.engine.api.data.DataDocument) Document(io.lumeer.api.model.Document) DelayedAction(io.lumeer.api.model.DelayedAction) Date(java.util.Date) Test(org.junit.Test)

Aggregations

UserNotification (io.lumeer.api.model.UserNotification)8 CreateOrUpdateUserNotification (io.lumeer.engine.api.event.CreateOrUpdateUserNotification)4 RemoveUserNotification (io.lumeer.engine.api.event.RemoveUserNotification)4 List (java.util.List)4 NotificationType (io.lumeer.api.model.NotificationType)3 User (io.lumeer.api.model.User)3 DataDocument (io.lumeer.engine.api.data.DataDocument)3 UserNotificationDao (io.lumeer.storage.api.dao.UserNotificationDao)3 ZonedDateTime (java.time.ZonedDateTime)3 ArrayList (java.util.ArrayList)3 Map (java.util.Map)3 Set (java.util.Set)3 Collectors (java.util.stream.Collectors)3 Inject (javax.inject.Inject)3 DeleteResult (com.mongodb.client.result.DeleteResult)2 Collection (io.lumeer.api.model.Collection)2 NotificationChannel (io.lumeer.api.model.NotificationChannel)2 Organization (io.lumeer.api.model.Organization)2 Permissions (io.lumeer.api.model.Permissions)2 Project (io.lumeer.api.model.Project)2