1 /*
2  *  Make.org Core API
3  *  Copyright (C) 2018 Make.org
4  *
5  * This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  *
18  */
19 
20 package org.make.api.proposal
21 
22 import akka.actor.typed.Behavior
23 import akka.util.Timeout
24 import org.make.api.proposal.PublishedProposalEvent._
25 import org.make.api.user.PersistentUserProposalsService
26 import org.make.api.technical.crm.SendMailPublisherService
27 import org.make.api.technical.{KafkaConsumerBehavior, TimeSettings, ValueNotFoundException}
28 
29 import scala.concurrent.Future
30 import scala.concurrent.ExecutionContext.Implicits.global
31 import akka.actor.typed.ActorSystem
32 
33 class ProposalEmailConsumerBehavior(
34   sendMailPublisherService: SendMailPublisherService,
35   userProposalsService: PersistentUserProposalsService
36 ) extends KafkaConsumerBehavior[ProposalEventWrapper] {
37 
38   override protected val topicKey: String = ProposalKafkaProducerBehavior.topicKey
39   override val groupId = "proposal-email"
40 
41   implicit val timeout: Timeout = TimeSettings.defaultTimeout
42 
43   override def handleMessage(message: ProposalEventWrapper)(system: ActorSystem[_]): Future[Unit] = {
44     message.event match {
45       case event: ProposalAccepted             => handleProposalAccepted(event)
46       case event: ProposalRefused              => handleProposalRefused(event)
47       case event: ProposalReportedNotice       => handleProposalReported(event)
48       case event: ProposalPostponed            => doNothing(event)
49       case event: ProposalViewed               => doNothing(event)
50       case event: ProposalUpdated              => doNothing(event)
51       case event: ProposalVotesVerifiedUpdated => doNothing(event)
52       case event: ProposalVotesUpdated         => doNothing(event)
53       case event: ReindexProposal              => doNothing(event)
54       case event: ProposalProposed             => handleProposalProposed(event, MaxPropositionsThresholds(system))
55       case event: ProposalVoted                => doNothing(event)
56       case event: ProposalUnvoted              => doNothing(event)
57       case event: ProposalQualified            => doNothing(event)
58       case event: ProposalUnqualified          => doNothing(event)
59       case event: SimilarProposalsAdded        => doNothing(event)
60       case event: ProposalLocked               => doNothing(event)
61       case event: ProposalPatched              => doNothing(event)
62       case event: ProposalAddedToOperation     => doNothing(event)
63       case event: ProposalRemovedFromOperation => doNothing(event)
64       case event: ProposalAnonymized           => doNothing(event)
65       case event: ProposalKeywordsSet          => doNothing(event)
66     }
67   }
68 
69   def handleProposalAccepted(event: ProposalAccepted): Future[Unit] = {
70     if (event.sendValidationEmail) {
71       sendMailPublisherService.publishAcceptProposal(event.id)
72     } else {
73       Future.unit
74     }
75   }
76 
77   def handleProposalRefused(event: ProposalRefused): Future[Unit] = {
78     if (event.sendRefuseEmail) {
79       sendMailPublisherService.publishRefuseProposal(event.id)
80     } else {
81       Future.unit
82     }
83   }
84 
85   def handleProposalReported(event: ProposalReportedNotice): Future[Unit] =
86     sendMailPublisherService.publishProposalReportedNotice(event.id, event.proposalLanguage, event.reason)
87 
88   def handleProposalProposed(
89     event: ProposalProposed,
90     maxPropositionsThresholds: MaxPropositionsThresholds
91   ): Future[Unit] =
92     event.question match {
93       case None =>
94         Future.failed(ValueNotFoundException("No question was attached to the proposal"))
95       case Some(questionId) =>
96         val authorId = event.author.userId
97         userProposalsService
98           .incrementCounter(authorId, questionId)
99           .flatMap({
100             case maxPropositionsThresholds.warnThreshold =>
101               sendMailPublisherService.publishAbusiveProposerWarn(questionId, authorId, event.requestContext)
102             case maxPropositionsThresholds.blockThreshold =>
103               sendMailPublisherService.publishAbusiveProposerBlock(questionId, authorId, event.requestContext)
104             case _ =>
105               Future.unit
106           })
107     }
108 }
109 
110 object ProposalEmailConsumerActor {
111   val name: String = "proposal-emails-consumer"
112   def apply(
113     sendMailPublisherService: SendMailPublisherService,
114     userProposalsService: PersistentUserProposalsService
115   ): Behavior[KafkaConsumerBehavior.Protocol] =
116     new ProposalEmailConsumerBehavior(sendMailPublisherService, userProposalsService)
117       .createBehavior(name)
118 }
Line Stmt Id Pos Tree Symbol Tests Code
38 7227 1469 - 1507 Select org.make.api.proposal.ProposalKafkaProducerBehavior.topicKey ProposalKafkaProducerBehavior.topicKey
39 6356 1533 - 1549 Literal <nosymbol> "proposal-email"
41 7749 1585 - 1612 Select org.make.api.technical.TimeSettings.defaultTimeout org.make.api.technical.TimeSettings.defaultTimeout
44 7398 1720 - 1733 Select org.make.api.proposal.ProposalEventWrapper.event message.event
45 6600 1792 - 1821 Apply org.make.api.proposal.ProposalEmailConsumerBehavior.handleProposalAccepted ProposalEmailConsumerBehavior.this.handleProposalAccepted(event)
46 5712 1872 - 1900 Apply org.make.api.proposal.ProposalEmailConsumerBehavior.handleProposalRefused ProposalEmailConsumerBehavior.this.handleProposalRefused(event)
47 7063 1951 - 1980 Apply org.make.api.proposal.ProposalEmailConsumerBehavior.handleProposalReported ProposalEmailConsumerBehavior.this.handleProposalReported(event)
48 6721 2031 - 2047 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
49 5860 2098 - 2114 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
50 7232 2165 - 2181 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
51 6429 2232 - 2248 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
52 7837 2299 - 2315 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
53 7402 2366 - 2382 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
54 5716 2433 - 2497 Apply org.make.api.proposal.ProposalEmailConsumerBehavior.handleProposalProposed ProposalEmailConsumerBehavior.this.handleProposalProposed(event, MaxPropositionsThresholds.apply(system))
54 6508 2463 - 2496 Apply akka.actor.typed.ExtensionId.apply MaxPropositionsThresholds.apply(system)
55 7142 2548 - 2564 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
56 6299 2615 - 2631 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
57 5862 2682 - 2698 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
58 7207 2749 - 2765 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
59 6431 2816 - 2832 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
60 7791 2883 - 2899 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
61 7384 2950 - 2966 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
62 6512 3017 - 3033 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
63 5679 3084 - 3100 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
64 7053 3151 - 3167 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
65 6264 3218 - 3234 Apply org.make.api.technical.KafkaConsumerBehavior.doNothing ProposalEmailConsumerBehavior.this.doNothing(event)
70 5841 3326 - 3351 Select org.make.api.proposal.PublishedProposalEvent.ProposalAccepted.sendValidationEmail event.sendValidationEmail
71 7209 3408 - 3416 Select org.make.api.proposal.PublishedProposalEvent.ProposalAccepted.id event.id
71 7746 3361 - 3417 Block org.make.api.technical.crm.SendMailPublisherService.publishAcceptProposal ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishAcceptProposal(event.id)
71 6436 3361 - 3417 Apply org.make.api.technical.crm.SendMailPublisherService.publishAcceptProposal ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishAcceptProposal(event.id)
73 6945 3437 - 3448 Select scala.concurrent.Future.unit scala.concurrent.Future.unit
73 6499 3437 - 3448 Block scala.concurrent.Future.unit scala.concurrent.Future.unit
78 5682 3538 - 3559 Select org.make.api.proposal.PublishedProposalEvent.ProposalRefused.sendRefuseEmail event.sendRefuseEmail
79 6229 3569 - 3625 Apply org.make.api.technical.crm.SendMailPublisherService.publishRefuseProposal ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishRefuseProposal(event.id)
79 5858 3569 - 3625 Block org.make.api.technical.crm.SendMailPublisherService.publishRefuseProposal ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishRefuseProposal(event.id)
79 7061 3616 - 3624 Select org.make.api.proposal.PublishedProposalEvent.ProposalRefused.id event.id
81 6480 3645 - 3656 Block scala.concurrent.Future.unit scala.concurrent.Future.unit
81 7193 3645 - 3656 Select scala.concurrent.Future.unit scala.concurrent.Future.unit
86 7754 3803 - 3811 Select org.make.api.proposal.PublishedProposalEvent.ProposalReportedNotice.id event.id
86 6561 3837 - 3849 Select org.make.api.proposal.PublishedProposalEvent.ProposalReportedNotice.reason event.reason
86 5685 3748 - 3850 Apply org.make.api.technical.crm.SendMailPublisherService.publishProposalReportedNotice ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishProposalReportedNotice(event.id, event.proposalLanguage, event.reason)
86 6923 3813 - 3835 Select org.make.api.proposal.PublishedProposalEvent.ProposalReportedNotice.proposalLanguage event.proposalLanguage
92 7177 3992 - 4006 Select org.make.api.proposal.PublishedProposalEvent.ProposalProposed.question event.question
94 6234 4056 - 4122 Apply org.make.api.technical.ValueNotFoundException.apply org.make.api.technical.ValueNotFoundException.apply("No question was attached to the proposal")
94 5838 4042 - 4123 Apply scala.concurrent.Future.failed scala.concurrent.Future.failed[Nothing](org.make.api.technical.ValueNotFoundException.apply("No question was attached to the proposal"))
96 7275 4178 - 4197 Select org.make.api.proposal.PublishedProposalEvent.ProposalAuthorInfo.userId event.author.userId
99 7179 4295 - 4295 Select scala.concurrent.ExecutionContext.Implicits.global scala.concurrent.ExecutionContext.Implicits.global
99 6335 4206 - 4700 ApplyToImplicitArgs scala.concurrent.Future.flatMap ProposalEmailConsumerBehavior.this.userProposalsService.incrementCounter(authorId, questionId).flatMap[Unit](((x0$1: Int) => x0$1 match { case maxPropositionsThresholds.warnThreshold => ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishAbusiveProposerWarn(questionId, authorId, event.requestContext) case maxPropositionsThresholds.blockThreshold => ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishAbusiveProposerBlock(questionId, authorId, event.requestContext) case _ => scala.concurrent.Future.unit }))(scala.concurrent.ExecutionContext.Implicits.global)
101 7857 4372 - 4467 Apply org.make.api.technical.crm.SendMailPublisherService.publishAbusiveProposerWarn ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishAbusiveProposerWarn(questionId, authorId, event.requestContext)
101 6481 4446 - 4466 Select org.make.api.proposal.PublishedProposalEvent.ProposalProposed.requestContext event.requestContext
103 6985 4618 - 4638 Select org.make.api.proposal.PublishedProposalEvent.ProposalProposed.requestContext event.requestContext
103 6530 4543 - 4639 Apply org.make.api.technical.crm.SendMailPublisherService.publishAbusiveProposerBlock ProposalEmailConsumerBehavior.this.sendMailPublisherService.publishAbusiveProposerBlock(questionId, authorId, event.requestContext)
105 5676 4676 - 4687 Select scala.concurrent.Future.unit scala.concurrent.Future.unit
111 7678 4767 - 4793 Literal <nosymbol> "proposal-emails-consumer"
117 7278 5076 - 5080 Select org.make.api.proposal.ProposalEmailConsumerActor.name ProposalEmailConsumerActor.this.name
117 6394 4972 - 5081 Apply org.make.api.technical.KafkaConsumerBehavior.createBehavior new ProposalEmailConsumerBehavior(sendMailPublisherService, userProposalsService).createBehavior(ProposalEmailConsumerActor.this.name)