Merge pull request 'API 1.1 WT Club, add customer_membership' (#8) from tibor into master

Reviewed-on: https://git.workouttest.org/bossanyit/aitrainer_server/pulls/8
This commit is contained in:
bossanyit 2023-02-05 08:38:12 +00:00
commit 65143895b0
15 changed files with 71 additions and 102 deletions

View File

@ -7,16 +7,19 @@ CREATE TABLE `membership` (
`duration` INT(11) NULL DEFAULT NULL, `duration` INT(11) NULL DEFAULT NULL,
`duration_type` ENUM('free','subscription','lifetime','limited') NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', `duration_type` ENUM('free','subscription','lifetime','limited') NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
`duration_unit` ENUM('day','week','month','year') NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', `duration_unit` ENUM('day','week','month','year') NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
`training_plan_id` INT(11) NULL DEFAULT '0',
`training_plan_day_ids` CHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
PRIMARY KEY (`membership_id`) USING BTREE PRIMARY KEY (`membership_id`) USING BTREE
); INDEX `training_plan_id` (`training_plan_id`) USING BTREE,
)
ENGINE=InnoDB
;
CREATE TABLE `customer_membership` ( CREATE TABLE `customer_membership` (
`id` INT(11) NOT NULL AUTO_INCREMENT, `id` INT(11) NOT NULL AUTO_INCREMENT,
`customer_id` INT(11) NOT NULL DEFAULT '0', `customer_id` INT(11) NOT NULL DEFAULT '0',
`membership_id` INT(11) NOT NULL DEFAULT '0', `membership_id` INT(11) NOT NULL DEFAULT '0',
`start_date` DATETIME NULL DEFAULT NULL, `start_date` DATETIME NULL DEFAULT NULL,
`training_plan_id` INT(11) NULL DEFAULT NULL,
`days` CHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `customer_id` (`customer_id`) USING BTREE, INDEX `customer_id` (`customer_id`) USING BTREE,
INDEX `membership_id` (`membership_id`) USING BTREE INDEX `membership_id` (`membership_id`) USING BTREE
@ -36,9 +39,9 @@ ALTER TABLE `customer_training_plan`
ALTER TABLE `customer` ALTER TABLE `customer`
CHANGE COLUMN `firebase_uid` `firebase_uid` CHAR(200) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci' AFTER `body_type`; CHANGE COLUMN `firebase_uid` `firebase_uid` CHAR(200) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci' AFTER `body_type`;
ALTER TABLE `customer` ALTER TABLE `customer`
ADD COLUMN `id_token` TEXT NULL DEFAULT NULL AFTER `lang_sync`; CHANGE COLUMN `firebase_reg_token` `firebase_reg_token` TEXT NULL COLLATE 'utf8mb4_general_ci' AFTER `trial_date`;
ALTER TABLE `customer` ALTER TABLE `customer`
ADD INDEX `id_token` (`id_token`); ADD INDEX `firebase_reg_token` (`firebase_reg_token`);
UPDATE configuration set config_value = "1.1.0", date_change=CURRENT_DATE WHERE config_key = "db_version"; UPDATE configuration set config_value = "1.1.0", date_change=CURRENT_DATE WHERE config_key = "db_version";

View File

@ -1,8 +1,10 @@
#aitrainer server API v1.0.57 #aitrainer server API v1.1
connects the MYSQL Database connects the MYSQL Database
provide a RESTful API for the mobile app provide a RESTful API for the mobile app
Workout Test Club
##finished API ##finished API
* customers * customers

View File

@ -190,24 +190,26 @@ class CustomerController ( private val customerRepository: CustomerRepository) {
val signupResponse = firebase.signUp(newUser.email, genPassword) val signupResponse = firebase.signUp(newUser.email, genPassword)
?: return ResponseEntity.badRequest().body("Firebase exception ${firebase.error}") ?: return ResponseEntity.badRequest().body("Firebase exception ${firebase.error}")
val saving_customer = Customer() val savingCustomer = Customer()
if ( serviceBeans == null ) { if ( serviceBeans == null ) {
serviceBeans = ServiceBeans() serviceBeans = ServiceBeans()
} }
with (saving_customer) { with (savingCustomer) {
email = newUser.email email = newUser.email
password = serviceBeans!!.passwordEncoder().encode(genPassword) password = serviceBeans!!.passwordEncoder().encode(genPassword)
idToken = signupResponse.idToken firebaseRegToken = signupResponse.idToken
firebaseUid = signupResponse.localId firebaseUid = signupResponse.localId
dateAdd = nowFormatted dateAdd = nowFormatted
firstname = newUser.firstname firstname = newUser.firstname
name = "" name = ""
goal = newUser.goal goal = newUser.goal
fitnessLevel = newUser.fitnessLevel fitnessLevel = newUser.fitnessLevel
birthYear = newUser.birthYear
sex = newUser.sex
} }
val newCustomer = customerRepository.save(saving_customer) val newCustomer = customerRepository.save(savingCustomer)
if ( newUser.weight != 0.0 ) { if ( newUser.weight != 0.0 ) {
val property = CustomerPropertyProperty() val property = CustomerPropertyProperty()
@ -225,13 +227,24 @@ class CustomerController ( private val customerRepository: CustomerRepository) {
with (property) { with (property) {
propertyId = 2 propertyId = 2
propertyValue = newUser.height propertyValue = newUser.height
dateAdd= nowFormatted dateAdd = nowFormatted
goal = false goal = false
customer = newCustomer customer = newCustomer
} }
newCustomer.properties.add(property) newCustomer.properties.add(property)
} }
val newMembershipId = newUser.membershipId
if ( newMembershipId != 0L) {
val membership = CustomerMembership()
with(membership) {
customer = newCustomer
membershipId = newMembershipId
startDate = nowFormatted
}
newCustomer.memberships.add(membership)
}
customerRepository.save(newCustomer) customerRepository.save(newCustomer)
// create email link // create email link

View File

@ -2,6 +2,7 @@ package com.aitrainer.api.controller
import com.aitrainer.api.model.CustomerMembership import com.aitrainer.api.model.CustomerMembership
import com.aitrainer.api.repository.CustomerMembershipRepository import com.aitrainer.api.repository.CustomerMembershipRepository
import com.aitrainer.api.repository.CustomerRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.security.access.annotation.Secured import org.springframework.security.access.annotation.Secured
@ -10,7 +11,7 @@ import javax.validation.Valid
@RestController @RestController
@RequestMapping("/api") @RequestMapping("/api")
class CustomerMembershipController(private val customerMembershipRepository: CustomerMembershipRepository) { class CustomerMembershipController(private val customerMembershipRepository: CustomerMembershipRepository, private val customerRepository: CustomerRepository) {
private val logger = LoggerFactory.getLogger(javaClass) private val logger = LoggerFactory.getLogger(javaClass)
@PostMapping("/customer_membership") @PostMapping("/customer_membership")
@ -19,25 +20,12 @@ class CustomerMembershipController(private val customerMembershipRepository: Cus
return ResponseEntity.ok().body(customerMembershipRepository.save(customerMembership)) return ResponseEntity.ok().body(customerMembershipRepository.save(customerMembership))
} }
@Secured
@PostMapping("customer_membership/update/{id}")
fun updateCustomerMembership(@PathVariable(value = "id") membershipId: Long,
@Valid @RequestBody membershipToUpdate: CustomerMembership): ResponseEntity<CustomerMembership> {
val customerMembership = customerMembershipRepository.findById(membershipId).orElse(null)
?: return ResponseEntity.notFound().build()
val updatedCustomerMembership = customerMembership.copy(
trainingPlanId = membershipToUpdate.trainingPlanId,
days = membershipToUpdate.days,
)
return ResponseEntity.ok().body(customerMembershipRepository.save(updatedCustomerMembership))
}
@GetMapping("/customer_membership/{customer_id}") @GetMapping("/customer_membership/{customer_id}")
fun getAllByCustomerId(@PathVariable(value = "customer_id") customerId: Long): ResponseEntity<List<CustomerMembership>> { fun getAllByCustomerId(@PathVariable(value = "customer_id") customerId: Long): ResponseEntity<List<CustomerMembership>> {
val customer = customerRepository.findByCustomerIdAndActive(customerId, "Y")
?: return ResponseEntity.notFound().build()
val membershipList: List<CustomerMembership> = customerMembershipRepository.findAllByCustomerId(customerId) val membershipList: List<CustomerMembership> = customerMembershipRepository.findAllByCustomer(customer)
logger.info("Get all customer_membership by by customerId") logger.info("Get all customer_membership by by customerId")
return if(membershipList.isNotEmpty()) return if(membershipList.isNotEmpty())

View File

@ -47,7 +47,7 @@ class CustomerPackageController( private val customerRepository: CustomerReposit
val listTrainingPlan = customerTrainingPlanRepository.findAllByCustomerId(customerId) val listTrainingPlan = customerTrainingPlanRepository.findAllByCustomerId(customerId)
val listTrainingPlanJson = gson.toJson(listTrainingPlan) val listTrainingPlanJson = gson.toJson(listTrainingPlan)
val listMembership = customerMembership.findAllByCustomerId(customerId) val listMembership = customerMembership.findAllByCustomer(customer)
val listMembershipJson = gson.toJson(listMembership) val listMembershipJson = gson.toJson(listMembership)
val packageJson: String = val packageJson: String =

View File

@ -7,10 +7,13 @@ import kotlinx.serialization.json.*
data class ClubUser ( data class ClubUser (
var email: String = "", var email: String = "",
var firstname: String = "", var firstname: String = "",
var sex: String = "m",
var birthYear: Int = 0,
var weight: Double = 0.0, var weight: Double = 0.0,
var height: Double = 0.0, var height: Double = 0.0,
var goal: String = "", var goal: String = "",
var fitnessLevel: String = "", var fitnessLevel: String = "",
var membershipId: Long = 0,
) { ) {
fun fromJson(json: String): ClubUser { fun fromJson(json: String): ClubUser {
return Json.decodeFromString(serializer(), json) return Json.decodeFromString(serializer(), json)

View File

@ -34,11 +34,14 @@ data class Customer (
@Expose var lang: String? = null, @Expose var lang: String? = null,
@Expose var phone: String? = null, @Expose var phone: String? = null,
@Expose var lifeLong: Int? = null, @Expose var lifeLong: Int? = null,
@Expose var idToken: String? = null,
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose var customerId: Long = 0, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose var customerId: Long = 0,
) { ) {
@OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.EAGER, mappedBy = "customer") @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.EAGER, mappedBy = "customer")
@Fetch(value = FetchMode.SUBSELECT) @Fetch(value = FetchMode.SUBSELECT)
@Expose val properties: MutableList<CustomerPropertyProperty> = mutableListOf() @Expose val properties: MutableList<CustomerPropertyProperty> = mutableListOf()
@OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.EAGER, mappedBy = "customer")
@Fetch(value = FetchMode.SUBSELECT)
@Expose val memberships: MutableList<CustomerMembership> = mutableListOf()
} }

View File

@ -1,5 +1,6 @@
package com.aitrainer.api.model package com.aitrainer.api.model
import com.fasterxml.jackson.annotation.JsonIgnore
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import org.springframework.lang.NonNull import org.springframework.lang.NonNull
import jakarta.persistence.* import jakarta.persistence.*
@ -7,9 +8,10 @@ import jakarta.persistence.*
@Entity @Entity
data class CustomerMembership ( data class CustomerMembership (
@Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @get: NonNull var id: Long = 0, @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @get: NonNull var id: Long = 0,
@Expose @get: NonNull var customerId: Long = 0,
@Expose @get: NonNull var membershipId: Long = 0, @Expose @get: NonNull var membershipId: Long = 0,
@Expose @get: NonNull var startDate: String? = null, @Expose @get: NonNull var startDate: String? = null,
@Expose @get: NonNull var trainingPlanId: Long = 0, ) {
@Expose @get: NonNull var days: String? = null @ManyToOne(fetch = FetchType.EAGER, optional = false)
) @JoinColumn(name = "customerId", nullable = false)
@JsonIgnore var customer: Customer? = null
}

View File

@ -12,4 +12,6 @@ data class Membership (
@Expose @get: NonNull var duration: Int? = null, @Expose @get: NonNull var duration: Int? = null,
@Expose @get: NonNull var durationType: String? = null, @Expose @get: NonNull var durationType: String? = null,
@Expose @get: NonNull var durationUnit: String? = null, @Expose @get: NonNull var durationUnit: String? = null,
@Expose @get: NonNull var trainingPlanId: Long = 0,
@Expose @get: NonNull var trainingPlanDayIds: String? = null
) )

View File

@ -1,5 +1,6 @@
package com.aitrainer.api.repository package com.aitrainer.api.repository
import com.aitrainer.api.model.Customer
import com.aitrainer.api.model.CustomerMembership import com.aitrainer.api.model.CustomerMembership
import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query import org.springframework.data.jpa.repository.Query
@ -8,7 +9,7 @@ import org.springframework.stereotype.Repository
@Repository @Repository
interface CustomerMembershipRepository : JpaRepository<CustomerMembership, Long> { interface CustomerMembershipRepository : JpaRepository<CustomerMembership, Long> {
@Query(" FROM CustomerMembership " + @Query(" FROM CustomerMembership " +
" WHERE customerId = :customerId" " WHERE customer = :customer"
) )
fun findAllByCustomerId(customerId: Long): List<CustomerMembership> fun findAllByCustomer(customer: Customer): List<CustomerMembership>
} }

View File

@ -59,8 +59,6 @@ class Firebase {
error = JSONObject(response.body()).getJSONObject("error").getString("message").toString() error = JSONObject(response.body()).getJSONObject("error").getString("message").toString()
return error return error
} }
print("Firebase $command response $response")
error = "" error = ""
return response.body() return response.body()
} }

View File

@ -80,9 +80,6 @@ class AppCustomerPackageTest {
val customerMembershipList: List<CustomerMembership> = gson.fromJson(customerMembershipJson, type) val customerMembershipList: List<CustomerMembership> = gson.fromJson(customerMembershipJson, type)
assertEquals(customerMembershipList.size, 2) assertEquals(customerMembershipList.size, 2)
assertEquals(customerMembershipList[0].membershipId, 1) assertEquals(customerMembershipList[0].membershipId, 1)
assertEquals(customerMembershipList[0].trainingPlanId, 99)
assertEquals(customerMembershipList[0].days, "22|23")
assertEquals(customerMembershipList[1].trainingPlanId, 102)
} }
record[0] == CustomerProperty::class.simpleName -> { record[0] == CustomerProperty::class.simpleName -> {

View File

@ -100,6 +100,14 @@ class AppPackageTest {
assertEquals(listMembership[1].name, "Lifetime") assertEquals(listMembership[1].name, "Lifetime")
assertEquals(listMembership[3].durationUnit, "month") assertEquals(listMembership[3].durationUnit, "month")
assertEquals(listMembership[2].durationType, "limited") assertEquals(listMembership[2].durationType, "limited")
assertEquals(listMembership.size, 5)
assertEquals(listMembership[0].name, "Free")
assertEquals(listMembership[4].name, "Mezomorph Free 1W")
assertEquals(listMembership[4].duration, 1)
assertEquals(listMembership[4].durationUnit, "week")
assertEquals(listMembership[4].trainingPlanId, 99)
assertEquals(listMembership[4].trainingPlanDayIds, "21|22")
} }
} }
} }

