diff --git a/src/main/java/org/genesys/catalog/service/impl/DatasetServiceImpl.java b/src/main/java/org/genesys/catalog/service/impl/DatasetServiceImpl.java index 551b1616f9d82a7bba258100cb724951bfd96cad..d8f5003fa609aee544fa51f896dbaf99c17353b1 100644 --- a/src/main/java/org/genesys/catalog/service/impl/DatasetServiceImpl.java +++ b/src/main/java/org/genesys/catalog/service/impl/DatasetServiceImpl.java @@ -67,6 +67,8 @@ import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; import org.genesys.filerepository.model.RepositoryFile; import org.genesys.filerepository.service.RepositoryService; +import org.genesys2.server.component.aspect.NotifyOnPublished; +import org.genesys2.server.component.aspect.NotifyForReview; import org.genesys2.server.component.security.AsAdminInvoker; import org.genesys2.server.component.security.SecurityUtils; import org.genesys2.server.exception.InvalidApiUsageException; @@ -802,6 +804,7 @@ public class DatasetServiceImpl implements DatasetService { @Override @Transactional @PreAuthorize("hasRole('ADMINISTRATOR')") + @NotifyOnPublished public Dataset approveDataset(final Dataset dataset) { Dataset loaded = getUnpublishedDataset(dataset); @@ -876,6 +879,7 @@ public class DatasetServiceImpl implements DatasetService { @Override @Transactional @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#dataset, 'write')") + @NotifyForReview public Dataset reviewDataset(final Dataset dataset) { final Dataset loaded = getUnpublishedDataset(dataset); diff --git a/src/main/java/org/genesys/catalog/service/impl/DescriptorListServiceImpl.java b/src/main/java/org/genesys/catalog/service/impl/DescriptorListServiceImpl.java index 9b8979d86764aac3496559201b4867453833b02f..2b000f44a09b24218891c1850065394af40d2b35 100644 --- a/src/main/java/org/genesys/catalog/service/impl/DescriptorListServiceImpl.java +++ b/src/main/java/org/genesys/catalog/service/impl/DescriptorListServiceImpl.java @@ -41,6 +41,8 @@ import org.genesys.catalog.model.traits.DescriptorList; import org.genesys.catalog.persistence.traits.DescriptorListRepository; import org.genesys.catalog.service.DescriptorListService; import org.genesys.catalog.service.DescriptorService; +import org.genesys2.server.component.aspect.NotifyOnPublished; +import org.genesys2.server.component.aspect.NotifyForReview; import org.genesys2.server.component.security.SecurityUtils; import org.genesys2.server.exception.InvalidApiUsageException; import org.genesys2.server.exception.NotFoundElement; @@ -401,6 +403,7 @@ public class DescriptorListServiceImpl implements DescriptorListService { @Override @Transactional @PreAuthorize("hasRole('ADMINISTRATOR')") + @NotifyOnPublished public DescriptorList approveDescriptorList(final DescriptorList descriptorList) { final DescriptorList loaded = getUnpublishedDescriptorList(descriptorList); @@ -429,6 +432,7 @@ public class DescriptorListServiceImpl implements DescriptorListService { @Override @Transactional @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#descriptorList, 'WRITE')") + @NotifyForReview public DescriptorList reviewDescriptorList(final DescriptorList descriptorList) { final DescriptorList loaded = getUnpublishedDescriptorList(descriptorList); diff --git a/src/main/java/org/genesys2/server/component/aspect/EmailNotificationAspect.java b/src/main/java/org/genesys2/server/component/aspect/EmailNotificationAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..a10dd676d438ae4c9d68577021c024e0dac07a8c --- /dev/null +++ b/src/main/java/org/genesys2/server/component/aspect/EmailNotificationAspect.java @@ -0,0 +1,155 @@ +/* + * Copyright 2019 Global Crop Diversity Trust + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.genesys2.server.component.aspect; + +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.genesys.blocks.model.AuditedVersionedModel; +import org.genesys.blocks.model.UuidModel; +import org.genesys.catalog.model.dataset.Dataset; +import org.genesys.catalog.model.traits.DescriptorList; +import org.genesys2.server.model.impl.Article; +import org.genesys2.server.model.impl.Subset; +import org.genesys2.server.model.impl.User; +import org.genesys2.server.service.ContentService; +import org.genesys2.server.service.EMailService; +import org.genesys2.server.service.UserService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * @author Maxym Borodenko + */ +@Aspect +@Component +public class EmailNotificationAspect { + + private final static Logger LOG = LoggerFactory.getLogger(EmailNotificationAspect.class); + + @Value("${mail.helpdesk}") + private String helpdeskEmail; + + @Value("${frontend.url}") + private String frontendUrl; + + @Autowired + private EMailService emailService; + + @Autowired + private ContentService contentService; + + @Autowired + private UserService userService; + + @AfterReturning(value = "execution(public * *(..)) && @annotation(NotifyForReview)", returning = "result") + public void afterSentToReview(final Object result) { + + if (result == null) { + LOG.warn("@NotifyOnReview received null object"); + return; + } + + // Create the root hash + final Map root = new HashMap<>(); + + if (result instanceof Dataset) { + root.put("publicationType", "dataset"); + root.put("title", ((Dataset) result).getTitle()); + } else if (result instanceof Subset) { + root.put("publicationType", "subset"); + root.put("title", ((Subset) result).getTitle()); + } else if (result instanceof DescriptorList) { + root.put("publicationType", "descriptor list"); + root.put("title", ((DescriptorList) result).getTitle()); + } else { + LOG.warn("@NotifyOnReview not supported for {}", result.getClass()); + return; + } + + root.put("uuid", ((UuidModel) result).getUuid().toString()); + root.put("baseUrl", frontendUrl); + + try { + Article article = contentService.getGlobalArticle(ContentService.REVIEW_PUBLICATION, Locale.ENGLISH); + final String mailBody = contentService.processTemplate(article.getBody(), root); + final String mailSubject = article.getTitle(); + LOG.debug(">>>{}", mailBody); + + emailService.sendMail(mailSubject, mailBody, helpdeskEmail); + + } catch (Throwable e) { + LOG.warn("Error processing @NotifyForReview: {}", e.getMessage(), e); + } + } + + @AfterReturning(value = "execution(public * *(..)) && @annotation(NotifyOnPublished)", returning = "result") + public void afterPublishing(final Object result) { + + if (result == null) { + LOG.warn("@NotifyOnPublished received null object"); + return; + } + + Long creatorId = ((AuditedVersionedModel) result).getCreatedBy(); + if (creatorId == null) { + LOG.warn("Skipping @NotifyOnPublished, no createdBy for {}", result); + return; + } + + // Create the root hash + final Map root = new HashMap<>(); + + if (result instanceof Dataset) { + root.put("publicationType", "dataset"); + root.put("title", ((Dataset) result).getTitle()); + } else if (result instanceof Subset) { + root.put("publicationType", "subset"); + root.put("title", ((Subset) result).getTitle()); + } else if (result instanceof DescriptorList) { + root.put("publicationType", "descriptor list"); + root.put("title", ((DescriptorList) result).getTitle()); + } else { + LOG.warn("@NotifyOnPublished not supported for {}", result.getClass()); + return; + } + + root.put("uuid", ((UuidModel) result).getUuid().toString()); + root.put("baseUrl", frontendUrl); + + try { + Article article = contentService.getGlobalArticle(ContentService.PUBLISH_PUBLICATION, LocaleContextHolder.getLocale()); + + final String mailBody = contentService.processTemplate(article.getBody(), root); + final String mailSubject = article.getTitle(); + LOG.debug(">>>{}", mailBody); + + User user = userService.getUser(creatorId); + + emailService.sendMail(mailSubject, mailBody, user.getEmail()); + } catch (Throwable e) { + LOG.warn("Error processing @NotifyForReview: {}", e.getMessage(), e); + } + } +} diff --git a/src/main/java/org/genesys2/server/component/aspect/NotifyForReview.java b/src/main/java/org/genesys2/server/component/aspect/NotifyForReview.java new file mode 100644 index 0000000000000000000000000000000000000000..30814c8e2960ddf1c11277811d3ccc2d8b0dae73 --- /dev/null +++ b/src/main/java/org/genesys2/server/component/aspect/NotifyForReview.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019 Global Crop Diversity Trust + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.genesys2.server.component.aspect; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Maxym Borodenko + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface NotifyForReview { + // marker annotation +} diff --git a/src/main/java/org/genesys2/server/component/aspect/NotifyOnPublished.java b/src/main/java/org/genesys2/server/component/aspect/NotifyOnPublished.java new file mode 100644 index 0000000000000000000000000000000000000000..dd7623fd0633cd04ecbbf8c5bcd6a1a8e7b7569f --- /dev/null +++ b/src/main/java/org/genesys2/server/component/aspect/NotifyOnPublished.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019 Global Crop Diversity Trust + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.genesys2.server.component.aspect; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Maxym Borodenko + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface NotifyOnPublished { + // marker annotation +} diff --git a/src/main/java/org/genesys2/server/service/ContentService.java b/src/main/java/org/genesys2/server/service/ContentService.java index e7d13592e49a3e74e55d82635e29144b96baa770..bfe759f329a081fb6d2e8969f295408f0673ab9a 100644 --- a/src/main/java/org/genesys2/server/service/ContentService.java +++ b/src/main/java/org/genesys2/server/service/ContentService.java @@ -69,7 +69,9 @@ public interface ContentService { public final String DELETE_ACCOUNT_SENT = "account-delete-requested"; public final String DELETE_ACCOUNT_CONFIRMED = "account-delete-confirmed"; public final String SMTP_DELETE_ACCOUNT_INPROGRESS = "smtp-delete-account-inprogress"; - + public final String PUBLISH_PUBLICATION = "publish-published"; + public final String REVIEW_PUBLICATION = "publish-for-review"; + List lastNews(); Page allNews(Pageable page); diff --git a/src/main/java/org/genesys2/server/service/impl/SubsetServiceImpl.java b/src/main/java/org/genesys2/server/service/impl/SubsetServiceImpl.java index 67a9d7ef66a0bd6a86586184e82552860edd0d72..5783e2647c3421f153cdd8fc5a707d90bb2c3055 100644 --- a/src/main/java/org/genesys2/server/service/impl/SubsetServiceImpl.java +++ b/src/main/java/org/genesys2/server/service/impl/SubsetServiceImpl.java @@ -39,6 +39,8 @@ import com.google.common.collect.Sets; import org.apache.commons.lang3.StringUtils; import org.genesys.blocks.security.service.CustomAclService; import org.genesys.catalog.model.Partner; +import org.genesys2.server.component.aspect.NotifyOnPublished; +import org.genesys2.server.component.aspect.NotifyForReview; import org.genesys2.server.component.security.SecurityUtils; import org.genesys2.server.exception.InvalidApiUsageException; import org.genesys2.server.exception.NotFoundElement; @@ -457,6 +459,7 @@ public class SubsetServiceImpl implements SubsetService { @Override @Transactional @PreAuthorize("hasRole('ADMINISTRATOR')") + @NotifyOnPublished public Subset approveSubset(final Subset subset) { final Subset loadedSubset = getUnpublishedSubset(subset); @@ -487,6 +490,7 @@ public class SubsetServiceImpl implements SubsetService { @Override @Transactional @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#subset, 'write')") + @NotifyForReview public Subset reviewSubset(final Subset subset) { final Subset loadedSubset = getUnpublishedSubset(subset); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index cf4dac7d0eb4b3e8d1c91bd6a7b41cb559b15394..dcf78e2bc8491b971f023713d8b4cf84638c6caa 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -100,6 +100,7 @@ mail.port=25 mail.user.from=test@localhost mail.requests.to=test@localhost +mail.helpdesk=helpdesk@genesys-pgr.org mail.user.password= mail.user.name= diff --git a/src/main/resources/default-content/publish-for-review.json b/src/main/resources/default-content/publish-for-review.json new file mode 100644 index 0000000000000000000000000000000000000000..ce73515278cf8aeee30669d4efba687958bef8e8 --- /dev/null +++ b/src/main/resources/default-content/publish-for-review.json @@ -0,0 +1,7 @@ +{ + "template": true, + "en": { + "title": "New publication submitted", + "body": "## VELOCITY\n

${baseUrl}
New ${publicationType} submitted

\n\n

The ${publicationType} titled \"${title}\" is ready for your review.

\n\n

Review it at \n\n#if ($publicationType == \"dataset\")\n ${baseUrl}/datasets/${uuid}\n#elseif ($publicationType == \"subset\")\n ${baseUrl}/subsets/${uuid}\n#elseif ($publicationType == \"descriptor list\")\n ${baseUrl}/descriptorlists/${uuid}\n#end\n\n

\n\n

Thanks,
Genesys team

\n" + } +} diff --git a/src/main/resources/default-content/publish-published.json b/src/main/resources/default-content/publish-published.json new file mode 100644 index 0000000000000000000000000000000000000000..171b447820dfc73b30b1b0ba65f69cbdcb4b41ce --- /dev/null +++ b/src/main/resources/default-content/publish-published.json @@ -0,0 +1,7 @@ +{ + "template": true, + "en": { + "title": "Publication approved", + "body": "## VELOCITY\n

${baseUrl}
Publication approved

\n\n

The ${publicationType} titled \"${title}\" is now published on Genesys.

\n\n

It is publicly accessible at \n\n#if ($publicationType == \"dataset\")\n${baseUrl}/datasets/${uuid}\n#elseif ($publicationType == \"subset\")\n${baseUrl}/subsets/${uuid}\n#elseif ($publicationType == \"descriptor list\")\n${baseUrl}/descriptorlists/${uuid}\n#end\n\n

\n\n

Thanks,
Genesys team

" + } +}