diff --git a/.gitignore b/.gitignore
index 40e55bd..81514b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,10 @@ target/
*.iml
*.ipr
src/main/resources/config.properties
+src/main/resources/application.properties
+src/main/resources/hibernate.config.xml
+.env
+.idea/dataSources
### Eclipse ###
.apt_generated
diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml
new file mode 100644
index 0000000..9787612
--- /dev/null
+++ b/.idea/dataSources.local.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+ master_key
+ vkuzir7
+
+
+
+
+
+
+
+
+ true
+
+
+ master_key
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..2c56436
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ mongo
+ true
+ com.dbschema.MongoJdbcDriver
+ mongodb+srv://quizbot.sintcow.mongodb.net/
+
+
+
+
+
+ $ProjectFileDir$
+
+
+ redis
+ true
+ jdbc.RedisDriver
+ jdbc:redis://localhost:6379/
+
+
+
+
+
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/dataSources/aecaf689-ba27-4473-b219-9de8a6857761.xml b/.idea/dataSources/aecaf689-ba27-4473-b219-9de8a6857761.xml
new file mode 100644
index 0000000..8f96a26
--- /dev/null
+++ b/.idea/dataSources/aecaf689-ba27-4473-b219-9de8a6857761.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ 5.0.14
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dataSources/aeece5ee-e1bd-4a69-b12e-d4f8e3b18884.xml b/.idea/dataSources/aeece5ee-e1bd-4a69-b12e-d4f8e3b18884.xml
new file mode 100644
index 0000000..7c510eb
--- /dev/null
+++ b/.idea/dataSources/aeece5ee-e1bd-4a69-b12e-d4f8e3b18884.xml
@@ -0,0 +1,75 @@
+
+
+
+
+ 7.0.8
+
+
+ 2024-05-06.16:20:08
+
+
+ 2024-04-20.07:04:15
+
+
+ 2024-04-20.07:04:15
+
+
+
+
+ Int64|12s
+ 1
+
+
+ Boolean|12s
+ 1
+
+
+ String|12s
+ 1
+
+
+ String|12s
+ 2
+
+
+ ObjectId|12s
+ 1
+
+
+ String|12s
+ 1
+
+
+ list|4999545s
+ 1
+
+
+ String|12s
+ 2
+
+
+ list|4999545s
+ 3
+
+
+ ObjectId|12s
+ 4
+
+
+ Boolean|12s
+ 5
+
+
+ String|12s
+ 6
+
+
+ String|12s
+ 7
+
+
+ String|12s
+ 8
+
+
+
\ No newline at end of file
diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml
index 257f3c7..ccef0da 100644
--- a/.idea/dbnavigator.xml
+++ b/.idea/dbnavigator.xml
@@ -1,10 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -353,9 +481,6 @@
-
-
-
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index aa00ffa..30abd72 100644
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -1,6 +1,7 @@
+
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..ff97446
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5d6b03c..6614044 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,10 @@
+
+
+
+
+
@@ -7,7 +12,9 @@
-
+
+
+
diff --git a/.idea/shelf/Uncommitted_changes_before_Checkout_at_19_04_2024_08_27_[Changes]/shelved.patch b/.idea/shelf/Uncommitted_changes_before_Checkout_at_19_04_2024_08_27_[Changes]/shelved.patch
new file mode 100644
index 0000000..1570e38
--- /dev/null
+++ b/.idea/shelf/Uncommitted_changes_before_Checkout_at_19_04_2024_08_27_[Changes]/shelved.patch
@@ -0,0 +1,24 @@
+Index: .idea/workspace.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
+<+>\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n {\r\n "lastFilter": {\r\n "state": "OPEN",\r\n "assignee": "XD-cods"\r\n }\r\n} \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n {\r\n "selectedUrlAndAccountId": {\r\n "url": "https://github.com/XD-cods/knowBot.git",\r\n "accountId": "716ae5f9-f2f0-4031-abaf-6f38b82326ad"\r\n }\r\n} \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {\r\n "customColor": "ff00f2ff",\r\n "associatedIndex": 5\r\n} \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {\r\n "keyToString": {\r\n "Application.Main.executor": "Run",\r\n "Downloaded.Files.Path.Enabled": "false",\r\n "JUnit.All in knowBot.executor": "Run",\r\n "JUnit.QuestionTest.executor": "Run",\r\n "JUnit.QuizTest.executor": "Run",\r\n "JUnit.QuizTest.getQuestionList.executor": "Run",\r\n "JUnit.QuizTest.getTopicName.executor": "Run",\r\n "JUnit.QuizTest.setQuestionList.executor": "Run",\r\n "JUnit.QuizTest.setTopicName.executor": "Run",\r\n "JUnit.UserQuizSessionTest.addRightCounter.executor": "Run",\r\n "JUnit.UserQuizSessionTest.executor": "Run",\r\n "JUnit.UserQuizSessionTest.getCurrentQuestion.executor": "Run",\r\n "JUnit.UserQuizSessionTest.getNextQuestion.executor": "Run",\r\n "JUnit.UserQuizSessionTest.getQuestionAmount.executor": "Run",\r\n "JUnit.UserQuizSessionTest.getQuestionCounter.executor": "Run",\r\n "JUnit.UserQuizSessionTest.getRightAnswerCounter.executor": "Run",\r\n "JUnit.UserQuizSessionTest.isNextQuestionAvailable.executor": "Run",\r\n "JUnit.UserQuizSessionTest.isNextQuestionNotAvailable.executor": "Run",\r\n "Repository.Attach.Annotations": "false",\r\n "Repository.Attach.JavaDocs": "false",\r\n "Repository.Attach.Sources": "false",\r\n "RunOnceActivity.OpenProjectViewOnStart": "true",\r\n "RunOnceActivity.ShowReadmeOnStart": "true",\r\n "SHARE_PROJECT_CONFIGURATION_FILES": "true",\r\n "com.intellij.testIntegration.createTest.CreateTestDialog.defaultLibrary": "JUnit5",\r\n "com.intellij.testIntegration.createTest.CreateTestDialog.defaultLibrarySuperClass.JUnit5": "",\r\n "extract.method.default.visibility": "private",\r\n "git-widget-placeholder": "dataBase",\r\n "kotlin-language-version-configured": "true",\r\n "last_opened_file_path": "/home/vlad/IdeaProjects/knowBot/src/main/resources/quizes",\r\n "project.structure.last.edited": "SDKs",\r\n "project.structure.proportion": "0.0",\r\n "project.structure.side.proportion": "0.52988505",\r\n "run.code.analysis.last.selected.profile": "pProject Default",\r\n "settings.editor.selected.configurable": "configurable.group.appearance"\r\n }\r\n} \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n 1697546185034 \r\n \r\n \r\n 1697546185034 \r\n \r\n \r\n \r\n 1697546304779 \r\n \r\n \r\n \r\n 1697546304779 \r\n \r\n \r\n \r\n 1698779798292 \r\n \r\n \r\n \r\n 1698779798292 \r\n \r\n \r\n \r\n 1699466758647 \r\n \r\n \r\n \r\n 1699466758647 \r\n \r\n \r\n \r\n 1699807317129 \r\n \r\n \r\n \r\n 1699807317129 \r\n \r\n \r\n \r\n 1700063559545 \r\n \r\n \r\n \r\n 1700063559545 \r\n \r\n \r\n \r\n 1700459010450 \r\n \r\n \r\n \r\n 1700459010451 \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n org.example.* \r\n \r\n \r\n
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+diff --git a/.idea/workspace.xml b/.idea/workspace.xml
+--- a/.idea/workspace.xml
++++ b/.idea/workspace.xml
+@@ -236,6 +236,13 @@
+
+
+
++
++
++
++
++
++
++
+
+
+
diff --git a/.idea/shelf/Uncommitted_changes_before_Checkout_at_19_04_2024_08_27__Changes_.xml b/.idea/shelf/Uncommitted_changes_before_Checkout_at_19_04_2024_08_27__Changes_.xml
new file mode 100644
index 0000000..e0c5211
--- /dev/null
+++ b/.idea/shelf/Uncommitted_changes_before_Checkout_at_19_04_2024_08_27__Changes_.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index e2addae..81b6972 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,10 +4,24 @@
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -17,13 +31,19 @@
-
+
+
+
+
+
+
+
{
@@ -34,23 +54,56 @@
}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "selectedUrlAndAccountId": {
+ "url": "https://github.com/XD-cods/knowBot.git",
+ "accountId": "716ae5f9-f2f0-4031-abaf-6f38b82326ad"
+ }
+}
+
+
+
+
+
+
+
{
- "associatedIndex": 3
+ "customColor": "ff00f2ff",
+ "associatedIndex": 5
}
@@ -60,21 +113,57 @@
- {
- "keyToString": {
- "Application.Main.executor": "Run",
- "RunOnceActivity.OpenProjectViewOnStart": "true",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "SHARE_PROJECT_CONFIGURATION_FILES": "true",
- "git-widget-placeholder": "main",
- "kotlin-language-version-configured": "true",
- "last_opened_file_path": "/home/vlad/IdeaProjects/knowBot/src/main/resources/quizes",
- "run.code.analysis.last.selected.profile": "pProject Default",
- "settings.editor.selected.configurable": "preferences.pluginManager"
+
+}]]>
+
@@ -82,10 +171,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -93,20 +214,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
@@ -118,6 +259,51 @@
1697546185034
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -167,9 +353,51 @@
1700459010451
-
+
+
+ 1714073610012
+
+
+
+ 1714073610012
+
+
+
+ 1714591704863
+
+
+
+ 1714591704863
+
+
+
+ 1715013545890
+
+
+
+ 1715013545890
+
+
+
+ 1715526133865
+
+
+
+ 1715526133865
+
+
+
+
+
+
+
+
+
+
+
+
@@ -181,7 +409,7 @@
-
+
@@ -200,7 +428,18 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..98e0166
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,4 @@
+FROM amazoncorretto:17-alpine3.12
+WORKDIR /bot
+COPY target/knowBot-1.0-SNAPSHOT-jar-with-dependencies.jar .
+CMD ["java", "-jar", "knowBot-1.0-SNAPSHOT-jar-with-dependencies.jar"]
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..dc98105
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,17 @@
+services:
+ bot:
+ build: .
+ environment:
+ - SPRING_DATA_MONGODB_URI=${SPRING_DATA_MONGODB_URI}
+ - TELEGRAM_USER_TOKEN=${TELEGRAM_USER_TOKEN}
+ - TELEGRAM_ADMIN_TOKEN=${TELEGRAM_ADMIN_TOKEN}
+ - SPRING_DATA_MONGODB_DATABASE=${SPRING_DATA_MONGODB_DATABASE}
+ - REDIS_PORT=${REDIS_PORT}
+ - REDIS_HOSTNAME=${REDIS_HOSTNAME}
+
+ grafana:
+ image: "grafana/grafana-enterprise:10.4.2"
+ ports:
+ - "3000:3000"
+ depends_on:
+ - bot
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 052791d..2dc2381 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,40 +7,104 @@
org.example
knowBot
1.0-SNAPSHOT
+ jar
17
17
UTF-8
+ 7.1.1
+ 4.2.4
+ 4.11.1
+ 2.16.1
+ 2.17.2
+
+ org.springframework.data
+ spring-data-redis
+ 3.2.5
+
+
+ redis.clients
+ jedis
+ 5.1.2
+
com.github.pengrad
java-telegram-bot-api
- 6.9.1
+ ${java-telegram-bot-api.version}
+
+
+ org.springframework.data
+ spring-data-mongodb
+ ${spring-data-mongodb.version}
-
- com.google.code.gson
- gson
- 2.10.1
+ org.mongodb
+ mongodb-driver-sync
+ ${mongodb-driver-sync.version}
com.fasterxml.jackson.core
jackson-databind
- 2.15.3
+ ${jackson-databind.version}
+
+
+ org.junit-pioneer
+ junit-pioneer
+ 2.2.0
+ test
+
+
+ org.cache2k
+ cache2k-base-bom
+ 1.6.0.Final
+ pom
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j-core.version}
-
-
- org.apache.logging.log4j
- log4j-api
- 2.17.2
-
-
-
- org.apache.logging.log4j
- log4j-core
- 2.17.2
-
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.0
+
+
+
+ org.example.Main
+
+
+
+
+
+
+ maven-assembly-plugin
+ 3.7.1
+
+
+
+ org.example.Main
+
+
+
+ jar-with-dependencies
+
+
+
+
+ package
+
+ single
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/example/AdminBotConstants.java b/src/main/java/org/example/AdminBotConstants.java
new file mode 100644
index 0000000..b7f2eae
--- /dev/null
+++ b/src/main/java/org/example/AdminBotConstants.java
@@ -0,0 +1,21 @@
+package org.example;
+
+public class AdminBotConstants {
+ /*commands*/
+ public static final String START_BOT_COMMAND = "/start";
+ public static final String ADD_NEW_QUIZ_COMMAND = "/add";
+ public static final String UPDATE_QUIZ_COMMAND = "/update";
+ public static final String CLEAR_DB_COMMAND = "/clear_database";
+ public static final String CANCEL_COMMAND = "/cancel";
+
+
+ public static final String START_BOT_MESSAGE = "Hello admin here's a list of commands you can use:\n"
+ + ADD_NEW_QUIZ_COMMAND + "\n"
+ + UPDATE_QUIZ_COMMAND + "\n"
+ + CLEAR_DB_COMMAND + "\n"
+ + CANCEL_COMMAND + "\n";
+
+ private AdminBotConstants() {
+ }
+
+}
diff --git a/src/main/java/org/example/BotUpdate.java b/src/main/java/org/example/BotUpdate.java
deleted file mode 100644
index 5dab633..0000000
--- a/src/main/java/org/example/BotUpdate.java
+++ /dev/null
@@ -1,302 +0,0 @@
-package org.example;
-
-import com.pengrad.telegrambot.TelegramBot;
-import com.pengrad.telegrambot.UpdatesListener;
-import com.pengrad.telegrambot.model.CallbackQuery;
-import com.pengrad.telegrambot.model.Message;
-import com.pengrad.telegrambot.model.Update;
-import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
-import com.pengrad.telegrambot.model.request.InlineKeyboardMarkup;
-import com.pengrad.telegrambot.model.request.Keyboard;
-import com.pengrad.telegrambot.model.request.ParseMode;
-import com.pengrad.telegrambot.request.EditMessageText;
-import com.pengrad.telegrambot.request.SendMessage;
-import org.example.model.Question;
-import org.example.model.UserInfo;
-import org.example.model.UserQuizSession;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class BotUpdate implements UpdatesListener {
-
- private final TelegramBot bot;
- private final Map users = new HashMap<>();
- private final QuizRepository readRepository;
-
- public BotUpdate(TelegramBot bot, QuizRepository readRepository) {
- this.bot = bot;
- this.readRepository = readRepository;
- }
-
- @Override
- public int process(List updates) throws NullPointerException {
- Update update = updates.get(updates.size() - 1);
- if (update.callbackQuery() != null) {
- return handleCallback(update.callbackQuery());
- } else if (update.message() == null) {
- return UpdatesListener.CONFIRMED_UPDATES_NONE;
- }
-
- Message message = update.message();
- Long chatId = message.chat().id();
- String messageText = message.text();
- if (!isRegisterUser(chatId) && !messageText.equals(BotConstants.START_BOT_COMMAND)) {
- bot.execute(new SendMessage(chatId, "input /start"));
- return UpdatesListener.CONFIRMED_UPDATES_ALL;
- }
-
- switch (messageText) {
- case BotConstants.START_BOT_COMMAND -> {
- if (isRegisterUser(chatId)) {
- break;
- }
- bot.execute(new SendMessage(chatId, BotConstants.STARTING_MESSAGE));
- UserInfo userInfo = new UserInfo();
- users.put(chatId, userInfo);
- }
- case BotConstants.CHOOSE_TOPIC_COMMAND -> {
- UserInfo userInfo = users.get(chatId);
- UserQuizSession userQuizSession = userInfo.getUserQuizSession();
- if (userQuizSession != null) {
- bot.execute(new SendMessage(chatId, "Please finish this quiz"));
- break;
- }
- if (userInfo.isTopicChosen()) {
- bot.execute(new SendMessage(chatId, "You are not chosen quiz"));
- break;
- }
- sendChoiceQuiz(chatId);
- }
- case BotConstants.START_QUIZ_COMMAND -> {
- UserInfo userInfo = users.get(chatId);
- UserQuizSession userQuizSession = userInfo.getUserQuizSession();
- if (userQuizSession != null) {
- bot.execute(new SendMessage(chatId, "Please finish this quiz"));
- break;
- }
-
- String currentTopicName = userInfo.getCurrentTopicName();
- if (currentTopicName == null) {
- bot.execute(new SendMessage(chatId, "Topic is not chosen, please use /choice command to choose"));
- break;
- }
- if (userInfo.isTopicChosen()) {
- bot.execute(new SendMessage(chatId, "You are not chosen quiz"));
- break;
- }
- userQuizSession = new UserQuizSession(readRepository.loadQuestions(currentTopicName));
- userInfo.setUserQuizSession(userQuizSession);
- bot.execute(new SendMessage(chatId, "Quiz: " + userInfo.getCurrentTopicName()));
- sendQuestion(chatId);
- }
- case BotConstants.CANCEL_QUIZ_COMMAND -> {
- UserInfo userInfo = users.get(chatId);
- UserQuizSession userQuizSession = userInfo.getUserQuizSession();
- if (userQuizSession == null) {
- bot.execute(new SendMessage(chatId, "You didn't start the quiz"));
- break;
- }
- clearLastMessageKeyboard(chatId);
- sendStatsCanceledQuiz(chatId);
- }
- }
- return UpdatesListener.CONFIRMED_UPDATES_ALL;
- }
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- private void sendChoiceQuiz(Long chatId) {
- users.get(chatId).setChoiceQuiz(true);
- SendMessage choiceQuiz = new SendMessage(chatId, "Choose your quiz!");
- Keyboard keyboard = buildTopicChoiceKeyboard();
- choiceQuiz.replyMarkup(keyboard);
- users.get(chatId).setLastBotMessage(bot.execute(choiceQuiz).message());
- }
-
- private void sendQuestion(Long chatId) {
- UserQuizSession userQuizSession = users.get(chatId).getUserQuizSession();
- Question question = userQuizSession.getNextQuestion();
- String[] questionOptions = question.getOptions();
- Keyboard inlineKeyboardMarkup = buildInlineKeyboard(questionOptions.length);
- StringBuilder questionTextMessage = new StringBuilder(String.format("❓ Question: %d\n%s\n",
- userQuizSession.getQuestionCounter(), question.getQuestion()));
- for (int i = 0; i < questionOptions.length; i++) {
- questionTextMessage.append(String.format("\n%d. %s", i + 1, questionOptions[i]));
- }
-
- SendMessage questionMessage = new SendMessage(chatId, questionTextMessage.toString());
- questionMessage.replyMarkup(inlineKeyboardMarkup);
- users.get(chatId).setLastBotMessage(bot.execute(questionMessage).message());
- }
-
- private void sendAnswer(CallbackQuery callbackQuery, Long chatId) {
- clearLastMessageKeyboard(chatId);
- int userAnswerNum = Integer.parseInt(callbackQuery.data());
- UserQuizSession userQuizSession = users.get(chatId).getUserQuizSession();
- String answerText = getAnswerText(userQuizSession, userAnswerNum);
- SendMessage answerMessage = new SendMessage(chatId, answerText).parseMode(ParseMode.HTML);
- users.get(chatId).setLastBotMessage(bot.execute(answerMessage).message());
- }
-
- private void sendQuizStats(Long chatId) {
- UserQuizSession userQuizSession = users.get(chatId).getUserQuizSession();
- int quizAmount = userQuizSession.getQuestionAmount();
- int rightAnswerCounter = userQuizSession.getRightAnswerCounter();
- String statMessageText = getQuizStatText(quizAmount, rightAnswerCounter);
- userQuizSession.setQuizMode(false);
- SendMessage statMessage = new SendMessage(chatId, statMessageText).parseMode(ParseMode.HTML);
- Message lastBotMessage = bot.execute(statMessage).message();
- users.get(chatId).setLastBotMessage(lastBotMessage);
- users.get(chatId).setUserQuizSession(null);
- }
-
- private static String getQuizStatText(int quizAmount, int rightAnswerCounter) {
- return String.format("❓ Question number: %d\n\n" +
- "✅ Right answers: %d\\%d\n\n" +
- "Input /start_quiz to reset bot or chose quiz another quiz /choice",
- quizAmount, rightAnswerCounter, quizAmount);
- }
-
- private void sendStatsCanceledQuiz(Long chatId) {
- UserQuizSession userQuizSession = users.get(chatId).getUserQuizSession();
- int questionCount = userQuizSession.getQuestionCounter();
- int rightAnswerCounter = userQuizSession.getRightAnswerCounter();
- String statMessageText = getCanceledQuizStatText(questionCount, rightAnswerCounter);
- userQuizSession.setQuizMode(false);
- SendMessage statMessage = new SendMessage(chatId, statMessageText).parseMode(ParseMode.HTML);
- users.get(chatId).setLastBotMessage(bot.execute(statMessage).message());
- users.get(chatId).setUserQuizSession(null);
- }
-
- private static String getCanceledQuizStatText(int questionCount, int rightAnswerCounter) {
- String statMessageText = String.format("❓You canceled quiz \n\nThe questions were: %d\n\n" +
- "✅ Right answers: %d\\%d\n\n" +
- "Input /start_quiz to reset bot or chose quiz another quiz /choice",
- questionCount, rightAnswerCounter, questionCount);
- return statMessageText;
- }
-
- private int handleCallback(CallbackQuery callbackQuery) {
- Long userId = callbackQuery.from().id();
- if (!isRegisterUser(userId)) {
- bot.execute(new SendMessage(userId, "Input /start"));
- return UpdatesListener.CONFIRMED_UPDATES_ALL;
- }
-
- String callbackData = callbackQuery.data();
- if (callbackData == null) {
- return UpdatesListener.CONFIRMED_UPDATES_NONE;
- }
- if (callbackData.startsWith("topicChoice:")) {
-
- chooseQuiz(callbackData, userId);
- return UpdatesListener.CONFIRMED_UPDATES_ALL;
- }
- handlerQuizAnswer(callbackQuery, userId);
- return UpdatesListener.CONFIRMED_UPDATES_ALL;
- }
-
- private void handlerQuizAnswer(CallbackQuery callbackQuery, Long chatId) {
- UserInfo userInfo = users.get(chatId);
- UserQuizSession userQuizSession = userInfo.getUserQuizSession();
- if (userQuizSession.isQuizMode()) {
- sendAnswer(callbackQuery, chatId);
- }
-
- if (userQuizSession.getQuestionCounter() == userQuizSession.getQuestionAmount()) {
- sendQuizStats(chatId);
- }
-
- if (userQuizSession.isNextQuestionAvailable()) {
- sendQuestion(chatId);
- }
- }
-
- private InlineKeyboardMarkup buildInlineKeyboard(int keyboardLength) {
- List inlineKeyboardButtons = new ArrayList<>();
- List rows = new ArrayList<>();
- for (int i = 0; i < keyboardLength; i++) {
- if (i % 2 == 0) {
- inlineKeyboardButtons.add(rows.toArray(new InlineKeyboardButton[]{}));
- rows = new ArrayList<>();
- }
-
- rows.add(new InlineKeyboardButton(String.valueOf(i + 1)).callbackData(String.valueOf(i)));
- }
-
- inlineKeyboardButtons.add(rows.toArray(new InlineKeyboardButton[]{}));
- return new InlineKeyboardMarkup(inlineKeyboardButtons.toArray(new InlineKeyboardButton[][]{}));
- }
-
- private InlineKeyboardMarkup buildTopicChoiceKeyboard() {
- String[] allTopicsName = readRepository.getAllTopicNames();
- List inlineKeyboardButtons = new ArrayList<>();
- List rows = new ArrayList<>();
- for (int i = 0; i < allTopicsName.length; i++) {
- if (i % 2 == 0) {
- inlineKeyboardButtons.add(rows.toArray(new InlineKeyboardButton[]{}));
- rows = new ArrayList<>();
- }
-
- rows.add(new InlineKeyboardButton(allTopicsName[i]).callbackData("topicChoice:" + allTopicsName[i]));
- }
-
- inlineKeyboardButtons.add(rows.toArray(new InlineKeyboardButton[]{}));
- return new InlineKeyboardMarkup(inlineKeyboardButtons.toArray(new InlineKeyboardButton[][]{}));
- }
-
- private boolean isRegisterUser(Long chatId) {
- return users.containsKey(chatId);
- }
-
- private void clearLastMessageKeyboard(Long chatId) {
- Message message = users.get(chatId).getLastBotMessage();
- EditMessageText editMessage = new EditMessageText(chatId, message.messageId(), message.text());
- editMessage.replyMarkup(new InlineKeyboardMarkup(new InlineKeyboardButton("").callbackData("deleted")));
- bot.execute(editMessage);
- }
-
- private void chooseQuiz(String callbackData, Long chatId) {
- UserInfo userInfo = users.get(chatId);
- String topicPrefix = "topicChoice:";
- String topicName = callbackData.substring(topicPrefix.length());
- userInfo.setCurrentTopicName(topicName);
- clearLastMessageKeyboard(chatId);
- userInfo.setChoiceQuiz(false);
- bot.execute(new SendMessage(chatId, String.format("Quiz: %s\n write /start_quiz or /choice for choice any quiz",
- topicName)));
- }
-
- private String getAnswerText(UserQuizSession userQuizSession, int userAnswerNum) {
- Question question = userQuizSession.getCurrentQuestion();
- int questionAnswerNum = question.getAnswer();
- String userAnswerText = question.getOptions()[userAnswerNum];
- String quizAnswerOption = question.getOptions()[questionAnswerNum];
- String quizAnswerDescription = question.getAnswerDescription();
- String answerMessageText;
- if (questionAnswerNum == userAnswerNum) {
- answerMessageText = String.format("✅ It's Right!\n\nAnswer: %s\n\n%s",
- quizAnswerOption, quizAnswerDescription);
- userQuizSession.addRightCounter();
- } else {
- answerMessageText = String.format("❌ It's wrong!\n\nYour answer: %s\nRight answer: %s\n\n%s",
- userAnswerText, quizAnswerOption, quizAnswerDescription);
- }
- return answerMessageText;
- }
-
-}
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java
index fd7bb29..9dc714b 100644
--- a/src/main/java/org/example/Main.java
+++ b/src/main/java/org/example/Main.java
@@ -1,30 +1,30 @@
package org.example;
import com.pengrad.telegrambot.TelegramBot;
+import org.example.configs.MongoDBConfig;
+import org.example.services.QuizService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.PropertySource;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-
+@PropertySource("classpath:application.properties")
public class Main {
- public static void main(String[] args) throws NullPointerException, IOException {
- TelegramBot bot = new TelegramBot(loadToken());
- QuizRepository readRepository = new QuizRepository("src/main/resources/quizes");
- BotUpdate listener = new BotUpdate(bot, readRepository);
- QuizBotExceptionHandler exception = new QuizBotExceptionHandler();
- bot.setUpdatesListener(listener, exception);
+ @Value("${telegram.user.token}")
+ private String userToken;
+ @Value("${telegram.admin.token}")
+ private String adminToken;
+
+ public static void main(String[] args) throws NullPointerException {
+ ApplicationContext context = new AnnotationConfigApplicationContext(Main.class, MongoDBConfig.class);
+ context.getBean(Main.class).run(context);
}
- private static String loadToken() throws IOException {
- Properties prop = new Properties();
- try (InputStream systemResourceAsStream = ClassLoader.getSystemResourceAsStream("config.properties")) {
- prop.load(systemResourceAsStream);
- String token = prop.getProperty("token");
- if (token == null) {
- throw new RuntimeException("Unable to load token");
- }
- return token;
- }
+ private void run(ApplicationContext context) {
+ QuizService quizService = context.getBean(QuizService.class);
+ TelegramBot userBot = new TelegramBot(userToken);
+ QuizBotListener userListener = new QuizBotListener(userBot, quizService);
+ QuizBotExceptionHandler exception = new QuizBotExceptionHandler();
+ userBot.setUpdatesListener(userListener, exception);
}
}
\ No newline at end of file
diff --git a/src/main/java/org/example/QuizBotExceptionHandler.java b/src/main/java/org/example/QuizBotExceptionHandler.java
index ca27275..25185fa 100644
--- a/src/main/java/org/example/QuizBotExceptionHandler.java
+++ b/src/main/java/org/example/QuizBotExceptionHandler.java
@@ -6,7 +6,10 @@
import org.apache.logging.log4j.Logger;
public class QuizBotExceptionHandler implements ExceptionHandler {
- Logger logger = LogManager.getLogger();
+
+
+ private static final Logger log = LogManager.getLogger(QuizBotExceptionHandler.class);
+
public QuizBotExceptionHandler() {
}
@@ -16,7 +19,7 @@ public void onException(TelegramException e) {
e.response().errorCode();
e.response().description();
} else {
- logger.fatal("Was throw exception in class QuizBotExceptionHandler");
+ log.fatal("Was throw exception in class QuizBotExceptionHandler");
throw new RuntimeException("Don't access to bot", e);
}
}
diff --git a/src/main/java/org/example/QuizBotListener.java b/src/main/java/org/example/QuizBotListener.java
new file mode 100644
index 0000000..65999e0
--- /dev/null
+++ b/src/main/java/org/example/QuizBotListener.java
@@ -0,0 +1,358 @@
+package org.example;
+
+import com.pengrad.telegrambot.TelegramBot;
+import com.pengrad.telegrambot.UpdatesListener;
+import com.pengrad.telegrambot.model.CallbackQuery;
+import com.pengrad.telegrambot.model.Message;
+import com.pengrad.telegrambot.model.Update;
+import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
+import com.pengrad.telegrambot.model.request.InlineKeyboardMarkup;
+import com.pengrad.telegrambot.model.request.Keyboard;
+import com.pengrad.telegrambot.model.request.ParseMode;
+import com.pengrad.telegrambot.request.EditMessageText;
+import com.pengrad.telegrambot.request.SendMessage;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.cache2k.Cache;
+import org.cache2k.Cache2kBuilder;
+import org.cache2k.event.CacheEntryCreatedListener;
+import org.cache2k.event.CacheEntryExpiredListener;
+import org.example.model.Question;
+import org.example.model.QuestionOption;
+import org.example.model.QuizBotSession;
+import org.example.model.QuizQuestions;
+import org.example.model.UserQuizSession;
+import org.example.services.QuizService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class QuizBotListener implements UpdatesListener {
+ private static final Logger log = LogManager.getLogger(QuizBotListener.class);
+ private final TelegramBot bot;
+ private final QuizService quizService;
+ private final Cache sessionCache;
+
+ public QuizBotListener(TelegramBot bot, QuizService quizService) {
+ this.bot = bot;
+ this.quizService = quizService;
+ this.sessionCache = Cache2kBuilder.of(Long.class, QuizBotSession.class).expireAfterWrite(120, TimeUnit.SECONDS).addListener((CacheEntryExpiredListener) (cache, entry) -> {
+ clearLastMessageKeyboard(cache.get(entry.getKey()), entry.getKey());
+ sendMessage(entry.getKey(), "You've been thinking too long, so you'll have to start over." + " Write /start or /choice.");
+ }).addListener((CacheEntryCreatedListener) (cache, entry) -> sendMessage(entry.getKey(), UserBotConstants.STARTING_MESSAGE)).build();
+ }
+
+ @Override
+ public int process(List updates) throws NullPointerException {
+ try {
+ Update update = updates.get(updates.size() - 1);
+ if (update.callbackQuery() != null) {
+ return handleCallback(update.callbackQuery());
+ } else if (update.message() == null) {
+ return UpdatesListener.CONFIRMED_UPDATES_NONE;
+ }
+
+ Message message = update.message();
+ Long userId = message.chat().id();
+ String messageText = message.text();
+ QuizBotSession quizBotSession = sessionCache.computeIfAbsent(userId, () -> new QuizBotSession(QuizBotSessionMode.SESSION_CREATED));
+ //todo start here
+ switch (messageText) {
+ case UserBotConstants.START_BOT_COMMAND -> {
+ clearLastMessageKeyboard(quizBotSession, userId);
+ sessionCache.remove(userId);
+ sessionCache.put(userId, new QuizBotSession(QuizBotSessionMode.SESSION_CREATED));
+ return UpdatesListener.CONFIRMED_UPDATES_ALL;
+ }
+ case UserBotConstants.CHOOSE_TOPIC_COMMAND -> {
+ UserQuizSession userQuizSession = quizBotSession.getUserQuizSession();
+ if (userQuizSession != null) {
+ sendMessage(userId, "Please finish this quiz");
+ break;
+ }
+ sendTopics(userId, quizBotSession);
+ }
+ case UserBotConstants.START_QUIZ_COMMAND -> {
+ UserQuizSession userQuizSession = quizBotSession.getUserQuizSession();
+ if (userQuizSession != null) {
+ sendMessage(userId, "Please finish this quiz");
+ break;
+ }
+ String currentTopicName = quizBotSession.getCurrentTopicName();
+ if (currentTopicName == null) {
+ sendMessage(userId, "Topic is not chosen, please use " + UserBotConstants.CHOOSE_TOPIC_COMMAND + " command to choose");
+ break;
+ }
+ if (quizBotSession.getBotSessionMode().equals(QuizBotSessionMode.QUESTION_COUNT_CHOICE)) {
+ sendMessage(userId, "You are not chosen quiz");
+ break;
+ }
+
+ userQuizSession = new UserQuizSession(getGeneratedQuiz(currentTopicName, quizBotSession));
+ quizBotSession.setUserQuizSession(userQuizSession);
+ sendMessage(userId, "Quiz: " + quizBotSession.getCurrentTopicName());
+ quizBotSession.setBotSessionMode(QuizBotSessionMode.QUIZ);
+ sendQuestion(userId, quizBotSession);
+ }
+ case UserBotConstants.CANCEL_COMMAND -> {
+ UserQuizSession userQuizSession = quizBotSession.getUserQuizSession();
+ if (userQuizSession == null) {
+ sendMessage(userId, "You aren't begin quiz");
+ break;
+ }
+ clearLastMessageKeyboard(quizBotSession, userId);
+ sendStatsCanceledQuiz(userId, quizBotSession);
+ }
+ }
+
+ if (messageText.matches("^[1-9][0-9]*$")) {
+ if (quizBotSession.getBotSessionMode().equals(QuizBotSessionMode.QUESTION_COUNT_CHOICE)) {
+ setCountOfQuiz(messageText, userId, quizBotSession);
+ }
+ if (quizBotSession.getBotSessionMode().equals(QuizBotSessionMode.TOPIC_CHOICE)) {
+ choiceTopic(messageText, quizBotSession, userId);
+ }
+ }
+ return UpdatesListener.CONFIRMED_UPDATES_ALL;
+ } catch (Exception e) {
+ log.error(e.getMessage());
+ }
+
+ return UpdatesListener.CONFIRMED_UPDATES_ALL;
+ }
+
+ private void setCountOfQuiz(String messageText, Long userId, QuizBotSession quizBotSession) {
+ int countOfQuestions = Integer.parseInt(messageText);
+ if (countOfQuestions > 20 || countOfQuestions < 5) {
+ sendMessage(userId, "Input valid count of question");
+ }
+ quizBotSession.setCountOfQuestion(countOfQuestions);
+ sendMessage(userId, String.format("Quiz: %s\nQuestions: %d\nInput " + UserBotConstants.START_QUIZ_COMMAND + " or " + UserBotConstants.CHOOSE_TOPIC_COMMAND + " for choice any topic", quizBotSession.getCurrentTopicName(), countOfQuestions));
+ quizBotSession.setBotSessionMode(QuizBotSessionMode.SESSION_CREATED);
+ }
+
+ private QuizQuestions getGeneratedQuiz(String currentTopicName, QuizBotSession quizBotSession) {
+ QuizQuestions quizQuestions = quizService.findByTopicName(currentTopicName);
+ List questionList = quizQuestions.getQuestionList();
+ int countOfQuestion = quizBotSession.getCountOfQuestion();
+ if (questionList.size() <= countOfQuestion) {
+ return quizQuestions;
+ }
+ QuizQuestions generatedQuizQuestions = new QuizQuestions();
+ List generatedQuestionList = new ArrayList<>();
+ Set uniqueNumbers = getUniqueNums(questionList.size() - 1, countOfQuestion);
+ for (Integer i : uniqueNumbers) {
+ generatedQuestionList.add(questionList.get(i));
+ }
+ generatedQuizQuestions.setQuestionList(generatedQuestionList);
+ generatedQuizQuestions.setTopicName(quizQuestions.getTopicName());
+ return generatedQuizQuestions;
+ }
+
+ private Set getUniqueNums(int max, int count) {
+ Set uniqueNums = new HashSet<>();
+ Random random = new Random();
+ while (count > uniqueNums.size()) {
+ uniqueNums.add(random.nextInt(max));
+ }
+ return uniqueNums;
+ }
+
+ private void sendMessage(Long userId, String s) {
+ bot.execute(new SendMessage(userId, s));
+ }
+
+ private void sendTopics(Long userId, QuizBotSession quizBotSession) {
+ List allTopicsName = quizService.getTopics();
+ if (allTopicsName.isEmpty()) {
+ allTopicsName = quizService.getTopics();
+ if (allTopicsName.isEmpty()) {
+ sendMessage(userId, "Sorry nothing topics");
+ return;
+ }
+ }
+ StringBuilder choiceTopicText = new StringBuilder("Choose your topic! Input number of quiz");
+ quizBotSession.setBotSessionMode(QuizBotSessionMode.TOPIC_CHOICE);
+ for (int i = 0; i < allTopicsName.size(); i++) {
+ int pagination = i + 1;
+ choiceTopicText.append("\n").append(pagination).append(". ").append(allTopicsName.get(i));
+ }
+ SendMessage choiceTopic = new SendMessage(userId, choiceTopicText.toString());
+ Message message = bot.execute(choiceTopic).message();
+ quizBotSession.setLastKeyboardBotMessageId(message.messageId());
+ quizBotSession.setLastKeyboardBotMessageText(message.text());
+ }
+
+ private void sendQuestion(Long userId, QuizBotSession quizBotSession) {
+ UserQuizSession userQuizSession = quizBotSession.getUserQuizSession();
+ Question question = userQuizSession.getNextQuestion();
+ List optionsList = question.getOptionList();
+ Collections.shuffle(optionsList);
+ Keyboard inlineKeyboardMarkup = buildInlineKeyboard(optionsList.size());
+ StringBuilder questionTextMessage = new StringBuilder(String.format("❓ Question: %d\n%s\n", userQuizSession.getQuestionCounter(), question.getQuestion()));
+ for (int i = 0; i < optionsList.size(); i++) {
+ questionTextMessage.append(String.format("\n%d. %s", i + 1, optionsList.get(i).getOptionText()));
+ }
+
+ SendMessage questionMessage = new SendMessage(userId, questionTextMessage.toString());
+ questionMessage.replyMarkup(inlineKeyboardMarkup);
+ Message message = bot.execute(questionMessage).message();
+ quizBotSession.setLastKeyboardBotMessageText(message.text());
+ quizBotSession.setLastKeyboardBotMessageId(message.messageId());
+ }
+
+ private void sendAnswer(CallbackQuery callbackQuery, Long userId, QuizBotSession quizBotSession) {
+ String callbackData = callbackQuery.data();
+ UserQuizSession userQuizSession = quizBotSession.getUserQuizSession();
+ int userAnswerNum = Integer.parseInt(callbackData);
+ String answerText = getAnswerText(userQuizSession, userAnswerNum);
+ SendMessage answerMessage = new SendMessage(userId, answerText).parseMode(ParseMode.HTML);
+ clearLastMessageKeyboard(quizBotSession, userId);
+ bot.execute(answerMessage);
+ }
+
+ private void sendQuizStats(Long userId, QuizBotSession quizBotSession) {
+ UserQuizSession userQuizSession = quizBotSession.getUserQuizSession();
+ int quizAmount = userQuizSession.getQuestionAmount();
+ int rightAnswerCounter = userQuizSession.getRightAnswerCounter();
+ String statMessageText = getQuizStatText(quizAmount, rightAnswerCounter);
+ SendMessage statMessage = new SendMessage(userId, statMessageText).parseMode(ParseMode.HTML);
+ bot.execute(statMessage).message();
+ quizBotSession.setUserQuizSession(null);
+ }
+
+ private void sendStatsCanceledQuiz(Long userId, QuizBotSession quizBotSession) {
+ UserQuizSession userQuizSession = quizBotSession.getUserQuizSession();
+ int questionCount = userQuizSession.getQuestionCounter();
+ int rightAnswerCounter = userQuizSession.getRightAnswerCounter();
+ String statMessageText = getCanceledQuizStatText(questionCount, rightAnswerCounter);
+ SendMessage statMessage = new SendMessage(userId, statMessageText).parseMode(ParseMode.HTML);
+ Message message = bot.execute(statMessage).message();
+ quizBotSession.setLastKeyboardBotMessageId(message.messageId());
+ quizBotSession.setLastKeyboardBotMessageText(message.text());
+ quizBotSession.setUserQuizSession(null);
+ }
+
+ private int handleCallback(CallbackQuery callbackQuery) {
+ Long userId = callbackQuery.from().id();
+ QuizBotSession quizBotSession = sessionCache.computeIfAbsent(userId, () -> new QuizBotSession(QuizBotSessionMode.SESSION_CREATED));
+
+ String callbackData = callbackQuery.data();
+ if (callbackData == null) {
+ return UpdatesListener.CONFIRMED_UPDATES_NONE;
+ }
+ clearLastMessageKeyboard(quizBotSession, userId);
+ handlerQuizAnswer(callbackQuery, userId, quizBotSession);
+ return UpdatesListener.CONFIRMED_UPDATES_ALL;
+ }
+
+ private void handlerQuizAnswer(CallbackQuery callbackQuery, Long userId, QuizBotSession quizBotSession) {
+ UserQuizSession userQuizSession = quizBotSession.getUserQuizSession();
+ if (userQuizSession == null) {
+ return;
+ }
+ int totalQuestion = userQuizSession.getQuestionAmount();
+ int currentQuestionIndex = userQuizSession.getCurrentQuestionIndex();
+ //todo refactoring
+ if (quizBotSession.getBotSessionMode().equals(QuizBotSessionMode.QUIZ)) {
+ sendAnswer(callbackQuery, userId, quizBotSession);
+ }
+
+ if (currentQuestionIndex == totalQuestion) {
+ sendQuizStats(userId, quizBotSession);
+ }
+
+ if (currentQuestionIndex < totalQuestion) {
+ sendQuestion(userId, quizBotSession);
+ }
+ }
+
+ private InlineKeyboardMarkup buildInlineKeyboard(int keyboardLength) {
+ List inlineKeyboardButtons = new ArrayList<>();
+ List rows = new ArrayList<>();
+ for (int i = 0; i < keyboardLength; i++) {
+ if (i % 2 == 0) {
+ inlineKeyboardButtons.add(rows.toArray(new InlineKeyboardButton[]{}));
+ rows = new ArrayList<>();
+ }
+
+ rows.add(new InlineKeyboardButton(String.valueOf(i + 1)).callbackData(String.valueOf(i)));
+ }
+
+ inlineKeyboardButtons.add(rows.toArray(new InlineKeyboardButton[]{}));
+ return new InlineKeyboardMarkup(inlineKeyboardButtons.toArray(new InlineKeyboardButton[][]{}));
+ }
+
+ private void choiceTopic(String messageText, QuizBotSession quizBotSession, Long userId) {
+ int topicIndex = Integer.parseInt(messageText) - 1;
+ List allTopicName = quizService.getTopics();
+ if (allTopicName.isEmpty()) {
+
+ quizBotSession.setBotSessionMode(QuizBotSessionMode.SESSION_CREATED);
+ sendMessage(userId, "Sorry nothing quiz, send " + UserBotConstants.CHOOSE_TOPIC_COMMAND + " for choice quiz");
+ return;
+ }
+ if (topicIndex >= allTopicName.size()) {
+ sendMessage(userId, "You input over large digital, send me correct digital");
+ sendTopics(userId, quizBotSession);
+ return;
+ } else if (topicIndex < 0) {
+ sendMessage(userId, "You input so small digital, send me correct digital");
+ sendTopics(userId, quizBotSession);
+ return;
+ }
+ String currentTopicName = allTopicName.get(topicIndex);
+ quizBotSession.setCurrentTopicName(currentTopicName);
+ quizBotSession.setCurrentQuiz(quizService.findByTopicName(currentTopicName));
+ quizBotSession.setBotSessionMode(QuizBotSessionMode.QUESTION_COUNT_CHOICE);
+ sendMessage(userId, "Input count to your quiz (at 5 to 20)");
+ }
+
+ private void clearLastMessageKeyboard(QuizBotSession quizBotSession, Long userId) {
+ if (quizBotSession.getLastKeyboardBotMessageId() == 0) {
+ return;
+ }
+ EditMessageText editMessage = new EditMessageText(userId, quizBotSession.getLastKeyboardBotMessageId(), quizBotSession.getLastKeyboardBotMessageText());
+ editMessage.replyMarkup(new InlineKeyboardMarkup(new InlineKeyboardButton("").callbackData("deleted")));
+ bot.execute(editMessage);
+ }
+
+ private static String getQuizStatText(int quizAmount, int rightAnswerCounter) {
+ return String.format("❓ Question number: %d" + "\n\n" + "✅ Right answers: %d\\%d" + "\n\n" + "Input " + UserBotConstants.START_QUIZ_COMMAND + " to start quiz or chose quiz another quiz " + UserBotConstants.CHOOSE_TOPIC_COMMAND, quizAmount, rightAnswerCounter, quizAmount);
+ }
+
+ private static String getCanceledQuizStatText(int questionCount, int rightAnswerCounter) {
+ return String.format("❓You canceled quiz \n" + "\n" + "The questions were: %d\n\n" + "✅ Right answers: %d\\%d\n" + "\n" + "Input " + UserBotConstants.START_QUIZ_COMMAND + " to start quiz or chose quiz another quiz " + UserBotConstants.CHOOSE_TOPIC_COMMAND, questionCount, rightAnswerCounter, questionCount);
+ }
+
+ private String getAnswerText(UserQuizSession userQuizSession, int userAnswerNum) {
+ Question question = userQuizSession.getCurrentQuestion();
+ List optionsList = question.getOptionList();
+ String quizAnswerOption = null;
+ int questionAnswerNum = 0;
+ for (int i = 0; i < optionsList.size(); i++) {
+ QuestionOption questionOption = optionsList.get(i);
+ if (questionOption.isAnswer()) {
+ questionAnswerNum = i;
+ quizAnswerOption = questionOption.getOptionText();
+ break;
+ }
+ }
+ String userAnswerText = question.getAnswerDescription();
+ String quizAnswerDescription = question.getAnswerDescription();
+ String answerMessageText;
+ if (questionAnswerNum == userAnswerNum) {
+ answerMessageText = String.format("✅ It's Right!\n\nAnswer: %s\n\n%s", quizAnswerOption, quizAnswerDescription);
+ userQuizSession.incRightCounter();
+ } else {
+ answerMessageText = String.format("❌ It's wrong!\n\nYour answer: %s\nRight answer: %s\n\n%s", userAnswerText, quizAnswerOption, quizAnswerDescription);
+ }
+ return answerMessageText;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/example/QuizBotSessionMode.java b/src/main/java/org/example/QuizBotSessionMode.java
new file mode 100644
index 0000000..3f6438c
--- /dev/null
+++ b/src/main/java/org/example/QuizBotSessionMode.java
@@ -0,0 +1,9 @@
+package org.example;
+
+public enum QuizBotSessionMode {
+ SESSION_CREATED,
+ TOPIC_CHOICE,
+ QUESTION_COUNT_CHOICE,
+ QUIZ;
+
+}
diff --git a/src/main/java/org/example/QuizRepository.java b/src/main/java/org/example/QuizRepository.java
deleted file mode 100644
index 0378605..0000000
--- a/src/main/java/org/example/QuizRepository.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.example;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.example.model.Question;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class QuizRepository {
- private final Map quizesTopics = new HashMap<>();
- private static final Logger logger = LogManager.getLogger(QuizRepository.class);
- public QuizRepository(String jsonPath) {
- try (DirectoryStream directoryStream = Files.newDirectoryStream(Path.of(jsonPath))) {
- for (Path path : directoryStream) {
- String fileName = path.getFileName().toString();
- String topicName = fileName.substring(0, fileName.indexOf(".json"));
- quizesTopics.put(topicName, path);
- }
- } catch (IOException e) {
- throw new RuntimeException("Unable to read quizes", e);
- }
- }
-
- public Collection loadQuestions(String topicName) {
- if (!quizesTopics.containsKey(topicName)) {
- return List.of();
- }
- try (BufferedReader reader = new BufferedReader(Files.newBufferedReader(quizesTopics.get(topicName)))) {
- Gson gson = new GsonBuilder().create();
- return Arrays.asList(gson.fromJson(reader, Question[].class));
- } catch (IOException e) {
- logger.error("Error appeared while loading quiz");
- return List.of();
- }
- }
-
- public String[] getAllTopicNames() {
- return quizesTopics.keySet().toArray(new String[]{});
- }
-
-}
diff --git a/src/main/java/org/example/BotConstants.java b/src/main/java/org/example/UserBotConstants.java
similarity index 50%
rename from src/main/java/org/example/BotConstants.java
rename to src/main/java/org/example/UserBotConstants.java
index 4094bfd..7822b66 100644
--- a/src/main/java/org/example/BotConstants.java
+++ b/src/main/java/org/example/UserBotConstants.java
@@ -1,15 +1,16 @@
package org.example;
-public class BotConstants {
+public class UserBotConstants {
public static final String START_BOT_COMMAND = "/start";
public static final String CHOOSE_TOPIC_COMMAND = "/choice";
public static final String START_QUIZ_COMMAND = "/start_quiz";
- public static final String ERROR_MESSAGE = "Error appeared while loading quiz, sorry :)";
+ public static final String CANCEL_COMMAND = "/cancel";
+
public static final String STARTING_MESSAGE = "\uD83D\uDE2E Hello! I'm bot for testing your knowledge! " +
- "\uD83E\uDD2F\n\n❓For choosing quiz input /choice❓\n❓For starting quiz /start_quiz❓";
- public static final String CANCEL_QUIZ_COMMAND = "/cancel";
+ "\uD83E\uDD2F\n\n❓For choosing quiz input /choice❓" +
+ "\n❓For starting quiz /start_quiz❓";
- private BotConstants() {
+ private UserBotConstants() {
}
}
diff --git a/src/main/java/org/example/configs/MongoDBConfig.java b/src/main/java/org/example/configs/MongoDBConfig.java
new file mode 100644
index 0000000..de2d7af
--- /dev/null
+++ b/src/main/java/org/example/configs/MongoDBConfig.java
@@ -0,0 +1,45 @@
+package org.example.configs;
+
+import com.mongodb.ConnectionString;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+@Configuration
+@ComponentScan(basePackages = "org.example")
+@PropertySource("classpath:application.properties")
+@EnableMongoRepositories("org.example.repositories")
+public class MongoDBConfig extends AbstractMongoClientConfiguration {
+
+
+ @Value("${spring.data.mongodb.database}")
+ private String databaseName;
+ @Value("${spring.data.mongodb.uri}")
+ private String connectionUri;
+
+ @NotNull
+ @Override
+ protected String getDatabaseName() {
+ return databaseName;
+ }
+
+ @Bean
+ @NotNull
+ @Override
+ public MongoClient mongoClient() {
+ return MongoClients.create(new ConnectionString(connectionUri));
+ }
+
+ public MongoClient reconnectToDB() {
+ MongoClient currentClient = mongoClient();
+ currentClient.close();
+ return MongoClients.create(new ConnectionString(connectionUri));
+ }
+}
diff --git a/src/main/java/org/example/model/PermanentUserInfo.java b/src/main/java/org/example/model/PermanentUserInfo.java
new file mode 100644
index 0000000..582c5e3
--- /dev/null
+++ b/src/main/java/org/example/model/PermanentUserInfo.java
@@ -0,0 +1,50 @@
+package org.example.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+import org.springframework.data.redis.core.RedisHash;
+
+@Document
+public class PermanentUserInfo {
+ @Id
+ @Field(name = "userId")
+ private Long userId;
+ @Field(name = "userName")
+ private String userName;
+ @Field(name = "isAdmin")
+ private boolean isAdmin = false;
+
+ public PermanentUserInfo() {
+ }
+
+ public PermanentUserInfo(String userName, Long userId, boolean isAdmin) {
+ this.userName = userName;
+ this.userId = userId;
+ this.isAdmin = isAdmin;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public boolean getIsAdmin() {
+ return isAdmin;
+ }
+
+ public void setAdmin(boolean admin) {
+ isAdmin = admin;
+ }
+}
diff --git a/src/main/java/org/example/model/Question.java b/src/main/java/org/example/model/Question.java
index 1688785..421b7fa 100644
--- a/src/main/java/org/example/model/Question.java
+++ b/src/main/java/org/example/model/Question.java
@@ -1,25 +1,63 @@
package org.example.model;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Document(collection = "question")
public class Question {
- private String question;
- private String[] options;
- private int answer;
- private String answerDescription;
+ @Id
+ @JsonIgnore
+ private ObjectId id;
+ private String question = "";
+ private String answerDescription = "";
+ private List optionList = new ArrayList<>();
+
+ public Question() {
+ }
+
+ public Question(String question, List questionOptions, String answerDescription) {
+ this.question = question;
+ this.answerDescription = answerDescription;
+ this.optionList = questionOptions;
+ }
+
+
+ public String getQuestion() {
+ return question;
+ }
+
+ public void setQuestion(String question) {
+ this.question = question;
+ }
+
+ public String getAnswerDescription() {
+ return answerDescription;
+ }
- public String[] getOptions() {
- return options;
- }
+ public void setAnswerDescription(String answerDescription) {
+ this.answerDescription = answerDescription;
+ }
- public String getQuestion() {
- return question;
- }
+ public List getOptionList() {
+ return optionList;
+ }
- public int getAnswer() {
- return answer;
- }
+ public void setOptionList(List optionList) {
+ this.optionList = optionList;
+ }
- public String getAnswerDescription() {
- return answerDescription;
- }
+ @JsonIgnore
+ public ObjectId getId() {
+ return id;
+ }
+ @JsonIgnore
+ public void setId(ObjectId id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/org/example/model/QuestionOption.java b/src/main/java/org/example/model/QuestionOption.java
new file mode 100644
index 0000000..894868c
--- /dev/null
+++ b/src/main/java/org/example/model/QuestionOption.java
@@ -0,0 +1,54 @@
+package org.example.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "options")
+public class QuestionOption {
+ @Id
+ @JsonIgnore
+ private ObjectId id = new ObjectId();
+ @JsonProperty("isAnswer")
+ private boolean isAnswer = false;
+ private String optionText = "";
+
+ public QuestionOption() {
+
+ }
+
+ public QuestionOption(boolean isAnswer, String optionText) {
+ this.isAnswer = isAnswer;
+ this.optionText = optionText;
+ }
+
+ @JsonProperty("isAnswer")
+ public boolean isAnswer() {
+ return isAnswer;
+ }
+
+ @JsonProperty("isAnswer")
+ public void setIsAnswer(boolean answer) {
+ this.isAnswer = answer;
+ }
+
+ public String getOptionText() {
+ return optionText;
+ }
+
+ public void setOptionText(String optionText) {
+ this.optionText = optionText;
+ }
+
+ @JsonIgnore
+ public ObjectId getId() {
+ return id;
+ }
+
+ @JsonIgnore
+ public void setId(ObjectId id) {
+ this.id = id;
+ }
+}
diff --git a/src/main/java/org/example/model/QuizBotSession.java b/src/main/java/org/example/model/QuizBotSession.java
new file mode 100644
index 0000000..9d31329
--- /dev/null
+++ b/src/main/java/org/example/model/QuizBotSession.java
@@ -0,0 +1,74 @@
+package org.example.model;
+
+import org.example.QuizBotSessionMode;
+
+public class QuizBotSession {
+ private QuizBotSessionMode botSessionMode;
+
+ private QuizQuestions currentQuizQuestions;
+ private UserQuizSession userQuizSession;
+ private String currentTopicName;
+ private int lastKeyboardBotMessageId = 0;
+ private String lastKeyboardBotMessageText;
+ private int countOfQuestion = 0;
+
+ public QuizBotSession(QuizBotSessionMode botSessionMode) {
+ this.botSessionMode = botSessionMode;
+ }
+
+ public String getCurrentTopicName() {
+ return currentTopicName;
+ }
+
+ public void setCurrentTopicName(String currentTopicName) {
+ this.currentTopicName = currentTopicName;
+ }
+
+ public UserQuizSession getUserQuizSession() {
+ return userQuizSession;
+ }
+
+ public void setUserQuizSession(UserQuizSession userQuizSession) {
+ this.userQuizSession = userQuizSession;
+ }
+
+ public int getLastKeyboardBotMessageId() {
+ return lastKeyboardBotMessageId;
+ }
+
+ public void setLastKeyboardBotMessageId(int lastKeyboardBotMessageId) {
+ this.lastKeyboardBotMessageId = lastKeyboardBotMessageId;
+ }
+
+ public String getLastKeyboardBotMessageText() {
+ return lastKeyboardBotMessageText;
+ }
+
+ public void setLastKeyboardBotMessageText(String lastKeyboardBotMessageText) {
+ this.lastKeyboardBotMessageText = lastKeyboardBotMessageText;
+ }
+
+ public QuizQuestions getCurrentQuiz() {
+ return currentQuizQuestions;
+ }
+
+ public void setCurrentQuiz(QuizQuestions currentQuizQuestions) {
+ this.currentQuizQuestions = currentQuizQuestions;
+ }
+
+ public int getCountOfQuestion() {
+ return countOfQuestion;
+ }
+
+ public void setCountOfQuestion(int countOfQuestion) {
+ this.countOfQuestion = countOfQuestion;
+ }
+
+ public QuizBotSessionMode getBotSessionMode() {
+ return botSessionMode;
+ }
+
+ public void setBotSessionMode(QuizBotSessionMode botSessionMode) {
+ this.botSessionMode = botSessionMode;
+ }
+}
diff --git a/src/main/java/org/example/model/QuizQuestions.java b/src/main/java/org/example/model/QuizQuestions.java
new file mode 100644
index 0000000..f13c15f
--- /dev/null
+++ b/src/main/java/org/example/model/QuizQuestions.java
@@ -0,0 +1,56 @@
+package org.example.model;
+
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Document(collection = "quizQuestions")
+public class QuizQuestions {
+ @Id
+ @JsonIgnore
+ private ObjectId id = new ObjectId();
+ private String topicName = "";
+ private List questionList = new ArrayList<>();
+
+ public QuizQuestions() {
+ }
+
+ public QuizQuestions(String topicName, List questionList) {
+ this.topicName = topicName;
+ this.questionList = questionList;
+ }
+
+ public String getTopicName() {
+ return topicName;
+ }
+
+ public void setTopicName(String topicName) {
+ if (topicName == null) {
+ return;
+ }
+ this.topicName = topicName;
+ }
+
+ public List getQuestionList() {
+ return questionList;
+ }
+
+ public void setQuestionList(List questionList) {
+ this.questionList = questionList;
+ }
+
+ @JsonIgnore
+ public ObjectId getId() {
+ return id;
+ }
+
+ @JsonIgnore
+ public void setId(ObjectId id) {
+ this.id = id;
+ }
+}
diff --git a/src/main/java/org/example/model/UserInfo.java b/src/main/java/org/example/model/UserInfo.java
deleted file mode 100644
index 85efcbf..0000000
--- a/src/main/java/org/example/model/UserInfo.java
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-package org.example.model;
-
-import com.pengrad.telegrambot.model.Message;
-
-public class UserInfo {
- private boolean choiceQuiz = false;
- private UserQuizSession userQuizSession = null;
- private String currentTopicName;
- private Message lastBotMessage = null;
-
- public String getCurrentTopicName() {
- return currentTopicName;
- }
-
- public void setCurrentTopicName(String currentTopicName) {
- this.currentTopicName = currentTopicName;
- }
-
- public boolean isTopicChosen() {
- return choiceQuiz;
- }
-
- public void setChoiceQuiz(boolean choiceQuiz) {
- this.choiceQuiz = choiceQuiz;
- }
-
- public UserQuizSession getUserQuizSession() {
- return userQuizSession;
- }
-
- public void setUserQuizSession(UserQuizSession userQuizSession) {
- this.userQuizSession = userQuizSession;
- }
-
- public Message getLastBotMessage() {
- return lastBotMessage;
- }
-
- public void setLastBotMessage(Message lastBotMessage) {
- this.lastBotMessage = lastBotMessage;
- }
-}
diff --git a/src/main/java/org/example/model/UserQuizSession.java b/src/main/java/org/example/model/UserQuizSession.java
index 0a0f710..cdf4cdc 100644
--- a/src/main/java/org/example/model/UserQuizSession.java
+++ b/src/main/java/org/example/model/UserQuizSession.java
@@ -1,57 +1,62 @@
package org.example.model;
-import java.util.Collection;
-import java.util.Iterator;
+import java.util.List;
+
public class UserQuizSession {
- private final int questionAmount;
- private final Iterator questionIterator;
- private Question currentQuestion;
+ private final List questions;
+ Question currentQuestion;
+ private int currentQuestionIndex = 0;
private int questionCounter = 0;
private int rightAnswerCounter = 0;
- private boolean quizMode = true;
- public UserQuizSession(Collection questions) {
- this.questionIterator = questions.iterator();
- this.questionAmount = questions.size();
-// this.currentQuestion = this.questionIterator.next();
+ public UserQuizSession(List questions) {
+ this.questions = questions;
}
- public boolean isQuizMode() {
- return quizMode;
+ public UserQuizSession(QuizQuestions quizQuestions) {
+
+ this.questions = quizQuestions.getQuestionList();
}
- public boolean isNextQuestionAvailable() {
- return questionIterator.hasNext();
+ public List getQuestions() {
+ return questions;
}
- public void addRightCounter() {
- rightAnswerCounter++;
+ public int getRightAnswerCounter() {
+ return rightAnswerCounter;
}
+ public int getQuestionCounter() {
+ return questionCounter;
+ }
- public void setQuizMode(boolean quizMode) {
- this.quizMode = quizMode;
+ public void incQuestionCounter() {
+ questionCounter++;
}
- public Question getCurrentQuestion() {
- return currentQuestion;
+ public int getCurrentQuestionIndex() {
+ return currentQuestionIndex;
}
- public Question getNextQuestion() {
- questionCounter++;
- return currentQuestion = questionIterator.next();
+ public void incCurrentQuestionIndex() {
+ currentQuestionIndex++;
}
- public int getQuestionCounter() {
- return questionCounter;
+ public void incRightCounter() {
+ rightAnswerCounter++;
}
public int getQuestionAmount() {
- return questionAmount;
+ return questions.size();
}
- public int getRightAnswerCounter() {
- return rightAnswerCounter;
+ public Question getCurrentQuestion() {
+ return currentQuestion;
+ }
+
+ public Question getNextQuestion() {
+ incQuestionCounter();
+ return currentQuestion = questions.get(currentQuestionIndex++);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/example/repositories/QuizRepo.java b/src/main/java/org/example/repositories/QuizRepo.java
new file mode 100644
index 0000000..07336eb
--- /dev/null
+++ b/src/main/java/org/example/repositories/QuizRepo.java
@@ -0,0 +1,27 @@
+package org.example.repositories;
+
+import org.example.model.Question;
+import org.example.model.QuizQuestions;
+import org.springframework.data.mongodb.repository.DeleteQuery;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
+import org.springframework.data.mongodb.repository.Update;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface QuizRepo extends MongoRepository {
+ @Query(value = "{}", fields = "{ 'topicName' : 1, '_id' : 0 }")
+ List findAllTopicName();
+
+ @Query("{'topicName' : ?0}")
+ QuizQuestions findByTopicName(String topicName);
+
+ @DeleteQuery("{'topicName' : ?0}")
+ void deleteByTopicName(String topicName);
+
+ @Query("{'topicName' : ?0}")
+ @Update("{$push : {'questionList' : {$each : ?1}}}")
+ void addByTopic(String topicName, List questionList);
+}
diff --git a/src/main/java/org/example/repositories/UserRepo.java b/src/main/java/org/example/repositories/UserRepo.java
new file mode 100644
index 0000000..0ced5ee
--- /dev/null
+++ b/src/main/java/org/example/repositories/UserRepo.java
@@ -0,0 +1,10 @@
+package org.example.repositories;
+
+import org.bson.types.ObjectId;
+import org.example.model.PermanentUserInfo;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserRepo extends MongoRepository {
+}
diff --git a/src/main/java/org/example/services/QuizService.java b/src/main/java/org/example/services/QuizService.java
new file mode 100644
index 0000000..4dbb92d
--- /dev/null
+++ b/src/main/java/org/example/services/QuizService.java
@@ -0,0 +1,51 @@
+package org.example.services;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.example.model.QuizQuestions;
+import org.example.repositories.QuizRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class QuizService {
+ private static List topics = new ArrayList<>();
+ private final QuizRepo quizRepo;
+
+ @Autowired
+ public QuizService(QuizRepo quizRepo) {
+ this.quizRepo = quizRepo;
+ topics = quizRepo.findAllTopicName();
+ }
+
+ public List getTopics() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ List topic = quizRepo.findAllTopicName();
+ if (topic == null) {
+ return List.of();
+ }
+ return topics = topic.stream().map(string -> {
+ try {
+ JsonNode jsonNode = objectMapper.readTree(string);
+ return jsonNode.get("topicName").asText();
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }).collect(Collectors.toList());
+ }
+
+ public void deleteAllQuiz() {
+ topics = new ArrayList<>();
+ quizRepo.deleteAll();
+ }
+
+ public QuizQuestions findByTopicName(String topicName) {
+ return quizRepo.findByTopicName(topicName);
+ }
+
+}
diff --git a/src/main/java/org/example/services/UsersService.java b/src/main/java/org/example/services/UsersService.java
new file mode 100644
index 0000000..5d3f4dd
--- /dev/null
+++ b/src/main/java/org/example/services/UsersService.java
@@ -0,0 +1,23 @@
+package org.example.services;
+
+import org.example.repositories.UserRepo;
+import org.example.model.PermanentUserInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UsersService {
+ private final UserRepo userRepo;
+
+ @Autowired
+ public UsersService(UserRepo userRepo) {
+ this.userRepo = userRepo;
+ }
+
+ public PermanentUserInfo addNewUser(String userName, Long userId) {
+ PermanentUserInfo permanentUserInfo = new PermanentUserInfo(userName, userId, false);
+ userRepo.insert(permanentUserInfo);
+ return permanentUserInfo;
+ }
+
+}
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
index 16afeeb..23c259b 100644
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -1,13 +1,22 @@
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
diff --git a/src/main/resources/quizes/CSS.json b/src/main/resources/quizes/CSS.json
deleted file mode 100644
index f5bbf7d..0000000
--- a/src/main/resources/quizes/CSS.json
+++ /dev/null
@@ -1,112 +0,0 @@
-[
- {
- "question": "How do you select an element with the id 'example' in CSS?",
- "options": [
- "#example",
- ".example",
- "element.example",
- "id.example"
- ],
- "answer": 0,
- "answerDescription": "In CSS, the '#' symbol is used to select an element with a specific id. Option 'a' is the correct answer."
- },
- {
- "question": "What property is used to change the text color of an element in CSS?",
- "options": [
- "text-color",
- "color",
- "font-color",
- "text-style"
- ],
- "answer": 1,
- "answerDescription": "The 'color' property is used to change the text color of an element in CSS. Option 'b' is the correct answer."
- },
- {
- "question": "Which CSS property is used to control the spacing between elements?",
- "options": [
- "margin",
- "padding",
- "spacing",
- "border-spacing"
- ],
- "answer": 0,
- "answerDescription": "The 'margin' property is used to control the spacing outside the border of an element in CSS. Option 'a' is the correct answer."
- },
- {
- "question": "How can you make a list item's marker appear outside its box in CSS?",
- "options": [
- "marker-position: outside;",
- "list-style-position: outside;",
- "marker-outside: true;",
- "list-marker-outside: true;"
- ],
- "answer": 1,
- "answerDescription": "The 'list-style-position: outside;' property is used to make a list item's marker appear outside its box in CSS. Option 'b' is the correct answer."
- },
- {
- "question": "Which property is used to set the background color of an element in CSS?",
- "options": [
- "background-color",
- "color",
- "bgcolor",
- "background"
- ],
- "answer": 0,
- "answerDescription": "The 'background-color' property is used to set the background color of an element in CSS. Option 'a' is the correct answer."
- },
- {
- "question": "In CSS, how do you make a text bold?",
- "options": [
- "text-style: bold;",
- "font-weight: bold;",
- "bold: true;",
- "text-bold: true;"
- ],
- "answer": 1,
- "answerDescription": "The 'font-weight: bold;' property is used to make text bold in CSS. Option 'b' is the correct answer."
- },
- {
- "question": "What does the 'box-sizing' property in CSS control?",
- "options": [
- "Element visibility",
- "Element positioning",
- "Element sizing",
- "Element rotation"
- ],
- "answer": 2,
- "answerDescription": "The 'box-sizing' property in CSS controls how the sizing of an element is calculated, including or excluding padding and borders. Option 'c' is the correct answer."
- },
- {
- "question": "Which CSS pseudo-class is used to select and style the last child element of a parent?",
- "options": [
- ":last",
- ":last-child",
- ":nth-child(last)",
- ":end-child"
- ],
- "answer": 1,
- "answerDescription": "The ':last-child' pseudo-class is used to select and style the last child element of a parent in CSS. Option 'b' is the correct answer."
- },
- {
- "question": "What is the purpose of the 'z-index' property in CSS?",
- "options": [
- "To control the transparency of an element",
- "To control the stacking order of elements",
- "To control the rotation of an element",
- "To control the zoom level of an element"
- ],
- "answer": 1,
- "answerDescription": "The 'z-index' property in CSS is used to control the stacking order of elements, determining which elements appear on top. Option 'b' is the correct answer."
- },
- {
- "question": "Which CSS property is used to create rounded corners for an element?",
- "options": [
- "border-radius",
- "corner-radius",
- "rounded-corners",
- "border-style"
- ],
- "answer": 0,
- "answerDescription": "The 'border-radius' property is used to create rounded corners for an element in CSS. Option 'a' is the correct answer."
- }
-]
diff --git a/src/main/resources/quizes/Java.json b/src/main/resources/quizes/Java.json
deleted file mode 100644
index 1ef4dc5..0000000
--- a/src/main/resources/quizes/Java.json
+++ /dev/null
@@ -1,112 +0,0 @@
-[
- {
- "question": "What is the correct way to declare a variable in Java?",
- "options": [
- "variable myVar = 10;",
- "let myVar = 10;",
- "int myVar = 10;",
- "var myVar = 10;"
- ],
- "answer": 2,
- "answerDescription": "In Java, the correct way to declare an integer variable is by using the 'int' keyword. Option 'c' is the correct answer."
- },
- {
- "question": "Which keyword is used to indicate that a method does not return any value in Java?",
- "options": [
- "void",
- "null",
- "none",
- "nil"
- ],
- "answer": 0,
- "answerDescription": "The 'void' keyword is used in Java to indicate that a method does not return any value. Option 'a' is the correct answer."
- },
- {
- "question": "How do you create a new instance of a class in Java?",
- "options": [
- "MyClass obj = create MyClass();",
- "MyClass obj = new MyClass();",
- "new MyClass() = obj;",
- "create MyClass obj;"
- ],
- "answer": 1,
- "answerDescription": "To create a new instance of a class in Java, you use the 'new' keyword followed by the class constructor. Option 'b' is the correct answer."
- },
- {
- "question": "Which access modifier is used for a variable that should be accessible only within its own class and not from outside the class in Java?",
- "options": [
- "private",
- "protected",
- "public",
- "default"
- ],
- "answer": 0,
- "answerDescription": "The 'private' access modifier is used for a variable that should be accessible only within its own class in Java. Option 'a' is the correct answer."
- },
- {
- "question": "What is the purpose of the 'super' keyword in Java?",
- "options": [
- "To call the superclass constructor",
- "To create a new instance of a class",
- "To access a static variable",
- "To define a constant"
- ],
- "answer": 0,
- "answerDescription": "The 'super' keyword in Java is used to call the superclass constructor. Option 'a' is the correct answer."
- },
- {
- "question": "Which loop is used for iterating over elements of an array or a collection in Java?",
- "options": [
- "for loop",
- "while loop",
- "do-while loop",
- "foreach loop"
- ],
- "answer": 3,
- "answerDescription": "The 'foreach' loop is used for iterating over elements of an array or a collection in Java. Option 'd' is the correct answer."
- },
- {
- "question": "What is the purpose of the 'break' statement in Java?",
- "options": [
- "To terminate the program",
- "To exit a loop or switch statement",
- "To skip the next iteration of a loop",
- "To jump to a specific label in the code"
- ],
- "answer": 1,
- "answerDescription": "The 'break' statement in Java is used to exit a loop or switch statement prematurely. Option 'b' is the correct answer."
- },
- {
- "question": "Which of the following is not a primitive data type in Java?",
- "options": [
- "int",
- "float",
- "char",
- "class"
- ],
- "answer": 3,
- "answerDescription": "In Java, 'class' is not a primitive data type. It is a reference data type. Option 'd' is the correct answer."
- },
- {
- "question": "What is the purpose of the 'this' keyword in Java?",
- "options": [
- "To refer to the current instance of the class",
- "To create a new instance of a class",
- "To access a static method",
- "To define a constant"
- ],
- "answer": 0,
- "answerDescription": "The 'this' keyword in Java is used to refer to the current instance of the class. Option 'a' is the correct answer."
- },
- {
- "question": "Which of the following exceptions is a checked exception in Java?",
- "options": [
- "NullPointerException",
- "ArrayIndexOutOfBoundsException",
- "ArithmeticException",
- "IOException"
- ],
- "answer": 3,
- "answerDescription": "IOException is a checked exception in Java. Option 'd' is the correct answer."
- }
-]
diff --git a/src/main/resources/quizes/JavaScript.json b/src/main/resources/quizes/JavaScript.json
deleted file mode 100644
index 11b2b31..0000000
--- a/src/main/resources/quizes/JavaScript.json
+++ /dev/null
@@ -1,112 +0,0 @@
-[
- {
- "question": "What is the correct way to write a JavaScript comment?",
- "options": [
- "",
- "/* This is a comment */",
- "// This is a comment",
- "-- This is a comment"
- ],
- "answer": 2,
- "answerDescription": "The correct way to write a JavaScript comment is by using '//' at the beginning of the line. Option 'c' is the correct answer."
- },
- {
- "question": "Which method is used to add an element to the end of an array in JavaScript?",
- "options": [
- "push()",
- "add()",
- "append()",
- "insert()"
- ],
- "answer": 0,
- "answerDescription": "The 'push()' method is used to add an element to the end of an array in JavaScript. Option 'a' is the correct answer."
- },
- {
- "question": "What is the correct syntax to declare a variable in JavaScript?",
- "options": [
- "var myVariable = 10;",
- "variable myVariable = 10;",
- "let myVariable = 10;",
- "const myVariable = 10;"
- ],
- "answer": 0,
- "answerDescription": "The correct syntax to declare a variable in JavaScript is by using the 'var' keyword followed by the variable name and an optional initial value. Option 'a' is the correct answer."
- },
- {
- "question": "How do you convert a string to a number in JavaScript?",
- "options": [
- "parseInt()",
- "parseFloat()",
- "toNumber()",
- "convertToNumber()"
- ],
- "answer": 0,
- "answerDescription": "The 'parseInt()' function is used to convert a string to an integer in JavaScript. Option 'a' is the correct answer."
- },
- {
- "question": "What is the output of the following code snippet?\n\nconsole.log(2 + \"2\");",
- "options": [
- "4",
- "22",
- "\"22\"",
- "NaN"
- ],
- "answer": 2,
- "answerDescription": "When JavaScript encounters the '+' operator with a string involved, it performs string concatenation. In this case, '2 + \"2\"' results in the string '22'. Option 'c' is the correct answer."
- },
- {
- "question": "Which event is triggered when a user clicks on an HTML element?",
- "options": [
- "onhover",
- "onmouseclick",
- "onclick",
- "onselect"
- ],
- "answer": 2,
- "answerDescription": "The 'onclick' event is triggered when a user clicks on an HTML element. Option 'c' is the correct answer."
- },
- {
- "question": "What does the \"DOM\" stand for in JavaScript?",
- "options": [
- "Document Object Model",
- "Dynamic Object Model",
- "Data Object Model",
- "Document Order Model"
- ],
- "answer": 0,
- "answerDescription": "The acronym 'DOM' stands for 'Document Object Model', which represents the structured representation of HTML elements that JavaScript can interact with. Option 'a' is the correct answer."
- },
- {
- "question": "Which method is used to remove the last element from an array in JavaScript?",
- "options": [
- "remove()",
- "pop()",
- "delete()",
- "shift()"
- ],
- "answer": 1,
- "answerDescription": "The 'pop()' method is used to remove the last element from an array in JavaScript. Option 'b' is the correct answer."
- },
- {
- "question": "How do you check if a variable is an array in JavaScript?",
- "options": [
- "isArray()",
- "isArrayOf()",
- "typeofArray()",
- "checkArray()"
- ],
- "answer": 0,
- "answerDescription": "To check if a variable is an array in JavaScript, you can use the 'isArray()' method. Option 'a' is the correct answer."
- },
- {
- "question": "What is the purpose of the \"typeof\" operator in JavaScript?",
- "options": [
- "It returns the type of a variable.",
- "It checks if a variable is defined.",
- "It converts a value to a string.",
- "It performs a type conversion."
- ],
- "answer": 0,
- "answerDescription": "The 'typeof' operator is used to determine the type of a variable in JavaScript. Option 'a' is the correct answer."
- }
-]
\ No newline at end of file
diff --git a/src/main/resources/quizes/Python.json b/src/main/resources/quizes/Python.json
deleted file mode 100644
index 2a6767d..0000000
--- a/src/main/resources/quizes/Python.json
+++ /dev/null
@@ -1,57 +0,0 @@
-[
- {
- "question": "Which of the following is the correct way to comment out multiple lines in Python?",
- "options": [
- "/* This is a comment */",
- "# This is a comment",
- "// This is a comment",
- "''' This is a comment '''"
- ],
- "answer": 3,
- "answerDescription": "The correct way to comment out multiple lines in Python is by using triple-quotes (''' or \"\"\"). Option 'd' is the correct answer."
- },
- {
- "question": "How do you check the length of a list in Python?",
- "options": [
- "len(list)",
- "list.size()",
- "list.length()",
- "list.count()"
- ],
- "answer": 0,
- "answerDescription": "To check the length of a list in Python, you use the 'len()' function. Option 'a' is the correct answer."
- },
- {
- "question": "What is the output of the following code snippet?\n\n```\nprint(\"Hello\" + 2)\n```",
- "options": [
- "Hello2",
- "Hello",
- "TypeError",
- "Hello 2"
- ],
- "answer": 2,
- "answerDescription": "The code snippet will result in a TypeError since you cannot concatenate a string with an integer directly in Python."
- },
- {
- "question": "What is the purpose of the 'elif' keyword in Python?",
- "options": [
- "It represents the end of a block of code",
- "It is short for 'else if' and is used to check multiple conditions",
- "It is a built-in function for mathematical calculations",
- "It is used to define a class"
- ],
- "answer": 1,
- "answerDescription": "The 'elif' keyword in Python is short for 'else if' and is used to check multiple conditions after an 'if' statement. Option 'b' is the correct answer."
- },
- {
- "question": "Which of the following is the correct way to open and read a file in Python?",
- "options": [
- "file = open('example.txt', 'r')\ndata = file.read()",
- "file = open('example.txt', 'w')\ndata = file.read()",
- "file = read('example.txt')",
- "file.read('example.txt')"
- ],
- "answer": 0,
- "answerDescription": "The correct way to open and read a file in Python is by using the 'open()' function with the 'r' mode to indicate reading. Option 'a' is the correct answer."
- }
-]
diff --git a/src/main/resources/quizes/SQL.json b/src/main/resources/quizes/SQL.json
deleted file mode 100644
index 7c7cfa9..0000000
--- a/src/main/resources/quizes/SQL.json
+++ /dev/null
@@ -1,167 +0,0 @@
-[
- {
- "question": "What does SQL stand for?",
- "options": [
- "Structured Language",
- "Simple Language",
- "Sequential Language",
- "Structured Query Language"
- ],
- "answer": 3,
- "answerDescription": "SQL stands for Structured Query Language. Option 'd' is the correct answer."
- },
- {
- "question": "Which SQL statement is used to retrieve data from a database?",
- "options": [
- "GET",
- "FETCH",
- "SELECT",
- "RETRIEVE"
- ],
- "answer": 2,
- "answerDescription": "The 'SELECT' statement is used to retrieve data from a database in SQL. Option 'c' is the correct answer."
- },
- {
- "question": "In SQL, what is the purpose of the WHERE clause?",
- "options": [
- "To filter the result set based on conditions",
- "To order the result set",
- "To perform aggregate functions",
- "To join tables"
- ],
- "answer": 0,
- "answerDescription": "The WHERE clause in SQL is used to filter the result set based on specified conditions. Option 'a' is the correct answer."
- },
- {
- "question": "Which SQL command is used to update data in a database?",
- "options": [
- "CHANGE",
- "MODIFY",
- "UPDATE",
- "ALTER"
- ],
- "answer": 2,
- "answerDescription": "The 'UPDATE' command is used to modify data in a database in SQL. Option 'c' is the correct answer."
- },
- {
- "question": "What is the purpose of the SQL ORDER BY clause?",
- "options": [
- "To filter the result set",
- "To group rows based on a condition",
- "To sort the result set",
- "To join tables"
- ],
- "answer": 2,
- "answerDescription": "The ORDER BY clause in SQL is used to sort the result set in ascending or descending order. Option 'c' is the correct answer."
- },
- {
- "question": "Which SQL command is used to delete data from a database?",
- "options": [
- "REMOVE",
- "DELETE",
- "DROP",
- "ERASE"
- ],
- "answer": 1,
- "answerDescription": "The 'DELETE' command is used to remove data from a database in SQL. Option 'b' is the correct answer."
- },
- {
- "question": "In SQL, what is the purpose of the GROUP BY clause?",
- "options": [
- "To filter the result set",
- "To sort the result set",
- "To perform aggregate functions on grouped data",
- "To join tables"
- ],
- "answer": 2,
- "answerDescription": "The GROUP BY clause in SQL is used to group rows based on specified columns and perform aggregate functions on the grouped data. Option 'c' is the correct answer."
- },
- {
- "question": "What is the primary key in a database?",
- "options": [
- "A key used for encryption",
- "A unique identifier for a record in a table",
- "A foreign key in another table",
- "A key used for sorting"
- ],
- "answer": 1,
- "answerDescription": "The primary key in a database is a unique identifier for a record in a table. Option 'b' is the correct answer."
- },
- {
- "question": "Which SQL command is used to add a new column to a table?",
- "options": [
- "ALTER TABLE",
- "ADD COLUMN",
- "INSERT COLUMN",
- "MODIFY TABLE"
- ],
- "answer": 0,
- "answerDescription": "The 'ALTER TABLE' command is used to modify the structure of a table in SQL, including adding a new column. Option 'a' is the correct answer."
- },
- {
- "question": "What is the purpose of the SQL JOIN operation?",
- "options": [
- "To filter the result set",
- "To group rows",
- "To combine rows from two or more tables based on a related column",
- "To sort the result set"
- ],
- "answer": 2,
- "answerDescription": "The SQL JOIN operation is used to combine rows from two or more tables based on a related column. Option 'c' is the correct answer."
- },
- {
- "question": "What SQL statement is used to count the number of rows in a table?",
- "options": [
- "COUNT",
- "SUM",
- "TOTAL",
- "NUMROWS"
- ],
- "answer": 0,
- "answerDescription": "The 'COUNT' statement is used to count the number of rows in a table in SQL. Option 'a' is the correct answer."
- },
- {
- "question": "Which SQL function is used to find the highest value in a column?",
- "options": [
- "MAX()",
- "TOP()",
- "HIGH()",
- "PEAK()"
- ],
- "answer": 0,
- "answerDescription": "The 'MAX()' function is used to find the highest value in a column in SQL. Option 'a' is the correct answer."
- },
- {
- "question": "What is the purpose of the SQL HAVING clause?",
- "options": [
- "To filter the result set",
- "To sort the result set",
- "To filter results based on aggregate conditions",
- "To group rows"
- ],
- "answer": 2,
- "answerDescription": "The HAVING clause in SQL is used to filter results based on aggregate conditions, especially when used with the GROUP BY clause. Option 'c' is the correct answer."
- },
- {
- "question": "Which SQL data type is used to store date and time values?",
- "options": [
- "DATE",
- "TIME",
- "DATETIME",
- "TIMESTAMP"
- ],
- "answer": 3,
- "answerDescription": "The 'TIMESTAMP' data type is used to store date and time values in SQL. Option 'd' is the correct answer."
- },
- {
- "question": "In SQL, what is the purpose of the DISTINCT keyword?",
- "options": [
- "To limit the number of rows returned",
- "To select unique values from a column",
- "To sort the result set",
- "To group rows"
- ],
- "answer": 1,
- "answerDescription": "The DISTINCT keyword in SQL is used to select unique values from a column. Option 'b' is the correct answer."
- }
-]
diff --git a/src/main/resources/quizes/Spring.json b/src/main/resources/quizes/Spring.json
deleted file mode 100644
index 6b53b07..0000000
--- a/src/main/resources/quizes/Spring.json
+++ /dev/null
@@ -1,112 +0,0 @@
-[
- {
- "question": "What is the primary goal of the Spring Framework?",
- "options": [
- "To provide a comprehensive platform for enterprise Java development",
- "To replace the Java programming language",
- "To focus on web development only",
- "To provide a lightweight alternative to Java"
- ],
- "answer": 0,
- "answerDescription": "The primary goal of the Spring Framework is to provide a comprehensive platform for enterprise Java development. Option 'a' is the correct answer."
- },
- {
- "question": "What is inversion of control (IoC) in the context of the Spring Framework?",
- "options": [
- "It refers to a design pattern in Java",
- "It means giving control of object creation and management to the Spring container",
- "It is a type of dependency injection",
- "It is a feature of the Java programming language"
- ],
- "answer": 1,
- "answerDescription": "In the Spring Framework, inversion of control (IoC) means giving control of object creation and management to the Spring container. Option 'b' is the correct answer."
- },
- {
- "question": "What is the role of the BeanFactory in Spring?",
- "options": [
- "To manage database connections",
- "To manage Spring beans and their dependencies",
- "To handle HTTP requests",
- "To create user interfaces"
- ],
- "answer": 1,
- "answerDescription": "The role of the BeanFactory in Spring is to manage Spring beans and their dependencies. Option 'b' is the correct answer."
- },
- {
- "question": "What is Spring MVC used for?",
- "options": [
- "Database access",
- "Aspect-oriented programming",
- "Web application development",
- "Object-relational mapping"
- ],
- "answer": 2,
- "answerDescription": "Spring MVC is used for web application development in the Spring Framework. Option 'c' is the correct answer."
- },
- {
- "question": "What is the purpose of the @Autowired annotation in Spring?",
- "options": [
- "To declare a bean in the Spring configuration file",
- "To inject dependencies automatically",
- "To define a controller in Spring MVC",
- "To handle HTTP requests"
- ],
- "answer": 1,
- "answerDescription": "The @Autowired annotation in Spring is used to inject dependencies automatically. Option 'b' is the correct answer."
- },
- {
- "question": "What is AOP in the context of the Spring Framework?",
- "options": [
- "An Object-Oriented Programming language",
- "Aspect-Oriented Programming",
- "Advanced Object Processing",
- "Application Object Protocol"
- ],
- "answer": 1,
- "answerDescription": "AOP stands for Aspect-Oriented Programming in the context of the Spring Framework. Option 'b' is the correct answer."
- },
- {
- "question": "What is the purpose of the Spring Boot framework?",
- "options": [
- "To provide a lightweight alternative to the Spring Framework",
- "To focus on web development only",
- "To simplify the development of production-ready applications",
- "To replace the Java programming language"
- ],
- "answer": 2,
- "answerDescription": "The purpose of the Spring Boot framework is to simplify the development of production-ready applications by providing a set of conventions and defaults. Option 'c' is the correct answer."
- },
- {
- "question": "What is the role of the DispatcherServlet in Spring MVC?",
- "options": [
- "To handle database queries",
- "To manage Spring beans",
- "To handle HTTP requests and responses",
- "To create user interfaces"
- ],
- "answer": 2,
- "answerDescription": "The role of the DispatcherServlet in Spring MVC is to handle HTTP requests and responses for a Spring web application. Option 'c' is the correct answer."
- },
- {
- "question": "What is the purpose of the @Transactional annotation in Spring?",
- "options": [
- "To define a transactional aspect",
- "To handle HTTP requests",
- "To create a new thread",
- "To manage Spring beans"
- ],
- "answer": 0,
- "answerDescription": "The @Transactional annotation in Spring is used to define a transactional aspect, indicating that a method should be wrapped in a transaction. Option 'a' is the correct answer."
- },
- {
- "question": "What is Spring Data JPA used for?",
- "options": [
- "Aspect-oriented programming",
- "Object-relational mapping",
- "Database access",
- "Web application development"
- ],
- "answer": 1,
- "answerDescription": "Spring Data JPA is used for object-relational mapping (ORM) in the Spring Framework. Option 'b' is the correct answer."
- }
-]
diff --git a/src/main/resources/quizes/Telegram bot api.json b/src/main/resources/quizes/Telegram bot api.json
deleted file mode 100644
index 1ceb930..0000000
--- a/src/main/resources/quizes/Telegram bot api.json
+++ /dev/null
@@ -1,57 +0,0 @@
-[
- {
- "question": "What is the primary programming language used to interact with the Telegram Bot API?",
- "options": [
- "Python",
- "JavaScript",
- "Java",
- "C#"
- ],
- "answer": 0,
- "answerDescription": "Python is commonly used to interact with the Telegram Bot API, thanks to libraries such as python-telegram-bot. Option 'a' is the correct answer."
- },
- {
- "question": "Which type of messages can a Telegram bot receive?",
- "options": [
- "Text messages only",
- "Text and multimedia messages",
- "Multimedia messages only",
- "Binary messages"
- ],
- "answer": 1,
- "answerDescription": "Telegram bots can receive both text and multimedia messages, including images, audio, video, and documents. Option 'b' is the correct answer."
- },
- {
- "question": "What is a webhook in the context of the Telegram Bot API?",
- "options": [
- "A method for sending messages to users",
- "A mechanism for handling user authentication",
- "A way for a bot to receive updates by providing a URL endpoint",
- "A special type of chat in Telegram"
- ],
- "answer": 2,
- "answerDescription": "In the Telegram Bot API, a webhook is a way for a bot to receive updates by providing a URL endpoint that Telegram will send new messages and other events to. Option 'c' is the correct answer."
- },
- {
- "question": "What is the purpose of the 'sendMessage' method in the Telegram Bot API?",
- "options": [
- "To receive messages from users",
- "To send messages to users",
- "To update a bot's profile information",
- "To delete messages"
- ],
- "answer": 1,
- "answerDescription": "The 'sendMessage' method in the Telegram Bot API is used to send messages from a bot to users. Option 'b' is the correct answer."
- },
- {
- "question": "What is the Bot API token, and why is it important?",
- "options": [
- "It is a unique identifier for a user in Telegram",
- "It is a unique identifier for a Telegram bot",
- "It is used for encrypting messages sent by a bot",
- "It is required for accessing the Telegram API documentation"
- ],
- "answer": 1,
- "answerDescription": "The Bot API token is a unique identifier for a Telegram bot, and it is crucial for authenticating and authorizing the bot to interact with the Telegram API. Option 'b' is the correct answer."
- }
-]
diff --git a/src/main/resources/topics b/src/main/resources/topics
new file mode 100644
index 0000000..72581d0
--- /dev/null
+++ b/src/main/resources/topics
@@ -0,0 +1,4 @@
+Python Programming
+Spring Framework
+Java Programming
+CSS (Cascading Style Sheets)
diff --git a/src/test/java/org/example/QuizQuestionsBotListenerTest.java b/src/test/java/org/example/QuizQuestionsBotListenerTest.java
new file mode 100644
index 0000000..29d8443
--- /dev/null
+++ b/src/test/java/org/example/QuizQuestionsBotListenerTest.java
@@ -0,0 +1,18 @@
+package org.example;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class QuizQuestionsBotListenerTest {
+ private QuizBotListener quizBotListener;
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @Test
+ void process() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/example/model/QuestionOptionTest.java b/src/test/java/org/example/model/QuestionOptionTest.java
new file mode 100644
index 0000000..30890be
--- /dev/null
+++ b/src/test/java/org/example/model/QuestionOptionTest.java
@@ -0,0 +1,12 @@
+package org.example.model;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class QuestionOptionTest {
+
+ @Test
+ void getOptionText() {
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/example/model/QuestionTest.java b/src/test/java/org/example/model/QuestionTest.java
new file mode 100644
index 0000000..4b5c04c
--- /dev/null
+++ b/src/test/java/org/example/model/QuestionTest.java
@@ -0,0 +1,29 @@
+package org.example.model;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class QuestionTest {
+ private Question question;
+
+ @BeforeEach
+ void setUp() {
+ question = new Question();
+ }
+
+ @Test
+ void getQuestion() {
+ Assertions.assertNotNull(question.getQuestion());
+ }
+
+ @Test
+ void getAnswerDescription() {
+ Assertions.assertNotNull(question.getAnswerDescription());
+ }
+
+ @Test
+ void getOptionList() {
+ Assertions.assertNotNull(question.getOptionList());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/example/model/QuizQuestionsSessionTest.java b/src/test/java/org/example/model/QuizQuestionsSessionTest.java
new file mode 100644
index 0000000..71aae85
--- /dev/null
+++ b/src/test/java/org/example/model/QuizQuestionsSessionTest.java
@@ -0,0 +1,13 @@
+package org.example.model;
+
+import org.junit.jupiter.api.BeforeEach;
+
+class QuizQuestionsSessionTest {
+ private QuizBotSession quizBotSession;
+
+ @BeforeEach
+ void setUp() {
+ quizBotSession = new QuizBotSession();
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/example/model/QuizQuestionsTest.java b/src/test/java/org/example/model/QuizQuestionsTest.java
new file mode 100644
index 0000000..e1cc12b
--- /dev/null
+++ b/src/test/java/org/example/model/QuizQuestionsTest.java
@@ -0,0 +1,44 @@
+package org.example.model;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class QuizQuestionsTest {
+ private QuizQuestions quizQuestions;
+
+ @BeforeEach
+ void setUp() {
+ quizQuestions = new QuizQuestions();
+ }
+
+ @Test
+ void getTopicName() {
+ assertNotNull(quizQuestions.getTopicName());
+ }
+
+ @Test
+ void setTopicName() {
+ quizQuestions.setTopicName(null);
+ Assertions.assertNotNull(quizQuestions.getTopicName());
+ quizQuestions.setTopicName("java");
+ Assertions.assertEquals(quizQuestions.getTopicName(),"java");
+ }
+
+ @Test
+ void getQuestionList() {
+ assertNotNull(quizQuestions.getQuestionList());
+ }
+
+ @Test
+ void setQuestionList() {
+ List questionList = new ArrayList<>();
+ quizQuestions.setQuestionList(questionList);
+ Assertions.assertEquals(quizQuestions.getQuestionList(),questionList);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/example/model/UserQuizQuestionsSessionTest.java b/src/test/java/org/example/model/UserQuizQuestionsSessionTest.java
new file mode 100644
index 0000000..08f0e89
--- /dev/null
+++ b/src/test/java/org/example/model/UserQuizQuestionsSessionTest.java
@@ -0,0 +1,88 @@
+package org.example.model;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class UserQuizQuestionsSessionTest {
+ private UserQuizSession userQuizSession;
+ private Question question1;
+ private Question question2;
+
+ @BeforeEach
+ public void setUp() {
+ List questionList = new ArrayList<>();
+ question1 = new Question("asddsasda",new ArrayList<>(),"asdsdasd");
+ question2 = new Question("asddsasdsssa",new ArrayList<>(),"asdsdasd");
+ questionList.add(question1);
+ questionList.add(question2);
+ QuizQuestions quizQuestions = new QuizQuestions();
+ quizQuestions.setQuestionList(questionList);
+ userQuizSession = new UserQuizSession(quizQuestions);
+ }
+
+ @Test
+ void isNextQuestionAvailable(){
+ Assertions.assertTrue(userQuizSession.isNextQuestionAvailable());
+ }
+
+ @Test
+ void isNextQuestionNotAvailable() {
+ userQuizSession = new UserQuizSession(new QuizQuestions());
+ Assertions.assertFalse(userQuizSession.isNextQuestionAvailable());
+ }
+
+ @Test
+ void incRightCounter() {
+ Assertions.assertEquals(userQuizSession.getRightAnswerCounter(),0);
+ userQuizSession.incRightCounter();
+ Assertions.assertEquals(userQuizSession.getRightAnswerCounter(),1);
+ }
+
+ @Test
+ void getCurrentQuestion() {
+ Assertions.assertNull(userQuizSession.getCurrentQuestionIndex());
+ userQuizSession.getNextQuestion();
+ Assertions.assertEquals(userQuizSession.getCurrentQuestionIndex(), question1);
+ userQuizSession.getNextQuestion();
+ Assertions.assertEquals(userQuizSession.getCurrentQuestionIndex(), question2);
+ userQuizSession.getNextQuestion();
+ Assertions.assertEquals(userQuizSession.getCurrentQuestionIndex(), question2);
+ }
+
+ @Test
+ void getNextQuestion() {
+ Assertions.assertEquals(userQuizSession.getNextQuestion(), question1);
+ Assertions.assertEquals(userQuizSession.getNextQuestion(), question2);
+ }
+
+ @Test
+ void getQuestionCounter() {
+ Assertions.assertEquals(userQuizSession.getQuestionCounter(),0);
+ userQuizSession.getNextQuestion();
+ Assertions.assertEquals(userQuizSession.getQuestionCounter(),1);
+ userQuizSession.getNextQuestion();
+ Assertions.assertEquals(userQuizSession.getQuestionCounter(),2);
+ userQuizSession.getNextQuestion();
+ Assertions.assertEquals(userQuizSession.getQuestionCounter(),2);
+ }
+
+ @Test
+ void getQuestionAmount() {
+ Assertions.assertEquals(userQuizSession.getQuestionAmount(),2);
+ }
+
+ @Test
+ void getRightAnswerCounter() {
+ Assertions.assertEquals(userQuizSession.getRightAnswerCounter(),0);
+ userQuizSession.incRightCounter();
+ Assertions.assertEquals(userQuizSession.getRightAnswerCounter(),1);
+ userQuizSession.incRightCounter();
+ Assertions.assertEquals(userQuizSession.getRightAnswerCounter(),2);
+ userQuizSession.incRightCounter();
+ Assertions.assertEquals(userQuizSession.getRightAnswerCounter(),2);
+ }
+}
\ No newline at end of file