View File

@ -1,8 +1,10 @@
package com.aitrainer.api.test package com.aitrainer.api.test
import com.aitrainer.api.controller.CustomerMembershipController import com.aitrainer.api.controller.CustomerMembershipController
import com.aitrainer.api.model.Customer
import com.aitrainer.api.model.CustomerMembership import com.aitrainer.api.model.CustomerMembership
import com.aitrainer.api.repository.CustomerMembershipRepository import com.aitrainer.api.repository.CustomerMembershipRepository
import com.aitrainer.api.repository.CustomerRepository
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
@ -15,16 +17,15 @@ import kotlin.test.assertTrue
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CustomerMembershipTest { class CustomerMembershipTest {
private var insertedId: Long = 0
private var deleteInsert: Boolean = true
@Autowired @Autowired
private lateinit var customerMembershipRepository: CustomerMembershipRepository private lateinit var customerMembershipRepository: CustomerMembershipRepository
@Autowired lateinit var customerRepository: CustomerRepository
@Test @Test
fun testCustomerMembershipByCustomerId() { fun testCustomerMembershipByCustomerId() {
val controller = CustomerMembershipController(customerMembershipRepository ) val controller = CustomerMembershipController(customerMembershipRepository, customerRepository )
val response = controller.getAllByCustomerId(90) val response = controller.getAllByCustomerId(90)
val properties = response.body val properties = response.body
@ -32,65 +33,24 @@ class CustomerMembershipTest {
assertTrue(properties is List) assertTrue(properties is List)
assertTrue(properties.isNotEmpty()) assertTrue(properties.isNotEmpty())
assertEquals(properties.size, 2) assertEquals(properties.size, 2)
assertEquals(properties[0].trainingPlanId, 99)
assertEquals(properties[0].days, "22|23")
} }
@Test @Test
fun testInsert() { fun testInsert() {
/* val foundCustomer: Customer? = customerRepository.findByCustomerIdAndActive(90, "Y")
val customerMembership = CustomerMembership( val customerMembership = CustomerMembership(
customerId = 90,
membershipId = 3, membershipId = 3,
startDate = "2023-01-30", startDate = "2023-01-30",
trainingPlanId = 103
) )
customerMembership.customer = foundCustomer
val controller = CustomerMembershipController(customerMembershipRepository) val controller = CustomerMembershipController(customerMembershipRepository, customerRepository)
val response = controller.createNewCustomerMembership(customerMembership) val response = controller.createNewCustomerMembership(customerMembership)
val newCustomerMembership = response.body val newCustomerMembership = response.body
assertTrue(newCustomerMembership is CustomerMembership) assertTrue(newCustomerMembership is CustomerMembership)
assertEquals(newCustomerMembership.trainingPlanId, 103) customerMembershipRepository.delete(newCustomerMembership) // does not delete the customer_membership
*/
if ( this.deleteInsert ) {
customerMembershipRepository.delete(customerMembership)
} else {
this.insertedId = newCustomerMembership.id
}
} }
@Test
fun testUpdate() {
this.deleteInsert = false
this.testInsert()
var customerMembership = CustomerMembership(
customerId = 90,
startDate = "2020-11-10",
trainingPlanId = 99
)
val controller = CustomerMembershipController(customerMembershipRepository)
var response = controller.updateCustomerMembership(this.insertedId, customerMembership)
assertTrue(response.body is CustomerMembership)
val updated = response.body
assertEquals(updated!!.trainingPlanId, 99)
assertEquals(updated.startDate, "2023-01-30 00:00:00" )
customerMembershipRepository.delete(updated)
//notFound
customerMembership = CustomerMembership(
id = 10000,
startDate = "2021-02-15",
trainingPlanId = 83
)
response = controller.updateCustomerMembership(customerMembership.id, customerMembership)
assertEquals(response.statusCode, HttpStatus.NOT_FOUND)
}
} }

View File

@ -238,17 +238,6 @@ class CustomerTests {
val controller = CustomerController(customerRepository) val controller = CustomerController(customerRepository)
val response: ResponseEntity<*> = controller.clubRegistration(json) val response: ResponseEntity<*> = controller.clubRegistration(json)
assertEquals(response.statusCode, HttpStatus.BAD_REQUEST) assertEquals(response.statusCode, HttpStatus.BAD_REQUEST)
/*
json = "{\"firstname\":\"Tib\", \"email\": \"mr@workouttest.com\", \"goal\": \"shape\", \"fitnessLevel\": \"advanced\", \"weight\": 85}";
response = controller.clubRegistration(json)
assertEquals(response.statusCode, HttpStatus.OK)
val newCustomer: Customer = response.body as Customer
assertTrue(newCustomer.firebaseUid!!.isNotEmpty())
val firebase = Firebase()
firebase.deleteUser(newCustomer.firebaseUid!!)
customerRepository.delete(newCustomer)
*/
} }
@Test @Test