diff --git a/build.gradle.kts b/build.gradle.kts index 37cdf7d..a2eee37 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "com.aitrainer" -version = "1.1.0" +version = "1.2.0" java.sourceCompatibility = JavaVersion.VERSION_17 repositories { @@ -34,7 +34,7 @@ dependencies { implementation("org.apache.logging.log4j:log4j-core:2.19.0") implementation("org.apache.logging.log4j:log4j-api:2.19.0") implementation("org.slf4j:slf4j-api:2.0.6") - //implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:1.0-M1-1.4.0-rc") // JVM dependency + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1") implementation("io.jsonwebtoken:jjwt:0.9.1") @@ -48,6 +48,9 @@ dependencies { implementation("jakarta.mail:jakarta.mail-api:2.1.1") implementation("org.eclipse.angus:angus-mail:2.0.1") + implementation ("com.aallam.openai:openai-client:2.1.3") + implementation("io.ktor:ktor-client-java:2.2.3") + runtimeOnly("mysql:mysql-connector-java") testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") diff --git a/data/db/diet4you.sql b/data/db/diet4you.sql new file mode 100644 index 0000000..8c5785d --- /dev/null +++ b/data/db/diet4you.sql @@ -0,0 +1,444 @@ +-- -------------------------------------------------------- +-- Hoszt: 127.0.0.1 +-- Szerver verzió: 10.4.11-MariaDB - mariadb.org binary distribution +-- Szerver OS: Win64 +-- HeidiSQL Verzió: 12.3.0.6589 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- Struktúra mentése tábla aitrainer2. app_text +CREATE TABLE IF NOT EXISTS `app_text` ( + `text_id` int(13) NOT NULL AUTO_INCREMENT, + `text_key` mediumtext DEFAULT NULL, + `screenshot_url` char(200) DEFAULT NULL, + `checked` tinyint(1) DEFAULT 0, + PRIMARY KEY (`text_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. app_text_translation +CREATE TABLE IF NOT EXISTS `app_text_translation` ( + `translation_id` int(13) NOT NULL AUTO_INCREMENT, + `text_id` int(11) NOT NULL, + `language_code` char(2) NOT NULL DEFAULT 'en', + `translation` char(50) DEFAULT NULL, + PRIMARY KEY (`translation_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Az adatok exportálása nem lett kiválasztva. + + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. configuration +CREATE TABLE IF NOT EXISTS `configuration` ( + `configuration_id` int(11) NOT NULL AUTO_INCREMENT, + `config_key` char(50) COLLATE utf8_hungarian_ci DEFAULT NULL, + `config_value` char(50) COLLATE utf8_hungarian_ci DEFAULT NULL, + `date_add` datetime DEFAULT NULL, + `date_change` datetime DEFAULT NULL, + PRIMARY KEY (`configuration_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. customer +CREATE TABLE IF NOT EXISTS `customer` ( + `customer_id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(100) COLLATE utf8_hungarian_ci NOT NULL, + `firstname` char(100) COLLATE utf8_hungarian_ci NOT NULL, + `email` char(100) COLLATE utf8_hungarian_ci DEFAULT NULL, + `password` char(100) COLLATE utf8_hungarian_ci DEFAULT NULL, + `sex` enum('m','w') COLLATE utf8_hungarian_ci DEFAULT 'm', + `age` tinyint(4) DEFAULT NULL, + `active` enum('Y','N','D','S') COLLATE utf8_hungarian_ci DEFAULT 'N', + `date_add` datetime DEFAULT NULL, + `date_change` datetime DEFAULT NULL, + `data_policy_allowed` tinyint(4) DEFAULT 1, + `admin` tinyint(4) DEFAULT 0, + `trainer` tinyint(4) DEFAULT 0, + `trainer_id` int(11) DEFAULT 0, + `birth_year` int(4) DEFAULT 0, + `weight` int(3) DEFAULT 0, + `goal` char(250) COLLATE utf8_hungarian_ci DEFAULT '', + `fitness_level` enum('beginner','intermediate','advanced','professional') COLLATE utf8_hungarian_ci NOT NULL DEFAULT 'beginner', + `body_type` enum('ectomorph','mesomorph','endomorph') COLLATE utf8_hungarian_ci DEFAULT NULL, + `firebase_uid` char(200) COLLATE utf8_hungarian_ci DEFAULT NULL, + `sport_id` int(13) DEFAULT NULL, + `email_subscription` tinyint(1) DEFAULT NULL, + `synced_date` datetime DEFAULT NULL, + `trial_date` datetime DEFAULT NULL, + `firebase_reg_token` text COLLATE utf8_hungarian_ci DEFAULT NULL, + `lang` char(5) COLLATE utf8_hungarian_ci DEFAULT NULL, + `phone` char(50) COLLATE utf8_hungarian_ci DEFAULT NULL, + `life_long` tinyint(4) DEFAULT NULL, + `lang_sync` datetime DEFAULT NULL, + PRIMARY KEY (`customer_id`), + UNIQUE KEY `firebase_uid` (`firebase_uid`), + KEY `firebase_reg_token` (`firebase_reg_token`(1024)), + KEY `sport_id` (`sport_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + + +-- Struktúra mentése tábla aitrainer2. customer_conversation +CREATE TABLE IF NOT EXISTS `customer_conversation` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11) NOT NULL DEFAULT 0, + `conversation_date` datetime DEFAULT NULL, + `question` text COLLATE utf8_hungarian_ci DEFAULT NULL, + `answer` text COLLATE utf8_hungarian_ci DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. customer_membership +CREATE TABLE IF NOT EXISTS `customer_membership` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11) NOT NULL DEFAULT 0, + `membership_id` int(11) NOT NULL DEFAULT 0, + `start_date` datetime DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + KEY `customer_id` (`customer_id`) USING BTREE, + KEY `membership_id` (`membership_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. customer_property +CREATE TABLE IF NOT EXISTS `customer_property` ( + `customer_property_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `customer_id` int(10) unsigned NOT NULL DEFAULT 0, + `property_id` int(10) unsigned NOT NULL DEFAULT 0, + `property_value` double unsigned NOT NULL DEFAULT 0, + `date_add` datetime DEFAULT NULL, + `goal` tinyint(4) DEFAULT 0, + `goal_date` date DEFAULT NULL, + PRIMARY KEY (`customer_property_id`), + KEY `property_id` (`property_id`), + KEY `customer_id` (`customer_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. diet +CREATE TABLE IF NOT EXISTS `diet` ( + `diet_id` int(11) NOT NULL AUTO_INCREMENT, + `diet_user_id` int(11) NOT NULL DEFAULT 0, + `diet_text` text COLLATE utf8_hungarian_ci DEFAULT NULL, + PRIMARY KEY (`diet_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. diet_meal +CREATE TABLE IF NOT EXISTS `diet_meal` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `diet_id` int(11) DEFAULT NULL, + `meal_name` char(100) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '0' COMMENT 'i.e. monday|breakfast', + `meal` char(250) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `meal_name` (`meal_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. diet_raw_material +CREATE TABLE IF NOT EXISTS `diet_raw_material` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `diet_meal_id` int(11) NOT NULL DEFAULT 0, + `raw_material_id` int(11) DEFAULT 0, + `kcal_min` int(11) DEFAULT 0, + `kcal_max` int(11) DEFAULT 0, + `protein_min` int(11) DEFAULT 0, + `protein_max` int(11) DEFAULT 0, + `ch_min` int(11) DEFAULT 0, + `ch_max` int(11) DEFAULT 0, + `fat_min` int(11) DEFAULT 0, + `fat_max` int(11) DEFAULT 0, + `sugar` int(11) DEFAULT 0, + `name` char(50) COLLATE utf8_hungarian_ci DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. diet_sensitivity +CREATE TABLE IF NOT EXISTS `diet_sensitivity` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(100) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. diet_user +CREATE TABLE IF NOT EXISTS `diet_user` ( + `diet_user_id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`diet_user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. diet_user_consumption +CREATE TABLE IF NOT EXISTS `diet_user_consumption` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `diet_user_id` int(11) NOT NULL, + `raw_material_id` int(11) NOT NULL DEFAULT 0, + `date_consumption` datetime NOT NULL, + `name` char(100) COLLATE utf8_hungarian_ci DEFAULT NULL, + `quantity` double NOT NULL DEFAULT 0, + `quantity_unit` char(10) COLLATE utf8_hungarian_ci DEFAULT NULL, + `cal` int(11) DEFAULT NULL, + `protein` double DEFAULT NULL, + `fat` double DEFAULT NULL, + `ch` double DEFAULT NULL, + `sugar` double DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `diet_user_id` (`diet_user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. diet_user_preference +CREATE TABLE IF NOT EXISTS `diet_user_preference` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `diet_user_id` int(11) NOT NULL DEFAULT 0, + `raw_material_id` int(11) NOT NULL DEFAULT 0, + `temperature` decimal(1,0) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) USING BTREE, + KEY `diet_user_id` (`diet_user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. diet_user_sensitivity +CREATE TABLE IF NOT EXISTS `diet_user_sensitivity` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `sensitivity_id` int(11) NOT NULL DEFAULT 0, + `diet_user_id` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + KEY `diet_user_id` (`diet_user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + + +-- Struktúra mentése tábla aitrainer2. faq +CREATE TABLE IF NOT EXISTS `faq` ( + `faq_id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(200) COLLATE utf8_hungarian_ci NOT NULL, + `description` text COLLATE utf8_hungarian_ci DEFAULT NULL, + `sort` int(11) DEFAULT NULL, + PRIMARY KEY (`faq_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. faq_translation +CREATE TABLE IF NOT EXISTS `faq_translation` ( + `translation_id` int(11) NOT NULL AUTO_INCREMENT, + `faq_id` int(11) NOT NULL DEFAULT 0, + `name_translation` char(200) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '0', + `description_translation` text COLLATE utf8_hungarian_ci DEFAULT NULL, + `language_code` char(2) COLLATE utf8_hungarian_ci DEFAULT 'en', + PRIMARY KEY (`translation_id`) USING BTREE, + KEY `faq_id` (`faq_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + + +-- Struktúra mentése tábla aitrainer2. membership +CREATE TABLE IF NOT EXISTS `membership` ( + `membership_id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(100) CHARACTER SET utf8mb4 NOT NULL, + `description` char(200) CHARACTER SET utf8mb4 DEFAULT NULL, + `duration` int(11) DEFAULT NULL, + `duration_type` enum('free','subscription','lifetime','limited') CHARACTER SET utf8mb4 DEFAULT NULL, + `duration_unit` enum('day','week','month','year') COLLATE utf8_hungarian_ci DEFAULT NULL, + `training_plan_id` int(11) DEFAULT 0, + `training_plan_day_ids` char(50) COLLATE utf8_hungarian_ci DEFAULT NULL, + PRIMARY KEY (`membership_id`) USING BTREE, + KEY `training_plan_id` (`training_plan_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. notification +CREATE TABLE IF NOT EXISTS `notification` ( + `notification_id` int(11) NOT NULL AUTO_INCREMENT, + `internal_name` char(50) COLLATE utf8_hungarian_ci DEFAULT NULL, + `internal_description` mediumtext COLLATE utf8_hungarian_ci DEFAULT NULL, + `message_title` char(50) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '', + `message_body` char(100) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '', + `image_url` char(100) COLLATE utf8_hungarian_ci DEFAULT '', + `schedule_date` datetime DEFAULT NULL, + `schedule_hook` char(100) COLLATE utf8_hungarian_ci DEFAULT NULL, + `schedule_sql` mediumtext COLLATE utf8_hungarian_ci DEFAULT NULL, + `active` tinyint(1) DEFAULT 0, + PRIMARY KEY (`notification_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. notification_history +CREATE TABLE IF NOT EXISTS `notification_history` ( + `notification_history_id` int(11) NOT NULL AUTO_INCREMENT, + `notification_id` int(11) NOT NULL, + `customer_id` int(11) NOT NULL, + `response` char(255) COLLATE utf8_hungarian_ci DEFAULT NULL, + `notification_date` datetime DEFAULT NULL, + PRIMARY KEY (`notification_history_id`), + KEY `notification_id` (`notification_id`), + KEY `customer_id` (`customer_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. product +CREATE TABLE IF NOT EXISTS `product` ( + `product_id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(50) NOT NULL, + `description` mediumtext DEFAULT NULL, + `app_version` char(50) NOT NULL, + `product_set` int(5) NOT NULL, + `sort` int(5) NOT NULL, + `type` enum('subscription','in-app-currency') NOT NULL DEFAULT 'subscription', + `valid_from` date DEFAULT NULL, + `valid_to` date DEFAULT NULL, + `product_id_ios` char(50) DEFAULT NULL, + `product_id_android` char(50) DEFAULT NULL, + `price_ios` float DEFAULT NULL, + `price_android` float DEFAULT NULL, + PRIMARY KEY (`product_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Struktúra mentése tábla aitrainer2. property +CREATE TABLE IF NOT EXISTS `property` ( + `property_id` int(11) NOT NULL AUTO_INCREMENT, + `property_name` char(50) COLLATE utf8_hungarian_ci DEFAULT NULL, + `property_unit` char(50) COLLATE utf8_hungarian_ci DEFAULT NULL, + PRIMARY KEY (`property_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. property_translation +CREATE TABLE IF NOT EXISTS `property_translation` ( + `translation_id` int(13) NOT NULL AUTO_INCREMENT, + `language_code` char(2) NOT NULL DEFAULT 'en', + `property_id` int(13) NOT NULL DEFAULT 0, + `property_name` char(50) DEFAULT NULL, + PRIMARY KEY (`translation_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. purchase +CREATE TABLE IF NOT EXISTS `purchase` ( + `purchase_id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11) NOT NULL DEFAULT 0, + `product_id` int(11) NOT NULL DEFAULT 0, + `date_add` datetime DEFAULT NULL, + `purchase_sum` double(22,0) DEFAULT NULL, + `currency` char(3) DEFAULT NULL, + `expiring` datetime DEFAULT NULL, + PRIMARY KEY (`purchase_id`) USING BTREE, + KEY `customer_id` (`customer_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. raw_material +CREATE TABLE IF NOT EXISTS `raw_material` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(100) COLLATE utf8_hungarian_ci NOT NULL, + `description` text COLLATE utf8_hungarian_ci DEFAULT NULL, + `kcal_min` int(11) DEFAULT 0, + `kcal_max` int(11) DEFAULT 0, + `protein_min` int(11) DEFAULT 0, + `protein_max` int(11) DEFAULT 0, + `ch_min` int(11) DEFAULT 0, + `ch_max` int(11) DEFAULT 0, + `fat_min` int(11) DEFAULT 0, + `fat_max` int(11) DEFAULT 0, + `sugar` int(11) DEFAULT 0, + `store_id` int(11) DEFAULT 0, + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci ROW_FORMAT=DYNAMIC; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. recipe +CREATE TABLE IF NOT EXISTS `recipe` ( + `recipe_id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(250) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '', + `description` text COLLATE utf8_hungarian_ci DEFAULT NULL, + `cal` int(11) DEFAULT NULL, + `protein` double DEFAULT NULL, + `fat` double DEFAULT NULL, + `ch` double DEFAULT NULL, + `diet_user_id` int(11) DEFAULT 0, + PRIMARY KEY (`recipe_id`) USING BTREE, + KEY `name` (`name`), + KEY `diet_user_id` (`diet_user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. recipe_raw_material +CREATE TABLE IF NOT EXISTS `recipe_raw_material` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `raw_material_id` int(11) NOT NULL DEFAULT 0, + `recipe_id` int(11) NOT NULL DEFAULT 0, + `quantity` int(11) DEFAULT 0, + `quantity_unit` char(10) COLLATE utf8_hungarian_ci DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. store +CREATE TABLE IF NOT EXISTS `store` ( + `store_id` int(11) NOT NULL AUTO_INCREMENT, + `store_name` char(50) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '', + `country` char(4) COLLATE utf8_hungarian_ci NOT NULL DEFAULT '', + PRIMARY KEY (`store_id`), + KEY `store_name` (`store_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + +-- Az adatok exportálása nem lett kiválasztva. + +-- Struktúra mentése tábla aitrainer2. tracking +CREATE TABLE IF NOT EXISTS `tracking` ( + `tracking_id` int(20) NOT NULL AUTO_INCREMENT, + `customer_id` int(20) NOT NULL DEFAULT 0, + `date_add` datetime NOT NULL, + `event` char(100) COLLATE utf8_hungarian_ci DEFAULT NULL, + `event_value` text COLLATE utf8_hungarian_ci DEFAULT NULL, + `area` char(100) COLLATE utf8_hungarian_ci DEFAULT NULL, + `platform` char(20) COLLATE utf8_hungarian_ci DEFAULT NULL, + `version` char(20) COLLATE utf8_hungarian_ci DEFAULT NULL, + PRIMARY KEY (`tracking_id`) USING BTREE, + KEY `customer_id` (`customer_id`), + KEY `event` (`event`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; + + +INSERT INTO `customer` VALUES (54, 'Dummy User', '', 'bosi', '$2a$10$thOc8jS750c7xe9U9Qq3GuSPs/H0Pt2Ads05yzUlyzQBIj.Rk9QCy', 'm', 0, 'N', NULL, NULL, 1, 1, 0, 0, 0, 0, '', 'beginner', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + +/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */; +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */; diff --git a/data/db/update_1_1_0.sql b/data/db/update_1_1_0.sql index bdcff28..5fafeaa 100644 --- a/data/db/update_1_1_0.sql +++ b/data/db/update_1_1_0.sql @@ -9,8 +9,8 @@ CREATE TABLE `membership` ( `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 - INDEX `training_plan_id` (`training_plan_id`) USING BTREE, + PRIMARY KEY (`membership_id`) USING BTREE, + INDEX `training_plan_id` (`training_plan_id`) USING BTREE ) ENGINE=InnoDB ; diff --git a/data/db/update_1_2_0.sql b/data/db/update_1_2_0.sql new file mode 100644 index 0000000..e016437 --- /dev/null +++ b/data/db/update_1_2_0.sql @@ -0,0 +1,187 @@ +START TRANSACTION; + +CREATE TABLE `customer_conversation` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `customer_id` INT(11) NOT NULL DEFAULT '0', + `conversation_date` DATETIME NULL DEFAULT NULL, + `question` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `answer` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `diet_user` ( + `diet_user_id` INT(11) NOT NULL AUTO_INCREMENT, + `customer_id` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`diet_user_id`) USING BTREE +) +ENGINE=InnoDB +; + + +CREATE TABLE `diet` ( + `diet_id` INT(11) NOT NULL AUTO_INCREMENT, + `diet_user_id` INT(11) NOT NULL DEFAULT '0', + `diet_text` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `start_date` DATE NULL DEFAULT NULL, + PRIMARY KEY (`diet_id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `diet_meal` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `diet_id` INT(11) NULL DEFAULT NULL, + `meal_name` CHAR(100) NOT NULL DEFAULT '0' COMMENT 'i.e. monday|breakfast' COLLATE 'utf8mb4_general_ci', + `meal` CHAR(250) NOT NULL DEFAULT '0' COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`id`) USING BTREE, + INDEX `meal_name` (`meal_name`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `diet_raw_material` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `diet_meal_id` INT(11) NOT NULL DEFAULT '0', + `raw_material_id` INT(11) NULL DEFAULT '0', + `kcal_min` INT(11) NULL DEFAULT '0', + `kcal_max` INT(11) NULL DEFAULT '0', + `protein_min` INT(11) NULL DEFAULT '0', + `protein_max` INT(11) NULL DEFAULT '0', + `ch_min` INT(11) NULL DEFAULT '0', + `ch_max` INT(11) NULL DEFAULT '0', + `fat_min` INT(11) NULL DEFAULT '0', + `fat_max` INT(11) NULL DEFAULT '0', + `sugar` INT(11) NULL DEFAULT '0', + `name` CHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `diet_sensitivity` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` CHAR(100) NOT NULL DEFAULT '0' COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `diet_user_consumption` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `diet_user_id` INT(11) NOT NULL, + `raw_material_id` INT(11) NOT NULL DEFAULT '0', + `date_consumption` DATETIME NOT NULL, + `name` CHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `quantity` DOUBLE NOT NULL DEFAULT '0', + `quantity_unit` CHAR(10) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `cal` INT(11) NULL DEFAULT NULL, + `protein` DOUBLE NULL DEFAULT NULL, + `fat` DOUBLE NULL DEFAULT NULL, + `ch` DOUBLE NULL DEFAULT NULL, + `sugar` DOUBLE NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + INDEX `diet_user_id` (`diet_user_id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `diet_user_preference` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `diet_user_id` INT(11) NOT NULL DEFAULT '0', + `raw_material_id` INT(11) NOT NULL DEFAULT '0', + `temperature` DECIMAL(1,0) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) USING BTREE, + INDEX `diet_user_id` (`diet_user_id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `diet_user_sensitivity` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `sensitivity_id` INT(11) NOT NULL DEFAULT '0', + `diet_user_id` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) USING BTREE, + INDEX `diet_user_id` (`diet_user_id`) USING BTREE +) +COLLATE='utf8_hungarian_ci' +ENGINE=InnoDB +; + + + +CREATE TABLE `raw_material` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` CHAR(100) NOT NULL COLLATE 'utf8mb4_general_ci', + `description` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `kcal_min` INT(11) NULL DEFAULT '0', + `kcal_max` INT(11) NULL DEFAULT '0', + `protein_min` INT(11) NULL DEFAULT '0', + `protein_max` INT(11) NULL DEFAULT '0', + `ch_min` INT(11) NULL DEFAULT '0', + `ch_max` INT(11) NULL DEFAULT '0', + `fat_min` INT(11) NULL DEFAULT '0', + `fat_max` INT(11) NULL DEFAULT '0', + `sugar` INT(11) NULL DEFAULT '0', + `store_id` INT(11) NULL DEFAULT '0', + PRIMARY KEY (`id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +ROW_FORMAT=DYNAMIC +; + +CREATE TABLE `recipe` ( + `recipe_id` INT(11) NOT NULL AUTO_INCREMENT, + `name` CHAR(250) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci', + `description` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `cal` INT(11) NULL DEFAULT NULL, + `protein` DOUBLE NULL DEFAULT NULL, + `fat` DOUBLE NULL DEFAULT NULL, + `ch` DOUBLE NULL DEFAULT NULL, + `diet_user_id` INT(11) NULL DEFAULT '0', + `meal_id` INT(11) NULL DEFAULT NULL, + PRIMARY KEY (`recipe_id`) USING BTREE, + INDEX `name` (`name`) USING BTREE, + INDEX `diet_user_id` (`diet_user_id`) USING BTREE + INDEX `meal_id` (`meal_id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `store` ( + `store_id` INT(11) NOT NULL AUTO_INCREMENT, + `store_name` CHAR(50) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci', + `country` CHAR(4) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`store_id`) USING BTREE, + INDEX `store_name` (`store_name`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + +CREATE TABLE `recipe_raw_material` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `raw_material_id` INT(11) NOT NULL DEFAULT '0', + `recipe_id` INT(11) NOT NULL DEFAULT '0', + `quantity` INT(11) NULL DEFAULT '0', + `quantity_unit` CHAR(10) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; + + +UPDATE configuration set config_value = "1.2.0", date_change=CURRENT_DATE WHERE config_key = "db_version"; + +COMMIT; diff --git a/readme.MD b/readme.MD index d027165..ae5b955 100644 --- a/readme.MD +++ b/readme.MD @@ -1,7 +1,8 @@ -#aitrainer server API v1.1 +#aitrainer server API v1.2 connects the MYSQL Database provide a RESTful API for the mobile app +Open AI API Workout Test Club @@ -28,5 +29,7 @@ Workout Test Club * exercise_device_translation * exercise_type_device * deactivate customer +* diet tables +* openAI with automatic database update diff --git a/src/deploy/Dockerfile b/src/deploy/Dockerfile index 6bd8c77..e8416ad 100644 --- a/src/deploy/Dockerfile +++ b/src/deploy/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:12 +FROM openjdk:18 RUN mkdir aitrainer_server RUN mkdir aitrainer_server/data RUN mkdir aitrainer_server/data/db diff --git a/src/main/kotlin/com/aitrainer/api/ApiApplication.kt b/src/main/kotlin/com/aitrainer/api/ApiApplication.kt index cf16629..8ade98e 100644 --- a/src/main/kotlin/com/aitrainer/api/ApiApplication.kt +++ b/src/main/kotlin/com/aitrainer/api/ApiApplication.kt @@ -9,6 +9,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.builder.SpringApplicationBuilder import org.springframework.context.annotation.Bean + @SpringBootApplication class ApiApplication { @Bean(name = ["jasyptStringEncryptor"]) @@ -43,3 +44,5 @@ class ApiApplication { + + diff --git a/src/main/kotlin/com/aitrainer/api/controller/ApplicationProperties.kt b/src/main/kotlin/com/aitrainer/api/controller/ApplicationProperties.kt index 927c727..3987d59 100644 --- a/src/main/kotlin/com/aitrainer/api/controller/ApplicationProperties.kt +++ b/src/main/kotlin/com/aitrainer/api/controller/ApplicationProperties.kt @@ -1,12 +1,14 @@ package com.aitrainer.api.controller import org.springframework.beans.factory.annotation.Value +import org.springframework.stereotype.Component import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping +@Component class ApplicationProperties { @Value("\${application.version}") @@ -21,7 +23,8 @@ class ApplicationProperties { @Value("\${spring.datasource.password}") private lateinit var datasourcePassword: String - + @Value("\${openai.key}") + private lateinit var apiKey: String @GetMapping("/version") fun getVersion(): String { @@ -42,4 +45,11 @@ class ApplicationProperties { fun getDatasourcePassword(): String { return this.datasourcePassword } + + @GetMapping("/openAIKey") + fun getOpenAIKey(): String { + return this.apiKey + } + + } \ 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 c6f36cc..dda552b 100644 --- a/src/main/kotlin/com/aitrainer/api/controller/CustomerController.kt +++ b/src/main/kotlin/com/aitrainer/api/controller/CustomerController.kt @@ -8,17 +8,14 @@ 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.http.HttpHeaders import org.springframework.http.ResponseEntity import org.springframework.security.access.annotation.Secured import org.springframework.web.bind.annotation.* -import java.io.ByteArrayOutputStream -import java.nio.charset.StandardCharsets.UTF_8 import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.* -import java.util.zip.GZIPInputStream -import java.util.zip.GZIPOutputStream import javax.validation.Valid @@ -157,16 +154,7 @@ class CustomerController ( private val customerRepository: CustomerRepository) { } @PostMapping("/club_registration") - fun clubRegistration(@Valid @RequestBody json: String): ResponseEntity<*> { - - fun gzip(content: String): String { - val bos = ByteArrayOutputStream() - GZIPOutputStream(bos).bufferedWriter(UTF_8).use { it.write(content) } - return bos.toByteArray().toString() - } - - fun unzip(content: ByteArray): String = - GZIPInputStream(content.inputStream()).bufferedReader(UTF_8).use { it.readText() } + fun clubRegistration(@Valid @RequestBody json: String, @Value("\${firebase.key}") apiKey: String): ResponseEntity<*> { val newUser: ClubUser = ClubUser().fromJson(json) @@ -186,7 +174,7 @@ class CustomerController ( private val customerRepository: CustomerRepository) { val stringCharacters = ('0'..'z').toList().toTypedArray() val genPassword = (1..10).map { stringCharacters.random() }.joinToString("") - val firebase = Firebase() + val firebase = Firebase(apiKey) val signupResponse = firebase.signUp(newUser.email, genPassword) ?: return ResponseEntity.badRequest().body("Firebase exception ${firebase.error}") @@ -252,7 +240,7 @@ class CustomerController ( private val customerRepository: CustomerRepository) { if ( emailTemplateService == null ) { emailTemplateService = EmailTemplateService() } - val html = emailTemplateService!!.getEmailBody(newUser.firstname, activationLink) + val html = emailTemplateService!!.getEmailBody(newUser.firstname, activationLink, "registration_email") val subject = emailTemplateService!!.getSubject() // send email diff --git a/src/main/kotlin/com/aitrainer/api/controller/CustomerConversationController.kt b/src/main/kotlin/com/aitrainer/api/controller/CustomerConversationController.kt new file mode 100644 index 0000000..130e7f4 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/CustomerConversationController.kt @@ -0,0 +1,25 @@ +package com.aitrainer.api.controller + +import com.aitrainer.api.model.CustomerConversation +import com.aitrainer.api.repository.CustomerConversationRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + + +@RestController +@RequestMapping("/api") +class CustomerConversationController (private val customerConversationRepository: CustomerConversationRepository +) { + + @PostMapping("/customer_conversation") + fun insert(@RequestBody customerConversation: CustomerConversation): ResponseEntity { + return ResponseEntity.ok().body(customerConversationRepository.save(customerConversation)) + } + + @GetMapping("/customer_conversation/{customerId}") + fun getByCustomerId(@PathVariable customerId: Long): ResponseEntity> { + val list = customerConversationRepository.findByCustomerId(customerId) + 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/controller/CustomerPackageController.kt b/src/main/kotlin/com/aitrainer/api/controller/CustomerPackageController.kt index 45dd41b..1a8da2e 100644 --- a/src/main/kotlin/com/aitrainer/api/controller/CustomerPackageController.kt +++ b/src/main/kotlin/com/aitrainer/api/controller/CustomerPackageController.kt @@ -2,7 +2,9 @@ package com.aitrainer.api.controller import com.aitrainer.api.model.* import com.aitrainer.api.model.CustomerMembership +import com.aitrainer.api.model.diet.* import com.aitrainer.api.repository.* +import com.aitrainer.api.repository.diet.* import com.google.gson.GsonBuilder import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping @@ -21,8 +23,69 @@ class CustomerPackageController( private val customerRepository: CustomerReposit private val customerActivityRepository: CustomerActivityRepository, private val customerTrainingPlanRepository: CustomerTrainingPlanRepository, private val customerMembership: CustomerMembershipRepository, + private val dietRepository: DietRepository, + private val dietRawMaterialRepository: DietRawMaterialRepository, + private val dietUserConsumptionRepository: DietUserConsumptionRepository, + private val dietUserRepository: DietUserRepository, + private val dietUserPreferenceRepository: DietUserPreferenceRepository, + private val dietUserSensitivityRepository: DietUserSensitivityRepository, + private val customerConversationRepository: CustomerConversationRepository + ) { + @GetMapping("/diet_customer_package/{id}") + fun getDietCustomerPackageData(@PathVariable(value = "id") dietUserId: Long): ResponseEntity { + if (dietUserId <= 0) { + return ResponseEntity.notFound().build() + } + + val gson = GsonBuilder() + .excludeFieldsWithoutExposeAnnotation() + .setPrettyPrinting() + .create() + + val dietUser: DietUser = dietUserRepository.findByDietUserId(dietUserId) + ?: return ResponseEntity.notFound().build() + + val customerId = dietUser.customerId + val customer: Customer = customerRepository.findByCustomerIdAndActive(customerId, "Y") + ?: return ResponseEntity.notFound().build() + + val customerJson: String = gson.toJson(customer) + val dietUserJson: String = gson.toJson(dietUser) + + val listDiet = dietRepository.findByDietUserId(dietUserId) + val listDietJson = gson.toJson(listDiet) + + val listDietRawMaterial = dietRawMaterialRepository.findByDietMealId(dietUserId) + val listDietRawMaterialJson = gson.toJson(listDietRawMaterial) + + val listDietUserConsumption = dietUserConsumptionRepository.findByDietUserId(dietUserId) + val listDietUserConsumptionJson = gson.toJson(listDietUserConsumption) + + val listDietUserPreference = dietUserPreferenceRepository.findByDietUserId(dietUserId) + val listDietUserPreferenceJson = gson.toJson(listDietUserPreference) + + val listDietUserSensitivity = dietUserSensitivityRepository.findByDietUserId(dietUserId) + val listDietUserSensitivityJson = gson.toJson(listDietUserSensitivity) + + val listCustomerConversation = customerConversationRepository.findByCustomerId(customerId) + val listCustomerConversationJson = gson.toJson(listCustomerConversation) + + val packageJson: String = + getClassRecord(Customer::class.simpleName, customerJson) + + "|||" + getClassRecord(DietUser::class.simpleName, dietUserJson) + + "|||" + getClassRecord(Diet::class.simpleName, listDietJson) + + "|||" + getClassRecord(DietRawMaterial::class.simpleName, listDietRawMaterialJson) + + "|||" + getClassRecord(DietUserConsumption::class.simpleName, listDietUserConsumptionJson) + + "|||" + getClassRecord(DietUserPreference::class.simpleName, listDietUserPreferenceJson) + + "|||" + getClassRecord(DietUserSensitivity::class.simpleName, listDietUserSensitivityJson) + + "|||" + getClassRecord(CustomerConversation::class.simpleName, listCustomerConversationJson) + + return if (packageJson.isEmpty()) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(packageJson) + } + @GetMapping("/club_customer_package/{id}") fun getCustomerClubPackageData(@PathVariable(value = "id") customerId: Long): ResponseEntity { if (customerId <= 0) { diff --git a/src/main/kotlin/com/aitrainer/api/controller/EvaluationController.kt b/src/main/kotlin/com/aitrainer/api/controller/EvaluationController.kt index 1adcf95..0b361cb 100644 --- a/src/main/kotlin/com/aitrainer/api/controller/EvaluationController.kt +++ b/src/main/kotlin/com/aitrainer/api/controller/EvaluationController.kt @@ -1,10 +1,7 @@ package com.aitrainer.api.controller import com.aitrainer.api.model.Evaluation -import com.aitrainer.api.model.ExerciseTree import com.aitrainer.api.repository.EvaluationRepository -import com.aitrainer.api.repository.ExerciseTreeParentsRepository -import com.aitrainer.api.repository.ExerciseTreeRepository import org.slf4j.LoggerFactory import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping diff --git a/src/main/kotlin/com/aitrainer/api/controller/OpenAIController.kt b/src/main/kotlin/com/aitrainer/api/controller/OpenAIController.kt new file mode 100644 index 0000000..f4a0bb5 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/OpenAIController.kt @@ -0,0 +1,59 @@ +package com.aitrainer.api.controller + +import com.aitrainer.api.model.OpenAI +import com.aitrainer.api.openai.OpenAIService +import kotlinx.coroutines.* +import org.slf4j.LoggerFactory +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/api") +class OpenAIController() { + private val logger = LoggerFactory.getLogger(javaClass) + + @OptIn(DelicateCoroutinesApi::class) + @PostMapping("/openai/completion") + fun getOpenAIResponse(@RequestBody question: String) : String { + var result = "" + val openAIService = OpenAIService(null, null) + val deferred = GlobalScope.async { + openAIService.completion(question) + } + runBlocking { + result = deferred.await() + //println("Result: $result" ) + } + return result + } + + @OptIn(DelicateCoroutinesApi::class) + @PostMapping("/openai/completion_with_model") + fun getOpenAIResponseWithModel(@RequestBody openai: OpenAI) : String { + var result = "" + val openAIService = OpenAIService(openai.modelName, openai.temperature) + val deferred = GlobalScope.async { + openAIService.completion(openai.question) + } + runBlocking { + result = deferred.await() + //println("Result: $result" ) + } + return result + } + + @OptIn(DelicateCoroutinesApi::class) + @GetMapping("/openai/list_models") + fun getOpenAIModels(): MutableList { + var result = mutableListOf() + val openAIService = OpenAIService(null, null) + val deferred = GlobalScope.async { + openAIService.getModels() + } + runBlocking { + result = deferred.await() + //println("Result: $result" ) + } + return result + } +} + diff --git a/src/main/kotlin/com/aitrainer/api/controller/PackageController.kt b/src/main/kotlin/com/aitrainer/api/controller/PackageController.kt index ce181f2..8228615 100644 --- a/src/main/kotlin/com/aitrainer/api/controller/PackageController.kt +++ b/src/main/kotlin/com/aitrainer/api/controller/PackageController.kt @@ -1,7 +1,12 @@ package com.aitrainer.api.controller import com.aitrainer.api.model.* +import com.aitrainer.api.model.diet.DietSensitivity +import com.aitrainer.api.model.diet.RawMaterial +import com.aitrainer.api.model.diet.Recipe +import com.aitrainer.api.model.diet.Store import com.aitrainer.api.repository.* +import com.aitrainer.api.repository.diet.* import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping @@ -29,9 +34,50 @@ class PackageController(private val exerciseAbilityRepository: ExerciseAbilityRe private val trainingPlanDayRepository: TrainingPlanDayRepository, private val appTextRepository: AppTextRepository, private val trainingProgramRepository: TrainingProgramRepository, - private val membershipRepository: MembershipRepository + private val membershipRepository: MembershipRepository, + private val storeRepository: StoreRepository, + private val recipeRepository: RecipeRepository, + private val rawMaterialRepository: RawMaterialRepository, + private val dietSensitivityRepository: DietSensitivityRepository ) { + @GetMapping("/diet_package") + fun getDietPackageData(): ResponseEntity { + val gson = GsonBuilder() + .excludeFieldsWithoutExposeAnnotation() + .setPrettyPrinting() + .create() + + val listProperty:List = propertyRepository.getProperties() + val listPropertyJson: String = gson.toJson(listProperty) + + val listMembership = membershipRepository.findAll() + val listMembershipJson = gson.toJson(listMembership) + + val listStore = storeRepository.findAll() + val listStoreJson = gson.toJson(listStore) + + val listRecipe = recipeRepository.findAll() + val listRecipeJson = gson.toJson(listRecipe) + + val listRawMaterial = rawMaterialRepository.findAll() + val listRawMaterialJson = gson.toJson(listRawMaterial) + + val listDietSensitivity = dietSensitivityRepository.findAll() + val listDietSensitivityJson = gson.toJson(listDietSensitivity) + + val packageJson: String = + getClassRecord(Property::class.simpleName, listPropertyJson) + + "|||" + getClassRecord(Membership::class.simpleName, listMembershipJson) + + "|||" + getClassRecord(Store::class.simpleName, listStoreJson) + + "|||" + getClassRecord(Recipe::class.simpleName, listRecipeJson) + + "|||" + getClassRecord(RawMaterial::class.simpleName, listRawMaterialJson) + + "|||" + getClassRecord(DietSensitivity::class.simpleName, listDietSensitivityJson) + + return if (packageJson.isEmpty()) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(packageJson) + } + @GetMapping("/club_package") fun getClubPackageData(): ResponseEntity { diff --git a/src/main/kotlin/com/aitrainer/api/controller/diet/DietController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietController.kt new file mode 100644 index 0000000..05d0a65 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietController.kt @@ -0,0 +1,41 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.Diet +import com.aitrainer.api.repository.diet.DietRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import java.util.* + +@RestController +@RequestMapping("/api") +class DietController(private val dietRepository: DietRepository) { + + @PostMapping("/diet") + fun insert(@RequestBody diet: Diet): ResponseEntity<*> { + return ResponseEntity.ok().body(dietRepository.save(diet)) + } + + @PostMapping("/diet/{id}") + fun update(@PathVariable(value = "id") id: Long, @RequestBody diet: Diet): ResponseEntity { + val existingDiet = dietRepository.findByDietId(id) ?: return ResponseEntity.notFound().build() + + val updatedDiet: Diet = existingDiet.copy( + dietId = diet.dietId, + dietUserId = diet.dietUserId, + dietText = diet.dietText, + startDate = diet.startDate + ) + diet.meals.forEach { + it.diet = diet + updatedDiet.meals.add(it) + } + return ResponseEntity.ok().body(dietRepository.save(updatedDiet)) + } + + @GetMapping("/diet/{dietUserId}") + fun getByDietUserId(@PathVariable dietUserId: Long): ResponseEntity> { + val list = dietRepository.findByDietUserId(dietUserId) + 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/controller/diet/DietCustomerController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietCustomerController.kt new file mode 100644 index 0000000..4104394 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietCustomerController.kt @@ -0,0 +1,138 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.Customer +import com.aitrainer.api.model.CustomerMembership +import com.aitrainer.api.model.CustomerPropertyProperty +import com.aitrainer.api.model.diet.DietCustomer +import com.aitrainer.api.model.diet.DietUser +import com.aitrainer.api.repository.CustomerRepository +import com.aitrainer.api.repository.diet.DietUserRepository +import com.aitrainer.api.service.Firebase +import com.aitrainer.api.service.ServiceBeans +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.util.* + +@RestController +@RequestMapping("/api") +class DietCustomerController(private val dietUserRepository: DietUserRepository, private val customerRepository: CustomerRepository) { + + @Autowired + var serviceBeans: ServiceBeans? = null + + @PostMapping("/diet_registration") + fun insert(@RequestBody dietCustomerJson: String, @Value("\${firebase.key}") apiKey: String): ResponseEntity<*> { + val newDietCustomer: DietCustomer = DietCustomer().fromJson(dietCustomerJson) + + if ( newDietCustomer.email.isEmpty()) { + return ResponseEntity.badRequest().body("No Email") + } + + val current = LocalDateTime.now() + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS") + val nowFormatted = current.format(formatter) + + val stringCharacters = ('0'..'z').toList().toTypedArray() + val genPassword = (1..10).map { stringCharacters.random() }.joinToString("") + + val idToken: String? + + var existingCustomer: Customer? = customerRepository.findByEmailAndActive(newDietCustomer.email, "Y") + + if (existingCustomer == null ) { + val firebase = Firebase(apiKey) + val signupResponse = firebase.signUp(newDietCustomer.email, genPassword) + ?: return ResponseEntity.badRequest().body("Firebase exception ${firebase.error}") + idToken = signupResponse.idToken + + val savingCustomer = Customer() + + if ( serviceBeans == null ) { + serviceBeans = ServiceBeans() + } + with (savingCustomer) { + email = newDietCustomer.email + password = serviceBeans!!.passwordEncoder().encode(genPassword) + firebaseRegToken = signupResponse.idToken + firebaseUid = signupResponse.localId + dateAdd = nowFormatted + firstname = newDietCustomer.firstname + name = "" + goal = newDietCustomer.goal + fitnessLevel = newDietCustomer.fitnessLevel + birthYear = newDietCustomer.birthYear + sex = newDietCustomer.sex + } + + val newCustomer = customerRepository.save(savingCustomer) + + if ( newDietCustomer.weight != 0.0 ) { + val property = CustomerPropertyProperty() + with (property) { + propertyId = 1 + propertyValue = newDietCustomer.weight + dateAdd= nowFormatted + goal = false + customer = newCustomer + } + newCustomer.properties.add(property) + } + if ( newDietCustomer.height != 0.0 ) { + val property = CustomerPropertyProperty() + with (property) { + propertyId = 2 + propertyValue = newDietCustomer.height + dateAdd = nowFormatted + goal = false + customer = newCustomer + } + newCustomer.properties.add(property) + } + + val newMembershipId = newDietCustomer.membershipId + if ( newMembershipId != 0L) { + val membership = CustomerMembership() + with(membership) { + customer = newCustomer + membershipId = newMembershipId + startDate = nowFormatted + } + newCustomer.memberships.add(membership) + } + + customerRepository.save(newCustomer) + existingCustomer = newCustomer + } else { + val existingDietUser = dietUserRepository.findByCustomerId(existingCustomer.customerId) + if ( existingDietUser != null ) { + return ResponseEntity.badRequest().body("DietCustomer exists") + } else { + val newDietUser = DietUser( + customerId = existingCustomer.customerId + ) + dietUserRepository.save(newDietUser) + + } + idToken = existingCustomer.firebaseRegToken!! + } + + // create email link + /*val activationLink = "https://diet4you.andio.hu/welcome/id=$idToken" + if ( emailTemplateService == null ) { + emailTemplateService = EmailTemplateService() + } + val html = emailTemplateService!!.getEmailBody(newDietCustomer.firstname, activationLink, "diet_registration_email") + val subject = emailTemplateService!!.getSubjectDiet() + + // send email + val email = Email() + email.send(newDietCustomer.email, html, subject)*/ + + return ResponseEntity.ok().body(existingCustomer) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/controller/diet/DietRawMaterialController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietRawMaterialController.kt new file mode 100644 index 0000000..2dbefd1 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietRawMaterialController.kt @@ -0,0 +1,24 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.DietRawMaterial +import com.aitrainer.api.repository.diet.DietRawMaterialRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import java.util.* + +@RestController +@RequestMapping("/api") +class DietRawMaterialController(private val dietRawMaterialRepository: DietRawMaterialRepository) { + + @PostMapping("/diet_raw_material") + fun insert(@RequestBody dietRawMaterial: DietRawMaterial): ResponseEntity<*> { + return ResponseEntity.ok().body(dietRawMaterialRepository.save(dietRawMaterial)) + } + + @GetMapping("/diet_raw_material/{dietMealId}") + fun getByDietUserId(@PathVariable dietMealId: Long): ResponseEntity> { + val list = dietRawMaterialRepository.findByDietMealId(dietMealId) + 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/controller/diet/DietSensitivityController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietSensitivityController.kt new file mode 100644 index 0000000..1e98809 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietSensitivityController.kt @@ -0,0 +1,24 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.DietSensitivity +import com.aitrainer.api.repository.diet.DietSensitivityRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("api") +class DietSensitivityController(private val dietSensitivityRepository: DietSensitivityRepository) { + + @PostMapping ("/diet_sensitivity") + fun insert(@RequestBody dietSensitivity: DietSensitivity): ResponseEntity { + val newDietSensitivity = dietSensitivityRepository.save(dietSensitivity) + return ResponseEntity.ok().body(newDietSensitivity) + } + + @GetMapping("/diet_sensitivity") + fun getAll(): ResponseEntity> { + val list = dietSensitivityRepository.findAll() + 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/controller/diet/DietUserConsumptionController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserConsumptionController.kt new file mode 100644 index 0000000..87c1f5d --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserConsumptionController.kt @@ -0,0 +1,43 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.DietUserConsumption +import com.aitrainer.api.repository.diet.DietUserConsumptionRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import java.util.* + +@RestController +@RequestMapping("/api") +class DietUserConsumptionController(private val dietUserConsumptionRepository: DietUserConsumptionRepository) { + + @PostMapping("/diet_user_consumption") + fun insert(@RequestBody dietUserConsumption: DietUserConsumption): ResponseEntity<*> { + return ResponseEntity.ok().body(dietUserConsumptionRepository.save(dietUserConsumption)) + } + + @PostMapping("/diet_user_consumption/{id}") + fun update(@PathVariable(value = "id") id: Long, @RequestBody dietUserConsumption: DietUserConsumption): ResponseEntity<*> { + return dietUserConsumptionRepository.findById(id).map { existingConsumption -> + val updatedConsumption: DietUserConsumption = existingConsumption.copy( + rawMaterialId = dietUserConsumption.rawMaterialId, + dateConsumption = dietUserConsumption.dateConsumption, + name = dietUserConsumption.name, + quantity = dietUserConsumption.quantity, + quantityUnit = dietUserConsumption.quantityUnit, + cal = dietUserConsumption.cal, + protein = dietUserConsumption.protein, + fat = dietUserConsumption.fat, + ch = dietUserConsumption.ch, + sugar = dietUserConsumption.sugar + ) + ResponseEntity.ok().body(dietUserConsumptionRepository.save(updatedConsumption)) + }.orElse(ResponseEntity.notFound().build()) + } + + @GetMapping("/diet_user_consumption/{dietUserId}") + fun getByDietUserId(@PathVariable dietUserId: Long): ResponseEntity> { + val list = dietUserConsumptionRepository.findByDietUserId(dietUserId) + 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/controller/diet/DietUserController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserController.kt new file mode 100644 index 0000000..0927d33 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserController.kt @@ -0,0 +1,24 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.DietUser +import com.aitrainer.api.repository.diet.DietUserRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("api") +class DietUserController(private val dietUserRepository: DietUserRepository) { + + @PostMapping ("/diet_user") + fun insert(@RequestBody dietUser: DietUser): ResponseEntity { + val newDietUser = dietUserRepository.save(dietUser) + return ResponseEntity.ok().body(newDietUser) + } + + @GetMapping("/diet_user/{customerId}") + fun getByCustomerId(@PathVariable customerId: Long): ResponseEntity { + val dietUser = dietUserRepository.findByCustomerId(customerId) + return if (dietUser == null) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(dietUser) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserPreferenceController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserPreferenceController.kt new file mode 100644 index 0000000..1260c22 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserPreferenceController.kt @@ -0,0 +1,24 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.DietUserPreference +import com.aitrainer.api.repository.diet.DietUserPreferenceRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import java.util.* + +@RestController +@RequestMapping("/api") +class DietUserPreferenceController(private val dietUserPreferenceRepository: DietUserPreferenceRepository) { + + @PostMapping("/diet_user_preference") + fun insert(@RequestBody dietUserPreference: DietUserPreference): ResponseEntity<*> { + return ResponseEntity.ok().body(dietUserPreferenceRepository.save(dietUserPreference)) + } + + @GetMapping("/diet_user_preference/{dietUserId}") + fun getByDietUserId(@PathVariable dietUserId: Long): ResponseEntity> { + val list = dietUserPreferenceRepository.findByDietUserId(dietUserId) + 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/controller/diet/DietUserSensitivityController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserSensitivityController.kt new file mode 100644 index 0000000..a6e65b9 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietUserSensitivityController.kt @@ -0,0 +1,24 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.DietUserSensitivity +import com.aitrainer.api.repository.diet.DietUserSensitivityRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import java.util.* + +@RestController +@RequestMapping("/api") +class DietUserSensitivityController(private val dietUserSensitivityRepository: DietUserSensitivityRepository) { + + @PostMapping("/diet_user_sensitivity") + fun insert(@RequestBody dietUserSensitivity: DietUserSensitivity): ResponseEntity<*> { + return ResponseEntity.ok().body(dietUserSensitivityRepository.save(dietUserSensitivity)) + } + + @GetMapping("/diet_user_sensitivity/{dietUserId}") + fun getByDietUserId(@PathVariable dietUserId: Long): ResponseEntity> { + val list = dietUserSensitivityRepository.findByDietUserId(dietUserId) + 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/controller/diet/RawMaterialController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/RawMaterialController.kt new file mode 100644 index 0000000..0a947ff --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/RawMaterialController.kt @@ -0,0 +1,31 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.RawMaterial +import com.aitrainer.api.repository.diet.RawMaterialRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("api") +class RawMaterialController(private val rawMaterialRepository: RawMaterialRepository) { + + @PostMapping ("/raw_material") + fun insert(@RequestBody rawMaterial: RawMaterial): ResponseEntity { + val newRawMaterial = rawMaterialRepository.save(rawMaterial) + return ResponseEntity.ok().body(newRawMaterial) + } + + @GetMapping("/raw_material") + fun getAll(): ResponseEntity> { + val list = rawMaterialRepository.findAll() + return if (list.isEmpty()) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(list) + } + + @GetMapping("/raw_material/{id}") + fun getByRawMaterialId(@PathVariable id: Long): ResponseEntity { + val rawMaterial = rawMaterialRepository.findByRawMaterialId(id) + return if (rawMaterial == null) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(rawMaterial) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/controller/diet/RecipeController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/RecipeController.kt new file mode 100644 index 0000000..7274179 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/RecipeController.kt @@ -0,0 +1,66 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.Recipe +import com.aitrainer.api.repository.diet.RecipeRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("api") +class RecipeController(private val recipeRepository: RecipeRepository) { + + @PostMapping ("/recipe") + fun insert(@RequestBody recipe: Recipe): ResponseEntity { + val newRecipe = recipeRepository.save(recipe) + return ResponseEntity.ok().body(newRecipe) + } + + @PostMapping("/recipe/{id}") + fun update(@PathVariable(value = "id") id: Long, @RequestBody recipe: Recipe): ResponseEntity { + val existingRecipe = recipeRepository.findByRecipeId(id) ?: return ResponseEntity.notFound().build() + + val updatedRecipe: Recipe = existingRecipe.copy( + name = recipe.name, + description = recipe.description, + cal = recipe.cal, + ch = recipe.ch, + fat = recipe.fat, + protein = recipe.protein, + dietUserId = recipe.dietUserId, + mealId = recipe.mealId + ) + recipe.rawMaterials.forEach { + it.recipe = recipe + updatedRecipe.rawMaterials.add(it) + } + return ResponseEntity.ok().body(recipeRepository.save(updatedRecipe)) + } + + @GetMapping("/recipe") + fun getAll(): ResponseEntity> { + val list = recipeRepository.findAll() + return if (list.isEmpty()) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(list) + } + + @GetMapping("/recipe/user/{dietUserId}") + fun getByDietUserId(@PathVariable dietUserId: Long): ResponseEntity> { + val list = recipeRepository.findByDietUserId(dietUserId) + return if (list == null) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(list) + } + + @GetMapping("/recipe/meal/{mealId}") + fun getByMealId(@PathVariable mealId: Long): ResponseEntity> { + val list = recipeRepository.findByMealId(mealId) + return if (list == null) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(list) + } + + @GetMapping("/recipe/name/{name}") + fun getByName(@PathVariable name: String): ResponseEntity> { + val list = recipeRepository.findByName(name) + return if (list == null) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(list) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/controller/diet/RecipeRawMaterialController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/RecipeRawMaterialController.kt new file mode 100644 index 0000000..8a36598 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/RecipeRawMaterialController.kt @@ -0,0 +1,17 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.RecipeRawMaterial +import com.aitrainer.api.repository.diet.RecipeRawMaterialRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("api") +class RecipeRawMaterialController(private val recipeRawMaterialRepository: RecipeRawMaterialRepository) { + + @PostMapping ("/recipe_raw_material") + fun insert(@RequestBody recipeRawMaterial: RecipeRawMaterial): ResponseEntity { + val newRecipe = recipeRawMaterialRepository.save(recipeRawMaterial) + return ResponseEntity.ok().body(recipeRawMaterial) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/controller/diet/StoreController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/StoreController.kt new file mode 100644 index 0000000..0a750e2 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/StoreController.kt @@ -0,0 +1,32 @@ +package com.aitrainer.api.controller.diet + +import com.aitrainer.api.model.diet.Store +import com.aitrainer.api.repository.diet.StoreRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("api") +class StoreController(private val storeRepository: StoreRepository) { + + @PostMapping ("/store") + fun insert(@RequestBody store: Store): ResponseEntity { + val newStore = storeRepository.save(store) + return ResponseEntity.ok().body(newStore) + } + + @GetMapping("/store") + fun getAll(): ResponseEntity> { + val list = storeRepository.findAll() + return if (list.isEmpty()) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(list) + } + + @GetMapping("/store/{name}/{country}") + fun getByNameAndCountry(@PathVariable name: String, @PathVariable country: String ): ResponseEntity { + val store = storeRepository.findByNameAndCountry(name, country) + return if (store == null) ResponseEntity.notFound().build() else + ResponseEntity.ok().body(store) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/CustomerConversation.kt b/src/main/kotlin/com/aitrainer/api/model/CustomerConversation.kt new file mode 100644 index 0000000..158e3ec --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/CustomerConversation.kt @@ -0,0 +1,17 @@ +package com.aitrainer.api.model + +import com.google.gson.annotations.Expose +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import javax.validation.constraints.NotNull + +@Entity +data class CustomerConversation( + @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = 0, + @Expose @get: NotNull val customerId: Long, + @Expose @get: NotNull val conversationDate: String = "", + @Expose @get: NotNull val question: String = "", + @Expose @get: NotNull val answer: String = "" +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/OpenAI.kt b/src/main/kotlin/com/aitrainer/api/model/OpenAI.kt new file mode 100644 index 0000000..56ba465 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/OpenAI.kt @@ -0,0 +1,13 @@ +package com.aitrainer.api.model + +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.springframework.lang.NonNull + +@Entity +data class OpenAI ( + @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @get: NonNull var id: Long = 0, + @Expose @get: NonNull var question: String, + @Expose @get: NonNull var modelName: String? = null, + @Expose @get: NonNull var temperature: Double? = null, +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/Diet.kt b/src/main/kotlin/com/aitrainer/api/model/diet/Diet.kt new file mode 100644 index 0000000..69fcc47 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/Diet.kt @@ -0,0 +1,19 @@ +package com.aitrainer.api.model.diet + +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.hibernate.annotations.Fetch +import org.hibernate.annotations.FetchMode +import org.jetbrains.annotations.NotNull + +@Entity +data class Diet ( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose val dietId: Long = 0, + @Expose @get: NotNull val dietUserId: Long = 0, + @Expose @get: NotNull val dietText: String = "", + @Expose @get: NotNull val startDate: String = "", +) { + @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.EAGER, mappedBy = "diet") + @Fetch(value = FetchMode.SUBSELECT) + @Expose val meals: MutableList = mutableListOf() +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/DietCustomer.kt b/src/main/kotlin/com/aitrainer/api/model/diet/DietCustomer.kt new file mode 100644 index 0000000..fa1c8ec --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/DietCustomer.kt @@ -0,0 +1,23 @@ +package com.aitrainer.api.model.diet + +import com.google.gson.annotations.Expose +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json + +@Serializable +data class DietCustomer( + @Expose var firstname: String = "", + @Expose var email: String = "", + @Expose var sex: String = "m", + @Expose var goal: String = "", + @Expose var fitnessLevel: String = "beginner", + @Expose var birthYear: Int = 0, + @Expose var weight: Double = 0.0, + @Expose var height: Double = 0.0, + @Expose var membershipId: Long = 0, + +){ + fun fromJson(json: String): DietCustomer { + return Json.decodeFromString(serializer(), json) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/DietMeal.kt b/src/main/kotlin/com/aitrainer/api/model/diet/DietMeal.kt new file mode 100644 index 0000000..b928850 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/DietMeal.kt @@ -0,0 +1,19 @@ +package com.aitrainer.api.model.diet + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull + +@Entity +data class DietMeal ( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose val id: Long = 0, + //@Expose @get: NotNull val dietId: Long = 0, + @Expose @get: NotNull val mealName: String = "", + @Expose @get: NotNull val meal: String = "", +) { + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "dietId", nullable = false) + @JsonIgnore + var diet: Diet? = null +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/DietRawMaterial.kt b/src/main/kotlin/com/aitrainer/api/model/diet/DietRawMaterial.kt new file mode 100644 index 0000000..175e581 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/DietRawMaterial.kt @@ -0,0 +1,22 @@ +package com.aitrainer.api.model.diet +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull + +@Entity +data class DietRawMaterial ( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose val id: Long = 0, + + @Expose @get: NotNull val dietMealId: Long = 0, + @Expose @get: NotNull val rawMaterialId: Long = 0, + @Expose @get: NotNull val name: String = "", + @Expose @get: NotNull val kcalMin: Int = 0, + @Expose @get: NotNull val kcalMax: Int = 0, + @Expose @get: NotNull val proteinMin: Int = 0, + @Expose @get: NotNull val proteinMax: Int = 0, + @Expose @get: NotNull val fatMin: Int = 0, + @Expose @get: NotNull val fatMax: Int = 0, + @Expose @get: NotNull val chMin: Int = 0, + @Expose @get: NotNull val chMax: Int = 0, + @Expose @get: NotNull val sugar: Int = 0, +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/DietSensitivity.kt b/src/main/kotlin/com/aitrainer/api/model/diet/DietSensitivity.kt new file mode 100644 index 0000000..4327488 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/DietSensitivity.kt @@ -0,0 +1,14 @@ +package com.aitrainer.api.model.diet + +import com.google.gson.annotations.Expose +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import javax.validation.constraints.NotNull + +@Entity +data class DietSensitivity( + @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = 0, + @Expose @get: NotNull val name: String = "", +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/DietUser.kt b/src/main/kotlin/com/aitrainer/api/model/diet/DietUser.kt new file mode 100644 index 0000000..dc787ac --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/DietUser.kt @@ -0,0 +1,14 @@ +package com.aitrainer.api.model.diet + +import com.google.gson.annotations.Expose +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import javax.validation.constraints.NotNull + +@Entity +data class DietUser( + @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var dietUserId: Long = 0, + @Expose @get: NotNull val customerId: Long +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/DietUserConsumption.kt b/src/main/kotlin/com/aitrainer/api/model/diet/DietUserConsumption.kt new file mode 100644 index 0000000..5f9d935 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/DietUserConsumption.kt @@ -0,0 +1,24 @@ +package com.aitrainer.api.model.diet +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull +import org.springframework.lang.NonNull + +@Entity +data class DietUserConsumption( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose val id: Long = 0, + + @Expose @get: NotNull val dietUserId: Long = 0, + @Expose @get: NotNull val rawMaterialId: Long = 0, + @Expose @get: NotNull val name: String = "", + @Expose @get: NonNull var dateConsumption: String = "", + + @Expose @get: NotNull val quantity: Double = 0.0, + @Expose @get: NotNull val quantityUnit: String = "", + + @Expose @get: NotNull val cal: Int = 0, + @Expose @get: NotNull val protein: Double = 0.0, + @Expose @get: NotNull val fat: Double = 0.0, + @Expose @get: NotNull val ch: Double = 0.0, + @Expose @get: NotNull val sugar: Double = 0.0, +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/DietUserPreference.kt b/src/main/kotlin/com/aitrainer/api/model/diet/DietUserPreference.kt new file mode 100644 index 0000000..a66d8c2 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/DietUserPreference.kt @@ -0,0 +1,16 @@ +package com.aitrainer.api.model.diet + +import com.google.gson.annotations.Expose +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import javax.validation.constraints.NotNull + +@Entity +data class DietUserPreference( + @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = 0, + @Expose @get: NotNull val dietUserId: Long = 0, + @Expose @get: NotNull val rawMaterialId: Long = 0, + @Expose @get: NotNull val temperature: Byte = 0, +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/DietUserSensitivity.kt b/src/main/kotlin/com/aitrainer/api/model/diet/DietUserSensitivity.kt new file mode 100644 index 0000000..d9aa84c --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/DietUserSensitivity.kt @@ -0,0 +1,15 @@ +package com.aitrainer.api.model.diet + +import com.google.gson.annotations.Expose +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import javax.validation.constraints.NotNull + +@Entity +data class DietUserSensitivity( + @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = 0, + @Expose @get: NotNull val dietUserId: Long = 0, + @Expose @get: NotNull val sensitivityId: Long = 0, +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/RawMaterial.kt b/src/main/kotlin/com/aitrainer/api/model/diet/RawMaterial.kt new file mode 100644 index 0000000..85ba350 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/RawMaterial.kt @@ -0,0 +1,22 @@ +package com.aitrainer.api.model.diet +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull + +@Entity +data class RawMaterial ( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose val id: Long = 0, + + @Expose @get: NotNull val name: String = "", + @Expose @get: NotNull val description: String = "", + @Expose @get: NotNull val kcalMin: Int = 0, + @Expose @get: NotNull val kcalMax: Int = 0, + @Expose @get: NotNull val proteinMin: Int = 0, + @Expose @get: NotNull val proteinMax: Int = 0, + @Expose @get: NotNull val fatMin: Int = 0, + @Expose @get: NotNull val fatMax: Int = 0, + @Expose @get: NotNull val chMin: Int = 0, + @Expose @get: NotNull val chMax: Int = 0, + @Expose @get: NotNull val sugar: Int = 0, + @Expose @get: NotNull val storeId: Long = 0, +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/Recipe.kt b/src/main/kotlin/com/aitrainer/api/model/diet/Recipe.kt new file mode 100644 index 0000000..667acb3 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/Recipe.kt @@ -0,0 +1,27 @@ +package com.aitrainer.api.model.diet + + +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.hibernate.annotations.Fetch +import org.hibernate.annotations.FetchMode +import org.jetbrains.annotations.NotNull + +@Entity +data class Recipe ( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose val recipeId: Long = 0, + + @Expose @get: NotNull val name: String = "", + @Expose @get: NotNull val description: String = "", + + @Expose @get: NotNull val cal: Int = 0, + @Expose @get: NotNull val protein: Double = 0.0, + @Expose @get: NotNull val fat: Double = 0.0, + @Expose @get: NotNull val ch: Double = 0.0, + @Expose @get: NotNull val dietUserId: Long = 0, + @Expose @get: NotNull val mealId: Long = 0, +) { + @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.EAGER, mappedBy = "recipe") + @Fetch(value = FetchMode.SUBSELECT) + @Expose val rawMaterials: MutableList = mutableListOf() +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/RecipeRawMaterial.kt b/src/main/kotlin/com/aitrainer/api/model/diet/RecipeRawMaterial.kt new file mode 100644 index 0000000..7e8d62e --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/RecipeRawMaterial.kt @@ -0,0 +1,20 @@ +package com.aitrainer.api.model.diet + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull + +@Entity +data class RecipeRawMaterial ( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose val id: Long = 0, + + @Expose @get: NotNull var rawMaterialId: Int = 0, + @Expose @get: NotNull var quantity: Int = 0, + @Expose @get: NotNull var quantityUnit: String = "", +) { + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "recipeId", nullable = false) + @JsonIgnore + var recipe: Recipe? = null +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/model/diet/Store.kt b/src/main/kotlin/com/aitrainer/api/model/diet/Store.kt new file mode 100644 index 0000000..4534b16 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/model/diet/Store.kt @@ -0,0 +1,13 @@ +package com.aitrainer.api.model.diet + +import com.google.gson.annotations.Expose +import jakarta.persistence.* +import org.jetbrains.annotations.NotNull + +@Entity +data class Store ( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose val storeId: Long = 0, + + @Expose @get: NotNull val storeName: String = "", + @Expose @get: NotNull val country: String = "", +) \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/openai/OpenAIService.kt b/src/main/kotlin/com/aitrainer/api/openai/OpenAIService.kt new file mode 100644 index 0000000..1ce5f0c --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/openai/OpenAIService.kt @@ -0,0 +1,83 @@ +package com.aitrainer.api.openai + +import com.aallam.openai.client.OpenAI +import com.aallam.openai.api.completion.CompletionRequest +import com.aallam.openai.api.completion.TextCompletion +import com.aallam.openai.api.logging.LogLevel +import com.aallam.openai.api.model.Model +import com.aallam.openai.api.model.ModelId +import com.aallam.openai.client.OpenAIConfig +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.util.Properties + +class OpenAIService(private val modelName: String?, private val temperature: Double?) { + + + private var openAI: OpenAI? = null + var model: Model? = null + private val properties = Properties() + + init { + val inputStream = ClassLoader.getSystemResourceAsStream("application.properties") + properties.load(inputStream) + inputStream?.close() + } + + private var modelId: ModelId? = null + private suspend fun connect(modelName: String) { + val config = OpenAIConfig( + token = properties.getProperty("openai.key"), + logLevel = LogLevel.All + ) + openAI = OpenAI(config) + modelId = ModelId(modelName) + model = openAI!!.model(modelId!!) + + } + + suspend fun completion(question: String): String { + return withContext(Dispatchers.IO) { + var realModelName = "text-davinci-003" + if ( modelName != null) { + realModelName = modelName + } + var realTemperature = 0.1 + if ( temperature != null ) { + realTemperature = temperature + } + if (openAI == null) { + connect(realModelName) + } + println("OpenAI Question: $question") + val completionRequest = CompletionRequest( + model = modelId!!, + prompt = question, + //echo = true, + maxTokens = 2048 - question.length, + temperature=realTemperature, + ) + val completion: TextCompletion = openAI!!.completion(completionRequest) + + val result = completion.choices[0].text + result + } + } + + suspend fun getModels(): MutableList { + return withContext(Dispatchers.IO) { + if (openAI == null) { + openAI = OpenAI(token = properties.getProperty("openai.key")) + } + + val list: MutableList = mutableListOf() + openAI!!.models().forEach { + println(it) + list.add(it.id.id) + } + + return@withContext list + } + } +} + diff --git a/src/main/kotlin/com/aitrainer/api/repository/CustomerConversationRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/CustomerConversationRepository.kt new file mode 100644 index 0000000..ceaa384 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/CustomerConversationRepository.kt @@ -0,0 +1,10 @@ +package com.aitrainer.api.repository + +import com.aitrainer.api.model.CustomerConversation +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface CustomerConversationRepository : JpaRepository { + fun findByCustomerId(customerId: Long): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/DietRawMaterialRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/DietRawMaterialRepository.kt new file mode 100644 index 0000000..71cab66 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/DietRawMaterialRepository.kt @@ -0,0 +1,10 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.DietRawMaterial +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface DietRawMaterialRepository : JpaRepository { + fun findByDietMealId(dietMealId: Long): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/DietRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/DietRepository.kt new file mode 100644 index 0000000..abbf4f5 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/DietRepository.kt @@ -0,0 +1,14 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.Diet +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository + +@Repository +interface DietRepository : JpaRepository { + fun findByDietUserId(dietUserId: Long): List + + @Query(" FROM Diet WHERE dietId = :dietId") + fun findByDietId(dietId: Long): Diet? +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/DietSensitivityRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/DietSensitivityRepository.kt new file mode 100644 index 0000000..e4f3da6 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/DietSensitivityRepository.kt @@ -0,0 +1,6 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.DietSensitivity +import org.springframework.data.jpa.repository.JpaRepository + +interface DietSensitivityRepository : JpaRepository diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserConsumptionRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserConsumptionRepository.kt new file mode 100644 index 0000000..a25db25 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserConsumptionRepository.kt @@ -0,0 +1,10 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.DietUserConsumption +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface DietUserConsumptionRepository : JpaRepository { + fun findByDietUserId(dietUserId: Long): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserPreferenceRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserPreferenceRepository.kt new file mode 100644 index 0000000..aaa7fe9 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserPreferenceRepository.kt @@ -0,0 +1,10 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.DietUserPreference +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface DietUserPreferenceRepository : JpaRepository { + fun findByDietUserId(dietUserId: Long): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserRepository.kt new file mode 100644 index 0000000..b2accc3 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserRepository.kt @@ -0,0 +1,10 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.DietUser +import org.springframework.data.jpa.repository.JpaRepository + +interface DietUserRepository : JpaRepository { + fun findByCustomerId(customerId: Long): DietUser? + + fun findByDietUserId(dietUserId: Long): DietUser? +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserSensitivityRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserSensitivityRepository.kt new file mode 100644 index 0000000..326a589 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/DietUserSensitivityRepository.kt @@ -0,0 +1,10 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.DietUserSensitivity +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface DietUserSensitivityRepository : JpaRepository { + fun findByDietUserId(dietUserId: Long): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/RawMaterialRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/RawMaterialRepository.kt new file mode 100644 index 0000000..1a543ae --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/RawMaterialRepository.kt @@ -0,0 +1,12 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.RawMaterial +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface RawMaterialRepository : JpaRepository { + @Query(" FROM RawMaterial " + + " WHERE id = :id" + ) + fun findByRawMaterialId(id: Long): RawMaterial? +} diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/RecipeRawMaterialRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/RecipeRawMaterialRepository.kt new file mode 100644 index 0000000..f892160 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/RecipeRawMaterialRepository.kt @@ -0,0 +1,9 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.RecipeRawMaterial +import org.springframework.data.jpa.repository.JpaRepository + +interface RecipeRawMaterialRepository : JpaRepository { + + fun findByRawMaterialId(rawMaterialId: Long): List? +} diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/RecipeRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/RecipeRepository.kt new file mode 100644 index 0000000..47680f9 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/RecipeRepository.kt @@ -0,0 +1,18 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.Recipe +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface RecipeRepository : JpaRepository { + @Query(" FROM Recipe WHERE name like %:name%") + fun findByName(name: String): List? + + fun findByDietUserId(dietUserId: Long): List? + + @Query(" FROM Recipe WHERE recipeId = :recipeId") + fun findByRecipeId(recipeId: Long): Recipe? + + @Query(" FROM Recipe WHERE mealId = :mealId") + fun findByMealId(mealId: Long): List? +} diff --git a/src/main/kotlin/com/aitrainer/api/repository/diet/StoreRepository.kt b/src/main/kotlin/com/aitrainer/api/repository/diet/StoreRepository.kt new file mode 100644 index 0000000..1144a9a --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/repository/diet/StoreRepository.kt @@ -0,0 +1,11 @@ +package com.aitrainer.api.repository.diet + +import com.aitrainer.api.model.diet.Store +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface StoreRepository : JpaRepository { + @Query(" FROM Store WHERE storeName = :name and country = :country") + fun findByNameAndCountry(name: String, country: String ): Store? + +} diff --git a/src/main/kotlin/com/aitrainer/api/service/Email.kt b/src/main/kotlin/com/aitrainer/api/service/Email.kt index a0abd67..ce54b31 100644 --- a/src/main/kotlin/com/aitrainer/api/service/Email.kt +++ b/src/main/kotlin/com/aitrainer/api/service/Email.kt @@ -3,9 +3,6 @@ package com.aitrainer.api.service import java.util.Properties import jakarta.mail.* import jakarta.mail.internet.* -import org.jasypt.encryption.StringEncryptor -import org.jasypt.encryption.pbe.PooledPBEStringEncryptor -import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig class Email { @@ -19,23 +16,9 @@ class Email { put("mail.smtp.port", "587") } - fun getEncryptor(): StringEncryptor { - val encryptor = PooledPBEStringEncryptor() - val config = SimpleStringPBEConfig() - config.password = "workouttest" - config.algorithm = "PBEWithMD5AndDES" - config.setKeyObtentionIterations("1000") - config.setPoolSize("1") - config.providerName = "SunJCE" - config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator") - config.stringOutputType = "base64" - encryptor.setConfig(config) - return encryptor - } - val session: Session = Session.getInstance(properties, object : Authenticator() { override fun getPasswordAuthentication(): PasswordAuthentication { - return PasswordAuthentication("service@workouttest.com", getEncryptor().decrypt(encodedPassword)) + return PasswordAuthentication("service@workouttest.com", Encryptor.getEncryptor().decrypt(encodedPassword)) } }) @@ -47,7 +30,7 @@ class Email { } val bodyPart = MimeBodyPart().apply { - setContent(emailBody, "text/html") + setContent(emailBody, "text/html; charset=UTF-8") } val multipart = MimeMultipart().apply { diff --git a/src/main/kotlin/com/aitrainer/api/service/EmailTemplateService.kt b/src/main/kotlin/com/aitrainer/api/service/EmailTemplateService.kt index 5c74bcc..fe7ab78 100644 --- a/src/main/kotlin/com/aitrainer/api/service/EmailTemplateService.kt +++ b/src/main/kotlin/com/aitrainer/api/service/EmailTemplateService.kt @@ -10,14 +10,15 @@ class EmailTemplateService { @Autowired private var templateEngine: TemplateEngine? = null - fun getEmailBody(firstname: String, activationLink: String): String { + fun getEmailBody(firstname: String, activationLink: String, template: String): String { val context = Context() context.setVariable("firstname", firstname) context.setVariable("activationLink", activationLink) if ( templateEngine == null) { templateEngine = TemplateEngine() } - return templateEngine!!.process("registration_email", context) + + return templateEngine!!.process(template, context) } fun getSubject(): String { @@ -27,5 +28,12 @@ class EmailTemplateService { } return templateEngine!!.process("registration_subject", context) } + fun getSubjectDiet(): String { + val context = Context() + if ( templateEngine == null) { + templateEngine = TemplateEngine() + } + return templateEngine!!.process("diet_registration_subject", context) + } } diff --git a/src/main/kotlin/com/aitrainer/api/service/Encryptor.kt b/src/main/kotlin/com/aitrainer/api/service/Encryptor.kt new file mode 100644 index 0000000..8985943 --- /dev/null +++ b/src/main/kotlin/com/aitrainer/api/service/Encryptor.kt @@ -0,0 +1,21 @@ +package com.aitrainer.api.service + +import org.jasypt.encryption.StringEncryptor +import org.jasypt.encryption.pbe.PooledPBEStringEncryptor +import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig + +object Encryptor { + fun getEncryptor(): StringEncryptor { + val encryptor = PooledPBEStringEncryptor() + val config = SimpleStringPBEConfig() + config.password = "workouttest" + config.algorithm = "PBEWithMD5AndDES" + config.setKeyObtentionIterations("1000") + config.setPoolSize("1") + config.providerName = "SunJCE" + config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator") + config.stringOutputType = "base64" + encryptor.setConfig(config) + return encryptor + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/service/Firebase.kt b/src/main/kotlin/com/aitrainer/api/service/Firebase.kt index b8eaa6c..995e908 100644 --- a/src/main/kotlin/com/aitrainer/api/service/Firebase.kt +++ b/src/main/kotlin/com/aitrainer/api/service/Firebase.kt @@ -2,18 +2,22 @@ package com.aitrainer.api.service import com.aitrainer.api.model.firebase_response.SignupResponse import com.google.gson.Gson +import org.json.JSONObject +import org.springframework.beans.factory.annotation.Value +import org.springframework.stereotype.Service import java.net.URI import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse import java.nio.charset.StandardCharsets -import org.json.JSONObject +import java.util.* -class Firebase { - private val apiKey: String = "AIzaSyCUXBWV3_qzvV__ZWZA1siHftrrJpjDKh4" +@Service +class Firebase(@Value("\${firebase.key}") private val apiKey: String) { private val firebaseBaseUrl: String = "https://identitytoolkit.googleapis.com/v1/accounts" var statusCode: Int = 0 var error: String = "" + fun signUp(email: String, password: String): SignupResponse? { val json = JSONObject() @@ -42,6 +46,7 @@ class Firebase { } private fun call(command: String, postData: String): String { + val apiKey = this.apiKey val url = URI.create("$firebaseBaseUrl:$command?key=$apiKey") // Create the HTTP request object diff --git a/src/main/resources/application-diet.properties b/src/main/resources/application-diet.properties new file mode 100644 index 0000000..e305476 --- /dev/null +++ b/src/main/resources/application-diet.properties @@ -0,0 +1,26 @@ +#spring.config.activate.on-profile=dev,test,prod,prodtest +spring.config.use-legacy-processing = true +## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) +#spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false +spring.datasource.url = jdbc:mysql://localhost:3306/diet4you?serverTimezone=CET&useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true +spring.datasource.username = aitrainer +spring.datasource.password = ENC(WZplPYr8WmrLHshesY4T6oXplK3MlUVJ) + + +## Hibernate Properties + + +# The SQL dialect makes Hibernate generate better SQL for the chosen database +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect + +logging.config=classpath:logback-spring.xml +logging.file=logs + +# if the database structure has been changed, increment this version number +application.version=1.2.0 + +jwt.secret=aitrainer + +openai.key=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 +firebase.key=AIzaSyBLn7Bz73Z1hB-OhqphBDsskOyGmpI7J8E +spring.mail.properties.mail.mime.charset=UTF-8 diff --git a/src/main/resources/application-dietprod.properties b/src/main/resources/application-dietprod.properties new file mode 100644 index 0000000..b1168ed --- /dev/null +++ b/src/main/resources/application-dietprod.properties @@ -0,0 +1,22 @@ +spring.config.activate.on-profile=dietprod +spring.config.use-legacy-processing = true + +## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) +spring.datasource.url = jdbc:mysql://mariadb-shared.db.svc.cluster.local:3306/diet4you?serverTimezone=CET&useSSL=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&allowMultiQueries=true +spring.datasource.username = aitrainer +spring.datasource.password = ENC(WZplPYr8WmrLHshesY4T6oXplK3MlUVJ) + +# The SQL dialect makes Hibernate generate better SQL for the chosen database +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect + + +logging.config=classpath:logback-spring.xml +logging.file=logs + +# if the database structue has been changed, increment this version number +application.version=1.2.0 + +jwt.secret=aitrainer + +firebase.key=AIzaSyCUXBWV3_qzvV__ZWZA1siHftrrJpjDKh4 +openai.key=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 \ No newline at end of file diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 4497da4..136f313 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -14,6 +14,9 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structue has been changed, increment this version number -application.version=1.1.0 +application.version=1.2.0 -jwt.secret=aitrainer \ No newline at end of file +jwt.secret=aitrainer + +firebase.key=AIzaSyCUXBWV3_qzvV__ZWZA1siHftrrJpjDKh4 +openai.key=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 \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7f5a994..8dcd6d6 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -17,6 +17,10 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structure has been changed, increment this version number -application.version=1.1.0 +application.version=1.2.0 jwt.secret=aitrainer + +openai.key=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 +spring.mail.properties.mail.mime.charset=UTF-8 +firebase.key=AIzaSyCUXBWV3_qzvV__ZWZA1siHftrrJpjDKh4 \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 4c5614d..819a986 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -28,7 +28,7 @@ -