tramway-bots 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/tramway_bots_manifest.js +1 -0
  6. data/app/assets/stylesheets/tramway/bots/application.css +15 -0
  7. data/app/controllers/tramway/bots/application_controller.rb +6 -0
  8. data/app/helpers/tramway/bots/application_helper.rb +6 -0
  9. data/app/jobs/tramway/bots/application_job.rb +6 -0
  10. data/app/mailers/tramway/bots/application_mailer.rb +8 -0
  11. data/app/models/tramway/bots/application_record.rb +7 -0
  12. data/app/models/tramway/bots/bot.rb +50 -0
  13. data/app/models/tramway/bots/telegram/channel.rb +4 -0
  14. data/app/models/tramway/bots/telegram/chat.rb +12 -0
  15. data/app/models/tramway/bots/telegram/message.rb +15 -0
  16. data/app/models/tramway/bots/telegram/user.rb +37 -0
  17. data/app/models/tramway/bots/telegram/users/state.rb +6 -0
  18. data/app/models/tramway/bots/telegram/users.rb +7 -0
  19. data/app/views/layouts/tramway/bots/application.html.erb +15 -0
  20. data/config/routes.rb +2 -0
  21. data/lib/tramway/bots/engine.rb +7 -0
  22. data/lib/tramway/bots/generates/install_generator.rb +45 -0
  23. data/lib/tramway/bots/generates/templates/create_tramway_bots_bots.rb +17 -0
  24. data/lib/tramway/bots/generates/templates/create_tramway_bots_telegram_channels.rb +15 -0
  25. data/lib/tramway/bots/generates/templates/create_tramway_bots_telegram_chats.rb +17 -0
  26. data/lib/tramway/bots/generates/templates/create_tramway_bots_telegram_messages.rb +19 -0
  27. data/lib/tramway/bots/generates/templates/create_tramway_bots_telegram_users.rb +17 -0
  28. data/lib/tramway/bots/generates/templates/create_tramway_bots_telegram_users_states.rb +15 -0
  29. data/lib/tramway/bots/telegram/custom/message.rb +42 -0
  30. data/lib/tramway/bots/telegram/custom/notify/file.rb +22 -0
  31. data/lib/tramway/bots/telegram/custom/notify/text.rb +29 -0
  32. data/lib/tramway/bots/telegram/custom/notify.rb +12 -0
  33. data/lib/tramway/bots/telegram/custom/scenario.rb +17 -0
  34. data/lib/tramway/bots/telegram/custom.rb +6 -0
  35. data/lib/tramway/bots/telegram/info.rb +50 -0
  36. data/lib/tramway/bots/telegram/message.rb +42 -0
  37. data/lib/tramway/bots/telegram/messages_manager.rb +100 -0
  38. data/lib/tramway/bots/telegram.rb +6 -0
  39. data/lib/tramway/bots/version.rb +5 -0
  40. data/lib/tramway/bots.rb +10 -0
  41. metadata +82 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d462c8140b6b03f7886b70a4cd4c6149701bfc4de48ff6216d24d654a655a15c
