Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 0.0.3-maintenance
  • 1.0-maintenance
  • 2.0-maintenance
  • AOU-1412_Add_checksum_of_DataFile_when_importing_in_Fedora
  • HBO-test-jenkins-library
  • HCA-PortingSolidify-3.2
  • HCA-PortingSolidify-3.5
  • adf-1418-do-not-index-certain-files
  • adf-1464-job-clean-download-files
  • adf-1867-list-publications-stats
  • adf-763-1127-improve-license-mapping-during-imports
  • adf-907-notifications-mark-as-read
  • adf-956-add-imprimatur-and-mode-de-diffussion-for-thesis
  • adf-956-new-document-types-imprimatur-and-mode-de-diffusion
  • adf-979-add-depositor-in-notifications-email
  • adf-squash-commits-jb
  • adf-validator-name
  • aou-1512_fix_coherence_orders_for_indexed_structures
  • contributors-with-names
  • jbc-bibliography-tmpl
  • jbc-csl-correctionsDD
  • jbc-update-coverpage
  • master
  • remove-not-neccessary-ExtendWith-annotations
  • rod-refactor-fedora-storage-get-datastream-index
  • rodn-113-indexing-service
  • rodn-1136-author-can-send-in-validation
  • rodn-1253-fix-validator-comments-notifications
  • rodn-1634-bibliography-add-sort-by-validation-date
  • rodn-1829-scheduled-task-to-export-to-orcid
  • rodn-833-add-validation-rules-before-submit
  • rodn-access-contributor-by-orcid-old
  • rodn-finalize-swiss-library-exports-task
  • rodn-fix-IT
  • rodn-improve-access-it
  • rodn-index-contributors-without-director
  • rodn-index-fix-indexing-with-large-fulltext
  • rodn-index-subtype-code
  • rodn-language-refactoring
  • rodn-merge-users-it
  • rodn-orcid-export-master-with-other-id
  • rodn-orcid-solidify-webhooks
  • rodn-prevent-hibernate-circular-exception
  • rodn-refactor-labels
  • rodn-search-accent-insensitive
  • rodn-shared-reference-to-collection-debug
  • rodn-solidify-3.5
  • rodn-solidify-es-8
  • rodn-use-index-to-find-validable-publications
  • rodn-use-solidify-global-banner
  • unit-test-bibtex-escaper
  • aou-0.0.1
  • aou-0.0.2
  • aou-0.0.3
  • aou-0.0.3-patch1
  • aou-0.0.4
  • aou-0.0.5
  • aou-1.0.0
  • aou-1.0.1
  • aou-1.0.10
  • aou-1.0.11
  • aou-1.0.12
  • aou-1.0.13
  • aou-1.0.14
  • aou-1.0.15
  • aou-1.0.16
  • aou-1.0.17
  • aou-1.0.18
  • aou-1.0.19
  • aou-1.0.2
  • aou-1.0.20
  • aou-1.0.21
  • aou-1.0.3
  • aou-1.0.4
  • aou-1.0.5
  • aou-1.0.6
  • aou-1.0.7
  • aou-1.0.8
  • aou-1.0.9
  • aou-1.1.0
  • aou-2.0.0
  • aou-2.0.0-RC1
  • aou-2.0.0-RC2
  • aou-2.0.0-RC3
  • aou-2.0.1
  • aou-2.0.10
  • aou-2.0.11
  • aou-2.0.12
  • aou-2.0.13
  • aou-2.0.14
  • aou-2.0.15
  • aou-2.0.16
  • aou-2.0.17
  • aou-2.0.18
  • aou-2.0.19
  • aou-2.0.2
  • aou-2.0.20
  • aou-2.0.21
  • aou-2.0.22
  • aou-2.0.23
  • aou-2.0.24
  • aou-2.0.25
  • aou-2.0.26
  • aou-2.0.27
  • aou-2.0.28
  • aou-2.0.29
  • aou-2.0.3
  • aou-2.0.30
  • aou-2.0.31
  • aou-2.0.32
  • aou-2.0.33
  • aou-2.0.34
  • aou-2.0.4
  • aou-2.0.5
  • aou-2.0.6
  • aou-2.0.7
  • aou-2.0.8
  • aou-2.0.9
  • aou-2.1.0
  • aou-2.1.1
  • aou-2.1.10
  • aou-2.1.11
  • aou-2.1.12
  • aou-2.1.13
  • aou-2.1.14
  • aou-2.1.15
  • aou-2.1.16
  • aou-2.1.17
  • aou-2.1.18
  • aou-2.1.19
  • aou-2.1.2
  • aou-2.1.20
  • aou-2.1.21
  • aou-2.1.22
  • aou-2.1.23
  • aou-2.1.24
  • aou-2.1.25
  • aou-2.1.26
  • aou-2.1.27
  • aou-2.1.28
  • aou-2.1.29
  • aou-2.1.3
  • aou-2.1.30
  • aou-2.1.31
  • aou-2.1.32
  • aou-2.1.33
  • aou-2.1.4
  • aou-2.1.5
  • aou-2.1.6
  • aou-2.1.7
  • aou-2.1.8
151 results

Target

Select target project
  • aou/aou-backend
1 result
Select Git revision
  • 0.0.3-maintenance
  • 1.0-maintenance
  • 2.0-maintenance
  • AOU-1412_Add_checksum_of_DataFile_when_importing_in_Fedora
  • HBO-test-jenkins-library
  • HCA-PortingSolidify-3.2
  • HCA-PortingSolidify-3.5
  • adf-1418-do-not-index-certain-files
  • adf-1464-job-clean-download-files
  • adf-1867-list-publications-stats
  • adf-763-1127-improve-license-mapping-during-imports
  • adf-907-notifications-mark-as-read
  • adf-956-add-imprimatur-and-mode-de-diffussion-for-thesis
  • adf-956-new-document-types-imprimatur-and-mode-de-diffusion
  • adf-979-add-depositor-in-notifications-email
  • adf-squash-commits-jb
  • adf-validator-name
  • aou-1512_fix_coherence_orders_for_indexed_structures
  • contributors-with-names
  • jbc-bibliography-tmpl
  • jbc-csl-correctionsDD
  • jbc-update-coverpage
  • master
  • remove-not-neccessary-ExtendWith-annotations
  • rod-refactor-fedora-storage-get-datastream-index
  • rodn-113-indexing-service
  • rodn-1136-author-can-send-in-validation
  • rodn-1253-fix-validator-comments-notifications
  • rodn-1634-bibliography-add-sort-by-validation-date
  • rodn-1829-scheduled-task-to-export-to-orcid
  • rodn-833-add-validation-rules-before-submit
  • rodn-access-contributor-by-orcid-old
  • rodn-finalize-swiss-library-exports-task
  • rodn-fix-IT
  • rodn-improve-access-it
  • rodn-index-contributors-without-director
  • rodn-index-fix-indexing-with-large-fulltext
  • rodn-index-subtype-code
  • rodn-language-refactoring
  • rodn-merge-users-it
  • rodn-orcid-export-master-with-other-id
  • rodn-orcid-solidify-webhooks
  • rodn-prevent-hibernate-circular-exception
  • rodn-refactor-labels
  • rodn-search-accent-insensitive
  • rodn-shared-reference-to-collection-debug
  • rodn-solidify-3.5
  • rodn-solidify-es-8
  • rodn-use-index-to-find-validable-publications
  • rodn-use-solidify-global-banner
  • unit-test-bibtex-escaper
  • aou-0.0.1
  • aou-0.0.2
  • aou-0.0.3
  • aou-0.0.3-patch1
  • aou-0.0.4
  • aou-0.0.5
  • aou-1.0.0
  • aou-1.0.1
  • aou-1.0.10
  • aou-1.0.11
  • aou-1.0.12
  • aou-1.0.13
  • aou-1.0.14
  • aou-1.0.15
  • aou-1.0.16
  • aou-1.0.17
  • aou-1.0.18
  • aou-1.0.19
  • aou-1.0.2
  • aou-1.0.20
  • aou-1.0.21
  • aou-1.0.3
  • aou-1.0.4
  • aou-1.0.5
  • aou-1.0.6
  • aou-1.0.7
  • aou-1.0.8
  • aou-1.0.9
  • aou-1.1.0
  • aou-2.0.0
  • aou-2.0.0-RC1
  • aou-2.0.0-RC2
  • aou-2.0.0-RC3
  • aou-2.0.1
  • aou-2.0.10
  • aou-2.0.11
  • aou-2.0.12
  • aou-2.0.13
  • aou-2.0.14
  • aou-2.0.15
  • aou-2.0.16
  • aou-2.0.17
  • aou-2.0.18
  • aou-2.0.19
  • aou-2.0.2
  • aou-2.0.20
  • aou-2.0.21
  • aou-2.0.22
  • aou-2.0.23
  • aou-2.0.24
  • aou-2.0.25
  • aou-2.0.26
  • aou-2.0.27
  • aou-2.0.28
  • aou-2.0.29
  • aou-2.0.3
  • aou-2.0.30
  • aou-2.0.31
  • aou-2.0.32
  • aou-2.0.33
  • aou-2.0.34
  • aou-2.0.4
  • aou-2.0.5
  • aou-2.0.6
  • aou-2.0.7
  • aou-2.0.8
  • aou-2.0.9
  • aou-2.1.0
  • aou-2.1.1
  • aou-2.1.10
  • aou-2.1.11
  • aou-2.1.12
  • aou-2.1.13
  • aou-2.1.14
  • aou-2.1.15
  • aou-2.1.16
  • aou-2.1.17
  • aou-2.1.18
  • aou-2.1.19
  • aou-2.1.2
  • aou-2.1.20
  • aou-2.1.21
  • aou-2.1.22
  • aou-2.1.23
  • aou-2.1.24
  • aou-2.1.25
  • aou-2.1.26
  • aou-2.1.27
  • aou-2.1.28
  • aou-2.1.29
  • aou-2.1.3
  • aou-2.1.30
  • aou-2.1.31
  • aou-2.1.32
  • aou-2.1.33
  • aou-2.1.4
  • aou-2.1.5
  • aou-2.1.6
  • aou-2.1.7
  • aou-2.1.8
