2024-02-11 20:00:56 +00:00
|
|
|
|
import singlog;
|
|
|
|
|
|
|
|
|
|
import core.stdc.stdlib : exit, EXIT_SUCCESS, EXIT_FAILURE;
|
2024-02-17 18:47:20 +00:00
|
|
|
|
import std.stdio, std.conv, std.path, std.file, std.format, std.regex, std.array, std.algorithm, std.uuid;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
|
|
|
|
|
import source.database;
|
2024-02-13 00:44:54 +00:00
|
|
|
|
import source.sql;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
GROUP_THEME = 2,
|
|
|
|
|
GROUP_THEME_TEXT = 5,
|
|
|
|
|
GROUP_QUESTION = 7,
|
|
|
|
|
GROUP_QUESTION_TEXT = 10,
|
|
|
|
|
GROUP_ANSWER = 12,
|
|
|
|
|
GROUP_ANSWER_TEXT = 15,
|
|
|
|
|
GROUP_ANSWER_RIGHT = 17,
|
|
|
|
|
GROUP_ANSWER_RIGHT_TEXT = 20,
|
2024-02-17 18:47:20 +00:00
|
|
|
|
GROUP_IMAGE = 22,
|
|
|
|
|
GROUP_IMAGE_NAME = 25,
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(string[] args)
|
|
|
|
|
{
|
|
|
|
|
log.level(log.level.debugging)
|
|
|
|
|
.output(log.output.stdout.stderr)
|
|
|
|
|
.color(true);
|
|
|
|
|
|
2024-02-17 18:47:20 +00:00
|
|
|
|
const string pictures = "./images";
|
|
|
|
|
|
2024-02-11 20:00:56 +00:00
|
|
|
|
string testFilePath;
|
|
|
|
|
string databaseFile;
|
|
|
|
|
|
|
|
|
|
if (args.length != 3) {
|
|
|
|
|
log.e("Не было передано необходимое количество параметров для запуска программы");
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
databaseFile = args[1];
|
|
|
|
|
testFilePath = args[2];
|
|
|
|
|
|
|
|
|
|
const string pattern = "^((( |\\t)*\\#( |\\t)*)(.*[^\\s]))|((( |\\t)*\\?( |\\t)*)(.*[^\\s]))"
|
2024-02-17 18:47:20 +00:00
|
|
|
|
~ "|((( |\\t)*-( |\\t)*)(.*[^\\s]))|((( |\\t)*\\+( |\\t)*)(.*[^\\s]))|((( |\\t)*\\*( |\\t)*)(.*[^\\s]))$";
|
2024-02-11 20:00:56 +00:00
|
|
|
|
|
|
|
|
|
File testFile;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
testFile = File(testFilePath, "r");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.w("Unable to open the test file " ~ testFilePath);
|
|
|
|
|
log.e(e);
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dbliteConnect(databaseFile);
|
|
|
|
|
|
|
|
|
|
auto regular = regex(pattern, "m");
|
|
|
|
|
|
|
|
|
|
struct Answer {
|
2024-02-13 00:44:54 +00:00
|
|
|
|
int number;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
string text;
|
2024-02-13 00:44:54 +00:00
|
|
|
|
bool truth;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
|
2024-02-13 00:44:54 +00:00
|
|
|
|
bool addToDB(int question_id) {
|
|
|
|
|
int id = sqlAddNewAnswer(question_id, this.number, this.text, this.truth);
|
|
|
|
|
|
|
|
|
|
if (!id)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Question {
|
2024-02-13 00:44:54 +00:00
|
|
|
|
int number;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
string text;
|
|
|
|
|
Answer[int] answers;
|
2024-02-17 18:47:20 +00:00
|
|
|
|
bool hasPicture;
|
|
|
|
|
ubyte[] picture;
|
|
|
|
|
string pictureName;
|
|
|
|
|
int pictureSize;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
|
2024-02-13 00:44:54 +00:00
|
|
|
|
ulong count() {
|
2024-02-11 20:00:56 +00:00
|
|
|
|
return answers.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isValid() {
|
2024-02-17 18:47:20 +00:00
|
|
|
|
bool error = false;
|
|
|
|
|
|
|
|
|
|
if (answers.length <= 1)
|
|
|
|
|
error = true;
|
|
|
|
|
|
|
|
|
|
if (hasPicture && pictureSize > 256)
|
|
|
|
|
error = true;
|
|
|
|
|
|
|
|
|
|
return !error;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
2024-02-13 00:44:54 +00:00
|
|
|
|
|
|
|
|
|
bool addToDB(int topic_id) {
|
2024-02-17 18:47:20 +00:00
|
|
|
|
int id = sqlAddNewQuestion(
|
|
|
|
|
topic_id,
|
|
|
|
|
this.number,
|
|
|
|
|
this.text,
|
|
|
|
|
this.hasPicture,
|
|
|
|
|
this.picture,
|
|
|
|
|
this.pictureName);
|
2024-02-13 00:44:54 +00:00
|
|
|
|
|
|
|
|
|
if (!id)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
foreach (answer; answers.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
|
|
|
|
|
if (!answer.value.addToDB(id))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Theme {
|
|
|
|
|
string text;
|
|
|
|
|
Question[int] questions;
|
|
|
|
|
|
2024-02-13 00:44:54 +00:00
|
|
|
|
ulong count() {
|
2024-02-11 20:00:56 +00:00
|
|
|
|
return questions.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isValid() {
|
|
|
|
|
return questions.length > 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool addToDB() {
|
2024-02-13 00:44:54 +00:00
|
|
|
|
if (!check())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
int id = sqlAddNewTheme(this.text);
|
|
|
|
|
|
|
|
|
|
if (!id)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
|
|
|
|
|
if (!question.value.addToDB(id))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void print() {
|
2024-02-13 00:44:54 +00:00
|
|
|
|
writeln("Количество вопросов: %s".format(this.count()));
|
2024-02-11 20:00:56 +00:00
|
|
|
|
|
|
|
|
|
foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
|
|
|
|
|
writeln("\tВопрос №%d: %s".format(question.key, question.value.text));
|
2024-02-17 18:47:20 +00:00
|
|
|
|
if (question.value.hasPicture)
|
|
|
|
|
writeln("\tСодержит изображение: %s (%d kB)"
|
|
|
|
|
.format(question.value.pictureName, question.value.pictureSize));
|
2024-02-13 00:44:54 +00:00
|
|
|
|
writeln("\tКоличество ответов: %d".format(question.value.count()));
|
|
|
|
|
foreach (answer; question.value.answers.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
|
|
|
|
|
writeln("\t\tОтвет №%d: %s".format(answer.key, answer.value.text));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool check() {
|
|
|
|
|
bool error = false;
|
|
|
|
|
|
|
|
|
|
if (!this.isValid()) {
|
|
|
|
|
writeln("Недостаточное количество вопросов: %d".format(this.count()));
|
|
|
|
|
error = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!error) {
|
|
|
|
|
foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
|
|
|
|
|
if (!question.value.isValid()) {
|
2024-02-17 18:47:20 +00:00
|
|
|
|
writeln("Вопрос №%d \"%s\" содержит недостаточное количество ответов (%d) или большой (> 256 kB) размер изображения (%d kB)"
|
|
|
|
|
.format(question.key, question.value.text, question.value.count(), question.value.pictureSize));
|
2024-02-13 00:44:54 +00:00
|
|
|
|
error = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int truth;
|
|
|
|
|
|
|
|
|
|
foreach (answer; question.value.answers) {
|
|
|
|
|
if (answer.truth)
|
|
|
|
|
++truth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (truth > 1) {
|
|
|
|
|
writeln("Вопрос №%d \"%s\" содержит более одного правильного ответа".format(
|
|
|
|
|
question.key, question.value.text
|
|
|
|
|
));
|
|
|
|
|
error = true;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
2024-02-13 00:44:54 +00:00
|
|
|
|
}
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
2024-02-13 00:44:54 +00:00
|
|
|
|
return !error;
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Theme theme;
|
|
|
|
|
|
|
|
|
|
int numQuestion;
|
|
|
|
|
int numAnswer;
|
|
|
|
|
|
|
|
|
|
while (!testFile.eof())
|
|
|
|
|
{
|
|
|
|
|
string line = testFile.readln();
|
|
|
|
|
auto match = matchFirst(line, regular);
|
|
|
|
|
|
|
|
|
|
if (match.length == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (match[GROUP_THEME].length)
|
|
|
|
|
{
|
|
|
|
|
theme.text = match[GROUP_THEME_TEXT];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (match[GROUP_QUESTION].length)
|
|
|
|
|
{
|
|
|
|
|
numAnswer = 0;
|
2024-02-13 00:44:54 +00:00
|
|
|
|
theme.questions[++numQuestion] = Question(numQuestion, match[GROUP_QUESTION_TEXT]);
|
2024-02-11 20:00:56 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (match[GROUP_ANSWER].length)
|
|
|
|
|
{
|
2024-02-13 00:44:54 +00:00
|
|
|
|
theme.questions[numQuestion].answers[++numAnswer] = Answer(numAnswer, match[GROUP_ANSWER_TEXT], false);
|
2024-02-11 20:00:56 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (match[GROUP_ANSWER_RIGHT].length)
|
|
|
|
|
{
|
2024-02-13 00:44:54 +00:00
|
|
|
|
theme.questions[numQuestion].answers[++numAnswer] = Answer(numAnswer, match[GROUP_ANSWER_RIGHT_TEXT], true);
|
2024-02-11 20:00:56 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-02-17 18:47:20 +00:00
|
|
|
|
|
|
|
|
|
if (match[GROUP_IMAGE].length)
|
|
|
|
|
{
|
|
|
|
|
string currentPicture = buildPath(pictures, match[GROUP_IMAGE_NAME]);
|
|
|
|
|
if (currentPicture.exists) {
|
|
|
|
|
auto picFile = File(currentPicture, "r");
|
|
|
|
|
theme.questions[numQuestion].hasPicture = true;
|
|
|
|
|
theme.questions[numQuestion].picture = cast(ubyte[])read(currentPicture);
|
|
|
|
|
theme.questions[numQuestion].pictureName =
|
|
|
|
|
md5UUID(theme.questions[numQuestion].picture).to!string ~ currentPicture.extension;
|
|
|
|
|
theme.questions[numQuestion].pictureSize = picFile.size().to!int / 1024;
|
|
|
|
|
} else {
|
|
|
|
|
log.e("Файл \"%s\" не найден".format(currentPicture));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-02-11 20:00:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-13 00:44:54 +00:00
|
|
|
|
// theme.print();
|
|
|
|
|
// theme.check();
|
|
|
|
|
theme.addToDB();
|
2024-02-11 20:00:56 +00:00
|
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|