diff options
author | vlad <vlad@driver.xyz> | 2017-07-14 10:38:59 -0700 |
---|---|---|
committer | vlad <vlad@driver.xyz> | 2017-07-14 10:38:59 -0700 |
commit | 8353cc012328744c7cdfe0436e23d5e565bea570 (patch) | |
tree | 9ece288a43f30c3bd50393dd28fe17bf54b5e717 /src | |
parent | 93eb4829c0d11959709e18a7b489343550633e83 (diff) | |
download | rest-query-8353cc012328744c7cdfe0436e23d5e565bea570.tar.gz rest-query-8353cc012328744c7cdfe0436e23d5e565bea570.tar.bz2 rest-query-8353cc012328744c7cdfe0436e23d5e565bea570.zip |
Clean-up + New User constructor from Driver User
Diffstat (limited to 'src')
9 files changed, 66 insertions, 312 deletions
diff --git a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala index 0438dfc..276ef9f 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala @@ -243,12 +243,10 @@ object ACL extends PhiLogging { } private def check(action: String, isAllowed: AclCheck)(executorRoles: Set[Role]): Boolean = { - executorRoles.exists { role => - loggedError( - isAllowed(role), - phi"$role has no access to ${Unsafe(action)} a ${Unsafe(label)}" - ) - } + loggedError( + executorRoles.exists(isAllowed), + phi"${Unsafe(executorRoles.mkString(", "))} has no access to ${Unsafe(action)} a ${Unsafe(label)}" + ) } } } diff --git a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala b/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala index 159c144..af7d051 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala @@ -72,6 +72,17 @@ final case class Computation[+R, +T](future: Future[Either[R, T]]) { }) } + def mapAll[R2, T2](onLeft: R => Computation[R2, T2])(onRight: T => Computation[R2, T2])( + onFailure: () => Computation[R2, T2])(implicit ec: ExecutionContext): Computation[R2, T2] = { + + Computation(future.flatMap { success => + if (success.isRight) onRight(success.right.get).future + else onLeft(success.left.get).future + } recoverWith { + case _ => onFailure().future + }) + } + def andThen(f: T => Any)(implicit ec: ExecutionContext): Computation[R, T] = map { a => f(a) a @@ -98,7 +109,6 @@ final case class Computation[+R, +T](future: Future[Either[R, T]]) { case Left(x) => x case Right(x) => x } - } object Computation { diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala index ffc4bf9..cfc2270 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala @@ -2,7 +2,7 @@ package xyz.driver.pdsuicommon.domain import java.math.BigInteger import java.security.SecureRandom -import java.time.LocalDateTime +import java.time.{Instant, LocalDateTime, ZoneId} import xyz.driver.pdsuicommon.logging._ import xyz.driver.pdsuicommon.domain.User.Role @@ -14,7 +14,21 @@ case class User(id: StringId[User], roles: Set[Role], passwordHash: PasswordHash, latestActivity: Option[LocalDateTime], - deleted: Option[LocalDateTime]) + deleted: Option[LocalDateTime]) { + + def this(driverUser: xyz.driver.entities.users.UserInfo) { + this( + id = StringId[xyz.driver.pdsuicommon.domain.User](driverUser.id.value), + email = Email(driverUser.email.toString), + name = driverUser.name.toString, + roles = driverUser.roles.flatMap(User.mapRoles), + passwordHash = PasswordHash(""), + latestActivity = + driverUser.lastLoginTime.map(t => Instant.ofEpochMilli(t.millis).atZone(ZoneId.of("Z")).toLocalDateTime), + deleted = Option.empty[LocalDateTime] + ) + } +} object User { @@ -82,4 +96,39 @@ object User { def createPassword: String = new BigInteger(240, random).toString(32) + def mapRoles(coreRole: xyz.driver.core.auth.Role): Set[xyz.driver.pdsuicommon.domain.User.Role] = { + coreRole match { + case xyz.driver.entities.auth.AdministratorRole => + Set( + xyz.driver.pdsuicommon.domain.User.Role.SystemUser, + xyz.driver.pdsuicommon.domain.User.Role.RecordAdmin, + xyz.driver.pdsuicommon.domain.User.Role.TrialAdmin, + xyz.driver.pdsuicommon.domain.User.Role.TreatmentMatchingAdmin + ) + case xyz.driver.entities.auth.RecordAdmin => + Set(xyz.driver.pdsuicommon.domain.User.Role.RecordAdmin) + case xyz.driver.entities.auth.RecordCleaner => + Set(xyz.driver.pdsuicommon.domain.User.Role.RecordCleaner) + case xyz.driver.entities.auth.RecordOrganizer => + Set(xyz.driver.pdsuicommon.domain.User.Role.RecordOrganizer) + case xyz.driver.entities.auth.DocumentExtractor => + Set(xyz.driver.pdsuicommon.domain.User.Role.DocumentExtractor) + case xyz.driver.entities.auth.TrialSummarizer => + Set(xyz.driver.pdsuicommon.domain.User.Role.TrialSummarizer) + case xyz.driver.entities.auth.CriteriaCurator => + Set(xyz.driver.pdsuicommon.domain.User.Role.CriteriaCurator) + case xyz.driver.entities.auth.TrialAdmin => + Set(xyz.driver.pdsuicommon.domain.User.Role.TrialAdmin) + case xyz.driver.entities.auth.EligibilityVerifier => + Set(xyz.driver.pdsuicommon.domain.User.Role.EligibilityVerifier) + case xyz.driver.entities.auth.TreatmentMatchingAdmin => + Set(xyz.driver.pdsuicommon.domain.User.Role.TreatmentMatchingAdmin) + case xyz.driver.entities.auth.RoutesCurator => + Set(xyz.driver.pdsuicommon.domain.User.Role.RoutesCurator) + case xyz.driver.entities.auth.ResearchOncologist => + Set(xyz.driver.pdsuicommon.domain.User.Role.ResearchOncologist) + case _ => + Set.empty[xyz.driver.pdsuicommon.domain.User.Role] + } + } } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/linkedpatient/ApiLinkedPatient.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/linkedpatient/ApiLinkedPatient.scala deleted file mode 100644 index 327bda2..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/linkedpatient/ApiLinkedPatient.scala +++ /dev/null @@ -1,29 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json.linkedpatient - -import java.util.UUID - -import play.api.libs.json.{Format, Json} -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.services.LinkedPatientService.RichLinkedPatient - -final case class ApiLinkedPatient(email: String, name: String, patientId: UUID, trialId: String) { - - def toDomain = RichLinkedPatient( - email = Email(email), - name = name, - patientId = UuidId(patientId), - trialId = StringId(trialId) - ) -} - -object ApiLinkedPatient { - - implicit val format: Format[ApiLinkedPatient] = Json.format[ApiLinkedPatient] - - def fromDomain(entity: RichLinkedPatient) = ApiLinkedPatient( - email = entity.email.value, - name = entity.name, - patientId = entity.patientId.id, - trialId = entity.trialId.id - ) -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/LinkedPatientService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/LinkedPatientService.scala deleted file mode 100644 index a69283a..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/LinkedPatientService.scala +++ /dev/null @@ -1,58 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.{LinkedPatient, Patient, Trial} - -import scala.concurrent.Future - -object LinkedPatientService { - - trait DefaultTrialNotFoundError { - def userMessage: String = "Trial not found" - } - - trait DefaultPatientNotFoundError { - def userMessage: String = "Patient not found" - } - - final case class RichLinkedPatient(email: Email, name: String, patientId: UuidId[Patient], trialId: StringId[Trial]) { - def toLinkedPatient(user: User) = LinkedPatient( - userId = user.id, - patientId = patientId, - trialId = trialId - ) - } - - object RichLinkedPatient { - implicit def toPhiString(x: RichLinkedPatient): PhiString = { - import x._ - phi"RichLinkedPatient(email=${Unsafe(email)}, patientId=$patientId, trialId=$trialId)" - } - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - - /** - * @param createdUser None if a user was created before - */ - final case class Created(x: RichLinkedPatient, createdUser: Option[User]) extends CreateReply - - case object PatientNotFoundError - extends CreateReply with DefaultPatientNotFoundError with DomainError.NotFoundError - - case object TrialNotFoundError extends CreateReply with DefaultPatientNotFoundError with DomainError.NotFoundError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } -} - -trait LinkedPatientService { - - import LinkedPatientService._ - - def create(entity: RichLinkedPatient): Future[CreateReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MailService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MailService.scala deleted file mode 100644 index 53f897a..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/MailService.scala +++ /dev/null @@ -1,39 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.io.{InputStream, StringReader, StringWriter} - -import xyz.driver.pdsuidomain.services.MailService.Template -import com.github.mustachejava.DefaultMustacheFactory -import com.twitter.mustache.ScalaObjectHandler - -import scala.io.Source - -object MailService { - - trait Template { - val subject: String - def parameters: Map[String, Any] - def filename: String - val contentType: String = "text/html" - - protected val factory = new DefaultMustacheFactory() - factory.setObjectHandler(new ScalaObjectHandler) - - protected def inputStream: InputStream = getClass.getClassLoader.getResourceAsStream(filename) - protected def templateContent: String = Source.fromInputStream(inputStream).getLines().mkString - - def content: String = { - val template = factory.compile(new StringReader(templateContent), filename) - val writer = new StringWriter - template - .execute(writer, parameters) - .close() - writer.toString - } - } -} - -trait MailService { - - def sendTo(email: String, template: Template): Boolean -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala deleted file mode 100644 index b54b6a9..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala +++ /dev/null @@ -1,127 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.pdsuicommon.auth.{AnonymousRequestContext, AuthenticatedRequestContext} -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.error.DomainError - -import scala.concurrent.Future - -object UserService { - - trait DefaultCredentialsError { - def userMessage: String = "Incorrect email/password. Try again." - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - trait DefaultNotFoundError { - def userMessage: String = "User not found" - } - - sealed trait ActivateExecutorReply - object ActivateExecutorReply { - type Error = ActivateExecutorReply with DomainError - case class Entity(x: User) extends ActivateExecutorReply - case object NotFoundError extends ActivateExecutorReply with DomainError.NotFoundError { - val userMessage = "Info about you is not found on the server" - } - } - - sealed trait GetByIdReply - object GetByIdReply { - type Error = GetByIdReply with DomainError - case class Entity(x: User) extends GetByIdReply - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError - case class CommonError(userMessage: String) extends GetByIdReply with DomainError - } - - sealed trait GetByEmailReply - object GetByEmailReply { - case class Entity(x: User) extends GetByEmailReply - case object NotFoundError extends GetByEmailReply with DefaultNotFoundError with DomainError.NotFoundError { - override def userMessage: String = "Incorrect email. Try again." - } - } - - sealed trait GetByCredentialsReply - object GetByCredentialsReply { - case class Entity(x: User) extends GetByCredentialsReply - case object AuthenticationError - extends GetByCredentialsReply with DefaultCredentialsError with DomainError.AuthenticationError - case object NotFoundError extends GetByCredentialsReply with DomainError.NotFoundError with DefaultNotFoundError - } - - sealed trait GetListReply - object GetListReply { - case class EntityList(xs: Seq[User], totalFound: Int) extends GetListReply - case object AuthorizationError extends GetListReply with DomainError.AuthorizationError with DefaultNotFoundError - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - case class Created(x: User) extends CreateReply - case object AuthorizationError extends CreateReply with DefaultNotFoundError with DomainError.AuthorizationError - case class UserAlreadyExistsError(email: Email) extends CreateReply with DomainError { - val userMessage = s"The user with this email already exists." - } - case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - case class Updated(updated: User) extends UpdateReply - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) extends UpdateReply with DomainError - } - - sealed trait DeleteReply - object DeleteReply { - type Error = DeleteReply with DomainError - case object Deleted extends DeleteReply - case class AuthorizationError(user: User) - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case object AssignedToRecordAndDocumentError extends DeleteReply with DomainError { - val userMessage = "User is can not be deleted because he has record and document in work" - } - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait UserService { - - import UserService._ - - /** - * Utility method for getting request executor. - */ - def activateExecutor(executorId: StringId[User])( - implicit requestContext: AnonymousRequestContext): Future[ActivateExecutorReply] - - def getById(userId: StringId[User])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] - - def getByEmail(email: Email)(implicit requestContext: AnonymousRequestContext): Future[GetByEmailReply] - - def getByCredentials(email: Email, password: String)( - implicit requestContext: AnonymousRequestContext): Future[GetByCredentialsReply] - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - - def create(draftUser: User)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] - - def update(origUser: User, draftUser: User)( - implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - - def delete(userId: StringId[User])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/fake/StubMailService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/fake/StubMailService.scala deleted file mode 100644 index 932da67..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/fake/StubMailService.scala +++ /dev/null @@ -1,13 +0,0 @@ -package xyz.driver.pdsuidomain.services.fake - -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.services.MailService -import xyz.driver.pdsuidomain.services.MailService.Template - -object StubMailService extends MailService with PhiLogging { - - override def sendTo(email: String, template: Template): Boolean = { - logger.debug(phi"sendTo(email=${Unsafe(email)}") - true - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/SendGridMailService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/SendGridMailService.scala deleted file mode 100644 index bb3228e..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/SendGridMailService.scala +++ /dev/null @@ -1,37 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import com.sendgrid._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.services.MailService -import xyz.driver.pdsuidomain.services.MailService.Template - -import scala.util.control.NonFatal - -class SendGridMailService(apiKey: String, from: String) extends MailService with PhiLogging { - private val ExpectedHttpCode = 202 - - def sendTo(email: String, template: Template): Boolean = { - val to = new Email(email) - val content = new Content(template.contentType, template.content) - val mail = new Mail(new Email(from), template.subject, to, content) - - val request = new Request() - val sendGrid = new SendGrid(apiKey) - - try { - request.method = Method.POST - request.endpoint = "mail/send" - request.body = mail.build() - val response = sendGrid.api(request) - if (response.statusCode != ExpectedHttpCode) { - logger.error(phi"Unexpected response: ${Unsafe(response.statusCode)}, ${Unsafe(response.body.take(100))}") - } - - response.statusCode == ExpectedHttpCode - } catch { - case NonFatal(e) => - logger.error(phi"Can not send an email: $e") - false - } - } -} |