4
+ data.tar.gz: fc46a58321fba4a96af57e7b5e68e9ac9204699f07da2ce7cdef700c3882c682
5
+ SHA512:
6
+ metadata.gz: 58c561c068af69ed6b9aa05953a89b5f5388ba49e8180e4ad6b4c92c0a0b5872958b14348f9b47e79c10e9da25435e58e6f874a19106df8275e07c58bd178562
7
+ data.tar.gz: 8dff845aef42cd104405ae3b1e3b7ffed207bab999fba665ca39c6f5d43098b8a268e4e6763b84bc7e2f7be48475232c4175215abb75fd4406da6404e8c83ed1
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Pavel Kalashnikov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Tramway::Bots
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "tramway-bots"
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install tramway-bots
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/tramway/bots .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,6 @@
1
+ module Tramway
2
+ module Bots
3
+ class ApplicationController < ActionController::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Tramway
2
+ module Bots
3
+ module ApplicationHelper
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Tramway
2
+ module Bots
3
+ class ApplicationJob < ActiveJob::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module Tramway
2
+ module Bots
3
+ class ApplicationMailer < ActionMailer::Base
4
+ default from: "from@example.com"
5
+ layout "mailer"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Tramway
2
+ module Bots
3
+ class ApplicationRecord < Tramway::Core::ApplicationRecord
4
+ self.abstract_class = true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tramway::Bots::Bot < ApplicationRecord
4
+ has_many :scenario_steps, -> { order(:name) }, class_name: 'BotTelegram::Scenario::Step'
5
+ has_many :progress_records, through: :scenario_steps, class_name: 'BotTelegram::Scenario::ProgressRecord'
6
+ has_many :attenders, through: :progress_records, class_name: 'BotTelegram::User', source: :user
7
+ has_many :messages, class_name: 'BotTelegram::Message'
8
+ has_many :users, through: :messages, class_name: 'BotTelegram::User'
9
+
10
+ TEAMS = %i[rsm night purple_magic benchkiller].freeze
11
+
12
+ enumerize :team, in: TEAMS
13
+
14
+ TEAMS.each do |team|
15
+ scope "#{team}_scope".to_sym, lambda { |_user_id|
16
+ where team: team
17
+ }
18
+ end
19
+
20
+ store_accessor :options, :custom
21
+ store_accessor :options, :scenario
22
+
23
+ def start_step
24
+ # scenario_steps.find_by name: :start did not work for some reason. Think it's about step word in Rails
25
+ scenario_steps.select { |s| s.name == 'start' }.first
26
+ end
27
+
28
+ def finish_step
29
+ return unless team.night?
30
+
31
+ scenario_steps.finish_step
32
+ end
33
+
34
+ def finished_users
35
+ return [] unless finish_step.present?
36
+
37
+ progress_records.where(bot_telegram_scenario_step_id: finish_step.id).uniq(&:bot_telegram_user_id)
38
+ end
39
+
40
+ def new_users_between(begin_date, end_date)
41
+ users.uniq.map do |user|
42
+ first_message_created_at = user.messages.order(created_at: :asc).first.created_at
43
+ user if first_message_created_at.between?(begin_date, end_date)
44
+ end.compact
45
+ end
46
+
47
+ def uniq_users_between(begin_date, end_date)
48
+ messages.where('created_at >= ? AND created_at <= ?', begin_date, end_date).map(&:user).uniq
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tramway::Bots::Telegram::Channel < ApplicationRecord
4
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tramway::Bots::Telegram::Chat < ApplicationRecord
4
+ self.table_name = 'tramway_bots_telegram_chats'
5
+
6
+ has_many :messages, class_name: 'Tramway::Bots::Telegram::Message'
7
+ belongs_to :bot, class_name: 'Bot'
8
+
9
+ def private?
10
+ chat_type == 'private'
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tramway::Bots::Telegram::Message < ApplicationRecord
4
+ self.table_name = 'tramway_bots_telegram_messages'
5
+
6
+ belongs_to :user, class_name: 'Tramway::Bots::Telegram::User', optional: true
7
+ belongs_to :bot, class_name: 'Tramway::Bots::Bot', optional: true
8
+ belongs_to :chat, class_name: 'Tramway::Bots::Telegram::Chat', optional: true
9
+
10
+ enumerize :message_type, in: %i[regular callback], default: :regular
11
+
12
+ validates :telegram_message_id, uniqueness: { scope: [ :bot_id, :chat_id ] }, allow_nil: true
13
+
14
+ search_by :text, user: %i[username first_name]
15
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tramway::Bots::Telegram::User < ApplicationRecord
4
+ self.table_name = 'tramway_bots_telegram_users'
5
+
6
+ has_many :messages, class_name: 'Tramway::Bots::Telegram::Message'
7
+ has_many :bots, class_name: 'Tramway::Bots::Bot', through: :steps
8
+ has_many :states, class_name: 'Tramway::Bots::Telegram::Users::State'
9
+
10
+ validates :telegram_id, uniqueness: true
11
+ validates :username, uniqueness: true, allow_blank: true, allow_nil: true
12
+
13
+ search_by :first_name, :username, :last_name
14
+
15
+ scope :partner_scope, ->(_user_id) { all }
16
+ %i[rsm night purple_magic].each do |team|
17
+ scope "#{team}_scope".to_sym, lambda { |_user_id|
18
+ step_ids = Bot.where(team: team).map(&:steps).flatten.map(&:id)
19
+ records = BotTelegram::Scenario::ProgressRecord.where(bot_telegram_scenario_step_id: step_ids)
20
+ BotTelegram::User.where id: records.map(&:bot_telegram_user_id)
21
+ }
22
+ end
23
+
24
+ def current_state(bot)
25
+ states.where(bot_id: bot.id).last&.current_state
26
+ end
27
+
28
+ # rubocop:disable Naming/AccessorMethodName
29
+ def set_finished_state_for(bot:)
30
+ states.create! bot_id: bot.id, current_state: :finished
31
+ end
32
+ # rubocop:enable Naming/AccessorMethodName
33
+
34
+ def finished_state_for?(bot:)
35
+ states.empty? || states.where(bot_id: bot.id).last&.current_state == 'finished'
36
+ end
37
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tramway::Bots::Telegram::Users::State < ApplicationRecord
4
+ belongs_to :user, class_name: 'Tramway::Bots::Telegram::User'
5
+ belongs_to :bot, class_name: 'Tramway::Bots::Bot'
6
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Bots::Telegram::Users
4
+ def self.table_name_prefix
5
+ 'tramway_bots_telegram_users_'
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Tramway bots</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "tramway/bots/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Tramway::Bots::Engine.routes.draw do
2
+ end
@@ -0,0 +1,7 @@
1
+ module Tramway
2
+ module Bots
3
+ class Engine < ::Rails::Engine
4
+ isolate_namespace Tramway::Bots
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'tramway/core/generators/install_generator'
5
+
6
+ module Tramway::Bots::Generators
7
+ class InstallGenerator < ::Tramway::Core::Generators::InstallGenerator
8
+ include Rails::Generators::Migration
9
+ source_root File.expand_path('templates', __dir__)
10
+
11
+ def self.next_migration_number(path)
12
+ next_migration_number = current_migration_number(path) + 1
13
+ ActiveRecord::Migration.next_migration_number next_migration_number
14
+ end
15
+
16
+ def copy_migrations
17
+ migrations = %i[
18
+ create_tramway_bots_bots
19
+ create_tramway_bots_telegram_channels
20
+ create_tramway_bots_telegram_chats
21
+ create_tramway_bots_telegram_messages
22
+ create_tramway_bots_telegram_users
23
+ create_tramway_bots_telegram_users_states
24
+ ]
25
+
26
+ migrations.each do |migration|
27
+ migration_template "#{migration}.rb", "db/migrate/#{migration}.rb"
28
+ end
29
+ end
30
+
31
+ def copy_factories
32
+ factories = [
33
+ 'tramway/bots/telegram/messages',
34
+ 'tramway/bots/telegram/chats',
35
+ 'tramway/bots/telegram/users',
36
+ 'tramway/bots/bots'
37
+ ]
38
+
39
+ factories.each do |factory|
40
+ # TODO write generator for minitest
41
+ create_file "spec/factories/#{factory}.rb", File.read("#{File.dirname(__dir__)}/../../../spec/factories/#{factory}.rb")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateTramwayBotsBots < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :tramway_bots_bots do |t|
6
+ t.text :name
7
+ t.text :state
8
+ t.text :team
9
+ t.text :token
10
+ t.jsonb :options
11
+ t.text :slug
12
+ t.datetime :deleted_at
13
+
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateTramwayBotsTelegramChannels < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :tramway_bot_engine_telegram_channels do |t|
6
+ t.integer :bot_id
7
+ t.text :title
8
+ t.text :state
9
+ t.text :telegram_channel_id
10
+ t.datetime :deleted_at
11
+
12
+ t.timestamps
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateTramwayBotsTelegramChats < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :tramway_bots_telegram_chats do |t|
6
+ t.text :title
7
+ t.text :chat_type
8
+ t.jsonb :options
9
+ t.text :state
10
+ t.text :telegram_chat_id
11
+ t.integer :bot_id
12
+ t.datetime :deleted_at
13
+
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateTramwayBotsTelegramMessages < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :tramway_bots_telegram_messages do |t|
6
+ t.integer :chat_id
7
+ t.integer :user_id
8
+ t.text :text
9
+ t.jsonb :options
10
+ t.text :state
11
+ t.integer :bot_id
12
+ t.text :message_type, default: "regular"
13
+ t.datetime :deleted_at
14
+ t.integer :telegram_message_id
15
+
16
+ t.timestamps
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateTramwayBotsTelegramUsers < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :tramway_bots_telegram_users do |t|
6
+ t.text "first_name"
7
+ t.text "last_name"
8
+ t.text "username"
9
+ t.jsonb "options"
10
+ t.text "state"
11
+ t.text "telegram_id"
12
+ t.datetime "deleted_at"
13
+
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateTramwayBotsTelegramUsersStates < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :tramway_bots_telegram_users_states do |t|
6
+ t.integer "user_id"
7
+ t.integer "bot_id"
8
+ t.text "current_state"
9
+ t.text "state"
10
+ t.datetime "deleted_at"
11
+
12
+ t.timestamps
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'telegram/bot'
4
+
5
+ class Tramway::Bots::Telegram::Custom::Message
6
+ attr_reader :file
7
+
8
+ def initialize(text: nil, file: nil, reply_markup: nil, inline_keyboard: nil)
9
+ raise 'You set text: argument for message' unless text.present?
10
+
11
+ @text = text
12
+ @file = file
13
+ @reply_markup = reply_markup
14
+ @inline_keyboard = inline_keyboard
15
+ end
16
+
17
+ def build_options(button)
18
+ button_options = { text: button[0] }
19
+ button_options.merge! callback_data: button[1][:data].to_json if button[1][:data].present?
20
+ Telegram::Bot::Types::InlineKeyboardButton.new(**button_options)
21
+ end
22
+
23
+ def options
24
+ arguments = {}
25
+ arguments.merge!(text: @text) if @text.present?
26
+ if @reply_markup.present?
27
+ arguments.merge!(reply_markup: Telegram::Bot::Types::ReplyKeyboardMarkup.new(**@reply_markup))
28
+ elsif @inline_keyboard.present?
29
+ keyboard = @inline_keyboard.map do |button|
30
+ if button[0].is_a? Array
31
+ button.map do |b|
32
+ build_options b
33
+ end
34
+ else
35
+ build_options button
36
+ end
37
+ end
38
+ arguments.merge!(reply_markup: Telegram::Bot::Types::InlineKeyboardMarkup.new(inline_keyboard: keyboard))
39
+ end
40
+ arguments
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Bots::Telegram::Custom::Notify::File
4
+ class << self
5
+ include Tramway::Bots::Telegram::MessagesManager
6
+
7
+ def send_to_user(bot_id, username, file)
8
+ bot_record = Bot.find bot_id
9
+ bot = ::Telegram::Bot::Client.new bot_record.token
10
+ chat = ::Tramway::Bots::Telegram::Chat.where(bot_id: bot_id).find_by "options ->> 'username' = '#{username}'"
11
+ bot_message = ::Tramway::Bots::Telegram::Leopold::Message.new file
12
+ send_file bot.api, chat.telegram_chat_id, bot_message
13
+ end
14
+
15
+ def send_to_chat(bot_id, chat_id, file)
16
+ bot_record = Bot.find bot_id
17
+ bot = ::Telegram::Bot::Client.new bot_record.token
18
+ bot_message = ::Tramway::Bots::Telegram::Leopold::Message.new file
19
+ send_file bot.api, chat_id, bot_message.file
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'telegram/bot'
4
+ require 'tramway/bots/telegram/messages_manager'
5
+
6
+ module Tramway::Bots::Telegram::Custom::Notify::Text
7
+ class << self
8
+ include ::Tramway::Bots::Telegram::MessagesManager
9
+
10
+ def send_to_user(bot_id, username, message)
11
+ bot_record = Tramway::Bots::Bot.find bot_id
12
+ bot = ::Telegram::Bot::Client.new bot_record.token
13
+ chat = Tramway::Bots::Telegram::Chat.where(bot_id: bot_id).find_by "options ->> 'username' = '#{username}'"
14
+ message_to_user bot.api, message, chat.telegram_chat_id if chat.present?
15
+ end
16
+
17
+ def send_to_chat(bot_id, chat_id, message, **options)
18
+ bot_record = Tramway::Bots::Bot.find bot_id
19
+ bot = ::Telegram::Bot::Client.new bot_record.token
20
+ message_to_chat bot.api, chat_id, message, **options
21
+ end
22
+
23
+ def send_to_channel(bot_id, channel_id, message)
24
+ bot_record = Tramway::Bots::Bot.find bot_id
25
+ bot = ::Telegram::Bot::Client.new bot_record.token
26
+ message_to_user bot.api, message, channel_id
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ module Bots
5
+ module Telegram
6
+ module Custom
7
+ module Notify
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tramway::Bots::Telegram::Custom::Scenario
4
+ include ::Tramway::Bots::Telegram::MessagesManager
5
+ include ::Tramway::Bots::Telegram::Info
6
+
7
+ attr_reader :bot, :bot_record, :chat, :message_from_telegram, :message, :user
8
+
9
+ def initialize(**options)
10
+ @bot = options[:bot]
11
+ @message_from_telegram = options[:message]
12
+ @bot_record = options[:bot_record]
13
+ @chat = options[:chat]
14
+ @message = options[:message_object]
15
+ @user = options[:user]
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tramway/bots/telegram'
4
+
5
+ module Tramway::Bots::Telegram::Custom
6
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Bots::Telegram::Info
4
+ def user_from(sender)
5
+ user = Tramway::Bots::Telegram::User.find_by telegram_id: sender.id
6
+ params = {
7
+ username: sender.username,
8
+ first_name: sender.first_name,
9
+ last_name: sender.last_name,
10
+ project_id: Project.find_by(title: 'PurpleMagic').id,
11
+ options: {
12
+ can_join_groups: sender.can_join_groups,
13
+ can_read_all_group_messages: sender.can_read_all_group_messages,
14
+ language_code: sender.language_code,
15
+ supports_inline_queries: sender.supports_inline_queries,
16
+ is_bot: sender.is_bot
17
+ }
18
+ }
19
+ if user.present?
20
+ user.update! params
21
+ user.reload
22
+ else
23
+ Tramway::Bots::Telegram::User.create! telegram_id: sender.id, **params
24
+ end
25
+ end
26
+
27
+ def chat_from(message_chat, bot_record)
28
+ chat = Tramway::Bots::Telegram::Chat.find_or_create_by! telegram_chat_id: message_chat.id, bot_id: bot_record.id
29
+ chat.update! title: message_chat.title,
30
+ bot_id: bot_record.id,
31
+ chat_type: message_chat.type,
32
+ project_id: Project.find_by(title: 'PurpleMagic').id,
33
+ options: (%i[
34
+ all_members_are_administrators can_set_sticker_set description first_name invite_link
35
+ last_name permissions photo pinned_message slow_mode_delay sticker_set_name
36
+ username
37
+ ].reduce({}) do |hash, attribute|
38
+ hash.merge! attribute => message_chat.send(attribute)
39
+ end)
40
+ chat.reload
41
+ end
42
+
43
+ def channel_from(channel, bot_record)
44
+ channel_record = Tramway::Bots::Telegram::Channel.find_or_create_by! telegram_channel_id: channel.id
45
+ channel_record.update! title: channel.title,
46
+ bot_id: bot_record.id,
47
+ project_id: Project.find_by(title: 'PurpleMagic').id
48
+ channel_record.reload
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'telegram/bot'
4
+
5
+ class BotTelegram::Custom::Message
6
+ attr_reader :file
7
+
8
+ def initialize(text: nil, file: nil, reply_markup: nil, inline_keyboard: nil)
9
+ raise 'You set text: argument for message' unless text.present?
10
+
11
+ @text = text
12
+ @file = file
13
+ @reply_markup = reply_markup
14
+ @inline_keyboard = inline_keyboard
15
+ end
16
+
17
+ def build_options(button)
18
+ button_options = { text: button[0] }
19
+ button_options.merge! callback_data: button[1][:data].to_json if button[1][:data].present?
20
+ Telegram::Bot::Types::InlineKeyboardButton.new(**button_options)
21
+ end
22
+
23
+ def options
24
+ arguments = {}
25
+ arguments.merge!(text: @text) if @text.present?
26
+ if @reply_markup.present?
27
+ arguments.merge!(reply_markup: Telegram::Bot::Types::ReplyKeyboardMarkup.new(**@reply_markup))
28
+ elsif @inline_keyboard.present?
29
+ keyboard = @inline_keyboard.map do |button|
30
+ if button[0].is_a? Array
31
+ button.map do |b|
32
+ build_options b
33
+ end
34
+ else
35
+ build_options button
36
+ end
37
+ end
38
+ arguments.merge!(reply_markup: Telegram::Bot::Types::InlineKeyboardMarkup.new(inline_keyboard: keyboard))
39
+ end
40
+ arguments
41
+ end
42
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Bots::Telegram::MessagesManager
4
+ def log_message(message, user, chat, bot)
5
+ file_path = "#{Rails.root}/lib/tasks/bot_telegram/bot_message_attributes.yml"
6
+ telegram_message_attributes = YAML.load_file(file_path)['telegram_message']['attributes']
7
+
8
+ message_object = Tramway::Bots::Telegram::Message.find_or_create_by(
9
+ telegram_message_id: message.message_id,
10
+ bot_id: bot.id,
11
+ user_id: user.id,
12
+ chat_id: chat.id
13
+ )
14
+
15
+ message_object.update! text: message.try(:text),
16
+ project_id: Project.find_by(title: 'PurpleMagic').id,
17
+ options: (telegram_message_attributes.reduce({}) do |hash, attribute|
18
+ hash.merge! attribute => message.send(attribute)
19
+ end)
20
+
21
+ message_object
22
+ end
23
+
24
+ # :reek:FeatureEnvy { enabled: false }
25
+ def message_to_chat(bot_api, chat_id, message_obj, **options)
26
+ case message_obj.class.to_s
27
+ when 'String'
28
+ send_string bot_api, chat_id, message_obj, **options
29
+ when 'Tramway::Bots::Telegram::Custom::Message'
30
+ bot_api.send_message chat_id: chat_id, **message_obj.options.merge(options)
31
+ send_file bot_api, chat_id, message_obj if message_obj.file.present?
32
+ else
33
+ raise message_obj.class.to_s
34
+ end
35
+ rescue StandardError => error
36
+ Airbrake.notify error
37
+ end
38
+ # :reek:FeatureEnvy { enabled: true }
39
+
40
+ def message_to_user(bot_api, message_obj, chat_id)
41
+ case message_obj.class.to_s
42
+ when 'String'
43
+ send_string bot_api, chat_id, message_obj
44
+ when 'Tramway::Bots::Telegram::Scenario::Step'
45
+ send_scenario_step bot_api, chat_id, message_obj
46
+ when 'Tramway::Bots::Telegram::Custom::Message'
47
+ bot_api.send_message chat_id: chat_id, **message_obj.options
48
+ end
49
+ rescue StandardError => error
50
+ Airbrake.notify error
51
+ end
52
+
53
+ def send_file(bot_api, chat_id, message_obj)
54
+ mime_type = case message_obj.file.file.file[-3..].downcase
55
+ when 'jpg', 'png'
56
+ [:photo, 'image/jpeg']
57
+ when 'mp3'
58
+ [:voice, 'audio/mpeg']
59
+ end
60
+ params = {
61
+ chat_id: chat_id,
62
+ mime_type[0] => Faraday::UploadIO.new(message_obj.file.file.file, mime_type[1])
63
+ }
64
+ if message_obj.reply_markup.present?
65
+ params.merge!(
66
+ reply_markup: Telegram::Bot::Types::ReplyKeyboardMarkup.new(**message_obj.reply_markup),
67
+ parse_mode: :markdown
68
+ )
69
+ end
70
+
71
+ bot_api.public_send "send_#{mime_type[0]}", **params
72
+ end
73
+
74
+ private
75
+
76
+ def send_string(bot_api, chat_id, message_obj, **options)
77
+ sleep 1
78
+ bot_api.send_message(
79
+ chat_id: chat_id,
80
+ text: message_obj,
81
+ **options
82
+ )
83
+ end
84
+
85
+ def send_scenario_step(bot_api, chat_id, message_obj)
86
+ if message_obj.try(:text).present?
87
+ if message_obj.reply_markup.present?
88
+ bot_api.send_message(
89
+ chat_id: chat_id,
90
+ text: message_obj&.text,
91
+ reply_markup: Telegram::Bot::Types::ReplyKeyboardMarkup.new(**message_obj.reply_markup),
92
+ parse_mode: :markdown
93
+ )
94
+ else
95
+ bot_api.send_message chat_id: chat_id, text: message_obj.text, parse_mode: :markdown
96
+ end
97
+ end
98
+ send_file bot_api, chat_id, message_obj if message_obj.file.path.present?
99
+ end
100
+ end
@@ -0,0 +1,6 @@
1
+ module Tramway
2
+ module Bots
3
+ module Telegram
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Tramway
2
+ module Bots
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require "tramway/bots/version"
2
+ require "tramway/bots/engine"
3
+ require 'tramway/bots/generates/install_generator'
4
+ require 'tramway/bots/telegram/custom'
5
+ require 'tramway/bots/telegram/info'
6
+
7
+ module Tramway
8
+ module Bots
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tramway-bots
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Pavel Kalashnikov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-06-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - kalashnikovisme@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - MIT-LICENSE
21
+ - README.md
22
+ - Rakefile
23
+ - app/assets/config/tramway_bots_manifest.js
24
+ - app/assets/stylesheets/tramway/bots/application.css
25
+ - app/controllers/tramway/bots/application_controller.rb
26
+ - app/helpers/tramway/bots/application_helper.rb
27
+ - app/jobs/tramway/bots/application_job.rb
28
+ - app/mailers/tramway/bots/application_mailer.rb
29
+ - app/models/tramway/bots/application_record.rb
30
+ - app/models/tramway/bots/bot.rb
31
+ - app/models/tramway/bots/telegram/channel.rb
32
+ - app/models/tramway/bots/telegram/chat.rb
33
+ - app/models/tramway/bots/telegram/message.rb
34
+ - app/models/tramway/bots/telegram/user.rb
35
+ - app/models/tramway/bots/telegram/users.rb
36
+ - app/models/tramway/bots/telegram/users/state.rb
37
+ - app/views/layouts/tramway/bots/application.html.erb
38
+ - config/routes.rb
39
+ - lib/tramway/bots.rb
40
+ - lib/tramway/bots/engine.rb
41
+ - lib/tramway/bots/generates/install_generator.rb
42
+ - lib/tramway/bots/generates/templates/create_tramway_bots_bots.rb
43
+ - lib/tramway/bots/generates/templates/create_tramway_bots_telegram_channels.rb
44
+ - lib/tramway/bots/generates/templates/create_tramway_bots_telegram_chats.rb
45
+ - lib/tramway/bots/generates/templates/create_tramway_bots_telegram_messages.rb
46
+ - lib/tramway/bots/generates/templates/create_tramway_bots_telegram_users.rb
47
+ - lib/tramway/bots/generates/templates/create_tramway_bots_telegram_users_states.rb
48
+ - lib/tramway/bots/telegram.rb
49
+ - lib/tramway/bots/telegram/custom.rb
50
+ - lib/tramway/bots/telegram/custom/message.rb
51
+ - lib/tramway/bots/telegram/custom/notify.rb
52
+ - lib/tramway/bots/telegram/custom/notify/file.rb
53
+ - lib/tramway/bots/telegram/custom/notify/text.rb
54
+ - lib/tramway/bots/telegram/custom/scenario.rb
55
+ - lib/tramway/bots/telegram/info.rb
56
+ - lib/tramway/bots/telegram/message.rb
57
+ - lib/tramway/bots/telegram/messages_manager.rb
58
+ - lib/tramway/bots/version.rb
59
+ homepage: https://github.com/Purple-Magic/tramway-bots
60
+ licenses:
61
+ - MIT
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubygems_version: 3.1.6
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Rails Engine for bot management
82
+ test_files: []