Skip to content

Commit

Permalink
Merge pull request #265 from hmrc/ITSASU-2947
Browse files Browse the repository at this point in the history
[ITSASU-2947] - Create backend api for session data
  • Loading branch information
AlexRimmerHMRC authored Mar 15, 2024
2 parents 9586e97 + 5d4a69d commit 6c160f4
Show file tree
Hide file tree
Showing 6 changed files with 445 additions and 1 deletion.
70 changes: 70 additions & 0 deletions app/controllers/SessionDataController.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2023 HM Revenue & Customs
*
* 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 controllers

import common.Extractors
import play.api.Logging
import play.api.libs.json.JsValue
import play.api.mvc.{Action, AnyContent, ControllerComponents}
import services.{AuthService, SessionDataService}
import uk.gov.hmrc.play.bootstrap.backend.controller.BackendController

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

@Singleton
class SessionDataController @Inject()(authService: AuthService,
sessionDataService: SessionDataService,
cc: ControllerComponents)
(implicit ec: ExecutionContext) extends BackendController(cc) with Logging with Extractors {


def getAllSessionData: Action[AnyContent] = Action.async { implicit request =>
authService.authorised() {
sessionDataService.getAllSessionData.map {
case Some(data) => Ok(data)
case None => NoContent
}
}
}

def retrieveSessionData(id: String): Action[AnyContent] = Action.async { implicit request =>
authService.authorised() {
sessionDataService.getSessionData(id).map {
case Some(data) => Ok(data)
case None => NoContent
}
}
}

def insertSessionData(id: String): Action[JsValue] = Action.async(parse.json) { implicit request =>
authService.authorised() {
sessionDataService.insertSessionData(
dataId = id,
request.body
).map(_ => Ok)
}
}

def deleteSessionData(id: String): Action[AnyContent] = Action.async { implicit request =>
authService.authorised() {
sessionDataService.deleteSessionData(
dataId = id
).map(_ => Ok)
}
}
}
59 changes: 59 additions & 0 deletions app/services/SessionDataService.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2023 HM Revenue & Customs
*
* 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 services

import config.AppConfig
import config.featureswitch.FeatureSwitching
import play.api.libs.json.JsValue
import repositories.SessionDataRepository
import uk.gov.hmrc.http.{HeaderCarrier, InternalServerException}

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

@Singleton
class SessionDataService @Inject()(sessionDataRepository: SessionDataRepository, val appConfig: AppConfig)
(implicit ec: ExecutionContext) extends FeatureSwitching {


def getAllSessionData(implicit hc:HeaderCarrier): Future[Option[JsValue]] =
sessionDataRepository.getSessionData(sessionId = sessionIdFromHC)

def getSessionData(dataId: String)(implicit hc:HeaderCarrier): Future[Option[JsValue]] =
sessionDataRepository.getDataFromSession(sessionId = sessionIdFromHC, dataId = dataId)

def insertSessionData(dataId: String, data: JsValue)(implicit hc:HeaderCarrier): Future[Option[JsValue]] =
sessionDataRepository.insertDataWithSession(
sessionId = sessionIdFromHC,
dataId = dataId,
data = data
)

def deleteSessionData(dataId: String)(implicit hc:HeaderCarrier): Future[Option[JsValue]] =
sessionDataRepository.deleteDataWithSession(
sessionId = sessionIdFromHC,
dataId = dataId
)

private[services] def sessionIdFromHC(implicit hc: HeaderCarrier): String = {
hc.sessionId.fold(
throw new InternalServerException("[SessionDataService][sessionIdFromHC] - No session id in header carrier")
)(_.value)
}
}


6 changes: 6 additions & 0 deletions conf/subscription.routes
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ POST /subscription-data controllers.Subscription

DELETE /subscription-data/:reference/id/:id controllers.SubscriptionDataController.deleteSubscriptionData(reference: String, id: String)

#Session Data
GET /session-data/all controllers.SessionDataController.getAllSessionData
GET /session-data/id/:id controllers.SessionDataController.retrieveSessionData(id: String)
POST /session-data/id/:id controllers.SessionDataController.insertSessionData(id: String)
DELETE /session-data/id/:id controllers.SessionDataController.deleteSessionData(id: String)

POST /mis/sign-up/:nino/:taxYear controllers.SignUpController.signUp(nino: String, taxYear: String)

POST /mis/create/:mtdbsaRef controllers.BusinessIncomeSourcesController.createIncomeSource(mtdbsaRef: String)
Expand Down
180 changes: 180 additions & 0 deletions it/test/controllers/SessionDataControllerISpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
* Copyright 2018 HM Revenue & Customs
*
* 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 controllers

import config.AppConfig
import config.featureswitch.FeatureSwitching
import helpers.ComponentSpecBase
import helpers.servicemocks.AuthStub
import play.api.http.Status._
import play.api.libs.json.{JsObject, Json}
import play.api.test.Helpers.{await, defaultAwaitTimeout}
import repositories.SessionDataRepository

