First karma working achieved.
This commit is contained in:
parent
1cc0432e97
commit
06f832d8eb
@ -1,29 +0,0 @@
|
|||||||
#!/usr/bin/env perl
|
|
||||||
|
|
||||||
use v5.30.0;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use Data::Dumper;
|
|
||||||
use JSON;
|
|
||||||
|
|
||||||
use DoctorKarma::Config;
|
|
||||||
use DoctorKarma::Telegram;
|
|
||||||
use DoctorKarma::Logger;
|
|
||||||
|
|
||||||
my $config = DoctorKarma::Config->new;
|
|
||||||
my $logger = DoctorKarma::Logger->new;
|
|
||||||
my $telegram =
|
|
||||||
DoctorKarma::Telegram->new( telegram_token => $config->telegram_token );
|
|
||||||
while (1) {
|
|
||||||
my $updates = $telegram->get_updates;
|
|
||||||
for my $update ($updates->@*) {
|
|
||||||
if (exists $update->{message}{text}) {
|
|
||||||
my $message = $update->{message}{text};
|
|
||||||
my $user_id = $update->{message}{from}{id};
|
|
||||||
my $username = $update->{message}{from}{username};
|
|
||||||
$logger->log_info("'$message' received from $username:$user_id");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
118
bin/doctor_karma.pl
Executable file
118
bin/doctor_karma.pl
Executable file
@ -0,0 +1,118 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use v5.30.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
use JSON;
|
||||||
|
|
||||||
|
use DoctorKarma::Config;
|
||||||
|
use DoctorKarma::Telegram;
|
||||||
|
use DoctorKarma::Logger;
|
||||||
|
use DoctorKarma::DB;
|
||||||
|
|
||||||
|
use DoctorKarma::DAO::User;
|
||||||
|
use DoctorKarma::Model::User;
|
||||||
|
|
||||||
|
my $config = DoctorKarma::Config->new;
|
||||||
|
my $logger = DoctorKarma::Logger->new;
|
||||||
|
my $telegram =
|
||||||
|
DoctorKarma::Telegram->new( telegram_token => $config->telegram_token );
|
||||||
|
my $db = DoctorKarma::DB->dbh;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
my $updates = $telegram->get_updates;
|
||||||
|
for my $update ( $updates->@* ) {
|
||||||
|
my $message = $update->{message};
|
||||||
|
if ( defined $message ) {
|
||||||
|
proccess_new_message($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub proccess_new_message {
|
||||||
|
my $message = shift;
|
||||||
|
my $reply_to_message = $message->{reply_to_message};
|
||||||
|
|
||||||
|
update_user ($message);
|
||||||
|
if ( defined $message->{text} ) {
|
||||||
|
process_message_with_text($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub process_message_with_text {
|
||||||
|
my $message = shift;
|
||||||
|
|
||||||
|
my $text = $message->{text};
|
||||||
|
my $username = $message->{from}{username};
|
||||||
|
my $user_id = $message->{from}{id};
|
||||||
|
my $first_name = $message->{from}{first_name};
|
||||||
|
my $reply_to_message = $message->{reply_to_message};
|
||||||
|
|
||||||
|
my $log_username = defined $username ? "\@$username" : '';
|
||||||
|
$logger->log_info(
|
||||||
|
"'$message->{text}' received from $first_name:$log_username:$user_id");
|
||||||
|
if ( $text eq '+1' && defined $reply_to_message ) {
|
||||||
|
add_karma_to_replied_message_user ($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub add_karma_to_replied_message_user {
|
||||||
|
my $message = shift;
|
||||||
|
|
||||||
|
my $reply_to_message = $message->{reply_to_message};
|
||||||
|
my $user_giving_id = $message->{from}{id};
|
||||||
|
my $user_receiving_id = $reply_to_message->{from}{id};
|
||||||
|
|
||||||
|
my $user_dao = DoctorKarma::DAO::User->new( dbh => $db );
|
||||||
|
my $sending_karma_user = $user_dao->recover_id( id => $user_giving_id );
|
||||||
|
|
||||||
|
if ( $user_giving_id == $user_receiving_id ) {
|
||||||
|
$logger->log_info(<<"EOF");
|
||||||
|
User @{[$sending_karma_user->first_name]}:@{[$sending_karma_user->username]}:@{[$sending_karma_user->id_user]} tried to give karma to itself, refusing.
|
||||||
|
EOF
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $receiving_karma_user =
|
||||||
|
$user_dao->recover_id( id => $user_receiving_id );
|
||||||
|
if (!defined $receiving_karma_user) {
|
||||||
|
update_user ($reply_to_message);
|
||||||
|
$receiving_karma_user = $user_dao->recover_id (id => $user_receiving_id);
|
||||||
|
}
|
||||||
|
$user_dao->add_1_karma(user => $receiving_karma_user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub update_user {
|
||||||
|
my $message = shift;
|
||||||
|
|
||||||
|
my $user_id = $message->{from}{id};
|
||||||
|
my $username = $message->{from}{username};
|
||||||
|
my $first_name = $message->{from}{first_name};
|
||||||
|
|
||||||
|
my $user_dao = DoctorKarma::DAO::User->new( dbh => $db );
|
||||||
|
my $user = $user_dao->recover_id( id => $user_id );
|
||||||
|
if ( !defined $user ) {
|
||||||
|
$user = DoctorKarma::Model::User->new(
|
||||||
|
id_user => $user_id,
|
||||||
|
(defined $username) ? (username => $username) : (),
|
||||||
|
karma => 0
|
||||||
|
);
|
||||||
|
$user_dao->store(user => $user);
|
||||||
|
}
|
||||||
|
if ( ( $user->username // '' ) ne ( $username // '' ) ) {
|
||||||
|
$user_dao->update_username(
|
||||||
|
user => $user,
|
||||||
|
username => $username
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( ( $user->first_name // '' ) ne $first_name ) {
|
||||||
|
$user_dao->update_firstname(
|
||||||
|
user => $user,
|
||||||
|
first_name => $first_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
88
lib/DoctorKarma/Config.pm
Normal file
88
lib/DoctorKarma/Config.pm
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package DoctorKarma::Config;
|
||||||
|
|
||||||
|
use v5.30.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Term::ReadLine;
|
||||||
|
|
||||||
|
use Const::Fast;
|
||||||
|
use JSON;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
use DoctorKarma::Logger;
|
||||||
|
|
||||||
|
sub HOME { $ENV{HOME} }
|
||||||
|
sub CONFIG_DIR { "@{[HOME]}/.config/doctorkarma" }
|
||||||
|
sub CONFIG_FILE { "@{[CONFIG_DIR]}/config.json" }
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my $self = bless {}, $class;
|
||||||
|
$self->_create_config_file_if_not_exists;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub logger {
|
||||||
|
my $self = shift;
|
||||||
|
if ( !defined $self->{logger} ) {
|
||||||
|
my $logger = DoctorKarma::Logger->new;
|
||||||
|
$self->{logger} = $logger;
|
||||||
|
}
|
||||||
|
return $self->{logger};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _config {
|
||||||
|
my $self = shift;
|
||||||
|
if ( !defined $self->{config} ) {
|
||||||
|
if ( !-f CONFIG_FILE ) {
|
||||||
|
$self->logger->log_error(
|
||||||
|
qq(@{[CONFIG_FILE]} is not a plain file, unable to read config.)
|
||||||
|
);
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
my $config = decode_json( path(CONFIG_FILE)->slurp_utf8 );
|
||||||
|
$self->{config} = $config;
|
||||||
|
}
|
||||||
|
return $self->{config};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub telegram_token {
|
||||||
|
my $self = shift;
|
||||||
|
if ( !defined $self->{telegram_token} ) {
|
||||||
|
my $config = $self->_config;
|
||||||
|
$self->{telegram_token} = $config->{telegram_token};
|
||||||
|
}
|
||||||
|
return $self->{telegram_token};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _create_config_file_if_not_exists {
|
||||||
|
my $self = shift;
|
||||||
|
if ( !-e CONFIG_FILE ) {
|
||||||
|
$self->logger->log_info(q(Config file not detected));
|
||||||
|
$self->_create_config_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _create_config_file {
|
||||||
|
my $self = shift;
|
||||||
|
my $logger = $self->logger;
|
||||||
|
if ( !-e CONFIG_DIR ) {
|
||||||
|
$logger->log_info(qq(Creating @{[CONFIG_DIR]}));
|
||||||
|
eval { path(CONFIG_DIR)->mkpath; };
|
||||||
|
if ($@) {
|
||||||
|
$logger->log_error(
|
||||||
|
qq(Unable to create directory @{[CONFIG_DIR]}: $@));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $term = Term::ReadLine->new('Doctor Agustín');
|
||||||
|
my $token = $term->readline('Telegram token:');
|
||||||
|
my $config_contents = { telegram_token => $token };
|
||||||
|
$config_contents = encode_json($config_contents);
|
||||||
|
|
||||||
|
path(CONFIG_FILE)->spew_utf8($config_contents);
|
||||||
|
}
|
||||||
|
1;
|
240
lib/DoctorKarma/DAO/User.pm
Normal file
240
lib/DoctorKarma/DAO/User.pm
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
package DoctorKarma::DAO::User;
|
||||||
|
|
||||||
|
use v5.30.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Types::Standard qw/Str Int InstanceOf ArrayRef Maybe HasMethods/;
|
||||||
|
use Params::ValidationCompiler qw(validation_for);
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
dbh => { type => HasMethods [ 'selectrow_hashref', 'do' ] }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my $self = bless {}, $class;
|
||||||
|
$self->{dbh} = $params{dbh};
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _logger {
|
||||||
|
my $self = shift;
|
||||||
|
if ( !defined $self->{logger} ) {
|
||||||
|
$self->{logger} = DoctorKarma::Logger->new;
|
||||||
|
}
|
||||||
|
return $self->{logger};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _db {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{dbh};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
user => { type => InstanceOf ['DoctorKarma::Model::User'] }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub store {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my $user = $params{user};
|
||||||
|
my $db = $self->_db;
|
||||||
|
my $logger = $self->_logger;
|
||||||
|
|
||||||
|
my $insert = <<'EOF';
|
||||||
|
INSERT INTO users (id, first_name, username, karma) VALUES (?, ?, ?, 0);
|
||||||
|
EOF
|
||||||
|
my $username = "\@@{[$user->username]}:" // '';
|
||||||
|
my $user_id = $user->id_user;
|
||||||
|
my $success = 0 +
|
||||||
|
$db->do( $insert, {}, $user->id_user, $user->username, $user->karma );
|
||||||
|
if ($success) {
|
||||||
|
$logger->log_info("${username}${user_id} registered.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
user => { type => InstanceOf ['DoctorKarma::Model::User'] },
|
||||||
|
first_name => { type => Str },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub update_firstname {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my $user = $params{user};
|
||||||
|
my $first_name = $params{first_name};
|
||||||
|
|
||||||
|
my $db = $self->_db;
|
||||||
|
my $logger = $self->_logger;
|
||||||
|
|
||||||
|
my $success = 0 + $db->do( <<'EOF', {}, $first_name, $user->id_user );
|
||||||
|
UPDATE users SET first_name = ? WHERE id = ?;
|
||||||
|
EOF
|
||||||
|
if ($success) {
|
||||||
|
my $old_first_name = $user->first_name // 'NULL';
|
||||||
|
$logger->log_info(<<"EOF");
|
||||||
|
Updated first_name for id @{[$user->id_user]}
|
||||||
|
From: ${old_first_name} -> ${first_name}.
|
||||||
|
EOF
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
user => { type => InstanceOf ['DoctorKarma::Model::User'] },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub add_1_karma {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my $user = $params{user};
|
||||||
|
|
||||||
|
my $db = $self->_db;
|
||||||
|
my $logger = $self->_logger;
|
||||||
|
|
||||||
|
$db->do( <<'EOF', {}, $user->id_user );
|
||||||
|
UPDATE users SET karma=karma+1 WHERE id = ?;
|
||||||
|
EOF
|
||||||
|
my $user_with_new_karma = $self->recover_id( id => $user->id_user );
|
||||||
|
$user->karma( $user_with_new_karma->karma );
|
||||||
|
$logger->log_info( 'User '
|
||||||
|
. $user->first_name . ':'
|
||||||
|
. $user->username . ':'
|
||||||
|
. $user->id_user
|
||||||
|
. ' has now '
|
||||||
|
. $user->karma
|
||||||
|
. ' of karma.' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
user => { type => InstanceOf ['DoctorKarma::Model::User'] },
|
||||||
|
username => { type => Maybe [Str] },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub update_username {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my $user = $params{user};
|
||||||
|
my $username = $params{username};
|
||||||
|
|
||||||
|
my $db = $self->_db;
|
||||||
|
my $logger = $self->_logger;
|
||||||
|
|
||||||
|
my $success = 0 + $db->do( <<'EOF', {}, $username, $user->id_user );
|
||||||
|
UPDATE users SET username = ? WHERE id = ?;
|
||||||
|
EOF
|
||||||
|
if ($success) {
|
||||||
|
my $old_username = $user->username ? '@' . $user->username : 'NULL';
|
||||||
|
$username = $username ? "\@$username" : 'NULL';
|
||||||
|
$logger->log_info(<<"EOF");
|
||||||
|
Updated username for id @{[$user->id_user]}
|
||||||
|
From: ${old_username} -> ${username}.
|
||||||
|
EOF
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
id => { type => Int },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub recover_id {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my $user_id = $params{id};
|
||||||
|
my $query = <<'EOF';
|
||||||
|
SELECT id as id_user, first_name, username, karma, last_karma_given_date
|
||||||
|
FROM users
|
||||||
|
WHERE id = ?;
|
||||||
|
EOF
|
||||||
|
return $self->_recover_by_query(
|
||||||
|
query => $query,
|
||||||
|
arguments => [$user_id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
username => { type => Str },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub recover_username {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my $username = $params{username};
|
||||||
|
my $query = <<'EOF';
|
||||||
|
SELECT id as user_id, first_name, username, karma, last_karma_given_date
|
||||||
|
FROM users
|
||||||
|
WHERE username = ?;
|
||||||
|
EOF
|
||||||
|
return $self->_recover_by_query(
|
||||||
|
query => $query,
|
||||||
|
arguments => [$username]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
query => { type => Str },
|
||||||
|
arguments => { type => ArrayRef },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _recover_by_query {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my $query = $params{query};
|
||||||
|
my $arguments = $params{arguments};
|
||||||
|
|
||||||
|
my $db = $self->_db;
|
||||||
|
my $user_db = $db->selectrow_hashref( $query, {}, @$arguments );
|
||||||
|
|
||||||
|
if ( defined $user_db ) {
|
||||||
|
for my $key_field ( keys %$user_db ) {
|
||||||
|
$user_db->{$key_field} // delete $user_db->{$key_field};
|
||||||
|
}
|
||||||
|
return DoctorKarma::Model::User->new(%$user_db);
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1
|
70
lib/DoctorKarma/DB.pm
Normal file
70
lib/DoctorKarma/DB.pm
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package DoctorKarma::DB;
|
||||||
|
|
||||||
|
use v5.30.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use DBI;
|
||||||
|
use Const::Fast;
|
||||||
|
|
||||||
|
use DoctorKarma::Config;
|
||||||
|
|
||||||
|
const my $dbname => "@{[DoctorKarma::Config::CONFIG_DIR()]}/database.sqlite";
|
||||||
|
|
||||||
|
my @migrations = (
|
||||||
|
'CREATE TABLE options (
|
||||||
|
key TEXT PRIMARY KEY,
|
||||||
|
value TEXT
|
||||||
|
);',
|
||||||
|
'CREATE TABLE users (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
username TEXT,
|
||||||
|
karma INTEGER,
|
||||||
|
last_karma_given_date TEXT
|
||||||
|
)',
|
||||||
|
'ALTER TABLE users
|
||||||
|
ADD COLUMN first_name TEXT',
|
||||||
|
);
|
||||||
|
|
||||||
|
sub dbh {
|
||||||
|
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname", '', '' , {
|
||||||
|
AutoCommit => 1,
|
||||||
|
RaiseError => 1,
|
||||||
|
});
|
||||||
|
state $migrations_run = 0;
|
||||||
|
if (!$migrations_run) {
|
||||||
|
run_migrations($dbh);
|
||||||
|
$migrations_run = 1;
|
||||||
|
}
|
||||||
|
return $dbh;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub run_migrations {
|
||||||
|
my $dbh = shift;
|
||||||
|
my $current_migration = _get_current_migration_number($dbh);
|
||||||
|
say $current_migration;
|
||||||
|
if ($current_migration < scalar @migrations) {
|
||||||
|
my @needed_migrations = @migrations[$current_migration .. $#migrations];
|
||||||
|
for my $migration (@needed_migrations) {
|
||||||
|
$dbh->do($migration);
|
||||||
|
if (!(0+$dbh->do('UPDATE options SET value = ? WHERE key = "migration"', undef, ++$current_migration))) {
|
||||||
|
$dbh->do('INSERT INTO options (key, value) VALUES ("migration", ?)', undef, $current_migration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _get_current_migration_number {
|
||||||
|
my $dbh = shift;
|
||||||
|
local $dbh->{RaiseError} = 0;
|
||||||
|
my $migration = $dbh->selectrow_hashref(<<'EOF', {});
|
||||||
|
SELECT value FROM options WHERE key = 'migration'
|
||||||
|
EOF
|
||||||
|
my $value = 0;
|
||||||
|
if (defined $migration) {
|
||||||
|
$value = $migration->{value};
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
1;
|
39
lib/DoctorKarma/Logger.pm
Normal file
39
lib/DoctorKarma/Logger.pm
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package DoctorKarma::Logger;
|
||||||
|
|
||||||
|
use Carp;
|
||||||
|
use Sys::Syslog;
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my $self = bless {}, $class;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _log {
|
||||||
|
my $self = shift;
|
||||||
|
my $level = shift;
|
||||||
|
my $message = shift;
|
||||||
|
my $critical = shift;
|
||||||
|
|
||||||
|
openlog ('DoctorKarma', $critical ? '': 'perror', 'user');
|
||||||
|
syslog ($level, $message);
|
||||||
|
closelog();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub log_error {
|
||||||
|
my $self = shift;
|
||||||
|
$self->_log (LOG_ERR, shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub log_critical {
|
||||||
|
my $self = shift;
|
||||||
|
my $error = shift;
|
||||||
|
$self->_log (LOG_ERR, $error, 1);
|
||||||
|
confess $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub log_info {
|
||||||
|
my $self = shift;
|
||||||
|
$self->_log (LOG_INFO, shift);
|
||||||
|
}
|
||||||
|
1;
|
79
lib/DoctorKarma/Model/User.pm
Normal file
79
lib/DoctorKarma/Model/User.pm
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package DoctorKarma::Model::User;
|
||||||
|
|
||||||
|
use v5.30.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Types::Standard qw/Str Int InstanceOf/;
|
||||||
|
use Params::ValidationCompiler qw(validation_for);
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
id_user => { type => Int },
|
||||||
|
username => { type => Str, optional => 1 },
|
||||||
|
first_name => { type => Str, optional => 1 },
|
||||||
|
karma => { type => Int },
|
||||||
|
last_karma_given_date => { type => InstanceOf ['DateTime'], optional => 1 },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my $self = bless \%params, $class;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub first_name {
|
||||||
|
my $self = shift;
|
||||||
|
if (exists $self->{first_name}) {
|
||||||
|
return $self->{first_name};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub id_user {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{id_user};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator =
|
||||||
|
validation_for( params => [ { type => Str, optional => 1 } ] );
|
||||||
|
|
||||||
|
sub username {
|
||||||
|
my $self = shift;
|
||||||
|
my ($new_username) = $validator->(@_);
|
||||||
|
if ( defined $new_username ) {
|
||||||
|
$self->{username} = $new_username;
|
||||||
|
}
|
||||||
|
if ( exists $self->{username} ) {
|
||||||
|
return $self->{username};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub last_karma_given_date {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{last_karma_given_date};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator =
|
||||||
|
validation_for( params => [ { type => Int, optional => 1 } ] );
|
||||||
|
|
||||||
|
sub karma {
|
||||||
|
my $self = shift;
|
||||||
|
my ($new_karma) = $validator->(@_);
|
||||||
|
if ( defined $new_karma ) {
|
||||||
|
$self->{new_karma} = $new_karma;
|
||||||
|
}
|
||||||
|
return $self->{karma};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1;
|
130
lib/DoctorKarma/Telegram.pm
Normal file
130
lib/DoctorKarma/Telegram.pm
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package DoctorKarma::Telegram;
|
||||||
|
|
||||||
|
use v5.30.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Types::Standard qw/Str Int Ref/;
|
||||||
|
use Params::ValidationCompiler qw(validation_for);
|
||||||
|
|
||||||
|
use Mojo::UserAgent;
|
||||||
|
use JSON;
|
||||||
|
|
||||||
|
use DoctorKarma::Logger;
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
telegram_token => { type => Str },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my $self = bless {}, $class;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my $telegram_token = $params{telegram_token};
|
||||||
|
$self->{telegram_token} = $telegram_token;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _logger {
|
||||||
|
my $self = shift;
|
||||||
|
if (!defined $self->{logger}) {
|
||||||
|
$self->{logger} = DoctorKarma::Logger->new;
|
||||||
|
}
|
||||||
|
return $self->{logger};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _user_agent {
|
||||||
|
my $self = shift;
|
||||||
|
if ( !defined $self->{user_agent} ) {
|
||||||
|
$self->{user_agent} = Mojo::UserAgent->new;
|
||||||
|
}
|
||||||
|
return $self->{user_agent};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
method => { type => Str },
|
||||||
|
body => { type => Ref },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _request {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my $method = $params{method};
|
||||||
|
my $body = $params{body};
|
||||||
|
my $ua = $self->_user_agent;
|
||||||
|
my $logger = $self->_logger;
|
||||||
|
my $url = $self->_generate_url( method => $method );
|
||||||
|
my $response = decode_json(
|
||||||
|
$ua->post( $url => {} => json => $body )->result->body );
|
||||||
|
unless ($response->{ok}) {
|
||||||
|
$logger->log_critical($response->{description});
|
||||||
|
}
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_updates {
|
||||||
|
my $self = shift;
|
||||||
|
my $last_update = $self->_last_update;
|
||||||
|
if ( !defined $last_update ) {
|
||||||
|
$last_update = 0;
|
||||||
|
}
|
||||||
|
my $response = $self->_request(
|
||||||
|
method => q/getUpdates/,
|
||||||
|
body => { offset => $last_update + 1 }
|
||||||
|
);
|
||||||
|
if ( scalar $response->{result}->@* ) {
|
||||||
|
$last_update = $response->{result}[-1]{update_id};
|
||||||
|
$self->_set_last_update($last_update);
|
||||||
|
}
|
||||||
|
return $response->{result};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
method => { type => Str },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _generate_url {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my $method = $params{method};
|
||||||
|
my $telegram_token = $self->_telegram_token;
|
||||||
|
my $url = qq(https://api.telegram.org/bot$telegram_token/$method);
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for( params => [ { type => Int } ] );
|
||||||
|
|
||||||
|
sub _set_last_update {
|
||||||
|
my $self = shift;
|
||||||
|
my ($last_update) = $validator->(@_);
|
||||||
|
$self->{last_update} = $last_update;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _last_update {
|
||||||
|
my $self = shift;
|
||||||
|
if ( !exists $self->{last_update} ) {
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
return $self->{last_update};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _telegram_token {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{telegram_token};
|
||||||
|
}
|
||||||
|
1;
|
Loading…
Reference in New Issue
Block a user