diff --git a/build.gradle.kts b/build.gradle.kts index 2515bc4..96e0866 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "com.aitrainer" -version = "1.2.6" +version = "1.2.7" java.sourceCompatibility = JavaVersion.VERSION_17 repositories { diff --git a/data/db/update_1_2_7.sql b/data/db/update_1_2_7.sql new file mode 100644 index 0000000..1236782 --- /dev/null +++ b/data/db/update_1_2_7.sql @@ -0,0 +1,8 @@ +START TRANSACTION; + +ALTER TABLE `customer_membership` + ADD COLUMN `end_date` DATETIME NULL DEFAULT NULL AFTER `start_date`; + +UPDATE configuration set config_value = "1.2.7", date_change=CURRENT_DATE WHERE config_key = "db_version"; + +COMMIT; \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/controller/CustomerController.kt b/src/main/kotlin/com/aitrainer/api/controller/CustomerController.kt index 1e155a8..0c3f712 100644 --- a/src/main/kotlin/com/aitrainer/api/controller/CustomerController.kt +++ b/src/main/kotlin/com/aitrainer/api/controller/CustomerController.kt @@ -3,12 +3,14 @@ package com.aitrainer.api.controller import com.aitrainer.api.model.* import com.aitrainer.api.service.ServiceBeans import com.aitrainer.api.repository.CustomerRepository +import com.aitrainer.api.repository.MembershipRepository import com.aitrainer.api.service.Email import com.aitrainer.api.service.EmailTemplateService import com.aitrainer.api.service.Firebase import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value +import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpHeaders import org.springframework.http.ResponseEntity import org.springframework.security.access.annotation.Secured @@ -22,7 +24,7 @@ import java.util.Base64 @RestController @RequestMapping("/api") -class CustomerController ( private val customerRepository: CustomerRepository) { +class CustomerController (private val customerRepository: CustomerRepository, private val membershipRepository: MembershipRepository,) { private val logger = LoggerFactory.getLogger(javaClass) @Autowired @@ -325,4 +327,60 @@ class CustomerController ( private val customerRepository: CustomerRepository) { ResponseEntity.badRequest().body("Customer does not exist or the password is wrong") } } + + @PostMapping("/membership/{id}") + fun newMembership(@PathVariable(value = "id") membershipId: Long, @Valid @RequestBody customer: Customer): ResponseEntity { + val returnCustomer: Customer = customerRepository.findById(customer.customerId).orElse(null) + ?: return ResponseEntity.notFound().build() + println("found customer ${returnCustomer.customerId}") + + val membership: Membership = membershipRepository.findByIdOrNull(membershipId) + ?: return ResponseEntity.notFound().build() + + println("found membership $membershipId") + + val customerMembership = CustomerMembership() + customerMembership.membershipId = membershipId + customerMembership.customer = returnCustomer + val now = LocalDateTime.now() + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + customerMembership.startDate = now.format(formatter) + returnCustomer.memberships.add(customerMembership) + customerRepository.save(returnCustomer) + + val savedCustomer: Customer = customerRepository.findById(customer.customerId).orElse(null) + ?: return ResponseEntity.notFound().build() + + println("saved ${savedCustomer.customerId}") + return ResponseEntity.ok(savedCustomer) + } + + @PostMapping("/membership/cancel/{id}") + fun cancelMembership(@PathVariable(value = "id") membershipId: Long, @Valid @RequestBody customer: Customer): ResponseEntity { + val returnCustomer: Customer = customerRepository.findById(customer.customerId).orElse(null) + ?: return ResponseEntity.notFound().build() + println("found customer ${returnCustomer.customerId}") + + val membership: Membership = membershipRepository.findByIdOrNull(membershipId) + ?: return ResponseEntity.notFound().build() + println("found membership $membershipId") + + var found = false + var savedCustomer: Customer? = null + for ( customerMembership in returnCustomer.memberships ) { + if ( customerMembership.membershipId == membershipId) { + val now = LocalDateTime.now() + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + customerMembership.endDate = now.format(formatter) + savedCustomer = customerRepository.save(returnCustomer) + found = true + } + } + return if ( ! found ) { + println("not found customer membership to cancel $membershipId") + ResponseEntity.notFound().build() + } else { + ResponseEntity.ok(savedCustomer) + } + } } \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/CustomerMembership.kt b/src/main/kotlin/com/aitrainer/api/model/CustomerMembership.kt index b7409d7..250abca 100644 --- a/src/main/kotlin/com/aitrainer/api/model/CustomerMembership.kt +++ b/src/main/kotlin/com/aitrainer/api/model/CustomerMembership.kt @@ -10,6 +10,7 @@ data class CustomerMembership ( @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @get: NonNull var id: Long = 0, @Expose @get: NonNull var membershipId: Long = 0, @Expose @get: NonNull var startDate: String? = null, + @Expose @get: NonNull var endDate: String? = null, ) { @ManyToOne(fetch = FetchType.EAGER, optional = false) @JoinColumn(name = "customerId", nullable = false) diff --git a/src/main/resources/application-diet.properties b/src/main/resources/application-diet.properties index a68733d..6ecf468 100644 --- a/src/main/resources/application-diet.properties +++ b/src/main/resources/application-diet.properties @@ -16,7 +16,7 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structure has been changed, increment this version number -application.version=1.2.6 +application.version=1.2.7 jwt.secret=aitrainer diff --git a/src/main/resources/application-dietprod.properties b/src/main/resources/application-dietprod.properties index 2b9bbdf..0490de5 100644 --- a/src/main/resources/application-dietprod.properties +++ b/src/main/resources/application-dietprod.properties @@ -14,7 +14,7 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structue has been changed, increment this version number -application.version=1.2.6 +application.version=1.2.7 jwt.secret=aitrainer diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index e3fda7f..5cc5804 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -14,7 +14,7 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structue has been changed, increment this version number -application.version=1.2.6 +application.version=1.2.7 jwt.secret=aitrainer diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b313a1d..af6bc10 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -17,7 +17,7 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structure has been changed, increment this version number -application.version=1.2.6 +application.version=1.2.7 jwt.secret=aitrainer diff --git a/src/test/kotlin/com/aitrainer/api/test/CustomerTests.kt b/src/test/kotlin/com/aitrainer/api/test/CustomerTests.kt index d9004ed..7411046 100644 --- a/src/test/kotlin/com/aitrainer/api/test/CustomerTests.kt +++ b/src/test/kotlin/com/aitrainer/api/test/CustomerTests.kt @@ -4,7 +4,9 @@ import com.aitrainer.api.controller.CustomerController import com.aitrainer.api.model.Customer import com.aitrainer.api.model.User import com.aitrainer.api.repository.CustomerRepository +import com.aitrainer.api.repository.MembershipRepository import com.aitrainer.api.service.ServiceBeans +import com.fasterxml.jackson.databind.ObjectMapper import com.google.gson.Gson import org.json.JSONObject import org.junit.jupiter.api.BeforeAll @@ -22,12 +24,13 @@ import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.MvcResult import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status import java.time.LocalDateTime import java.time.format.DateTimeFormatter +import java.util.* import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue -import java.util.Base64 @SpringBootTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -48,6 +51,9 @@ class CustomerTests { @Autowired private lateinit var customerRepository: CustomerRepository + @Autowired + private lateinit var membershipRepository: MembershipRepository + private var insertedId: Long? = null @@ -58,7 +64,7 @@ class CustomerTests { assertEquals( customer.name, "Átlag 18 éves fiú") val id2: Long = 90 - val controller = CustomerController(customerRepository) + val controller = CustomerController(customerRepository, membershipRepository) val response = controller.getCustomerById(id2) val customer2: Customer = response.body as Customer @@ -111,7 +117,7 @@ class CustomerTests { fun testDeactivateCustomer() { val id: Long = 90 - val controller = CustomerController(customerRepository) + val controller = CustomerController(customerRepository, membershipRepository) controller.deactivateCustomer(id) val customer: Customer = customerRepository.findById(id).orElse(null) @@ -128,7 +134,7 @@ class CustomerTests { @Test fun testFindByEmail() { - val controller = CustomerController(customerRepository) + val controller = CustomerController(customerRepository, membershipRepository) var response = controller.getCustomerByEmail("sw@andio.biz") val customer = response.body @@ -204,7 +210,7 @@ class CustomerTests { customer.birthYear = 1972 customer.dateChange = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")) - val customerController = CustomerController(customerRepository) + val customerController = CustomerController(customerRepository, membershipRepository) var response: ResponseEntity<*> = customerController.updateCustomerById(id, customer, HttpHeaders.readOnlyHttpHeaders(HttpHeaders.EMPTY) ) print ("body " + response.body) var newCustomer: Customer? = response.body as Customer @@ -249,7 +255,7 @@ class CustomerTests { @Test fun testClubRegistration(@Value("\${firebase.key}") apiKey: java.lang.String) { val json = "{\"firstname\":\"Tib\", \"email\": \"mr@andio.biz\", \"goal\": \"shape\", \"fitnessLevel\": \"advanced\", \"weight\": 85}" - val controller = CustomerController(customerRepository) + val controller = CustomerController(customerRepository, membershipRepository) val response: ResponseEntity<*> = controller.clubRegistration(json, apiKey) assertEquals(response.statusCode, HttpStatus.BAD_REQUEST) } @@ -265,7 +271,7 @@ class CustomerTests { password = user.password firebaseUid = user.firebaseUid } - val customerController = CustomerController(customerRepository) + val customerController = CustomerController(customerRepository, membershipRepository) customerController.serviceBeans = serviceBean val response: ResponseEntity<*> = customerController.registration(json) print("body " + response.body) @@ -290,7 +296,7 @@ class CustomerTests { insertedId = savedCustomer.customerId - val customerController = CustomerController(customerRepository) + val customerController = CustomerController(customerRepository, membershipRepository) val response: ResponseEntity<*> = customerController.updateCustomerFirebaseUidById(insertedId!!, "3FirebusaeId4") val newCustomer2: Customer = response.body as Customer assertEquals(response.statusCode, HttpStatus.OK) @@ -305,7 +311,7 @@ class CustomerTests { @Test fun testGetCustomerByFirebaseUid() { val uid = "3FirebaseU1d" - val customerController = CustomerController(customerRepository) + val customerController = CustomerController(customerRepository, membershipRepository) val response: ResponseEntity<*> = customerController.getCustomerByFirebaseUid(uid) assertEquals(response.statusCode, HttpStatus.OK) val newCustomer: Customer = response.body as Customer @@ -317,7 +323,7 @@ class CustomerTests { @Test fun testGetCustomerByEmail() { val email = "sw2@andio.biz" - val customerController = CustomerController(customerRepository) + val customerController = CustomerController(customerRepository, membershipRepository) val response: ResponseEntity<*> = customerController.getCustomerByEmail(email) assertEquals(response.statusCode, HttpStatus.OK) @@ -330,7 +336,7 @@ class CustomerTests { } @Test - fun `get customer successfully`() { + fun `insert customer successfully`() { authToken = Tokenizer.getToken() val customer = Customer( @@ -347,7 +353,7 @@ class CustomerTests { .header("Authorization", "Bearer $authToken") .content(toJson(customer)) ) - .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(status().isOk) .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("Kadarka")) .andExpect(MockMvcResultMatchers.jsonPath("$.age").value(32)) .andExpect(MockMvcResultMatchers.jsonPath("$.birthYear").value(1987)) @@ -376,7 +382,7 @@ class CustomerTests { .header("Authorization", "Bearer $authToken") .content(toJson(user)) ) - .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(status().isOk) .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("Bos")) .andExpect(MockMvcResultMatchers.jsonPath("$.firstname").value("Kakadu")) .andExpect(MockMvcResultMatchers.jsonPath("$.birthYear").value(1972)) @@ -400,7 +406,7 @@ class CustomerTests { .header("Authorization", "Bearer $authToken") .content(password) ) - .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(status().isOk) .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("Bos")) .andExpect(MockMvcResultMatchers.jsonPath("$.firstname").value("Kakadu")) .andExpect(MockMvcResultMatchers.jsonPath("$.birthYear").value(1972)) @@ -417,10 +423,58 @@ class CustomerTests { .header("Authorization", "Bearer $authToken") .content(password) ) - .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(status().isOk) + } + + @Test + fun `new membership successfully`() { + authToken = Tokenizer.getToken() + val gson= Gson() + + val customer = getCustomer(103) + + mockMvc.perform( + MockMvcRequestBuilders.post("/api/membership/89") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer $authToken") + .content(toJson(customer)) + ).andExpect(status().isNotFound) + + val mvcResult2: MvcResult = mockMvc.perform( + MockMvcRequestBuilders.post("/api/membership/2") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer $authToken") + .content(toJson(customer)) + ).andExpect(status().isOk) + //.andExpect(MockMvcResultMatchers.jsonPath("$.memberships.length").value(3)) + .andReturn() + + val customer2Json = mvcResult2.response.contentAsString + println(customer2Json) + val customer2 = gson.fromJson(customer2Json, Customer::class.java) + println(customer2) + } + + fun getCustomer(customerId: Long) : Customer { + authToken = Tokenizer.getToken() + + val mvcResult: MvcResult = mockMvc.perform( + MockMvcRequestBuilders.get("/api/customers/$customerId") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer $authToken") + ) + .andExpect(status().isOk) + .andReturn() + + val gson= Gson() + val customerJson = mvcResult.response.contentAsString + return gson.fromJson(customerJson, Customer::class.java) + } private fun toJson(obj: Any): String { return Gson().toJson(obj) } + + } \ No newline at end of file