class SessionDataControllerISpec extends ComponentSpecBase with FeatureSwitching {

val appConfig: AppConfig = app.injector.instanceOf[AppConfig]
val repository: SessionDataRepository = app.injector.instanceOf[SessionDataRepository]


val testJson: JsObject = Json.obj("testDataIdKey" -> "testDataIdValue")
val testDocument: JsObject = Json.obj(
"session-id" -> "testSessionId",
"testDataId" -> Json.obj(
"testDataIdKey" -> "testDataIdValue",
"testDataIdKey2" -> 1
)
)

val testDocumentAll: JsObject = Json.obj(
"session-id" -> "testSessionId",
"testDataId" -> Json.obj(
"testDataIdKey" -> "testDataIdValue",
"testDataIdKey2" -> 1
),
"testDataId2" -> Json.obj(
"testDataId2Key" -> "testDataId2Value",
"testDataId2Key2" -> 2
)
)

override def beforeEach(): Unit = {
await(repository.drop())
super.beforeEach()
}


s"GET ${controllers.routes.SessionDataController.getAllSessionData.url}" should {
"return OK with all the data related to the user in mongo" when {
"the sessionId exists in mongo for the user" in {

AuthStub.stubAuthSuccess()
await(repository.insert(testDocumentAll))

IncomeTaxSubscription.getAllSessionData should have(
httpStatus(OK),
jsonBodyOf(testDocumentAll)
)
}
}
"return NO_CONTENT" when {
"the user's sessionId could not be found in mongo" in {

AuthStub.stubAuthSuccess()

IncomeTaxSubscription.getAllSessionData should have(
httpStatus(NO_CONTENT),
emptyBody
)
}
}
"return unauthorised" when {
"the user is not authorised" in {

AuthStub.stubAuthFailure()

IncomeTaxSubscription.getAllSessionData should have(
httpStatus(UNAUTHORIZED)
)
}
}
}

s"GET ${controllers.routes.SessionDataController.retrieveSessionData("testDataId").url}" should {
"return OK with the data related to the key in mongo" when {
"the data exists in mongo for the user" in {

AuthStub.stubAuthSuccess()
await(repository.insert(testDocument))

IncomeTaxSubscription.retrieveSessionData("testDataId") should have(
httpStatus(OK),
jsonBodyOf(Json.obj(
"testDataIdKey" -> "testDataIdValue",
"testDataIdKey2" -> 1
))
)
}
}
"return NO_CONTENT" when {
"the data could not be retrieved from mongo" in {

AuthStub.stubAuthSuccess()

IncomeTaxSubscription.retrieveSessionData("testDataId") should have(
httpStatus(NO_CONTENT),
emptyBody
)
}
}
"return unauthorised" when {
"the user is not authorised" in {

AuthStub.stubAuthFailure()

IncomeTaxSubscription.retrieveSessionData("testDataId") should have(
httpStatus(UNAUTHORIZED)
)
}
}
}

s"POST ${controllers.routes.SessionDataController.insertSessionData("testDataId").url}" should {
"return OK to upsert the data in mongo" when {
"the session document already existed for the user" in {

AuthStub.stubAuthSuccess()
await(repository.insert(testDocument))

IncomeTaxSubscription.insertSessionData("testDataId", testJson) should have(
httpStatus(OK)
)
}
"the session document did not exist for the user" in {

AuthStub.stubAuthSuccess()

IncomeTaxSubscription.insertSessionData("testDataId", testJson) should have(
httpStatus(OK)
)
}
}

"return unauthorised" when {
"the user is not authorised" in {

AuthStub.stubAuthFailure()

val res = IncomeTaxSubscription.insertSessionData("testDataId", testJson)

res should have(
httpStatus(UNAUTHORIZED)
)
}
}
}

s"DELETE ${controllers.routes.SessionDataController.deleteSessionData("testDataId").url}" should {
"return OK and remove select data related to the user in mongo" when {
"the sessionId exists in mongo for the user" in {
AuthStub.stubAuthSuccess()
await(repository.insert(testDocumentAll))
IncomeTaxSubscription.deleteSessionData(id = "testDataId") should have(httpStatus(OK))
}
}
}
}
15 changes: 14 additions & 1 deletion it/test/helpers/ComponentSpecBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike
import org.scalatestplus.play.guice.GuiceOneServerPerSuite
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.libs.json.{JsValue, Json, Writes}
import play.api.libs.json.{JsObject, JsValue, Json, Writes}
import play.api.libs.ws.WSResponse
import play.api.{Application, Environment, Mode}
import uk.gov.hmrc.http.HeaderCarrier
Expand Down Expand Up @@ -149,6 +149,19 @@ trait ComponentSpecBase extends AnyWordSpecLike
.get()
.futureValue


def getAllSessionData: WSResponse =
authorisedClient(s"/session-data/all").get().futureValue

def retrieveSessionData(id:String): WSResponse =
authorisedClient(s"/session-data/id/$id").get().futureValue

def deleteSessionData(id:String): WSResponse =
authorisedClient(s"/session-data/id/$id").delete().futureValue

def insertSessionData(id:String, body: JsObject): WSResponse =
authorisedClient(s"/session-data/id/$id", "Content-Type" -> "application/json").post(body.toString()).futureValue

def post[T](uri: String, body: T)(implicit writes: Writes[T]): WSResponse =
buildClient(uri)
.withHttpHeaders(
Expand Down
Loading

0 comments on commit 6c160f4

Please sign in to comment.