Commit 0875df37 authored by nazarf's avatar nazarf

add telegram bot, nottify, trigger

parent 8270064e
...@@ -31,6 +31,9 @@ gem 'devise-i18n' ...@@ -31,6 +31,9 @@ gem 'devise-i18n'
gem 'simple_form' gem 'simple_form'
gem 'nested_form' gem 'nested_form'
gem 'will_paginate' gem 'will_paginate'
gem 'curb'
gem 'telegram-bot-ruby'
gem 'whenever', require: false
......
GEM
remote: https://rubygems.org/
specs:
actioncable (5.2.4.2)
actionpack (= 5.2.4.2)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.4.2)
actionpack (= 5.2.4.2)
actionview (= 5.2.4.2)
activejob (= 5.2.4.2)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.4.2)
actionview (= 5.2.4.2)
activesupport (= 5.2.4.2)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.2.4.2)
activesupport (= 5.2.4.2)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.2.4.2)
activesupport (= 5.2.4.2)
globalid (>= 0.3.6)
activemodel (5.2.4.2)
activesupport (= 5.2.4.2)
activerecord (5.2.4.2)
activemodel (= 5.2.4.2)
activesupport (= 5.2.4.2)
arel (>= 9.0)
activestorage (5.2.4.2)
actionpack (= 5.2.4.2)
activerecord (= 5.2.4.2)
marcel (~> 0.3.1)
activesupport (5.2.4.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
autoprefixer-rails (9.7.5)
execjs
bcrypt (3.1.13)
bindex (0.8.1)
bootstrap (4.4.1)
autoprefixer-rails (>= 9.1.0)
popper_js (>= 1.14.3, < 2)
sassc-rails (>= 2.0.0)
bootstrap-will_paginate (1.0.0)
will_paginate
builder (3.2.4)
byebug (11.1.1)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.1.6)
crass (1.0.6)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise-i18n (1.9.1)
devise (>= 4.7.1)
erubi (1.9.0)
erubis (2.7.0)
execjs (2.7.0)
ffi (1.12.2)
font-awesome-sass (5.12.0)
sassc (>= 1.11)
globalid (0.4.2)
activesupport (>= 4.2.0)
haml (5.1.2)
temple (>= 0.8.0)
tilt
haml-rails (2.0.1)
actionpack (>= 5.1)
activesupport (>= 5.1)
haml (>= 4.0.6, < 6.0)
html2haml (>= 1.0.1)
railties (>= 5.1)
html2haml (2.2.0)
erubis (~> 2.7.0)
haml (>= 4.0, < 6)
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
i18n (1.8.2)
concurrent-ruby (~> 1.0)
jbuilder (2.10.0)
activesupport (>= 5.0.0)
jquery-rails (4.3.5)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jquery-ui-rails (6.0.1)
railties (>= 3.2.16)
js_cookie_rails (2.2.0)
railties (>= 3.1)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
loofah (2.4.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (1.0.0)
mimemagic (0.3.4)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.14.0)
mysql2 (0.4.10)
nested_form (0.3.2)
nio4r (2.5.2)
nokogiri (1.10.9)
mini_portile2 (~> 2.4.0)
orm_adapter (0.5.0)
popper_js (1.16.0)
puma (3.12.4)
rack (2.2.2)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (5.2.4.2)
actioncable (= 5.2.4.2)
actionmailer (= 5.2.4.2)
actionpack (= 5.2.4.2)
actionview (= 5.2.4.2)
activejob (= 5.2.4.2)
activemodel (= 5.2.4.2)
activerecord (= 5.2.4.2)
activestorage (= 5.2.4.2)
activesupport (= 5.2.4.2)
bundler (>= 1.3.0)
railties (= 5.2.4.2)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
railties (5.2.4.2)
actionpack (= 5.2.4.2)
activesupport (= 5.2.4.2)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rake (13.0.1)
rb-fsevent (0.10.3)
rb-inotify (0.10.1)
ffi (~> 1.0)
responders (3.0.0)
actionpack (>= 5.0)
railties (>= 5.0)
ruby_dep (1.5.0)
ruby_parser (3.14.2)
sexp_processor (~> 4.9)
sassc (2.2.1)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
sexp_processor (4.14.1)
simple_form (5.0.2)
actionpack (>= 5.0)
activemodel (>= 5.0)
spring (2.1.0)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
temple (0.8.2)
thor (1.0.1)
thread_safe (0.3.6)
tilt (2.0.10)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (1.2.6)
thread_safe (~> 0.1)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
warden (1.2.8)
rack (>= 2.0.6)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
websocket-driver (0.7.1)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.4)
will_paginate (3.3.0)
PLATFORMS
ruby
DEPENDENCIES
bcrypt (~> 3.1.7)
bootstrap (~> 4.4.1)
bootstrap-will_paginate
byebug
coffee-rails (~> 4.2)
devise
devise-i18n
font-awesome-sass (~> 5.12.0)
haml-rails
jbuilder (~> 2.5)
jquery-rails
jquery-ui-rails
js_cookie_rails
listen (>= 3.0.5, < 3.2)
mysql2 (>= 0.3.18, < 0.5)
nested_form
puma (~> 3.7)
rails (~> 5.2)
sassc-rails
simple_form
spring
spring-watcher-listen (~> 2.0.0)
turbolinks (~> 5)
uglifier (>= 1.3.0)
web-console (>= 3.3.0)
will_paginate
BUNDLED WITH
1.17.3
class TriggersController < ApplicationController
before_action :set_trigger, only: %i[ show edit update destroy ]
# GET /triggers or /triggers.json
def index
@triggers = Trigger.all
end
# GET /triggers/1 or /triggers/1.json
def show
end
# GET /triggers/new
def new
@trigger = Trigger.new
end
# GET /triggers/1/edit
def edit
end
# POST /triggers or /triggers.json
def create
@trigger = Trigger.new(trigger_params)
respond_to do |format|
if @trigger.save
format.html { redirect_to @trigger, notice: "Trigger was successfully created." }
format.json { render :show, status: :created, location: @trigger }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @trigger.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /triggers/1 or /triggers/1.json
def update
respond_to do |format|
if @trigger.update(trigger_params)
format.html { redirect_to @trigger, notice: "Trigger was successfully updated." }
format.json { render :show, status: :ok, location: @trigger }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @trigger.errors, status: :unprocessable_entity }
end
end
end
# DELETE /triggers/1 or /triggers/1.json
def destroy
@trigger.destroy
respond_to do |format|
format.html { redirect_to triggers_url, notice: "Trigger was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_trigger
@trigger = Trigger.find(params[:id])
end
# Only allow a list of trusted parameters through.
def trigger_params
params.require(:trigger).permit(:collection_name, :name, :rarity, :price, :enable)
end
end
class Notify < ApplicationRecord
belongs_to :trigger
after_create :notify
def notify
require 'telegram/bot'
token = '1711433709:AAFn8Yczyc435Dz7aIDph2fptpGU0doRLhk'
Telegram::Bot::Client.run(token) do |bot|
bot.api.sendMessage(chat_id: "@MarketGrab", text: "collection: #{trigger.name}\nrarity: #{trigger.rarity}\nprice: #{trigger.price}\n#{sale_link}")
end
end
def sale_link
"https://wax.atomichub.io/market/sale/#{sale_id}"
end
end
class Trigger < ApplicationRecord
has_many :notify
validates :collection_name, :name, :rarity, :price, presence: true
scope :enable, -> { where(enable: true) }
scope :collection_name, -> (name) { where(collection_name: name) }
end
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
= icon('fas', 'users', class: 'fa-fw') + "\n" + tag.span("Користувачі") = icon('fas', 'users', class: 'fa-fw') + "\n" + tag.span("Користувачі")
%li.nav-item
= link_to triggers_path, class: 'nav-link' do
= icon('fas', 'triggers', class: 'fa-fw') + "\n" + tag.span("Трігер")
%hr.sidebar-divider.d-none.d-md-block %hr.sidebar-divider.d-none.d-md-block
/ Sidebar Toggler (Sidebar) / Sidebar Toggler (Sidebar)
......
.row
.col-12.col-lg-6
.card.shadow.mb-4
.card-header.py-3
%h2.d-inline.m-0.font-weight-bold.text-primary= captures[:heading]
.float-right= captures[:links]
.card-body
= simple_form_for @trigger do |f|
= f.input :collection_name
= f.input :name
= f.input :rarity
= f.input :price
= f.input :enable
= f.submit "Save", class: "btn btn-success"
- captures[:heading] = capture do
Editing trigger
- captures[:links] = capture do
= link_to icon('fas', 'eye', class: 'fa-2x ml-2', title: 'Show'), @user
= link_to icon('fas', 'reply', class: 'fa-2x ml-2', title: 'Back'), users_path
= render 'form'
- model = Trigger
.card.shadow.mb-4
.card-header.py-3
%h2.d-inline.m-0.font-weight-bold.text-primary= model.model_name.human(count: 2)
.float-right= link_to icon('fas', 'plus-square', class: "fa-2x", title: "New #{model.model_name.human}"), new_trigger_path
.float-right= link_to icon('fas', 'share-square', class: "fa-2x", title: "Bot"), "https://t.me/marketParserNotifyBot", target: :_blank
.card-body
.table-responsive
%table.table.table-bordered.admin-table
%thead
%tr
%th= model.human_attribute_name(:name)
%th= model.human_attribute_name(:collection_name)
%th= model.human_attribute_name(:rarity)
%th= model.human_attribute_name(:price)
%th= model.human_attribute_name(:enable)
%th Actions
%tbody
- @triggers.each do |trigger|
%tr
%td= link_to trigger.name, trigger
%td= trigger.collection_name
%td= trigger.rarity
%td= trigger.price
%td= trigger.enable
%td
= link_to icon('fas', 'eye', title: "Show"), trigger_path(trigger)
= link_to icon('fas', 'edit', title: "Edit"), edit_trigger_path(trigger)
= link_to icon('fas', 'trash-alt', title: "Delete"), trigger_path(trigger), method: :delete, data: {confirm: "Are you sure?"}
- captures[:heading] = capture do
New trigger
- captures[:links] = capture do
= link_to icon('fas', 'reply', class: 'fa-2x ml-2', title: 'Back'), triggers_path
= render 'form'
.row
.col-12.col-lg-6
.card.shadow.mb-4
.card-header.py-3
%h2.d-inline.m-0.font-weight-bold.text-primary= Trigger
.float-right
= link_to icon('fas', 'edit', class: 'fa-2x ml-2', title: 'Edit'), edit_trigger_path(@trigger)
= link_to icon('fas', 'trash-alt', class: 'fa-2x ml-2', title: 'Delete'), @trigger, method: :delete, data: {confirm: "Are you sure?"}
= link_to icon('fas', 'reply', class: 'fa-2x ml-2', title: 'Back'), triggers_path
.card-body
%p
%b Collection name:
= @trigger.collection_name
%p
%b Name:
= @trigger.name
%p
%b Rarity:
= @trigger.rarity
%p
%b Price:
= @trigger.price
%p
%b Enable:
= @trigger.enable
.row
.card-body
.table-responsive
%table.table.table-bordered.admin-table
%thead
%tr
%th= "name"
%th Actions
%tbody
- @trigger.notify.each do |user|
%tr
%td= link_to user.sale_id, user.sale_link, target: :_blank
%td
\ No newline at end of file
...@@ -14,8 +14,7 @@ default: &default ...@@ -14,8 +14,7 @@ default: &default
encoding: utf8 encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root username: root
password: root host: 127.0.0.1
host: database
development: development:
<<: *default <<: *default
......
Rails.application.routes.draw do Rails.application.routes.draw do
resources :triggers
devise_for :users devise_for :users
resources :users resources :users
......
set :output, 'log/cron.log'
every :minute, roles: [:app] do
rake "atomic_market:grep_sale", output: 'log/atomic_market_grep_sale.log'
end
\ No newline at end of file
class CreateTriggers < ActiveRecord::Migration[5.2]
def change
create_table :triggers do |t|
t.string :collection_name
t.string :name
t.string :rarity
t.string :price
t.boolean :enable, default: true
t.timestamps
end
end
end
class CreateNotifies < ActiveRecord::Migration[5.2]
def change
create_table :notifies do |t|
t.string :sale_id
t.references :trigger, foreign_key: true
end
end
end
...@@ -10,9 +10,25 @@ ...@@ -10,9 +10,25 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_04_05_142932) do ActiveRecord::Schema.define(version: 2021_05_15_143911) do
create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| create_table "notifies", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "sale_id"
t.bigint "trigger_id"
t.index ["trigger_id"], name: "index_notifies_on_trigger_id"
end
create_table "triggers", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "collection_name"
t.string "name"
t.string "rarity"
t.string "price"
t.boolean "enable", default: true
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "name", null: false t.string "name", null: false
t.string "email" t.string "email"
t.string "encrypted_password", null: false t.string "encrypted_password", null: false
...@@ -21,4 +37,5 @@ ActiveRecord::Schema.define(version: 2020_04_05_142932) do ...@@ -21,4 +37,5 @@ ActiveRecord::Schema.define(version: 2020_04_05_142932) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
add_foreign_key "notifies", "triggers"
end end
...@@ -5,4 +5,4 @@ ...@@ -5,4 +5,4 @@
# #
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
# Character.create(name: 'Luke', movie: movies.first) # Character.create(name: 'Luke', movie: movies.first)
# TODO @kolosfed wright damn seeds User.create(name: "admin", email: "admin@example.com", password: "password")
\ No newline at end of file
namespace :atomic_market do
desc "TODO"
task grep_sale: :environment do
Trigger.enable.pluck(:collection_name).uniq.each do |collection_name|
triggers = Trigger.find_by(collection_name: collection_name)
http = Curl.post("http://wax.api.atomicassets.io/atomicmarket/v1/sales", { :collection_name => triggers.collection_name, :order => "desc", :sort => "created", :symbol => "WAX" })
parsed = JSON.parse(http.body_str)
# file = open("test.json")
# json = file.read
# parsed = JSON.parse(json)
parsed["data"].each do |shop|
name = shop["assets"][0]["template"]["immutable_data"]["name"]
rarity = shop["assets"][0]["template"]["immutable_data"]["rarity"]
sale_id = shop["sale_id"]
price = shop["listing_price"][0...-8].to_i
Trigger.enable.collection_name(triggers.collection_name).each do |trigger|
if trigger.name == name
if trigger.rarity == rarity
if trigger.price.to_i >= price
if Notify.find_by(sale_id: sale_id).blank?
Notify.create(sale_id: sale_id, trigger: trigger)
end
end
end
end
end
end
end
end
end
require 'telegram/bot'
token = '1711433709:AAFn8Yczyc435Dz7aIDph2fptpGU0doRLhk'
Telegram::Bot::Client.run(token) do |bot|
bot.listen do |message|
case message.text
when '/start'
bot.api.sendMessage(chat_id: message.chat.id, text: "Hello, #{message.from.first_name}")
end
end
end
\ No newline at end of file
{
"success": true,
"data": [
{
"market_contract": "atomicmarket",
"assets_contract": "atomicassets",
"sale_id": "14092459",
"seller": "rakedenxriva",
"buyer": null,
"offer_id": "14300767",
"price": {
"token_contract": "eosio.token",
"token_symbol": "WAX",
"token_precision": 8,
"median": null,
"amount": "30000000000"
},
"listing_price": "30000000000",
"listing_symbol": "WAX",
"assets": [
{
"contract": "atomicassets",
"asset_id": "1099519503475",
"owner": "rakedenxriva",
"is_transferable": true,
"is_burnable": true,
"collection": {
"collection_name": "rplanet",
"name": "RPlanet",
"img": "QmegodhiwaGMsKhCe74WjFtojrm7fPoFHP4w7HBJLd5qAP",
"author": "rplanet",
"allow_notify": true,
"authorized_accounts": [
"rplanet",
"u.rplanet",
"atomicdropsx",
"a.rplanet",
"l.rplanet"
],
"notify_accounts": [
"rplanet",
"u.rplanet"
],
"market_fee": 0.08,
"created_at_block": "105641520",
"created_at_time": "1614258637000"
},
"schema": {
"schema_name": "rigs2",
"format": [
{
"name": "name",
"type": "string"
},
{
"name": "img",
"type": "image"
},
{
"name": "edition",
"type": "uint8"
},
{
"name": "rarity",
"type": "string"
},
{
"name": "description",
"type": "string"
}
],
"created_at_block": "108221385",
"created_at_time": "1615549216500"
},
"template": {
"template_id": "69825",
"max_supply": "0",
"is_transferable": true,
"is_burnable": true,
"issued_supply": "395",
"immutable_data": {
"img": "https://static.rplanet.io/nft/rigs2/1/turntable_rig_3_1_common.png",
"name": "Turntable Rig 3.1",
"rarity": "common",
"edition": 1,
"description": "The Card is not just a collectible, it's also a highly efficient tool for mining aether in the R-Planet game. Stake the card and get hourly rewards."
},
"created_at_time": "1615549284500",
"created_at_block": "108221521"
},
"mutable_data": {},
"immutable_data": {},
"template_mint": "123",
"backed_tokens": [],
"burned_by_account": null,
"burned_at_block": null,
"burned_at_time": null,
"updated_at_block": "119131745",
"updated_at_time": "1621007286500",
"transferred_at_block": "119131745",
"transferred_at_time": "1621007286500",
"minted_at_block": "108620253",
"minted_at_time": "1615748684000",
"data": {
"img": "https://static.rplanet.io/nft/rigs2/1/turntable_rig_3_1_common.png",
"name": "Turntable Rig 3.1",
"rarity": "common",
"edition": 1,
"description": "The Card is not just a collectible, it's also a highly efficient tool for mining aether in the R-Planet game. Stake the card and get hourly rewards."
},
"name": "Turntable Rig 3.1"
}
],
"maker_marketplace": "",
"taker_marketplace": null,
"collection_name": "rplanet",
"collection": {
"collection_name": "rplanet",
"name": "RPlanet",
"img": "QmegodhiwaGMsKhCe74WjFtojrm7fPoFHP4w7HBJLd5qAP",
"author": "rplanet",
"allow_notify": true,
"authorized_accounts": [
"rplanet",
"u.rplanet",
"atomicdropsx",
"a.rplanet",
"l.rplanet"
],
"notify_accounts": [
"rplanet",
"u.rplanet"
],
"market_fee": 0.08,
"created_at_block": "105641520",
"created_at_time": "1614258637000"
},
"is_seller_contract": false,
"updated_at_block": "119145373",
"updated_at_time": "1621014101000",
"created_at_block": "119145373",
"created_at_time": "1621014101000",
"state": 1
}
],
"query_time": 1621014141772
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment