diff --git a/README.md b/README.md
index 323ec35..ed6b399 100755
--- a/README.md
+++ b/README.md
@@ -1,2 +1,44 @@
# parser_from_interneturok
+Chat-robot Telegram for parsing homeworks by subject name, grade and number of the week
+## Dependencies
+1. [PHP 8.4](https://www.php.net/releases/8.4/en.php)
+2. [Composer](https://getcomposer.org/) (php package manager)
+3. [MINIMAL](https://git.svoboda.works/mirzaev/minimal) (PHP framework)
+5. [Zanzara](https://github.com/badfarm/zanzara) (Telegram framework + ReactPHP)
+6. [Baza](https://git.svoboda.works/mirzaev/baza) (binary database)
+7. [NGINX](https://nginx.org/en/) (web server) *(can be replaced)*
+8. [SystemD](https://systemd.io/) (service manager) *(can be replaced)*
+
+You can find other dependencies in the file `/composer.json`
+
+## Installation
+
+### SystemD (or any alternative you like)
+You can copy an example of systemd file from here: `/examples/systemd/ parser_from_interneturok-telegram.service`
+**Execute:** `sudo cp parser_from_interneturok-telegram.service /etc/systemd/system/ parser_from_interneturok-telegram.service && sudo chmod +x /etc/systemd/system/ parser_from_interneturok-telegram.service`
+*before you execute the command think about **what it does** and whether the **paths** are specified correctly*
+*the configuration file is very simple and you can remake it for any alternative to SystemD that you like*
+
+### InternetUrok accounts
+Fill in the file: `/mirzaev/parser_from_interneturok/system/storage/accounts.csv`
+**Format:** "mail password" (**separated by 1 space symbol**)
+
+```CSV
+mail password
+mail password
+mail password
+```
+
+### Authorized Telegram accounts
+Fill in the file: `/mirzaev/parser_from_interneturok/system/settings/accounts.php`
+```php
+return [
+ 1053489457, // Arsen Mirzaev Tatyano-Muradovich @redloser
+]
+```
+You can get the telegram account identifier by [@RawDataBot](https://t.me/RawDataBot)
+
+### Chat-robot Telegram token
+Fill in the file: `/mirzaev/parser_from_interneturok/system/settings/telegram.php`
+You can get the chat-robot telegram token by [@BotFather](https://t.me/BotFather)
diff --git a/mirzaev/parser_from_interneturok/system/models/interneturok.php b/mirzaev/parser_from_interneturok/system/models/interneturok.php
index c214fab..e0ad351 100644
--- a/mirzaev/parser_from_interneturok/system/models/interneturok.php
+++ b/mirzaev/parser_from_interneturok/system/models/interneturok.php
@@ -163,11 +163,12 @@ final class interneturok extends core
*
* @param subject $subject The subject
* @param int $grade The grade
+ * @param datetime $date The date
* @param int $waiting Interval for processing requests (seconds)
*
* @return array|false Downloaded homework files
*/
- public function parse(subject $subject, int $grade, int $waiting = 3): array|false
+ public function parse(subject $subject, int $grade, datetime $date, int $week, int $waiting = 3): array|false
{
// Initializing accounts
$accounts = static::accounts();
@@ -185,7 +186,6 @@ final class interneturok extends core
sleep($waiting);
try {
-
if ($this->authentication($account)->wait()) {
// Authenticated the account
@@ -196,7 +196,7 @@ final class interneturok extends core
sleep($waiting);
// Initializing the user journal
- $journal = $this->journal(grade: $grade)->wait();
+ $journal = $this->journal(grade: $grade, week: $week)->wait();
if (!empty($journal)) {
// Initialized the user journal
@@ -204,9 +204,6 @@ final class interneturok extends core
// Writing into the output buffer
echo "Инициализирован журнал\n";
- // Initializing the actual date
- $date = new datetime();
-
// Initializing the homeworks database
$model = new homework();
@@ -229,16 +226,16 @@ final class interneturok extends core
// Initialized the target subject event (the homework exists)
if (new datetime($event->date) <= $date && new datetime($event->date)->modify('+6 days') >= $date) {
- // Found the current event
+ // Found the target event week
if ($event->subject?->name === $subject->value && $event->subject->grade === $grade) {
// Found the target subject
// Writing into the output buffer
- /* echo "Найден школьный предмет: $subject->value для $grade класса (с " . new datetime($event->date)->format('d.m') . ' по ' . new datetime($event->date)->modify('+6 days')->format('d.m') . ")\n"; */
+ echo "Найден школьный предмет: $subject->value для $grade класса (с " . new datetime($event->date)->format('d.m') . ' по ' . new datetime($event->date)->modify('+6 days')->format('d.m') . ")\n";
- // Initializing the unblock time
- $unblock = svoboda::timestamp() - 31536000;
+ // Initializing the current time
+ $now = svoboda::timestamp();
foreach ($event->homeworks as $homework) {
// Iterating over scheduled event homeworks
@@ -246,60 +243,53 @@ final class interneturok extends core
if ($homework->status === 'checked' && $homework->mark === 5) {
// Homework checked and completed for a grade of 5
- // Checking for the block record
- $blocked = $model->database->read(
- filter: fn(record $record) => $record->identifier === $homework->item_id && $record->created > $unblock,
- amount: 1
- )[0] ?? null;
- if ($blocked instanceof record) {
- // The account homework has been downloaded for 1 year
+ // Writing into the output buffer
+ echo "Найдено домашнее задание: $homework->item_id с оценкой $homework->mark\n";
- continue 3;
- } else {
- // The account homework has not been downloaded for 1 year
+ // Waiting for processing the request
+ sleep($waiting);
+
+ // Initializing the homework files
+ $files = $this->homework(lesson: $event->lesson->id, homework: $homework->item_id)->wait();
+
+ if (!empty($files)) {
+ // Initialized the homework files
// Writing into the output buffer
- echo "Найдено домашнее задание: $homework->item_id с оценкой $homework->mark\n";
+ echo "Получено домашнее задание\n";
- // Waiting for processing the request
- sleep($waiting);
+ // Declaring the homework downloads for 1 last year counter
+ $year = 0;
- // Initializing the homework files
- $files = $this->homework(lesson: $event->lesson->id, homework: $homework->item_id)->wait();
+ // Counting the homework downloading for 1 last year
+ $model->database->read(
+ filter: function (record $record) use ($homework, $now, &$year) {
+ if ($record->identifier === $homework->item_id && $now - $record->created < 31536000) {
+ // Found a downloading for 1 last year
- if (!empty($files)) {
- // Initialized the homework files
-
- // Writing into the output buffer
- echo "Получено домашнее задание\n";
-
- // Blocking the homework downloading for 1 year
- $blocked = $model->create(identifier: $homework->item_id);
-
- if ($blocked !== false) {
- // The homework was blocked for 1 year
-
- // Writing into the output buffer
- echo "Заблокировано на 1 год домашнее задание\n";
+ // Increasing the homework downloads for 1 last year counter
+ ++$year;
+ }
// Exit (success)
- return $files;
- }
- }
+ return false;
+ },
+ amount: 100
+ );
+
+ // Writing the homework downloading record
+ $model->create(identifier: $homework->item_id);
+
+ // Exit (success)
+ return ['downloads' => ['year' => $year], 'files' => $files];
}
}
}
}
-
- // Stopping processing events and starting processing the next account
- break 2;
}
}
}
-
- // Stopping processing events and starting processing the next account
- break;
}
}
} else {
@@ -458,10 +448,11 @@ final class interneturok extends core
* Search for the user homeworks journal
*
* @param int $grade The grade
+ * @param int $week Number of the week
*
* @return promise|null The journal data (object)
*/
- private function journal(int $grade): promise|null
+ private function journal(int $grade, int $week): promise|null
{
if (!empty($this->token)) {
// Initialized the account authorization token
@@ -476,7 +467,7 @@ final class interneturok extends core
);
return $this->browser->sendAsync($request)
- ->then(function ($response) use ($grade) {
+ ->then(function ($response) use ($grade, $week) {
// Sended the request and received the response
// Initializing the user data
@@ -501,7 +492,7 @@ final class interneturok extends core
);
return $this->browser->sendAsync($request)
- ->then(function ($response) use ($grade, $identifier) {
+ ->then(function ($response) use ($grade, $identifier, $week) {
// Sended the request and received the response
// Initializing the user schedules
@@ -529,7 +520,7 @@ final class interneturok extends core
);
return $this->browser->sendAsync($request)
- ->then(function ($response) use ($grade, $identifier, $year) {
+ ->then(function ($response) use ($grade, $identifier, $year, $week) {
// Sended the request and received the response
// Initializing the moscow time
@@ -542,51 +533,42 @@ final class interneturok extends core
$now = new datetime($time);
// Declaring the quarter buffer
- $quarter = null;
+ $quarter = static::quarter(number: $week);
- foreach ($year->quarters as $value) {
- // Iterating over study year quarters
+ if ($quarter !== false) {
+ // Initialized number of the quarter
- // Implementing the quarter start time and end time
- $start = new datetime($value->starts_at);
- $end = new datetime($value->ends_at);
+ // Initializing the request to the user journal API
+ $request = new request(
+ 'GET',
+ static::JOURNAL . "?grade=$grade&quarter=$quarter&year_id=$year->id&user_id=$identifier&token=$this->token"
+ );
- if ($now > $start && $now < $end) {
- // Found the current quarter
+ return $this->browser->sendAsync($request)
+ ->then(function ($response) {
+ // Sended the request and received the response
- // Writing the current quarter identifier into the quarter buffer
- $quarter = $value->quarter;
+ // Initializing the user journal
+ $journal = json_decode((string) $response->getBody());
- // Stopping iterating over study year quarters
- break;
- }
+ if (!empty($journal)) {
+ // Initialized the user journal
+
+ // Exit (success)
+ return $journal;
+ } else {
+ // Not initialized the user journal
+
+ // Exit (fail)
+ return false;
+ }
+ })->wait();
+ } else {
+ // Not initialized number of the quarter
+
+ // Exit (fail)
+ return false;
}
-
- // Initializing the request to the user journal API
- $request = new request(
- 'GET',
- static::JOURNAL . "?grade=$grade&quarter=$quarter&year_id=$year->id&user_id=$identifier&token=$this->token"
- );
-
- return $this->browser->sendAsync($request)
- ->then(function ($response) {
- // Sended the request and received the response
-
- // Initializing the user journal
- $journal = json_decode((string) $response->getBody());
-
- if (!empty($journal)) {
- // Initialized the user journal
-
- // Exit (success)
- return $journal;
- } else {
- // Not initialized the user journal
-
- // Exit (fail)
- return false;
- }
- })->wait();
} else {
// Not initialized the moscow time
@@ -922,4 +904,53 @@ final class interneturok extends core
return 0;
}
}
+
+ /**
+ * Week
+ *
+ * Generate datetime by number of the week (by 6 days)
+ *
+ * @param int $number Number of the week
+ *
+ * @return datetime The date
+ */
+ public static function week(int $number = 2): datetime
+ {
+ // Initializing the date
+ $date = new datetime('first day of september last year');
+
+ // Normalizing number of the week
+ if ($number < 2) $number = 2;
+ else if ($number > 37) $number = 37;
+
+ // Offsetting number of the week for calculating
+ $number = $number - 1;
+
+ // Calculating days for offsetting the date
+ $days = 6 * $number;
+
+ // Exit (success)
+ return $date->modify("+$days days +$number days");
+ }
+
+ /**
+ * Quarter
+ *
+ * Generate number of the quarter by number of the week
+ *
+ * @param int $number Number of the week
+ *
+ * @return int|false Number of the quarter
+ */
+ public static function quarter(int $number = 2): int|false
+ {
+ // Exit (success)
+ return match (true) {
+ $number >= 2 && $number <= 9 => 1,
+ $number >= 11 && $number <= 18 => 2,
+ $number >= 21 && $number <= 30 => 3,
+ $number >= 32 && $number <= 38 => 4,
+ default => false
+ };
+ }
}
diff --git a/mirzaev/parser_from_interneturok/system/models/telegram/parser.php b/mirzaev/parser_from_interneturok/system/models/telegram/parser.php
index fc23f88..f002efa 100644
--- a/mirzaev/parser_from_interneturok/system/models/telegram/parser.php
+++ b/mirzaev/parser_from_interneturok/system/models/telegram/parser.php
@@ -18,7 +18,8 @@ use Zanzara\Context as context,
use function React\Async\await;
// Built-in libraries
-use Exception as exception;
+use Exception as exception,
+ DateTime as datetime;
/**
* Telegram shcool subjects parser
@@ -52,7 +53,9 @@ final class parser extends core
// Initializing the parsing target buffer
$target = [
'subject' => $subject,
- 'grade' => null
+ 'grade' => null,
+ 'date' => null,
+ 'week' => null
];
// Writing to the telegram user buffer
@@ -114,7 +117,7 @@ final class parser extends core
/**
* Grade
*
- * Write grade to the buffer and request confirmation for starting the parsing process
+ * Write grade to the buffer and request date
*
* @param context $context Request data from Telegram
* @param int $grade The grade
@@ -134,6 +137,207 @@ final class parser extends core
// Initializing the grade
$target['grade'] = $grade;
+ // Writing to the telegram user buffer
+ $context->setUserDataItem(static::PROCESS, $target)
+ ->then(function () use ($context, $target) {
+ // Writed to the telegram user buffer
+
+ // Sending the message
+ $context->sendMessage(
+ '📅 *Выберите номер недели*',
+ [
+ 'reply_markup' => [
+ 'inline_keyboard' => [
+ [
+ [
+ 'text' => '2',
+ 'callback_data' => 'week_2'
+ ],
+ [
+ 'text' => '3',
+ 'callback_data' => 'week_3'
+ ],
+ [
+ 'text' => '4',
+ 'callback_data' => 'week_4'
+ ],
+ [
+ 'text' => '5',
+ 'callback_data' => 'week_5'
+ ],
+ [
+ 'text' => '6',
+ 'callback_data' => 'week_6'
+ ],
+ [
+ 'text' => '7',
+ 'callback_data' => 'week_7'
+ ],
+ [
+ 'text' => '8',
+ 'callback_data' => 'week_8'
+ ],
+ [
+ 'text' => '9',
+ 'callback_data' => 'week_9'
+ ]
+ ],
+ [
+ [
+ 'text' => '11',
+ 'callback_data' => 'week_11'
+ ],
+ [
+ 'text' => '12',
+ 'callback_data' => 'week_12'
+ ],
+ [
+ 'text' => '13',
+ 'callback_data' => 'week_13'
+ ],
+ [
+ 'text' => '14',
+ 'callback_data' => 'week_14'
+ ],
+ [
+ 'text' => '15',
+ 'callback_data' => 'week_15'
+ ],
+ [
+ 'text' => '16',
+ 'callback_data' => 'week_16'
+ ],
+ [
+ 'text' => '17',
+ 'callback_data' => 'week_17'
+ ],
+ [
+ 'text' => '18',
+ 'callback_data' => 'week_18'
+ ]
+ ],
+ [
+ [
+ 'text' => '21',
+ 'callback_data' => 'week_21'
+ ],
+ [
+ 'text' => '22',
+ 'callback_data' => 'week_22'
+ ],
+ [
+ 'text' => '23',
+ 'callback_data' => 'week_23'
+ ],
+ [
+ 'text' => '24',
+ 'callback_data' => 'week_24'
+ ],
+ [
+ 'text' => '25',
+ 'callback_data' => 'week_25'
+ ]
+ ],
+ [
+ [
+ 'text' => '26',
+ 'callback_data' => 'week_26'
+ ],
+ [
+ 'text' => '27',
+ 'callback_data' => 'week_27'
+ ],
+ [
+ 'text' => '28',
+ 'callback_data' => 'week_28'
+ ],
+ [
+ 'text' => '29',
+ 'callback_data' => 'week_29'
+ ],
+ [
+ 'text' => '30',
+ 'callback_data' => 'week_30'
+ ]
+ ],
+ [
+ [
+ 'text' => '32',
+ 'callback_data' => 'week_32'
+ ],
+ [
+ 'text' => '33',
+ 'callback_data' => 'week_33'
+ ],
+ [
+ 'text' => '34',
+ 'callback_data' => 'week_34'
+ ],
+ [
+ 'text' => '35',
+ 'callback_data' => 'week_35'
+ ],
+ [
+ 'text' => '36',
+ 'callback_data' => 'week_36'
+ ],
+ [
+ 'text' => '37',
+ 'callback_data' => 'week_37'
+ ],
+ [
+ 'text' => '38',
+ 'callback_data' => 'week_38'
+ ]
+ ]
+ ],
+ 'disable_notification' => true,
+ 'remove_keyboard' => true
+ ]
+ ]
+ );
+ });
+ } else {
+ // Not initialized the parsing process
+
+ // Sending the message
+ $context->sendMessage('⚠️ *Не запущен процесс генерации парсинга*')
+ ->then(function (message $message) use ($context) {
+ // Sended the message
+
+ // Sending the menu with subjects
+ commands::menu($context);
+ });
+ }
+ });
+ }
+
+ /**
+ * Date
+ *
+ * Write date and request confirmation for starting the parsing process
+ *
+ * @param context $context Request data from Telegram
+ * @param int $week Number of the week
+ *
+ * @return void
+ */
+ public static function date(context $context, int $week): void
+ {
+ // Reading from the telegram user buffer
+ $context->getUserDataItem(static::PROCESS)
+ ->then(function (?array $target) use ($context, $week) {
+ // Readed from the telegram user buffer
+
+ if ($target) {
+ // Initialized the parsing process
+
+ // Initializing the week
+ $target['week'] = $week;
+
+ // Initializing the date
+ $target['date'] = interneturok::week($week);
+
// Writing to the telegram user buffer
$context->setUserDataItem(static::PROCESS, $target)
->then(function () use ($context, $target) {
@@ -145,14 +349,21 @@ final class parser extends core
// Initializing the grade
$grade = $target['grade'];
+ // Reinigitlizing the date
+ $date = $target['date']->format('Y\\\.m\\\.d');
+
+ // Inigitlizing number the week
+ $week = $target['week'];
+
// Sending the message
$context->sendMessage(
<< [
'inline_keyboard' => [
@@ -201,51 +412,71 @@ final class parser extends core
if ($target) {
// Initialized the parsing process
- // Initializing variables for the parsing process
- $subject = $target['subject'];
- $grade = $target['grade'];
+ // Sending the message
+ $context->sendMessage('⚡️ *Запущен процесс парсинга домашнего задания*')
+ ->then(function (message $message) use ($context, $target) {
+ // Sended the message
- // Initializing the parser
- $parser = new interneturok();
+ // Initializing variables for the parsing process
+ $subject = $target['subject'];
+ $grade = $target['grade'];
+ $date = $target['date'];
+ $week = $target['week'];
- try {
- // Parsing homework files
- $files = $parser->parse(subject: $subject, grade: $grade, waiting: 3);
+ // Initializing the parser
+ $parser = new interneturok();
- if (!empty($files)) {
- // Initialized homework files
+ try {
+ // Parsing homework
+ $homework = $parser->parse(subject: $subject, grade: $grade, date: $date, week: $week, waiting: 2);
- foreach ($files as $file) {
- // Iterating over files in the storage
+ if (!empty($homework)) {
+ // Initialized homework
- // Sending the file
- await($context->sendDocument(new file_input($file)));
+ foreach ($homework['files'] as $file) {
+ // Iterating over homework files in the storage
+
+ // Sending the file
+ await($context->sendDocument(new file_input($file)));
+ }
+
+ if ($homework['downloads']['year'] <= 100) {
+ // The homework was downloadsd 100 or less times for 1 last year
+
+ // Sending the message
+ $context->sendMessage('Домашнее задание было скачано *' . $homework['downloads']['year'] . ' раз* за последний год');
+ } else {
+ // The homework was downloaded more than 100 times for 1 last year
+
+ // Sending the message
+ $context->sendMessage('Домашнее задание было скачано *более чем 100 раз*) за последний год');
+ }
+
+ // Deleting in the telegram user buffer
+ $context->deleteUserDataItem(static::PROCESS);
+ } else {
+ // Not initialized homework files
+
+ // Sending the message
+ $context->sendMessage('❌ *Не найдены домашние задания*')
+ ->then(function (message $message) use ($context) {
+ // Sended the message
+
+ // Sending the menu with subjects
+ commands::menu($context);
+ });
+ }
+ } catch (exception $exception) {
+ // Sending the message
+ $context->sendMessage('⚠️ *Произошла ошибка при обработке домашних заданий*')
+ ->then(function (message $message) use ($context) {
+ // Sended the message
+
+ // Sending the menu with subjects
+ commands::menu($context);
+ });
}
-
- // Deleting in the telegram user buffer
- $context->deleteUserDataItem(static::PROCESS);
- } else {
- // Not initialized homework files
-
- // Sending the message
- $context->sendMessage('❌ *Не найдены домашние задания*')
- ->then(function (message $message) use ($context) {
- // Sended the message
-
- // Sending the menu with subjects
- commands::menu($context);
- });
- }
- } catch (exception $exception) {
- // Sending the message
- $context->sendMessage('⚠️ *Произошла ошибка при обработке домашних заданий*')
- ->then(function (message $message) use ($context) {
- // Sended the message
-
- // Sending the menu with subjects
- commands::menu($context);
- });
- }
+ });
} else {
// Not initialized the parsing process
diff --git a/mirzaev/parser_from_interneturok/system/public/telegram.php b/mirzaev/parser_from_interneturok/system/public/telegram.php
index 50f621b..7b15d3a 100755
--- a/mirzaev/parser_from_interneturok/system/public/telegram.php
+++ b/mirzaev/parser_from_interneturok/system/public/telegram.php
@@ -80,6 +80,34 @@ for ($i = 4; $i <= 11; ++$i) {
$robot->onCbQueryData(["grade_$i"], fn(context $context) => parser::grade(context: $context, grade: $i));
}
+for ($i = 2; $i <= 9; ++$i) {
+ // Generating buttons from 2 to 9 numbers of weeks
+
+ // Initializing numbers of weeks buttons
+ $robot->onCbQueryData(["week_$i"], fn(context $context) => parser::date(context: $context, week: $i));
+}
+
+for ($i = 11; $i <= 18; ++$i) {
+ // Generating buttons from 11 to 18 numbers of weeks
+
+ // Initializing numbers of weeks buttons
+ $robot->onCbQueryData(["week_$i"], fn(context $context) => parser::date(context: $context, week: $i));
+}
+
+for ($i = 21; $i <= 30; ++$i) {
+ // Generating buttons from 21 to 30 numbers of weeks
+
+ // Initializing numbers of weeks buttons
+ $robot->onCbQueryData(["week_$i"], fn(context $context) => parser::date(context: $context, week: $i));
+}
+
+for ($i = 32; $i <= 38; ++$i) {
+ // Generating buttons from 32 to 38 numbers of weeks
+
+ // Initializing numbers of weeks buttons
+ $robot->onCbQueryData(["week_$i"], fn(context $context) => parser::date(context: $context, week: $i));
+}
+
// Initializing the parse button
$robot->onCbQueryData(['parse'], [parser::class, 'parse']);