Skip to content

Commit

Permalink
feat: smithy
Browse files Browse the repository at this point in the history
  • Loading branch information
anderha committed Aug 26, 2022
1 parent 9c5afaa commit 4d43f72
Show file tree
Hide file tree
Showing 23 changed files with 179 additions and 1,044 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ This project is built with:
- Scala 2.13.X

A PostgreSQL Database with activated postgis extensions is needed (for geolocation queries)

**Swagger.json is available at /v1/swagger.json**


## Table of Contents:

- [Play2-Bootstrap](#play2-bootstrap)
Expand Down Expand Up @@ -59,7 +57,7 @@ This is necessary to load the packages from Github-Package-Registry.
#### Insomnia:

- [Download Insomnia](https://insomnia.rest/download) | [Docs](https://support.insomnia.rest/)
- Download and import Swagger.json to Insomnia:
- Download and import to Insomnia:
<a href="https://github.com/innFactory/bootstrap-play2/blob/master/doc-assets/insomnia-workspace.json" target="_blank"><img src="https://insomnia.rest/images/run.svg" alt="Run in Insomnia"></a>

- Configure Environment in Insomnia to match with local or prod/staging services
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ trait BaseMapper {
implicit def dateTimeToDateWithTime(dateTime: DateTime): DateWithTime =
DateWithTime(dateTime.toString())

implicit def optionMapper[T, R](option: Option[T])(implicit optionValueMapper: T => R): Option[R] =
option.map(optionValueMapper)

implicit def sequenceTransformer[T, R](seq: Seq[T])(implicit transform: T => R): List[R] =
seq.map(transform).toList

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ trait Showable { this: Product =>
val className = this.productPrefix
val fieldNames = this.productElementNames.toList
val fieldValues = this.productIterator.toList
val fields = fieldNames.zip(fieldValues).map { case (name, value) => s"$name = $value" }
val fields = fieldNames.zip(fieldValues).map { case (name, value) =>
s"$name = $value"
} // TODO match value -> if (product) call show else toString
fields.mkString(s"$className(", ", ", ")")
}
override def toString: String = show
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import scala.concurrent.{ExecutionContext, Future}
import scala.language.implicitConversions
import scala.util.Try

class BaseSlickDAO(db: Database)(implicit ec: ExecutionContext) extends ImplicitLogContext {
class BaseSlickRepository(db: Database)(implicit ec: ExecutionContext) extends ImplicitLogContext {

def lookupGeneric[R, T](
queryHeadOption: DBIOAction[Option[R], NoStream, Nothing]
Expand Down Expand Up @@ -123,6 +123,7 @@ class BaseSlickDAO(db: Database)(implicit ec: ExecutionContext) extends Implicit
update: T => DBIOAction[Int, NoStream, Effect.Write],
patch: T => T
)(implicit rowToObject: R => T, rc: TraceContext): EitherT[Future, ResultStatus, T] = EitherT {
// TODO rc.logIfDebug("", )
val result = for {
lookup <- EitherT(db.run(queryById).map(_.toEither(BadRequest())).trace("updateGeneric lookup"))
patchedObject <- EitherT(Future(Option(patch(rowToObject(lookup))).toEither(BadRequest())))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,124 +1,59 @@
package de.innfactory.bootstrapplay2.companies.application

import akka.NotUsed
import akka.stream.Materializer
import akka.stream.scaladsl.Source
import cats.data.EitherT
import de.innfactory.bootstrapplay2.commons.RequestContextWithUser
import de.innfactory.bootstrapplay2.application.controller.BaseController
import de.innfactory.bootstrapplay2.companies.application.mapper.CompanyMapper
import de.innfactory.play.smithy4play.ImplicitLogContext
import de.innfactory.bootstrapplay2.commons.application.actions.{TracingAction, TracingUserAction}
import de.innfactory.bootstrapplay2.commons.application.actions.models.{RequestWithTrace, RequestWithUser}
import de.innfactory.bootstrapplay2.companies.domain.interfaces.CompanyService
import play.api.mvc.{Action, AnyContent, ControllerComponents}
import de.innfactory.bootstrapplay2.companies.application.models.{CompanyRequest, CompanyResponse}
import de.innfactory.bootstrapplay2.companies.domain.models.{Company, CompanyId}
import play.api.mvc.ControllerComponents
import de.innfactory.bootstrapplay2.companies.domain.models.CompanyId
import de.innfactory.bootstrapplay2.definition
import de.innfactory.bootstrapplay2.definition.{CompaniesResponse, CompanyAPIController}
import de.innfactory.play.controller.{BaseController, ResultStatus}
import de.innfactory.bootstrapplay2.definition.{
CompaniesResponse,
CompanyAPIController,
CompanyRequestBody,
CompanyResponse
}
import de.innfactory.smithy4play.{AutoRouting, ContextRoute}
import smithy4s.Document
import play.api.Application

import javax.inject.{Inject, Singleton}
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.ExecutionContext
import scala.language.implicitConversions

@AutoRouting
@Singleton
class CompanyController @Inject() (
tracingUserAction: TracingUserAction,
companyService: CompanyService,
tracingAction: TracingAction
companyService: CompanyService
)(implicit
ec: ExecutionContext,
cc: ControllerComponents,
mat: Materializer
app: Application
) extends BaseController
with ImplicitLogContext
with CompanyAPIController[ContextRoute] {
with CompanyAPIController[ContextRoute]
with CompanyMapper {

// implicit private def companyRequestToCompany(companyRequest: CompanyRequest): Company = companyRequest.toCompany()
//
// implicit private val outMapperSeq: OutMapper[Seq[Company], Seq[CompanyResponse]] =
// OutMapper[Seq[Company], Seq[CompanyResponse]](companies => companies.map(CompanyResponse.fromCompany))
//
// implicit private val outMapper: OutMapper[Company, CompanyResponse] =
// OutMapper[Company, CompanyResponse](CompanyResponse.fromCompany)
//
// implicit private val outMapperBoolean: OutMapper[Boolean, Boolean] =
// OutMapper[Boolean, Boolean](b => b)
//
// implicit private val outMapperSource: OutMapper[Source[Company, NotUsed], Source[CompanyResponse, NotUsed]] =
// OutMapper[Source[Company, NotUsed], Source[CompanyResponse, NotUsed]](v => v.map(CompanyResponse.fromCompany))
//
// private val UserInEndpoint = Endpoint.in[RequestWithUser](tracingUserAction())
//
// def getById(id: Long): Action[AnyContent] =
// UserInEndpoint
// .logic((_, rc) => companyService.getById(CompanyId(id))(requestContextWithUser(rc)))
// .mapOutTo[CompanyResponse]
// .result(r => r.completeResult())
//
// def getAll: Action[AnyContent] =
// UserInEndpoint
// .logic((_, rc) => companyService.getAll()(requestContextWithUser(rc)))
// .mapOutTo[Seq[CompanyResponse]]
// .result(_.completeResult())
//
// def getAllPublic(filter: Option[String]): Action[AnyContent] =
// UserInEndpoint
// .logic((_, rc) => EitherT.right[ResultStatus](companyService.getAllForGraphQL(filter)(requestContext(rc))))
// .mapOutTo[Seq[CompanyResponse]]
// .result(_.completeResult())
//
// def delete(id: Long): Action[AnyContent] =
// UserInEndpoint
// .logic((_, r) => companyService.deleteCompany(CompanyId(id))(requestContextWithUser(r)))
// .mapOutTo[Boolean]
// .result(_.completeResultWithoutBody(statusCode = 204))
//
// private def UpdateCreateEndpoint(
// logic: (Company, RequestContextWithUser) => EitherT[Future, ResultStatus, Company]
// ): Endpoint[CompanyRequest, CompanyResponse, RequestWithUser, Company, Company] =
// Endpoint
// .in[CompanyRequest, RequestWithUser, Company](tracingUserAction())
// .logic((companyRequest, rc) => logic(companyRequest, requestContextWithUser(rc)))
// .mapOutTo[CompanyResponse]
//
// def update: Action[CompanyRequest] =
// UpdateCreateEndpoint((c, r) => companyService.updateCompany(c)(r))
// .result(_.completeResultWithoutBody(statusCode = 204))
//
// def create: Action[CompanyRequest] =
// UpdateCreateEndpoint((c, r) => companyService.createCompany(c)(r))
// .result(_.completeResult())
//
// def getAllCompaniesAsSource: Action[AnyContent] =
// UserInEndpoint
// .logic[Source[Company, NotUsed]]((_, r) => companyService.getAllCompaniesAsStream()(requestContextWithUser(r)))
// .mapOutTo[Source[CompanyResponse, NotUsed]]
// .result(_.completeSourceChunked())
override def getCompanyById(companyId: Long): ContextRoute[definition.CompanyResponse] =
Endpoint.withAuth
.execute(companyService.getById(CompanyId(companyId))(_))
.complete

override def getCompanyById(companyId: String): ContextRoute[definition.CompanyResponse] = ???
override def getAllCompanies(): ContextRoute[CompaniesResponse] =
Endpoint.withAuth
.execute(companyService.getAll()(_))
.complete

override def getAllCompanies(): ContextRoute[CompaniesResponse] = ???
override def createCompany(body: CompanyRequestBody): ContextRoute[CompanyResponse] = Endpoint.withAuth
.execute(companyService.createCompany(body)(_))
.complete

override def createCompany(
id: Option[Long],
settings: Option[Document],
stringAttribute1: Option[String],
stringAttribute2: Option[String],
longAttribute1: Option[Long],
booleanAttribute: Option[Boolean]
): ContextRoute[definition.CompanyResponse] = ???
override def updateCompany(body: CompanyRequestBody): ContextRoute[CompanyResponse] = Endpoint.withAuth
.execute(companyService.updateCompany(body)(_))
.complete

override def updateCompany(
id: Option[Long],
settings: Option[Document],
stringAttribute1: Option[String],
stringAttribute2: Option[String],
longAttribute1: Option[Long],
booleanAttribute: Option[Boolean]
): ContextRoute[definition.CompanyResponse] = ???
override def deleteCompany(companyId: Long): ContextRoute[Unit] = Endpoint.withAuth
.execute(companyService.deleteCompany(CompanyId(companyId))(_))
.complete

override def deleteCompany(companyId: String): ContextRoute[Unit] = ???
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package de.innfactory.bootstrapplay2.companies.application.mapper

import de.innfactory.bootstrapplay2.application.controller.BaseMapper
import de.innfactory.bootstrapplay2.companies.domain.models.{Company, CompanyId}
import de.innfactory.bootstrapplay2.definition.{CompaniesResponse, CompanyRequestBody, CompanyResponse}
import io.scalaland.chimney.dsl.TransformerOps

trait CompanyMapper extends BaseMapper {
implicit val companyToCompanyResponse: Company => CompanyResponse = (
company: Company
) =>
company
.into[CompanyResponse]
.withFieldComputed(_.id, c => c.id.get.value)
.withFieldComputed(_.created, c => dateTimeToDateWithTime(c.created.get))
.withFieldComputed(_.updated, c => dateTimeToDateWithTime(c.updated.get))
.transform

implicit val companiesToCompaniesResponse: Seq[Company] => CompaniesResponse = (companies: Seq[Company]) =>
CompaniesResponse(companies.map(companyToCompanyResponse))

implicit val companyRequestBodyToCompany: CompanyRequestBody => Company = (companyRequestBody: CompanyRequestBody) =>
companyRequestBody
.into[Company]
.withFieldComputed(_.id, c => c.id.map(CompanyId))
.withFieldConst(_.created, None)
.withFieldConst(_.updated, None)
.transform
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import dbdata.Tables
import de.innfactory.bootstrapplay2.commons.RequestContext
import de.innfactory.bootstrapplay2.commons.filteroptions.FilterOptionUtils
import de.innfactory.play.controller.ResultStatus
import de.innfactory.bootstrapplay2.commons.infrastructure.BaseSlickDAO
import de.innfactory.bootstrapplay2.commons.infrastructure.BaseSlickRepository
import de.innfactory.bootstrapplay2.commons.results.errors.Errors.BadRequest
import de.innfactory.bootstrapplay2.companies.domain.interfaces.CompanyRepository
import de.innfactory.bootstrapplay2.companies.domain.models.{Company, CompanyId}
Expand All @@ -24,7 +24,7 @@ import javax.inject.Inject
import scala.concurrent.{ExecutionContext, Future}

private[companies] class SlickCompanyRepository @Inject() (db: Database)(implicit ec: ExecutionContext)
extends BaseSlickDAO(db)
extends BaseSlickRepository(db)
with CompanyRepository {

private val queryById = (id: CompanyId) => Compiled(Tables.Company.filter(_.id === id.value))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ class RouteBlacklistFilter @Inject() (config: Config, implicit val mat: Material

private val accessLogger = Logger("AccessFilterLog")

private val blacklistedRoutes = Seq[BlackListEntry](
BlackListEntry("/v1/assets/swagger.json", Prod, "GET")
)
private val blacklistedRoutes = Seq[BlackListEntry]()

/**
* Check if route is contained in blacklistedRoutes and block request if true
Expand All @@ -31,7 +29,7 @@ class RouteBlacklistFilter @Inject() (config: Config, implicit val mat: Material
*/
def apply(nextFilter: RequestHeader => Future[Result])(request: RequestHeader): Future[Result] =
if (shouldBeBlocked(request.path, request.method)) {
accessLogger.logger.warn("Illegal access to swagger.json in production")
accessLogger.logger.warn(s"Illegal access to ${request.path} with ${request.method} in production")
Future(NotFound(""))
} else
nextFilter.apply(request)
Expand Down
Loading

0 comments on commit 4d43f72

Please sign in to comment.