diff --git a/build.gradle.kts b/build.gradle.kts index a3f333e..0308fa0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "com.aitrainer" -version = "1.0.12" +version = "1.0.14" java.sourceCompatibility = JavaVersion.VERSION_1_8 repositories { diff --git a/data/db/install.sql b/data/db/install.sql index 506b115..59fc445 100644 --- a/data/db/install.sql +++ b/data/db/install.sql @@ -380,6 +380,51 @@ COLLATE='utf8_hungarian_ci' ENGINE=InnoDB ; +CREATE TABLE `exercise_device` ( + `device_id` INT(11) NOT NULL AUTO_INCREMENT, + `name` CHAR(50) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + `description` VARCHAR(200) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + `image_url` CHAR(100) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + PRIMARY KEY (`device_id`) USING BTREE +) +COLLATE='utf8_hungarian_ci' +ENGINE=InnoDB +; + +INSERT INTO `exercise_device` (`device_id`, `name`, `description`, `image_url`) VALUES (1, 'Weight', NULL, NULL); +INSERT INTO `exercise_device` (`device_id`, `name`, `description`, `image_url`) VALUES (2, 'Own Weight', NULL, NULL); + + +CREATE TABLE `exercise_device_translation` ( + `translation_id` INT(11) NOT NULL AUTO_INCREMENT, + `device_id` INT(11) NULL DEFAULT NULL, + `language_code` CHAR(2) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + `name` CHAR(100) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + PRIMARY KEY (`translation_id`) USING BTREE +) +COLLATE='utf8_hungarian_ci' +ENGINE=InnoDB +; + +INSERT INTO `exercise_device_translation` (`translation_id`, `device_id`, `language_code`, `name`) VALUES (1, 1, 'hu', 'Súlyzó'); +INSERT INTO `exercise_device_translation` (`translation_id`, `device_id`, `language_code`, `name`) VALUES (2, 2, 'hu', 'Saját testsúly'); + + + +CREATE TABLE `exercise_type_device` ( + `exercise_type_device_id` INT(11) NOT NULL AUTO_INCREMENT, + `exercise_type_id` INT(11) NOT NULL DEFAULT '0', + `device_id` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`exercise_type_device_id`) USING BTREE, + INDEX `exercise_type_id` (`exercise_type_id`) USING BTREE, + INDEX `exercise_device_id` (`device_id`) USING BTREE +) +COLLATE='utf8_hungarian_ci' +ENGINE=InnoDB +; + +INSERT INTO `exercise_type_device` (`exercise_type_device_id`, `exercise_type_id`, `exercise_device_id`) VALUES (1, 37, 1); + /*!40000 ALTER TABLE `exercise_type` ENABLE KEYS */; diff --git a/data/db/update_1_0_13.sql b/data/db/update_1_0_13.sql new file mode 100644 index 0000000..49abd19 --- /dev/null +++ b/data/db/update_1_0_13.sql @@ -0,0 +1,4 @@ +INSERT INTO customer_property (customer_id, property_id, property_value, DATE_ADD) + SELECT customer_id, 1, weight, NOW() FROM customer WHERE weight IS NOT NULL AND weight != 0; + +UPDATE configuration set config_value = "1.0.13", date_change=CURRENT_DATE WHERE config_key = "db_version"; \ No newline at end of file diff --git a/data/db/update_1_0_14.sql b/data/db/update_1_0_14.sql new file mode 100644 index 0000000..5434de7 --- /dev/null +++ b/data/db/update_1_0_14.sql @@ -0,0 +1,47 @@ +CREATE TABLE `exercise_device` ( + `device_id` INT(11) NOT NULL AUTO_INCREMENT, + `name` CHAR(50) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + `description` VARCHAR(200) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + `image_url` CHAR(100) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + PRIMARY KEY (`device_id`) USING BTREE +) +COLLATE='utf8_hungarian_ci' +ENGINE=InnoDB +; + +INSERT INTO `exercise_device` (`device_id`, `name`, `description`, `image_url`) VALUES (1, 'Weight', NULL, NULL); +INSERT INTO `exercise_device` (`device_id`, `name`, `description`, `image_url`) VALUES (2, 'Own Weight', NULL, NULL); + + +CREATE TABLE `exercise_device_translation` ( + `translation_id` INT(11) NOT NULL AUTO_INCREMENT, + `device_id` INT(11) NULL DEFAULT NULL, + `language_code` CHAR(2) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + `name` CHAR(100) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci', + PRIMARY KEY (`translation_id`) USING BTREE +) +COLLATE='utf8_hungarian_ci' +ENGINE=InnoDB +; + +INSERT INTO `exercise_device_translation` (`translation_id`, `device_id`, `language_code`, `name`) VALUES (1, 1, 'hu', 'Súlyzó'); +INSERT INTO `exercise_device_translation` (`translation_id`, `device_id`, `language_code`, `name`) VALUES (2, 2, 'hu', 'Saját testsúly'); + + + +CREATE TABLE `exercise_type_device` ( + `exercise_type_device_id` INT(11) NOT NULL AUTO_INCREMENT, + `exercise_type_id` INT(11) NOT NULL DEFAULT '0', + `exercise_device_id` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`exercise_type_device_id`) USING BTREE, + INDEX `exercise_type_id` (`exercise_type_id`) USING BTREE, + INDEX `device_id` (`device_id`) USING BTREE +) +COLLATE='utf8_hungarian_ci' +ENGINE=InnoDB +; + +INSERT INTO `exercise_type_device` (`exercise_type_device_id`, `exercise_type_id`, `exercise_device_id`) VALUES (1, 37, 1); + + +UPDATE configuration set config_value = "1.0.14", date_change=CURRENT_DATE WHERE config_key = "db_version"; \ No newline at end of file diff --git a/readme.MD b/readme.MD index 84894c8..5e671f0 100644 --- a/readme.MD +++ b/readme.MD @@ -1,4 +1,4 @@ -#aitrainer server API v1.0.9 +#aitrainer server API v1.0.14 connects the MYSQL Database provide a RESTful API for the mobile app @@ -22,5 +22,8 @@ provide a RESTful API for the mobile app * property * property_translation * customer_property +* exercise_device +* exercise_device_translation +* exercise_type_device with automatic database update diff --git a/src/main/kotlin/com/aitrainer/api/controller/ExerciseDeviceController.kt b/src/main/kotlin/com/aitrainer/api/controller/ExerciseDeviceController.kt new file mode 100644 index 0000000..214b2ea --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/ExerciseDeviceController.kt @@ -0,0 +1,24 @@ +package com.aitrainer.api.controller + +import com.aitrainer.api.model.ExerciseDevice +import com.aitrainer.api.repository.ExerciseDeviceRepository +import org.slf4j.LoggerFactory +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/api") +class ExerciseDeviceController(private val exerciseDeviceRepository: ExerciseDeviceRepository) { + private val logger = LoggerFactory.getLogger(javaClass) + + @GetMapping("/exercise_device") + fun getDevicesWithTranslation(): ResponseEntity> { + val list = exerciseDeviceRepository.getExerciseDevices() + + logger.info(" -- Get All ExerciseDevices $list") + return if (list.isEmpty()) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(list) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/ExerciseDevice.kt b/src/main/kotlin/com/aitrainer/api/model/ExerciseDevice.kt new file mode 100644 index 0000000..8643f46 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/ExerciseDevice.kt @@ -0,0 +1,22 @@ +package com.aitrainer.api.model + +import com.fasterxml.jackson.annotation.JsonIgnore +import org.hibernate.annotations.Fetch +import org.hibernate.annotations.FetchMode +import javax.persistence.* +import javax.validation.constraints.NotBlank + +@Entity +data class ExerciseDevice ( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val deviceId: Long = 0, + + @get: NotBlank var name: String = "", + @get: NotBlank var description: String = "", + @get: NotBlank var imageUrl: String = "" +){ + @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.EAGER, mappedBy = "exerciseDevice") + @Fetch(value = FetchMode.SUBSELECT) + val translations: List = mutableListOf().toList() +} diff --git a/src/main/kotlin/com/aitrainer/api/model/ExerciseDeviceTranslation.kt b/src/main/kotlin/com/aitrainer/api/model/ExerciseDeviceTranslation.kt new file mode 100644 index 0000000..095c291 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/ExerciseDeviceTranslation.kt @@ -0,0 +1,23 @@ +package com.aitrainer.api.model + +import com.fasterxml.jackson.annotation.JsonIgnore +import javax.persistence.* +import javax.validation.constraints.NotBlank + +@Entity +data class ExerciseDeviceTranslation ( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val translationId: Long = 0, + + @get: NotBlank var languageCode: String?, + @get: NotBlank var name: String = "" + + +) { + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "deviceId", nullable = false) + @JsonIgnore + val exerciseDevice: ExerciseDevice? = null + +} diff --git a/src/main/kotlin/com/aitrainer/api/model/ExerciseType.kt b/src/main/kotlin/com/aitrainer/api/model/ExerciseType.kt index 2a65039..1a2e46d 100644 --- a/src/main/kotlin/com/aitrainer/api/model/ExerciseType.kt +++ b/src/main/kotlin/com/aitrainer/api/model/ExerciseType.kt @@ -32,4 +32,8 @@ data class ExerciseType( @Fetch(value = FetchMode.SUBSELECT) val translations: List = mutableListOf() + @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.EAGER, mappedBy = "exerciseType") + @Fetch(value = FetchMode.SUBSELECT) + val exerciseDevices: List = mutableListOf() + } diff --git a/src/main/kotlin/com/aitrainer/api/model/ExerciseTypeDevice.kt b/src/main/kotlin/com/aitrainer/api/model/ExerciseTypeDevice.kt new file mode 100644 index 0000000..9f70eb7 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/ExerciseTypeDevice.kt @@ -0,0 +1,23 @@ +package com.aitrainer.api.model + +import com.fasterxml.jackson.annotation.JsonIgnore +import javax.persistence.* +import javax.validation.constraints.NotNull + +@Entity +data class ExerciseTypeDevice ( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val exerciseTypeDeviceId: Long = 0, + + @get: NotNull var exerciseDeviceId: Int? + +) { + + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name="exerciseTypeId", nullable=false) + @JsonIgnore + val exerciseType: ExerciseType? = null + +} + diff --git a/src/main/kotlin/com/aitrainer/api/repository/ExerciseDeviceRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/ExerciseDeviceRepository.kt new file mode 100644 index 0000000..558c1d1 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/ExerciseDeviceRepository.kt @@ -0,0 +1,14 @@ +package com.aitrainer.api.repository + +import com.aitrainer.api.model.ExerciseDevice +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository + +@Repository +interface ExerciseDeviceRepository: JpaRepository { + @Query("FROM ExerciseDevice as e " + + "LEFT JOIN ExerciseDeviceTranslation as t ON e.deviceId = t.exerciseDevice AND t.languageCode = 'hu' " + + "ORDER BY e.deviceId ") + fun getExerciseDevices(): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/repository/ExerciseTypeRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/ExerciseTypeRepository.kt index ad19012..a5d1446 100644 --- a/src/main/kotlin/com/aitrainer/api/repository/ExerciseTypeRepository.kt +++ b/src/main/kotlin/com/aitrainer/api/repository/ExerciseTypeRepository.kt @@ -16,6 +16,7 @@ interface ExerciseTypeRepository : JpaRepository{ @Query("FROM ExerciseType as e " + "LEFT JOIN ExerciseTypeImage as i ON e.exerciseTypeId = i.exerciseType " + "LEFT JOIN ExerciseTypeTranslation as t ON e.exerciseTypeId = t.exerciseType " + + "LEFT JOIN ExerciseTypeDevice as td ON e.exerciseTypeId = td.exerciseType " + "WHERE e.active = 1 " + "AND t.languageCode = 'hu' " + "AND i.type = 'menu' " + diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 275db0d..21363ac 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -16,6 +16,6 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structure has been changed, increment this version number -application.version=1.0.12 +application.version=1.0.14 jwt.secret=aitrainer \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 82c52d9..e06bf3c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -16,6 +16,6 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structure has been changed, increment this version number -application.version=1.0.12 +application.version=1.0.14 jwt.secret=aitrainer \ No newline at end of file diff --git a/src/test/kotlin/com/aitrainer/api/test/CustomerPropertyTest.kt b/src/test/kotlin/com/aitrainer/api/test/CustomerPropertyTest.kt index 2ebb2c8..9c1e7df 100644 --- a/src/test/kotlin/com/aitrainer/api/test/CustomerPropertyTest.kt +++ b/src/test/kotlin/com/aitrainer/api/test/CustomerPropertyTest.kt @@ -28,7 +28,7 @@ class CustomerPropertyTest { assertTrue(properties is List) assertTrue(properties.isNotEmpty()) - assertEquals(properties.size, 4) + assertEquals(properties.size, 5) assertEquals(properties[0].propertyValue, 81.0) assertEquals(properties[1].propertyValue, 82.0) assertEquals(properties[3].propertyId, 4) @@ -43,8 +43,8 @@ class CustomerPropertyTest { assertTrue(properties is List) assertTrue(properties.isNotEmpty()) assertEquals(properties.size, 3) - assertEquals(properties[0].propertyValue, 82.0) - assertEquals(properties[1].propertyValue, 172.0) + assertEquals(properties[2].propertyValue, 79.0) + assertEquals(properties[0].propertyValue, 172.0) } @Test diff --git a/src/test/kotlin/com/aitrainer/api/test/ExerciseDeviceTest.kt b/src/test/kotlin/com/aitrainer/api/test/ExerciseDeviceTest.kt new file mode 100644 index 0000000..290dc08 --- /dev/null +++ b/src/test/kotlin/com/aitrainer/api/test/ExerciseDeviceTest.kt @@ -0,0 +1,35 @@ +package com.aitrainer.api.test + +import com.aitrainer.api.controller.ExerciseDeviceController +import com.aitrainer.api.repository.ExerciseDeviceRepository +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +@SpringBootTest +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ExerciseDeviceTest { + + @Autowired + private lateinit var exerciseDeviceRepository: ExerciseDeviceRepository + + + @Test + fun testGetProperties() { + val controller = ExerciseDeviceController(exerciseDeviceRepository ) + val response = controller.getDevicesWithTranslation() + + val properties = response.body + + assertTrue(properties is List) + assertTrue(properties.isNotEmpty()) + assertEquals(properties.size, 3) + assertEquals(properties[0].name, "Weight") + assertEquals(properties[0].translations[0].name, "Súlyzó") + assertEquals(properties[1].name, "Own Weight") + } + +} \ No newline at end of file diff --git a/src/test/kotlin/com/aitrainer/api/test/ExerciseTypeTest.kt b/src/test/kotlin/com/aitrainer/api/test/ExerciseTypeTest.kt index 7ef57ab..eb46a4e 100644 --- a/src/test/kotlin/com/aitrainer/api/test/ExerciseTypeTest.kt +++ b/src/test/kotlin/com/aitrainer/api/test/ExerciseTypeTest.kt @@ -73,6 +73,7 @@ class ExerciseTypeTest { assertEquals(exerciseType.name, "Chest Press") assertEquals(exerciseType.images[0].url, "images/2.2.1.1.chestpress.png") assertEquals(responseEntity.body!![2].translations[0].name, "Tricepsz") + assertEquals(exerciseType.exerciseDevices[0].exerciseDeviceId, 1) } } \ No newline at end of file