151 results
Show changes
Commits on Source (2)
Showing
with 489 additions and 422 deletions
package ch.unige.aou.controller.admin;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import java.time.OffsetDateTime;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ch.unige.solidify.SolidifyConstants;
import ch.unige.solidify.controller.ResourceController;
import ch.unige.solidify.exception.SolidifyResourceNotFoundException;
import ch.unige.solidify.rest.ActionName;
import ch.unige.solidify.rest.Collection;
import ch.unige.solidify.rest.Tool;
import ch.unige.solidify.security.AdminPermissions;
import ch.unige.solidify.security.UserPermissions;
import ch.unige.aou.business.NotificationService;
import ch.unige.aou.business.UserService;
import ch.unige.aou.controller.AdminController;
import ch.unige.aou.model.notification.Notification;
import ch.unige.aou.rest.AouActionName;
import ch.unige.aou.rest.UrlPath;
@RestController
@AdminPermissions
@ConditionalOnBean(AdminController.class)
@RequestMapping(UrlPath.ADMIN_NOTIFICATIONS)
public class NotificationController extends ResourceController<Notification> {
private final UserService userService;
public NotificationController(UserService userService) {
this.userService = userService;
}
@Override
@PreAuthorize("@notificationPermissionService.isAllowedToCreate(#notification)")
public HttpEntity<Notification> create(@RequestBody Notification notification) {
notification.setRecipient(this.userService.getCurrentUser().getPerson());
notification.setSentTime(OffsetDateTime.now());
return super.create(notification);
}
@Override
@AdminPermissions
public HttpStatus delete(@PathVariable String id) {
return super.delete(id);
}
@Override
@AdminPermissions
public HttpStatus deleteList(@RequestBody String[] ids) {
return super.deleteList(ids);
}
@Override
@AdminPermissions
public HttpEntity<Notification> get(@PathVariable String id) {
return super.get(id);
}
@UserPermissions
@GetMapping(SolidifyConstants.URL_SEP + AouActionName.INBOX + SolidifyConstants.URL_ID)
public HttpEntity<Notification> getInboxNotification(@PathVariable String id) {
final Notification inboxNotification = ((NotificationService) this.itemService).getInboxNotification(id, this.userService.getCurrentUser());
return new ResponseEntity<>(inboxNotification, HttpStatus.OK);
}
@Override
@AdminPermissions
public HttpEntity<Collection<Notification>> list(@ModelAttribute Notification search, Pageable pageable) {
return super.list(search, pageable);
}
@UserPermissions
@GetMapping(SolidifyConstants.URL_SEP + AouActionName.INBOX)
@SuppressWarnings("squid:S4684")
public HttpEntity<Collection<Notification>> listInboxNotification(@ModelAttribute Notification search, Pageable pageable) {
final Page<Notification> listItem = ((NotificationService) (this.itemService)).listInboxNotification(this.userService.getCurrentUser(), search, null, null, pageable);
final Collection<Notification> collection = this.addRemainingLinks(listItem, pageable);
return new ResponseEntity<>(collection, HttpStatus.OK);
}
@UserPermissions
@GetMapping(SolidifyConstants.URL_SEP + AouActionName.SEARCH_INBOX)
public HttpEntity<Collection<Notification>> advancedSearch(@ModelAttribute Notification notification,
@RequestParam(value="structureId", required = false) String structureId,
@RequestParam(value = "researchGroupId", required = false) String researchGroupId, Pageable pageable) {
final Page<Notification> listItem = ((NotificationService) (this.itemService)).listInboxNotification(this.userService.getCurrentUser(), notification, structureId, researchGroupId, pageable);
final Collection<Notification> collection = this.addRemainingLinks(listItem, pageable);
return new ResponseEntity<>(collection, HttpStatus.OK);
}
@PreAuthorize("@notificationPermissionService.isMyNotification(#id)")
@PostMapping(SolidifyConstants.URL_ID + SolidifyConstants.URL_SEP + AouActionName.SET_READ)
public HttpEntity<Notification> markNotificationAsRead(@PathVariable String id) {
final Notification notification = ((NotificationService) (this.itemService)).getInboxNotification(id, this.userService.getCurrentUser());
if (notification != null) {
notification.setReadTime(OffsetDateTime.now());
this.itemService.save(notification);
return new ResponseEntity<>(notification, HttpStatus.OK);
} else {
throw new SolidifyResourceNotFoundException("Notification " + id + " not found");
}
}
@Override
@AdminPermissions
public HttpEntity<Notification> update(@PathVariable String id, @RequestBody Notification t2) {
return super.update(id, t2);
}
private Collection<Notification> addRemainingLinks(Page<Notification> listItem, Pageable pageable) {
final Collection<Notification> collection = new Collection<>(listItem, pageable);
for (final Notification t : listItem) {
this.addLinks(t);
}
collection.add(linkTo(this.getClass()).withSelfRel());
collection.add(Tool.parentLink((linkTo(this.getClass())).toUriComponentsBuilder())
.withRel(ActionName.MODULE));
this.addSortLinks(linkTo(this.getClass()), collection);
this.addPageLinks(linkTo(this.getClass()), collection, pageable);
this.addOthersLinks(collection);
return collection;
}
}
package ch.unige.aou.controller.admin;
import java.time.OffsetDateTime;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ch.unige.solidify.SolidifyConstants;
import ch.unige.solidify.controller.CompositionController;
import ch.unige.solidify.model.RoleApplication;
import ch.unige.solidify.rest.Collection;
import ch.unige.solidify.security.UserPermissions;
import ch.unige.aou.controller.AdminController;
import ch.unige.aou.model.notification.Notification;
import ch.unige.aou.model.settings.Person;
import ch.unige.aou.rest.AouActionName;
import ch.unige.aou.rest.ResourceName;
import ch.unige.aou.rest.UrlPath;
import ch.unige.aou.specification.NotificationSpecification;
@UserPermissions
@RestController
@ConditionalOnBean(AdminController.class)
@RequestMapping(UrlPath.ADMIN_PEOPLE + SolidifyConstants.URL_PARENT_ID + ResourceName.NOTIFICATIONS)
public class PersonNotificationController extends CompositionController<Person, Notification> {
@Override
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
public HttpEntity<Collection<Notification>> list(@PathVariable String parentid, @ModelAttribute Notification filterItem,
Pageable pageable) {
return super.list(parentid, filterItem, pageable);
}
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
@GetMapping(params = "onlyWithNullReadTime")
public HttpEntity<Collection<Notification>> list(@PathVariable String parentid, @ModelAttribute Notification filterItem,
Pageable pageable, @RequestParam boolean onlyWithNullReadTime) {
if (onlyWithNullReadTime) {
final Person person = this.resourceService.findOne(parentid);
this.setParentResourceProperty(filterItem, person);
NotificationSpecification specification = (NotificationSpecification) this.subResourceService.getSpecification(filterItem);
specification.setOnlyWithNullReadTime(true);
return this.getSubResourcesCollectionAsResponseEntity(parentid, specification, pageable);
} else {
return super.list(parentid, filterItem, pageable);
}
}
@Override
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
public HttpEntity<Notification> get(@PathVariable String parentid, @PathVariable String id) {
return super.get(parentid, id);
}
@PostMapping(SolidifyConstants.URL_ID + SolidifyConstants.URL_SEP + AouActionName.SET_READ)
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
public HttpEntity<Notification> markNotificationAsRead(@PathVariable String parentid, @PathVariable String id) {
Notification notification = this.checkSubresourceExistsAndIsLinkedToParent(id, parentid);
notification.setReadTime(OffsetDateTime.now());
this.subResourceService.save(notification);
return new ResponseEntity<>(notification, HttpStatus.OK);
}
@Override
protected Person getParentResourceProperty(Notification notification) {
return notification.getRecipient();
}
@Override
protected void setParentResourceProperty(Notification notification, Person recipient) {
notification.setRecipient(recipient);
}
}
......@@ -15,10 +15,9 @@ import org.springframework.web.bind.annotation.RestController;
import ch.unige.solidify.SolidifyConstants;
import ch.unige.solidify.config.SolidifyEventPublisher;
import ch.unige.solidify.controller.Relation2TiersController;
import ch.unige.solidify.controller.AssociationController;
import ch.unige.solidify.model.RoleApplication;
import ch.unige.solidify.rest.Collection;
import ch.unige.solidify.rest.JoinResourceContainer;
import ch.unige.aou.business.UserService;
import ch.unige.aou.controller.AdminController;
......@@ -26,14 +25,13 @@ import ch.unige.aou.message.EmailMessage;
import ch.unige.aou.message.EmailMessage.EmailTemplate;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.settings.Person;
import ch.unige.aou.model.settings.PersonNotificationType;
import ch.unige.aou.rest.ResourceName;
import ch.unige.aou.rest.UrlPath;
@RestController
@ConditionalOnBean(AdminController.class)
@RequestMapping(UrlPath.ADMIN_PEOPLE + SolidifyConstants.URL_PARENT_ID + ResourceName.NOTIFICATION_TYPES)
public class PersonNotificationTypeController extends Relation2TiersController<Person, NotificationType, PersonNotificationType> {
public class PersonNotificationTypeController extends AssociationController<Person, NotificationType> {
private final UserService userService;
......@@ -44,43 +42,27 @@ public class PersonNotificationTypeController extends Relation2TiersController<P
@Override
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
public HttpEntity<Collection<JoinResourceContainer<PersonNotificationType>>> list(@PathVariable String parentid,
@ModelAttribute NotificationType filterItem, Pageable pageable) {
public HttpEntity<Collection<NotificationType>> list(@PathVariable String parentid, @ModelAttribute NotificationType filterItem,
Pageable pageable) {
return super.list(parentid, filterItem, pageable);
}
@Override
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
public HttpEntity<JoinResourceContainer<PersonNotificationType>> get(@PathVariable String parentid, @PathVariable String id) {
public HttpEntity<NotificationType> get(@PathVariable String parentid, @PathVariable String id) {
return super.get(parentid, id);
}
@Override
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
public HttpEntity<JoinResourceContainer<PersonNotificationType>> create(@PathVariable String parentid, @PathVariable String id,
@RequestBody PersonNotificationType joinResource) {
return super.create(parentid, id, joinResource);
}
@Override
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
public HttpEntity<List<JoinResourceContainer<PersonNotificationType>>> create(@PathVariable String parentid, @RequestBody String[] ids) {
HttpEntity<List<JoinResourceContainer<PersonNotificationType>>> result = super.create(parentid, ids);
public HttpEntity<List<NotificationType>> create(@PathVariable String parentid, @RequestBody String[] ids) {
HttpEntity<List<NotificationType>> result = super.create(parentid, ids);
this.sendEmailMessage(EmailTemplate.NEW_SUBSCRIPTION, ids);
return result;
}
@Override
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
public HttpEntity<JoinResourceContainer<PersonNotificationType>> update(@PathVariable String parentid, @PathVariable String id,
@RequestBody PersonNotificationType joinResource) {
return super.update(parentid, id, joinResource);
}
@Override
@PreAuthorize("hasAnyAuthority('" + RoleApplication.ADMIN_ID + "', '" + RoleApplication.TRUSTED_CLIENT_ID + "', '" + RoleApplication.ROOT_ID
+ "') or @personPermissionService.isUserConnectedLinkedToPerson(#parentid)")
......@@ -99,6 +81,21 @@ public class PersonNotificationTypeController extends Relation2TiersController<P
return result;
}
@Override
protected String getParentFieldName() {
return "subscribers";
}
@Override
protected boolean addChildOnParent(Person person, NotificationType notificationType) {
return person.addNotificationType(notificationType);
}
@Override
protected boolean removeChildFromParent(Person person, NotificationType notificationType) {
return person.removeNotificationType(notificationType);
}
private void sendEmailMessage(EmailTemplate template, String ids[]) {
SolidifyEventPublisher.getPublisher().publishEvent(new EmailMessage(this.userService.getCurrentUser().getEmail(), template, ids));
}
......
......@@ -15,11 +15,9 @@ import ch.unige.solidify.util.AbstractRestClientTool;
import ch.unige.solidify.util.CollectionTool;
import ch.unige.solidify.util.StringTool;
import ch.unige.aou.model.display.NotificationTypePerson;
import ch.unige.aou.model.display.StructureValidationRight;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.publication.PublicationSubtype;
import ch.unige.aou.model.security.Role;
import ch.unige.aou.model.settings.Institution;
import ch.unige.aou.model.settings.Person;
import ch.unige.aou.model.settings.ResearchGroup;
......@@ -175,8 +173,8 @@ public class PersonClientService extends ResourceClientService<Person> implement
/****************************************************************************************************/
@Override
public List<NotificationTypePerson> getNotificationTypes(String personId) {
return this.findAllLinkedResources(personId, ResourceName.NOTIFICATION_TYPES, NotificationTypePerson.class);
public List<NotificationType> getSubscribedNotificationTypes(String personId) {
return this.findAllLinkedResources(personId, ResourceName.NOTIFICATION_TYPES, NotificationType.class);
}
/*
......
......@@ -5,8 +5,8 @@ import java.util.List;
import org.springframework.core.io.Resource;
import ch.unige.aou.model.display.NotificationTypePerson;
import ch.unige.aou.model.display.StructureValidationRight;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.settings.Institution;
import ch.unige.aou.model.settings.Person;
import ch.unige.aou.model.settings.ResearchGroup;
......@@ -61,7 +61,7 @@ public interface PersonClientServiceInterface extends ResourceClientServiceInter
StructureValidationRight getValidationRightsStructure(String personId, String structureId);
List<NotificationTypePerson> getNotificationTypes(String personId);
List<NotificationType> getSubscribedNotificationTypes(String personId);
/*
* Add notification type with default frequency: DAILY
......
package ch.unige.aou.service.admin;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import ch.unige.solidify.SolidifyConstants;
import ch.unige.solidify.rest.CollectionPage;
import ch.unige.solidify.util.AbstractRestClientTool;
import ch.unige.solidify.util.CollectionTool;
import ch.unige.aou.model.notification.Notification;
import ch.unige.aou.model.settings.Person;
import ch.unige.aou.rest.AouActionName;
import ch.unige.aou.rest.ModuleName;
import ch.unige.aou.rest.ResourceName;
import ch.unige.aou.service.CompositionResourceClientService;
@Service
public class PersonNotificationClientService extends CompositionResourceClientService<Person, Notification>
implements PersonNotificationClientServiceInterface {
private static final String PEOPLE_NOTIFICATION_TYPES_PATH =
SolidifyConstants.URL_SEP + ResourceName.PEOPLE + SolidifyConstants.URL_PARENT_ID + ResourceName.NOTIFICATIONS;
public PersonNotificationClientService(AbstractRestClientTool restClientTool, Environment env) {
super(PEOPLE_NOTIFICATION_TYPES_PATH, Notification.class, ModuleName.ADMIN, restClientTool, env);
}
@Override
public List<Notification> findAll(String personId) {
return this.findAll(personId, Notification.class);
}
public List<Notification> findAll(String personId, Map<String, String> queryParameters) {
if (!queryParameters.containsKey("size")) {
queryParameters.put("size", String.valueOf(CollectionPage.MAX_SIZE_PAGE));
}
String url = this.getBaseUrl() + this.resourcePath + "?";
for (final Map.Entry<String, String> entry : queryParameters.entrySet()) {
url += "&" + entry.getKey() + "=" + entry.getValue();
}
final Map<String, String> params = new HashMap<>();
params.put(SolidifyConstants.URL_PARENT_ID_FIELD, personId);
final RestTemplate restTemplate = this.restClientTool.getClient();
final String jsonString = restTemplate.getForObject(url, String.class, params);
return CollectionTool.getList(jsonString, Notification.class);
}
public Notification markNotificationAsRead(String personId, String notificationId) {
final String url = this.getBaseUrl() + this.resourcePath + SolidifyConstants.URL_ID + SolidifyConstants.URL_SEP + AouActionName.SET_READ;
final Map<String, String> params = new HashMap<>();
params.put(SolidifyConstants.URL_PARENT_ID_FIELD, personId);
params.put(SolidifyConstants.URL_ID_FIELD, notificationId);
final RestTemplate restTemplate = this.restClientTool.getClient();
return restTemplate.postForObject(url, null, Notification.class, params);
}
}
package ch.unige.aou.service.admin;
import ch.unige.aou.model.notification.Notification;
import ch.unige.aou.model.settings.Person;
import ch.unige.aou.service.CompositionResourceClientServiceInterface;
public interface PersonNotificationClientServiceInterface extends CompositionResourceClientServiceInterface<Person, Notification> {
}
package ch.unige.aou.service.admin;
import java.nio.file.Path;
import org.springframework.util.MultiValueMap;
import ch.unige.aou.model.publication.DocumentFile;
import ch.unige.aou.model.publication.Publication;
import ch.unige.aou.service.CompositionResourceClientServiceInterface;
import java.nio.file.Path;
public interface PublicationDocumentFileClientServiceInterface extends CompositionResourceClientServiceInterface<Publication, DocumentFile> {
DocumentFile upload(String parentId, org.springframework.core.io.Resource file, MultiValueMap<String, Object> parameters);
......
......@@ -42,7 +42,10 @@ public class PublicationTypeClientService extends ResourceClientService<Publicat
List<PublicationType> publicationTypes = this.searchByProperties(properties);
if (publicationTypes.size() == 1) {
return publicationTypes.get(0);
} else if (publicationTypes.isEmpty()) {
throw new SolidifyRuntimeException("No publication type with name '" + name + "' found");
} else {
throw new SolidifyRuntimeException("Too many publication type with name '" + name + "' found");
}
throw new SolidifyRuntimeException("Too many publication type with name '" + name + "' found");
}
}
package ch.unige.aou.repository;
import org.springframework.stereotype.Repository;
import ch.unige.solidify.repository.JoinRepository;
import ch.unige.aou.model.settings.PersonNotificationType;
@Repository
public interface PersonNotificationTypeRepository extends JoinRepository<PersonNotificationType> {
}
......@@ -26,11 +26,11 @@ import ch.unige.solidify.util.StringTool;
import ch.unige.aou.AouConstants;
import ch.unige.aou.dto.OAuth2ClientDTO;
import ch.unige.aou.model.display.NotificationTypePerson;
import ch.unige.aou.model.display.StructureValidationRight;
import ch.unige.aou.model.notification.Event;
import ch.unige.aou.model.notification.EventType;
import ch.unige.aou.model.notification.Notification;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.publication.AbstractContributor;
import ch.unige.aou.model.publication.CollaborationDTO;
import ch.unige.aou.model.publication.Comment;
......@@ -144,8 +144,10 @@ public abstract class AbstractAdminIT extends AbstractIT {
List<Structure> structures = this.structureService.searchByProperties(properties);
if (structures.size() == 1) {
return structures.get(0);
} else if (structures.isEmpty()) {
throw new SolidifyRuntimeException("no structure with name '" + this.TOP_STRUCTURE_NAME + "' found");
} else {
throw new SolidifyRuntimeException("multiple structures with name " + this.TOP_STRUCTURE_NAME + " found");
throw new SolidifyRuntimeException("multiple structures with name '" + this.TOP_STRUCTURE_NAME + "' found");
}
}
......@@ -159,10 +161,10 @@ public abstract class AbstractAdminIT extends AbstractIT {
List<Publication> publications = this.publicationService.searchByProperties(properties);
if (publications.size() == 1) {
return publications.get(0);
} else if (publications.size() > 1) {
throw new SolidifyRuntimeException("multiple publications with title " + this.PUBLICATION_TEST_TITLE + " found");
} else if (publications.isEmpty()) {
throw new SolidifyRuntimeException("no publication with title '" + this.PUBLICATION_TEST_TITLE + "' found");
} else {
throw new SolidifyRuntimeException("no publication with title " + this.PUBLICATION_TEST_TITLE + " found");
throw new SolidifyRuntimeException("multiple publications with title '" + this.PUBLICATION_TEST_TITLE + "' found");
}
}
......@@ -693,9 +695,9 @@ public abstract class AbstractAdminIT extends AbstractIT {
User myUser = this.userService.getAuthenticatedUser();
Person myPerson = this.getLinkedPersonToUser(myUser);
List<NotificationTypePerson> notifications = this.personService.getNotificationTypes(myPerson.getResId());
for (NotificationTypePerson ntp : notifications) {
this.personService.removeNotificationType(myPerson.getResId(), ntp.getItem().getNotificationType().getResId());
List<NotificationType> notifications = this.personService.getSubscribedNotificationTypes(myPerson.getResId());
for (NotificationType ntp : notifications) {
this.personService.removeNotificationType(myPerson.getResId(), ntp.getResId());
}
}
......
package ch.unige.aou.test.admin;
import static ch.unige.aou.test.AouTestConstants.STRUCTURE_PERMANENT;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ch.unige.solidify.model.RoleApplication;
import org.springframework.beans.factory.annotation.Autowired;
import ch.unige.aou.AouConstants;
import ch.unige.aou.model.display.StructureValidationRight;
import ch.unige.aou.model.notification.Event;
import ch.unige.aou.model.notification.Notification;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.publication.Publication;
import ch.unige.aou.model.security.User;
import ch.unige.aou.model.settings.Person;
import ch.unige.aou.model.settings.Structure;
import ch.unige.aou.service.admin.PersonNotificationClientService;
public abstract class AbstractNotificationIT extends AbstractAdminIT {
Notification createLocalNotification(NotificationType notificationType, boolean isInResearchGroup) {
User emitter = this.userService.getAuthenticatedUser();
@Autowired
protected PersonNotificationClientService personNotificationClientService;
//Add the person to the structure(with role indicated) or research group
this.restClientTool.sudoAdmin();
this.addUserToPermanentResearchGroupOrStructure(emitter.getPerson(), isInResearchGroup);
this.restClientTool.exitSudo();
Notification localNotification = new Notification();
localNotification.setRecipient(emitter.getPerson());
localNotification.setMessage(AouConstants.TEMPORARY_TEST_DATA_LABEL + " A message");
localNotification.setNotificationType(notificationType);
//Get event remote
this.restClientTool.sudoAdmin();
Event event = this.createEventRemote(emitter.getPerson(), notificationType.getEventType(), isInResearchGroup);
@Override
protected void createFixtures() {
this.restClientTool.sudoRoot();
this.createTopStructureFixture();
this.createPublicationTypeAndSubtypeFixtures(false);
this.restClientTool.exitSudo();
localNotification.setEvent(event);
return localNotification;
}
Notification createLocalNotificationForValidator(NotificationType notificationType) {
User emitter = this.userService.getAuthenticatedUser();
//Add the person as validator for the structure used for testing
List<Structure> structureList = this.structureService.searchByProperties(Collections.singletonMap("name", STRUCTURE_PERMANENT));
if (!structureList.isEmpty()) {
//check if the user is already in the structure with role validator
List<StructureValidationRight> structureValidationRights = this.personService
.getValidationRightStructuresList(emitter.getPerson().getResId());
if (structureValidationRights.stream().noneMatch(
svr -> svr.getPeople().contains(emitter.getPerson().getResId()) && svr.getResId().equals(structureList.get(0).getResId()))) {
this.personService.addValidationRightStructure(emitter.getPerson().getResId(), structureList.get(0).getResId());
}
}
Notification localNotification = new Notification();
localNotification.setRecipient(emitter.getPerson());
localNotification.setMessage(AouConstants.TEMPORARY_TEST_DATA_LABEL + " A message");
localNotification.setNotificationType(notificationType);
protected Publication createNotificationForCurrentUser() {
// create a publication and send it to validation
Publication publication = this.createPublicationFixture(this.getTemporaryTestLabel("Test notifications"));
this.publicationService.submitForApproval(publication.getResId());
//Get event remote
// ask feedback on publication --> it creates an event and a notification
this.restClientTool.sudoAdmin();
Event event = this.createEventRemote(emitter.getPerson(), notificationType.getEventType(), false);
this.publicationService.askFeedback(publication.getResId(), "ask feedback to test notification creation");
this.restClientTool.exitSudo();
localNotification.setEvent(event);
return localNotification;
}
Notification createRemoteNotification(Notification localNotification) {
return this.notificationService.create(localNotification);
return publication;
}
void inboxTest(NotificationType notificationType, boolean shouldBeInInbox, boolean isInResearchGroup) {
final Notification localNotification = this.createLocalNotification(notificationType, isInResearchGroup);
final Notification remoteNotification = this.createRemoteNotification(localNotification);
final Notification inboxNotification = this.notificationService.getInboxNotification(remoteNotification.getResId());
assertEquals(inboxNotification != null, shouldBeInInbox, "Notification created should be in inbox");
if (shouldBeInInbox) {
final List<Notification> notificationList = this.notificationService.getInboxNotifications();
assertTrue(notificationList.size() >= 1, "There should be at least one notification in the inbox");
assertTrue(notificationList.stream().anyMatch(n -> n.getResId().equals(inboxNotification.getResId())),
"There should be a least one notification with id= "+ inboxNotification.getResId());
protected Notification getLastNotificationForCurrentUser() {
Map<String, String> queryParameters = new HashMap<>();
queryParameters.put("sort", "lastUpdate.when,desc");
List<Notification> notifications = this.personNotificationClientService.findAll(this.getCurrentPerson().getResId(), queryParameters);
if (notifications != null && !notifications.isEmpty()) {
return notifications.get(0);
}
}
void inboxTestAsValidator(NotificationType notificationType, boolean shouldBeInInbox) {
final Notification localNotification = this.createLocalNotificationForValidator(notificationType);
final Notification remoteNotification = this.createRemoteNotification(localNotification);
final Notification inboxNotification = this.notificationService.getInboxNotification(remoteNotification.getResId());
assertEquals(inboxNotification != null, shouldBeInInbox, "Notification created should be in inbox");
if (shouldBeInInbox) {
final List<Notification> notificationList = this.notificationService.getInboxNotifications();
assertTrue(notificationList.size() >= 1, "There should be at least one notification in the inbox");
assertTrue(notificationList.stream().anyMatch(n -> n.getResId().equals(inboxNotification.getResId())),
"There should be a least one notification with id= "+ inboxNotification.getResId());
}
return null;
}
private boolean isApplicationRole(String role) {
for (RoleApplication roleApplication : RoleApplication.getRoleApplicationList()) {
if (roleApplication.getResId().equals(role)) {
return true;
}
}
return false;
protected Person getCurrentPerson() {
this.restClientTool.sudoRoot();
User user = this.userService.findOne(this.getCurrentUserId());
this.restClientTool.exitSudo();
return user.getPerson();
}
protected abstract String getCurrentUserId();
@Override
protected void deleteFixtures() {
Person person = userService.getAuthenticatedUser().getPerson();
this.restClientTool.sudoRoot();
this.clearNotificationFixtures();
this.clearEventsFixtures();
this.clearPublicationFixtures();
this.clearPublicationSubtypeFixtures();
this.clearPublicationTypeFixtures();
this.clearStructureFixtures();
this.clearResearchGroupFixtures();
this.clearRolesInStructuresOrResearchGroupsFixtures();
this.clearPersonValidatorStructureFixtures(person);
this.restClientTool.exitSudo();
}
}
package ch.unige.aou.test.admin;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.HttpClientErrorException;
import ch.unige.aou.model.notification.Event;
import ch.unige.aou.model.notification.Notification;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.publication.Publication;
import ch.unige.aou.model.security.User;
class NotificationAsAdminIT extends AbstractNotificationIT {
@Override
protected void setUser() {
this.restClientTool.sudoAdmin();
}
@Test
void markAsReadTest() {
final Notification localNotification = this.createLocalNotification(NotificationType.PUBLICATION_CREATED_STRUCTURE, false);
Notification remoteNotification = this.createRemoteNotification(localNotification);
assertNull(remoteNotification.getReadTime(), "Initial notification read time should be null");
final String notificationId = remoteNotification.getResId();
this.notificationService.markAsRead(notificationId);
remoteNotification = this.notificationService.findOne(notificationId);
assertNotNull(remoteNotification.getReadTime(), "Notification status should be processed");
}
void createNotificationTest() {
List<Notification> notifications = this.personNotificationClientService.findAll(this.getCurrentPerson().getResId());
assertNotNull(notifications);
int initialSize = notifications.size();
@Test
void creationTest() {
final Notification localNotification = this.createLocalNotification(NotificationType.PUBLICATION_CREATED_RESEARCH_GROUP, true);
final Notification remoteNotification = this.createRemoteNotification(localNotification);
assertEquals(localNotification.getRecipient().getFirstName(), remoteNotification.getRecipient().getFirstName());
assertEquals(localNotification.getRecipient().getLastName(), remoteNotification.getRecipient().getLastName());
assertEquals(localNotification.getMessage(), remoteNotification.getMessage());
this.createNotificationForCurrentUser();
notifications = this.personNotificationClientService.findAll(this.getCurrentPerson().getResId());
assertNotNull(notifications);
assertEquals(initialSize + 1, notifications.size());
}
@Test
void deletionTest() {
final Notification localNotification = this.createLocalNotification(NotificationType.PUBLICATION_CREATED_RESEARCH_GROUP, true);
final Notification remoteNotification = this.createRemoteNotification(localNotification);
this.notificationService.delete(remoteNotification.getResId());
assertNull(this.notificationService.findOne(remoteNotification.getResId()));
void getNotificationWithEventAndPublicationIdTest() {
Publication notifiedPublication = this.createNotificationForCurrentUser();
Map<String, String> queryParameters = new HashMap<>();
queryParameters.put("sort", "lastUpdate.when,desc");
Notification notification = this.getLastNotificationForCurrentUser();
assertNotNull(notification);
Event event = notification.getEvent();
assertNotNull(event);
assertEquals(notifiedPublication.getResId(), event.getPublication().getResId());
}
@Test
void inboxTest() {
inboxTest(NotificationType.PUBLICATION_CREATED_STRUCTURE, true, false);
inboxTest(NotificationType.PUBLICATION_CREATED_RESEARCH_GROUP, true, false);
void markNotificationAsReadTest() {
this.createNotificationForCurrentUser();
Notification notification = this.getLastNotificationForCurrentUser();
assertNotNull(notification);
assertNull(notification.getReadTime(), "Initial notification read time should be null");
inboxTest(NotificationType.PUBLICATION_CREATED_RESEARCH_GROUP, true, true);
inboxTest(NotificationType.PUBLICATION_CREATED_STRUCTURE, true, true);
inboxTest(NotificationType.PUBLICATION_TO_VALIDATE, true, true);
OffsetDateTime beforeReadTime = OffsetDateTime.now();
this.personNotificationClientService.markNotificationAsRead(this.getCurrentPerson().getResId(), notification.getResId());
notification = this.getLastNotificationForCurrentUser();
assertNotNull(notification);
assertNotNull(notification.getReadTime(), "Notification should have a read time set at this step");
assertTrue(notification.getReadTime().isAfter(beforeReadTime));
}
@Test
void inboxStructuresAsValidatorTest() {
inboxTest(NotificationType.PUBLICATION_TO_VALIDATE, false, false);
inboxTestAsValidator(NotificationType.PUBLICATION_TO_VALIDATE, true);
void canReadOtherUserNotificationTest() {
this.restClientTool.sudoUser();
Publication notifiedPublication = this.createNotificationForCurrentUser();
this.restClientTool.exitSudo();
// user has no notification yet
Notification notification = this.getLastNotificationForCurrentUser();
assertNull(notification);
// although the notification exists and is readable by the user
this.restClientTool.sudoRoot();
User userUser = this.userService.findOne(this.TEST_USER_USER_ID);
this.restClientTool.exitSudo();
this.restClientTool.sudoUser();
Map<String, String> queryParameters = new HashMap<>();
queryParameters.put("sort", "lastUpdate.when,desc");
List<Notification> notifications = this.personNotificationClientService.findAll(userUser.getPerson().getResId(), queryParameters);
assertNotNull(notifications);
assertFalse(notifications.isEmpty());
assertEquals(notifiedPublication.getResId(), notifications.get(0).getEvent().getPublication().getResId());
this.restClientTool.exitSudo();
// try to read the user notification directly
Notification userNotification = notifications.get(0);
assertDoesNotThrow(() -> {
this.personNotificationClientService.findOne(userUser.getPerson().getResId(), userNotification.getResId());
});
}
@Test
void sentBoxTest() {
final Notification localNotification = this.createLocalNotification(NotificationType.PUBLICATION_CREATED_STRUCTURE, false);
final Notification remoteNotification = this.createRemoteNotification(localNotification);
final Notification sentNotification = notificationService.findOne(remoteNotification.getResId());
assertNotNull(sentNotification, "Sent notification should be in sent box");
void cannotDeleteNotificationTest() {
this.createNotificationForCurrentUser();
Notification notification = this.getLastNotificationForCurrentUser();
assertNotNull(notification);
HttpClientErrorException e = assertThrows(HttpClientErrorException.class, () -> {
this.personNotificationClientService.delete(this.getCurrentPerson().getResId(), notification.getResId());
});
assertEquals(HttpStatus.FORBIDDEN, e.getStatusCode());
}
@Override
protected String getCurrentUserId() {
return this.TEST_USER_ADMIN_ID;
}
}
package ch.unige.aou.test.admin;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.HttpClientErrorException;
import ch.unige.aou.model.notification.Event;
import ch.unige.aou.model.notification.Notification;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.publication.Publication;
import ch.unige.aou.model.security.User;
class NotificationAsUserIT extends AbstractNotificationIT {
@Test
void inboxTest() {
this.inboxTest(NotificationType.MY_PUBLICATION_COMMENTED, true, true);
this.inboxTest(NotificationType.MY_PUBLICATION_COMMENTED, true, false);
void createNotificationTest() {
List<Notification> notifications = this.personNotificationClientService.findAll(this.getCurrentPerson().getResId());
assertNotNull(notifications);
int initialSize = notifications.size();
this.createNotificationForCurrentUser();
notifications = this.personNotificationClientService.findAll(this.getCurrentPerson().getResId());
assertNotNull(notifications);
assertEquals(initialSize + 1, notifications.size());
}
@Test
void getNotificationWithEventAndPublicationIdTest() {
Publication notifiedPublication = this.createNotificationForCurrentUser();
Map<String, String> queryParameters = new HashMap<>();
queryParameters.put("sort", "lastUpdate.when,desc");
Notification notification = this.getLastNotificationForCurrentUser();
assertNotNull(notification);
Event event = notification.getEvent();
assertNotNull(event);
assertEquals(notifiedPublication.getResId(), event.getPublication().getResId());
}
@Test
void markNotificationAsReadTest() {
this.createNotificationForCurrentUser();
Notification notification = this.getLastNotificationForCurrentUser();
assertNotNull(notification);
assertNull(notification.getReadTime(), "Initial notification read time should be null");
OffsetDateTime beforeReadTime = OffsetDateTime.now();
this.personNotificationClientService.markNotificationAsRead(this.getCurrentPerson().getResId(), notification.getResId());
notification = this.getLastNotificationForCurrentUser();
assertNotNull(notification);
assertNotNull(notification.getReadTime(), "Notification should have a read time set at this step");
assertTrue(notification.getReadTime().isAfter(beforeReadTime));
}
@Test
void markAsReadTest() {
final Notification localNotification = this.createLocalNotification(NotificationType.MY_PUBLICATION_COMMENTED, true);
Notification remoteNotification = this.createRemoteNotification(localNotification);
assertNull(remoteNotification.getReadTime(), "Initial notification read time should be null");
final String notificationId = remoteNotification.getResId();
this.notificationService.markAsRead(notificationId);
remoteNotification = this.notificationService.getInboxNotification(notificationId);
assertNotNull(remoteNotification.getReadTime(), "Notification status should be processed");
void cannotReadOtherUserNotificationTest() {
this.restClientTool.sudoAdmin();
Publication notifiedPublication = this.createNotificationForCurrentUser();
this.restClientTool.exitSudo();
// user has no notification yet
Notification notification = this.getLastNotificationForCurrentUser();
assertNull(notification);
// although the notification exists and is readable by the admin
this.restClientTool.sudoRoot();
User adminUser = this.userService.findOne(this.TEST_USER_ADMIN_ID);
this.restClientTool.exitSudo();
this.restClientTool.sudoAdmin();
Map<String, String> queryParameters = new HashMap<>();
queryParameters.put("sort", "lastUpdate.when,desc");
List<Notification> notifications = this.personNotificationClientService.findAll(adminUser.getPerson().getResId(), queryParameters);
assertNotNull(notifications);
assertFalse(notifications.isEmpty());
assertEquals(notifiedPublication.getResId(), notifications.get(0).getEvent().getPublication().getResId());
this.restClientTool.exitSudo();
// try to read the admin notification directly
Notification adminNotification = notifications.get(0);
HttpClientErrorException e = assertThrows(HttpClientErrorException.class, () -> {
this.personNotificationClientService.findOne(adminUser.getPerson().getResId(), adminNotification.getResId());
});
assertEquals(HttpStatus.FORBIDDEN, e.getStatusCode());
}
@Test
void cannotDeleteNotificationTest() {
this.createNotificationForCurrentUser();
Notification notification = this.getLastNotificationForCurrentUser();
assertNotNull(notification);
HttpClientErrorException e = assertThrows(HttpClientErrorException.class, () -> {
this.personNotificationClientService.delete(this.getCurrentPerson().getResId(), notification.getResId());
});
assertEquals(HttpStatus.FORBIDDEN, e.getStatusCode());
}
@Override
protected String getCurrentUserId() {
return this.TEST_USER_USER_ID;
}
}
......@@ -16,7 +16,6 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.HttpClientErrorException;
import ch.unige.aou.model.display.NotificationTypePerson;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.security.User;
import ch.unige.aou.model.settings.Person;
......@@ -187,21 +186,20 @@ class PersonAsUserIT extends AbstractAdminIT {
Person myPerson = this.getLinkedPersonToUser(myUser);
// check the notification types that has been already described
List<NotificationTypePerson> notifications = this.personService.getNotificationTypes(myPerson.getResId());
final int initialState = notifications.size();
List<NotificationType> subscribedNotificationTypes = this.personService.getSubscribedNotificationTypes(myPerson.getResId());
final int initialState = subscribedNotificationTypes.size();
// Add new notification type to person
this.personService.addNotificationType(myPerson.getResId(), NotificationType.MY_PUBLICATION_COMMENTED.getResId());
notifications = this.personService.getNotificationTypes(myPerson.getResId());
subscribedNotificationTypes = this.personService.getSubscribedNotificationTypes(myPerson.getResId());
assertEquals(initialState + 1, notifications.size());
assertEquals(initialState + 1, subscribedNotificationTypes.size());
// Test added person on the OrganizationalUnit
for (final NotificationTypePerson n : notifications) {
if (n.getResId().equals(NotificationType.MY_PUBLICATION_COMMENTED.getResId())) {
assertNotNull(n);
assertEquals(NotificationType.MY_PUBLICATION_COMMENTED.getEventType(), n.getEventType());
assertEquals(NotificationType.MY_PUBLICATION_COMMENTED.getNotifiedApplicationRole(), n.getNotifiedApplicationRole());
for (final NotificationType notificationType : subscribedNotificationTypes) {
if (notificationType.getResId().equals(NotificationType.MY_PUBLICATION_COMMENTED.getResId())) {
assertNotNull(notificationType);
assertEquals(NotificationType.MY_PUBLICATION_COMMENTED.getEventType(), notificationType.getEventType());
}
}
......@@ -209,8 +207,8 @@ class PersonAsUserIT extends AbstractAdminIT {
this.personService.removeNotificationType(myPerson.getResId(), NotificationType.MY_PUBLICATION_COMMENTED.getResId());
// Test remove
notifications = this.personService.getNotificationTypes(myPerson.getResId());
assertEquals(initialState, notifications.size());
subscribedNotificationTypes = this.personService.getSubscribedNotificationTypes(myPerson.getResId());
assertEquals(initialState, subscribedNotificationTypes.size());
}
@Test
......
......@@ -112,6 +112,7 @@ public class AouConstants {
public static final String DB_PUBLICATION_ID = "publicationId";
public static final String DB_EVENT_TYPE_ID = "event_type_id";
public static final String DB_NOTIFICATION_ID = "notification_id";
public static final String DB_NOTIFICATION_TYPE_ID = "notification_type_id";
public static final String DB_CN_INDIVIDU = "cnIndividu";
// Index
......
package ch.unige.aou.model.display;
import java.util.List;
import javax.persistence.Transient;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.settings.PersonNotificationType;
public class NotificationTypePerson extends NotificationType implements ExtendedResourceInterface<PersonNotificationType> {
@Transient
PersonNotificationType personNotificationType;
public NotificationTypePerson() {
}
public NotificationTypePerson(NotificationType notificationType) {
this.mapResourceToExtendedResource(this, notificationType);
}
@Override
public PersonNotificationType getItem() {
return this.personNotificationType;
}
@Override
public List<PersonNotificationType> getItems() {
return null;
}
@Override
public void setItem(PersonNotificationType item) {
this.personNotificationType = item;
}
@Override
public void setItems(List<PersonNotificationType> items) {
}
}
package ch.unige.aou.model.display;
import ch.unige.solidify.rest.JoinResourceContainer;
import ch.unige.solidify.rest.ResourceBase;
import ch.unige.solidify.util.ReflectionTool;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.settings.PersonNotificationType;
public class NotificationTypeWithJoinInfosDTO extends NotificationType implements JoinResourceContainer<PersonNotificationType> {
private PersonNotificationType joinResource;
public NotificationTypeWithJoinInfosDTO() {
}
public NotificationTypeWithJoinInfosDTO(PersonNotificationType personNotificationType) {
ReflectionTool.copyFields(this, personNotificationType.getNotificationType(), ResourceBase.class);
this.add(personNotificationType.getNotificationType().getLinks());
this.joinResource = personNotificationType;
}
@Override
public PersonNotificationType getJoinResource() {
return this.joinResource;
}
}
package ch.unige.aou.model.notification;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import javax.persistence.CascadeType;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonIgnore;
import ch.unige.solidify.model.RoleApplication;
import ch.unige.aou.model.AouResourceNormalized;
import ch.unige.aou.model.security.Role;
import ch.unige.aou.model.settings.PersonNotificationType;
import ch.unige.aou.model.settings.Person;
@Entity
public class NotificationType extends AouResourceNormalized<NotificationType> {
// For User
public static final NotificationType PUBLICATION_CREATED_RESEARCH_GROUP = new NotificationType("PUBLICATION_CREATED_RESEARCH_GROUP", Role.USER,
null, EventType.PUBLICATION_CREATED);
public static final NotificationType PUBLICATION_SUBMITTED_RESEARCH_GROUP = new NotificationType("PUBLICATION_SUBMITTED_RESEARCH_GROUP",
Role.USER, null, EventType.PUBLICATION_SUBMITTED);
public static final NotificationType PUBLICATION_CREATED_STRUCTURE = new NotificationType("PUBLICATION_CREATED_STRUCTURE", Role.USER, null,
EventType.PUBLICATION_CREATED);
public static final NotificationType PUBLICATION_SUBMITTED_STRUCTURE = new NotificationType("PUBLICATION_SUBMITTED_STRUCTURE", Role.USER, null,
EventType.PUBLICATION_SUBMITTED);
public static final NotificationType MY_PUBLICATION_COMMENTED = new NotificationType("MY_PUBLICATION_COMMENTED", Role.USER, null,
public static final NotificationType MY_PUBLICATION_COMMENTED = new NotificationType("MY_PUBLICATION_COMMENTED",
EventType.COMMENT_IN_PUBLICATION);
public static final NotificationType MY_PUBLICATION_REJECTED = new NotificationType("MY_PUBLICATION_REJECTED", Role.USER, null,
EventType.PUBLICATION_REJECTED);
public static final NotificationType MY_PUBLICATION_VALIDATED = new NotificationType("MY_PUBLICATION_VALIDATED", Role.USER, null,
public static final NotificationType MY_PUBLICATION_REJECTED = new NotificationType("MY_PUBLICATION_REJECTED", EventType.PUBLICATION_REJECTED);
public static final NotificationType MY_PUBLICATION_VALIDATED = new NotificationType("MY_PUBLICATION_VALIDATED",
EventType.PUBLICATION_SUBMITTED);
public static final NotificationType MY_PUBLICATION_FEEDBACK_REQUIRED = new NotificationType("MY_PUBLICATION_FEEDBACK_REQUIRED", Role.USER,
null,
public static final NotificationType MY_PUBLICATION_FEEDBACK_REQUIRED = new NotificationType("MY_PUBLICATION_FEEDBACK_REQUIRED",
EventType.PUBLICATION_FEEDBACK_REQUIRED);
public static final NotificationType MY_INDIRECT_PUBLICATION_VALIDATED = new NotificationType("MY_INDIRECT_PUBLICATION_VALIDATED", Role.USER,
null, EventType.PUBLICATION_SUBMITTED);
public static final NotificationType MY_INDIRECT_PUBLICATION_VALIDATED = new NotificationType("MY_INDIRECT_PUBLICATION_VALIDATED",
EventType.PUBLICATION_SUBMITTED);
// For Validator
public static final NotificationType PUBLICATION_TO_VALIDATE = new NotificationType("PUBLICATION_TO_VALIDATE", Role.VALIDATOR, null,
public static final NotificationType PUBLICATION_TO_VALIDATE = new NotificationType("PUBLICATION_TO_VALIDATE",
EventType.PUBLICATION_TO_VALIDATE);
public static final NotificationType PUBLICATION_TO_VALIDATE_COMMENTED = new NotificationType("PUBLICATION_TO_VALIDATE_COMMENTED",
Role.VALIDATOR, null, EventType.COMMENT_IN_PUBLICATION);
// For Admin
public static final NotificationType PUBLICATION_IN_ERROR = new NotificationType("PUBLICATION_IN_ERROR", null, RoleApplication.ADMIN,
EventType.PUBLICATION_CREATED);
EventType.COMMENT_IN_PUBLICATION);
@NotNull
@ManyToOne
private EventType eventType;
@ManyToOne
private Role notifiedRoleStructure;
@ManyToOne
private RoleApplication notifiedApplicationRole;
@ManyToMany(mappedBy = "subscribedNotificationTypes")
@JsonIgnore
@OneToMany(mappedBy = PersonNotificationType.PATH_TO_NOTIFICATION_TYPE, cascade = CascadeType.ALL, orphanRemoval = true)
private List<PersonNotificationType> personsToNotify = new ArrayList<>();
private Set<Person> subscribers;
public NotificationType(String resId, Role notifiedRoleStructureOrResearchGroup, RoleApplication notifiedApplicationRole,
EventType eventType) {
public NotificationType(String resId, EventType eventType) {
this.setResId(resId);
this.notifiedRoleStructure = notifiedRoleStructureOrResearchGroup;
this.notifiedApplicationRole = notifiedApplicationRole;
this.eventType = eventType;
}
......@@ -80,10 +51,28 @@ public class NotificationType extends AouResourceNormalized<NotificationType> {
}
public static List<NotificationType> getAllNotificationTypes() {
return Arrays.asList(PUBLICATION_CREATED_RESEARCH_GROUP, PUBLICATION_CREATED_STRUCTURE, PUBLICATION_TO_VALIDATE,
PUBLICATION_SUBMITTED_RESEARCH_GROUP, PUBLICATION_SUBMITTED_STRUCTURE, PUBLICATION_IN_ERROR,
MY_PUBLICATION_COMMENTED, PUBLICATION_TO_VALIDATE_COMMENTED, MY_PUBLICATION_REJECTED, MY_PUBLICATION_VALIDATED,
MY_INDIRECT_PUBLICATION_VALIDATED, MY_PUBLICATION_FEEDBACK_REQUIRED);
return Arrays.asList(PUBLICATION_TO_VALIDATE, MY_PUBLICATION_COMMENTED, PUBLICATION_TO_VALIDATE_COMMENTED, MY_PUBLICATION_REJECTED,
MY_PUBLICATION_VALIDATED, MY_INDIRECT_PUBLICATION_VALIDATED, MY_PUBLICATION_FEEDBACK_REQUIRED);
}
public Set<Person> getSubscribers() {
return this.subscribers;
}
public boolean addSubscriber(Person p) {
final boolean result = this.subscribers.add(p);
if (!p.getSubscribedNotifications().contains(this)) {
p.addNotificationType(this);
}
return result;
}
public boolean removeSubscriber(Person p) {
final boolean result = this.subscribers.remove(p);
if (p.getSubscribedNotifications().contains(this)) {
p.removeNotificationType(this);
}
return result;
}
@Override
......@@ -109,20 +98,4 @@ public class NotificationType extends AouResourceNormalized<NotificationType> {
public void setEventType(EventType eventType) {
this.setCurrentProperty(eventType);
}
public Role getNotifiedRoleStructure() {
return this.notifiedRoleStructure;
}
public void setNotifiedRoleStructure(Role notifiedRoleStructureOrResearchGroup) {
this.setCurrentProperty(notifiedRoleStructureOrResearchGroup);
}
public RoleApplication getNotifiedApplicationRole() {
return this.notifiedApplicationRole;
}
public void setNotifiedApplicationRole(RoleApplication notifiedApplicationRole) {
this.setCurrentProperty(notifiedApplicationRole);
}
}
......@@ -30,6 +30,7 @@ import ch.unige.aou.model.AouSearchableResourceNormalized;
import ch.unige.aou.model.Image;
import ch.unige.aou.model.ImageInterface;
import ch.unige.aou.model.PersonInterface;
import ch.unige.aou.model.notification.NotificationType;
import ch.unige.aou.model.security.PersonAvatar;
import ch.unige.aou.rest.AouActionName;
import ch.unige.aou.rest.ModuleName;
......@@ -83,8 +84,11 @@ public class Person extends AouSearchableResourceNormalized<Person> implements P
private Set<ResearchGroup> researchGroups = new HashSet<>();
@JsonIgnore
@OneToMany(mappedBy = PersonNotificationType.PATH_TO_PERSON, cascade = CascadeType.ALL, orphanRemoval = true)
private List<PersonNotificationType> subscribedNotifications = new ArrayList<>();
@ManyToMany
@JoinTable(name = "personNotificationTypes", joinColumns = { @JoinColumn(name = AouConstants.DB_PERSON_ID) }, inverseJoinColumns = {
@JoinColumn(name = AouConstants.DB_NOTIFICATION_TYPE_ID) }, uniqueConstraints = {
@UniqueConstraint(columnNames = { AouConstants.DB_PERSON_ID, AouConstants.DB_NOTIFICATION_TYPE_ID }) })
private Set<NotificationType> subscribedNotificationTypes = new HashSet<>();
/****************************************************************/
......@@ -104,6 +108,22 @@ public class Person extends AouSearchableResourceNormalized<Person> implements P
return result;
}
public boolean addNotificationType(NotificationType notificationType) {
final boolean result = this.subscribedNotificationTypes.add(notificationType);
if (!notificationType.getSubscribers().contains(this)) {
notificationType.addSubscriber(this);
}
return result;
}
public boolean removeNotificationType(NotificationType notificationType) {
final boolean result = this.subscribedNotificationTypes.remove(notificationType);
if (notificationType.getSubscribers().contains(this)) {
notificationType.removeSubscriber(this);
}
return result;
}
public boolean addStructure(Structure structure) {
final boolean result = this.structures.add(structure);
if (!structure.getPeople().contains(this)) {
......@@ -182,8 +202,8 @@ public class Person extends AouSearchableResourceNormalized<Person> implements P
}
@JsonIgnore
public List<PersonNotificationType> getSubscribedNotifications() {
return this.subscribedNotifications;
public Set<NotificationType> getSubscribedNotifications() {
return this.subscribedNotificationTypes;
}
@Override
......