Skip to content

Commit 4d43f72

Browse files
committed
feat: smithy
1 parent 9c5afaa commit 4d43f72

23 files changed

+179
-1044
lines changed

README.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ This project is built with:
2121
- Scala 2.13.X
2222

2323
A PostgreSQL Database with activated postgis extensions is needed (for geolocation queries)
24-
25-
**Swagger.json is available at /v1/swagger.json**
26-
24+
2725
## Table of Contents:
2826

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

6159
- [Download Insomnia](https://insomnia.rest/download) | [Docs](https://support.insomnia.rest/)
62-
- Download and import Swagger.json to Insomnia:
60+
- Download and import to Insomnia:
6361
<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>
6462

6563
- Configure Environment in Insomnia to match with local or prod/staging services

app/de/innfactory/bootstrapplay2/application/controller/BaseMapper.scala

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ trait BaseMapper {
2222
implicit def dateTimeToDateWithTime(dateTime: DateTime): DateWithTime =
2323
DateWithTime(dateTime.toString())
2424

25+
implicit def optionMapper[T, R](option: Option[T])(implicit optionValueMapper: T => R): Option[R] =
26+
option.map(optionValueMapper)
27+
2528
implicit def sequenceTransformer[T, R](seq: Seq[T])(implicit transform: T => R): List[R] =
2629
seq.map(transform).toList
2730

app/de/innfactory/bootstrapplay2/commons/implicits/Showable.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ trait Showable { this: Product =>
66
val className = this.productPrefix
77
val fieldNames = this.productElementNames.toList
88
val fieldValues = this.productIterator.toList
9-
val fields = fieldNames.zip(fieldValues).map { case (name, value) => s"$name = $value" }
9+
val fields = fieldNames.zip(fieldValues).map { case (name, value) =>
10+
s"$name = $value"
11+
} // TODO match value -> if (product) call show else toString
1012
fields.mkString(s"$className(", ", ", ")")
1113
}
1214
override def toString: String = show

app/de/innfactory/bootstrapplay2/commons/infrastructure/BaseSlickDAO.scala app/de/innfactory/bootstrapplay2/commons/infrastructure/BaseSlickRepository.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import scala.concurrent.{ExecutionContext, Future}
2121
import scala.language.implicitConversions
2222
import scala.util.Try
2323

24-
class BaseSlickDAO(db: Database)(implicit ec: ExecutionContext) extends ImplicitLogContext {
24+
class BaseSlickRepository(db: Database)(implicit ec: ExecutionContext) extends ImplicitLogContext {
2525

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

3-
import akka.NotUsed
43
import akka.stream.Materializer
5-
import akka.stream.scaladsl.Source
6-
import cats.data.EitherT
7-
import de.innfactory.bootstrapplay2.commons.RequestContextWithUser
4+
import de.innfactory.bootstrapplay2.application.controller.BaseController
5+
import de.innfactory.bootstrapplay2.companies.application.mapper.CompanyMapper
86
import de.innfactory.play.smithy4play.ImplicitLogContext
9-
import de.innfactory.bootstrapplay2.commons.application.actions.{TracingAction, TracingUserAction}
10-
import de.innfactory.bootstrapplay2.commons.application.actions.models.{RequestWithTrace, RequestWithUser}
117
import de.innfactory.bootstrapplay2.companies.domain.interfaces.CompanyService
12-
import play.api.mvc.{Action, AnyContent, ControllerComponents}
13-
import de.innfactory.bootstrapplay2.companies.application.models.{CompanyRequest, CompanyResponse}
14-
import de.innfactory.bootstrapplay2.companies.domain.models.{Company, CompanyId}
8+
import play.api.mvc.ControllerComponents
9+
import de.innfactory.bootstrapplay2.companies.domain.models.CompanyId
1510
import de.innfactory.bootstrapplay2.definition
16-
import de.innfactory.bootstrapplay2.definition.{CompaniesResponse, CompanyAPIController}
17-
import de.innfactory.play.controller.{BaseController, ResultStatus}
11+
import de.innfactory.bootstrapplay2.definition.{
12+
CompaniesResponse,
13+
CompanyAPIController,
14+
CompanyRequestBody,
15+
CompanyResponse
16+
}
1817
import de.innfactory.smithy4play.{AutoRouting, ContextRoute}
19-
import smithy4s.Document
18+
import play.api.Application
2019

2120
import javax.inject.{Inject, Singleton}
22-
import scala.concurrent.{ExecutionContext, Future}
21+
import scala.concurrent.ExecutionContext
2322
import scala.language.implicitConversions
2423

2524
@AutoRouting
2625
@Singleton
2726
class CompanyController @Inject() (
28-
tracingUserAction: TracingUserAction,
29-
companyService: CompanyService,
30-
tracingAction: TracingAction
27+
companyService: CompanyService
3128
)(implicit
3229
ec: ExecutionContext,
3330
cc: ControllerComponents,
34-
mat: Materializer
31+
app: Application
3532
) extends BaseController
3633
with ImplicitLogContext
37-
with CompanyAPIController[ContextRoute] {
34+
with CompanyAPIController[ContextRoute]
35+
with CompanyMapper {
3836

39-
// implicit private def companyRequestToCompany(companyRequest: CompanyRequest): Company = companyRequest.toCompany()
40-
//
41-
// implicit private val outMapperSeq: OutMapper[Seq[Company], Seq[CompanyResponse]] =
42-
// OutMapper[Seq[Company], Seq[CompanyResponse]](companies => companies.map(CompanyResponse.fromCompany))
43-
//
44-
// implicit private val outMapper: OutMapper[Company, CompanyResponse] =
45-
// OutMapper[Company, CompanyResponse](CompanyResponse.fromCompany)
46-
//
47-
// implicit private val outMapperBoolean: OutMapper[Boolean, Boolean] =
48-
// OutMapper[Boolean, Boolean](b => b)
49-
//
50-
// implicit private val outMapperSource: OutMapper[Source[Company, NotUsed], Source[CompanyResponse, NotUsed]] =
51-
// OutMapper[Source[Company, NotUsed], Source[CompanyResponse, NotUsed]](v => v.map(CompanyResponse.fromCompany))
52-
//
53-
// private val UserInEndpoint = Endpoint.in[RequestWithUser](tracingUserAction())
54-
//
55-
// def getById(id: Long): Action[AnyContent] =
56-
// UserInEndpoint
57-
// .logic((_, rc) => companyService.getById(CompanyId(id))(requestContextWithUser(rc)))
58-
// .mapOutTo[CompanyResponse]
59-
// .result(r => r.completeResult())
60-
//
61-
// def getAll: Action[AnyContent] =
62-
// UserInEndpoint
63-
// .logic((_, rc) => companyService.getAll()(requestContextWithUser(rc)))
64-
// .mapOutTo[Seq[CompanyResponse]]
65-
// .result(_.completeResult())
66-
//
67-
// def getAllPublic(filter: Option[String]): Action[AnyContent] =
68-
// UserInEndpoint
69-
// .logic((_, rc) => EitherT.right[ResultStatus](companyService.getAllForGraphQL(filter)(requestContext(rc))))
70-
// .mapOutTo[Seq[CompanyResponse]]
71-
// .result(_.completeResult())
72-
//
73-
// def delete(id: Long): Action[AnyContent] =
74-
// UserInEndpoint
75-
// .logic((_, r) => companyService.deleteCompany(CompanyId(id))(requestContextWithUser(r)))
76-
// .mapOutTo[Boolean]
77-
// .result(_.completeResultWithoutBody(statusCode = 204))
78-
//
79-
// private def UpdateCreateEndpoint(
80-
// logic: (Company, RequestContextWithUser) => EitherT[Future, ResultStatus, Company]
81-
// ): Endpoint[CompanyRequest, CompanyResponse, RequestWithUser, Company, Company] =
82-
// Endpoint
83-
// .in[CompanyRequest, RequestWithUser, Company](tracingUserAction())
84-
// .logic((companyRequest, rc) => logic(companyRequest, requestContextWithUser(rc)))
85-
// .mapOutTo[CompanyResponse]
86-
//
87-
// def update: Action[CompanyRequest] =
88-
// UpdateCreateEndpoint((c, r) => companyService.updateCompany(c)(r))
89-
// .result(_.completeResultWithoutBody(statusCode = 204))
90-
//
91-
// def create: Action[CompanyRequest] =
92-
// UpdateCreateEndpoint((c, r) => companyService.createCompany(c)(r))
93-
// .result(_.completeResult())
94-
//
95-
// def getAllCompaniesAsSource: Action[AnyContent] =
96-
// UserInEndpoint
97-
// .logic[Source[Company, NotUsed]]((_, r) => companyService.getAllCompaniesAsStream()(requestContextWithUser(r)))
98-
// .mapOutTo[Source[CompanyResponse, NotUsed]]
99-
// .result(_.completeSourceChunked())
37+
override def getCompanyById(companyId: Long): ContextRoute[definition.CompanyResponse] =
38+
Endpoint.withAuth
39+
.execute(companyService.getById(CompanyId(companyId))(_))
40+
.complete
10041

101-
override def getCompanyById(companyId: String): ContextRoute[definition.CompanyResponse] = ???
42+
override def getAllCompanies(): ContextRoute[CompaniesResponse] =
43+
Endpoint.withAuth
44+
.execute(companyService.getAll()(_))
45+
.complete
10246

103-
override def getAllCompanies(): ContextRoute[CompaniesResponse] = ???
47+
override def createCompany(body: CompanyRequestBody): ContextRoute[CompanyResponse] = Endpoint.withAuth
48+
.execute(companyService.createCompany(body)(_))
49+
.complete
10450

105-
override def createCompany(
106-
id: Option[Long],
107-
settings: Option[Document],
108-
stringAttribute1: Option[String],
109-
stringAttribute2: Option[String],
110-
longAttribute1: Option[Long],
111-
booleanAttribute: Option[Boolean]
112-
): ContextRoute[definition.CompanyResponse] = ???
51+
override def updateCompany(body: CompanyRequestBody): ContextRoute[CompanyResponse] = Endpoint.withAuth
52+
.execute(companyService.updateCompany(body)(_))
53+
.complete
11354

114-
override def updateCompany(
115-
id: Option[Long],
116-
settings: Option[Document],
117-
stringAttribute1: Option[String],
118-
stringAttribute2: Option[String],
119-
longAttribute1: Option[Long],
120-
booleanAttribute: Option[Boolean]
121-
): ContextRoute[definition.CompanyResponse] = ???
55+
override def deleteCompany(companyId: Long): ContextRoute[Unit] = Endpoint.withAuth
56+
.execute(companyService.deleteCompany(CompanyId(companyId))(_))
57+
.complete
12258

123-
override def deleteCompany(companyId: String): ContextRoute[Unit] = ???
12459
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package de.innfactory.bootstrapplay2.companies.application.mapper
2+
3+
import de.innfactory.bootstrapplay2.application.controller.BaseMapper
4+
import de.innfactory.bootstrapplay2.companies.domain.models.{Company, CompanyId}
5+
import de.innfactory.bootstrapplay2.definition.{CompaniesResponse, CompanyRequestBody, CompanyResponse}
6+
import io.scalaland.chimney.dsl.TransformerOps
7+
8+
trait CompanyMapper extends BaseMapper {
9+
implicit val companyToCompanyResponse: Company => CompanyResponse = (
10+
company: Company
11+
) =>
12+
company
13+
.into[CompanyResponse]
14+
.withFieldComputed(_.id, c => c.id.get.value)
15+
.withFieldComputed(_.created, c => dateTimeToDateWithTime(c.created.get))
16+
.withFieldComputed(_.updated, c => dateTimeToDateWithTime(c.updated.get))
17+
.transform
18+
19+
implicit val companiesToCompaniesResponse: Seq[Company] => CompaniesResponse = (companies: Seq[Company]) =>
20+
CompaniesResponse(companies.map(companyToCompanyResponse))
21+
22+
implicit val companyRequestBodyToCompany: CompanyRequestBody => Company = (companyRequestBody: CompanyRequestBody) =>
23+
companyRequestBody
24+
.into[Company]
25+
.withFieldComputed(_.id, c => c.id.map(CompanyId))
26+
.withFieldConst(_.created, None)
27+
.withFieldConst(_.updated, None)
28+
.transform
29+
}

app/de/innfactory/bootstrapplay2/companies/application/models/CompanyRequest.scala

-30
This file was deleted.

app/de/innfactory/bootstrapplay2/companies/application/models/CompanyResponse.scala

-35
This file was deleted.

app/de/innfactory/bootstrapplay2/companies/infrastructure/SlickCompanyRepository.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import dbdata.Tables
77
import de.innfactory.bootstrapplay2.commons.RequestContext
88
import de.innfactory.bootstrapplay2.commons.filteroptions.FilterOptionUtils
99
import de.innfactory.play.controller.ResultStatus
10-
import de.innfactory.bootstrapplay2.commons.infrastructure.BaseSlickDAO
10+
import de.innfactory.bootstrapplay2.commons.infrastructure.BaseSlickRepository
1111
import de.innfactory.bootstrapplay2.commons.results.errors.Errors.BadRequest
1212
import de.innfactory.bootstrapplay2.companies.domain.interfaces.CompanyRepository
1313
import de.innfactory.bootstrapplay2.companies.domain.models.{Company, CompanyId}
@@ -24,7 +24,7 @@ import javax.inject.Inject
2424
import scala.concurrent.{ExecutionContext, Future}
2525

2626
private[companies] class SlickCompanyRepository @Inject() (db: Database)(implicit ec: ExecutionContext)
27-
extends BaseSlickDAO(db)
27+
extends BaseSlickRepository(db)
2828
with CompanyRepository {
2929

3030
private val queryById = (id: CompanyId) => Compiled(Tables.Company.filter(_.id === id.value))

app/de/innfactory/bootstrapplay2/filters/access/RouteBlacklistFilter.scala

+2-4
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ class RouteBlacklistFilter @Inject() (config: Config, implicit val mat: Material
1919

2020
private val accessLogger = Logger("AccessFilterLog")
2121

22-
private val blacklistedRoutes = Seq[BlackListEntry](
23-
BlackListEntry("/v1/assets/swagger.json", Prod, "GET")
24-
)
22+
private val blacklistedRoutes = Seq[BlackListEntry]()
2523

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

0 commit comments

Comments
 (0)