coins_paid_rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 76dfc07ca328248272a643ae517e9f4e3adfc8d4199df23c4e18aea9f90ee484
4
+ data.tar.gz: 522e768d858bc97704304a6021b42e06c5905cbebd151556de6d326a6fc5f62b
5
+ SHA512:
6
+ metadata.gz: 25c3a98da0c552ac54e791d4df5cf939ffdb47be6a6bf17dc1de240e03769c69dc2b1edfaaf492e52c53eec3b2ee20a105bb17bc04a6e2af410adb09dbbdbd42
7
+ data.tar.gz: e06207597934bcb1279527225c76ac08ffb0273cba8ad36d2db96a9a90e3fa3ac4e899b5c1a01f220ff3799ee43ee28ba00f6887a38634b33bd8905d434b01bb
@@ -0,0 +1,108 @@
1
+ version: 2.0
2
+ defaults: &defaults
3
+ docker:
4
+ - image: circleci/ruby:2.5-stretch-node
5
+ working_directory: ~/coins_paid
6
+
7
+ jobs:
8
+ checkout_code:
9
+ <<: *defaults
10
+ steps:
11
+ - checkout
12
+ - run: mkdir log
13
+ - save_cache:
14
+ key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
15
+ paths:
16
+ - ~/coins_paid
17
+
18
+ download_cc_reporter:
19
+ <<: *defaults
20
+ steps:
21
+ - run:
22
+ name: Download cc-test-reporter
23
+ command: |
24
+ mkdir -p cc/
25
+ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc/cc-test-reporter
26
+ chmod +x ./cc/cc-test-reporter
27
+ - persist_to_workspace:
28
+ root: ~/coins_paid
29
+ paths:
30
+ - cc/cc-test-reporter
31
+
32
+ run_bundler:
33
+ <<: *defaults
34
+ steps:
35
+ - restore_cache:
36
+ key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
37
+ - restore_cache:
38
+ key: v1-bundle-{{ checksum "Gemfile" }}
39
+ - run: echo "export rvm_ignore_gemsets_flag=1" >> ~/.rvmrc
40
+ - run: sudo apt-get update && sudo apt-get install -y libsodium-dev
41
+ - run: bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3
42
+ - save_cache:
43
+ key: v1-bundle-{{ checksum "Gemfile" }}
44
+ paths:
45
+ - ~/coins_paid/vendor/bundle
46
+
47
+ run_rspec_tests:
48
+ <<: *defaults
49
+ docker:
50
+ - image: circleci/ruby:2.5-stretch-node
51
+ environment:
52
+ RACK_ENV: "test"
53
+ CIRCLE_ARTIFACTS: "./tmp"
54
+ steps:
55
+ - restore_cache:
56
+ key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
57
+ - restore_cache:
58
+ key: v1-bundle-{{ checksum "Gemfile" }}
59
+ - attach_workspace:
60
+ at: ~/coins_paid
61
+ - run: sudo apt-get update && sudo apt-get install -y libsodium-dev
62
+ - run: bundle check --path vendor/bundle
63
+ - run: bundle exec rspec spec
64
+ - run: ./cc/cc-test-reporter format-coverage -t simplecov -o cc/codeclimate.rspec.json tmp/coverage/.resultset.json
65
+ - persist_to_workspace:
66
+ root: ~/coins_paid
67
+ paths:
68
+ - cc/codeclimate.rspec.json
69
+
70
+ upload_cc_coverage:
71
+ <<: *defaults
72
+ steps:
73
+ - attach_workspace:
74
+ at: ~/coins_paid
75
+ - run:
76
+ name: Upload coverage results to Code Climate
77
+ command: |
78
+ ./cc/cc-test-reporter upload-coverage -i cc/codeclimate.rspec.json
79
+
80
+ deploy:
81
+ <<: *defaults
82
+ steps:
83
+ - restore_cache:
84
+ key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
85
+ - restore_cache:
86
+ key: v1-bundle-{{ checksum "Gemfile" }}
87
+ - run: mkdir -p ~/.ssh && ssh-keyscan -H github.com >> ~/.ssh/known_hosts
88
+ - run: sudo apt-get update && sudo apt-get install -y libsodium-dev
89
+ - run: bundle check --path vendor/bundle
90
+ - run: bundle exec rake deploy:branch_or_label
91
+
92
+ workflows:
93
+ version: 2
94
+ build_test_deploy:
95
+ jobs:
96
+ - checkout_code
97
+ - download_cc_reporter:
98
+ requires:
99
+ - checkout_code
100
+ - run_bundler:
101
+ requires:
102
+ - download_cc_reporter
103
+ - run_rspec_tests:
104
+ requires:
105
+ - run_bundler
106
+ - upload_cc_coverage:
107
+ requires:
108
+ - run_rspec_tests
@@ -0,0 +1,3 @@
1
+ /*.gem
2
+ /Gemfile.lock
3
+ **/test.db
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://www.rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'simplecov', require: false
7
+ gem 'sqlite3'
8
+ gem 'rspec-its'
9
+ end
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'coins_paid_rails'
3
+ s.authors = ['Artem Biserov(artembiserov)', 'Oleg Ivanov(morhekil)']
4
+ s.version = '1.0.0'
5
+ s.files = `git ls-files`.split("\n")
6
+ s.summary = 'CoinsPaid Rails Integration'
7
+ s.license = 'MIT'
8
+
9
+ s.add_runtime_dependency 'coins_paid_api', '~> 1.0'
10
+ s.add_runtime_dependency 'activerecord', '>= 4.2.0'
11
+ s.add_runtime_dependency 'dry-initializer', '~> 3.0'
12
+ s.add_runtime_dependency 'dry-struct', '~> 1.0'
13
+ s.add_development_dependency 'rspec-rails', '~> 3.0'
14
+ end
15
+
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ require 'dry-struct'
3
+ require 'dry-initializer'
4
+ require_relative 'coins_paid/address'
5
+ require_relative 'coins_paid/coins_paid_address'
6
+ require_relative 'coins_paid/qr_code'
7
+
8
+ module CoinsPaid
9
+ module_function
10
+
11
+ UnknownCurrency = Class.new RuntimeError
12
+
13
+ DEFAULT_CONVERT_TO = ENV['COINS_PAID_CURRENCY']
14
+
15
+ CRYPTO_CURRENCIES = {
16
+ 'BTC' => 'bitcoin',
17
+ 'ETH' => 'ethereum',
18
+ 'LTC' => 'litecoin'
19
+ }.freeze
20
+
21
+ def address(foreign_id, currency:)
22
+ Address.new(foreign_id: foreign_id, currency: currency, convert_to: DEFAULT_CONVERT_TO).call
23
+ end
24
+
25
+ def qr_code(player_id, currency:, label:, message:)
26
+ QrCode.new(player_id, currency: currency, label: label, message: message)
27
+ end
28
+
29
+ def currency(name)
30
+ CoinsPaid::API.currencies_list.find { |item| item.currency == name } || raise(UnknownCurrency, name)
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoinsPaid
4
+ class Address
5
+ module Types
6
+ include Dry.Types()
7
+ end
8
+
9
+ class Data < Dry::Struct
10
+ attribute :foreign_id, Types::Coercible::String
11
+ attribute :currency, Types::String
12
+ attribute :convert_to, Types::String
13
+ end
14
+
15
+ include Dry::Initializer.define -> do
16
+ param :request_data, Data
17
+ end
18
+
19
+ def call
20
+ CoinsPaidAddress.find_or_create_by!(request_data.attributes.slice(:foreign_id, :currency)) do |address|
21
+ response = CoinsPaid::API.take_address(request_data.attributes)
22
+ address.assign_attributes(response.attributes)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoinsPaid
4
+ class CoinsPaidAddress < ActiveRecord::Base
5
+ end
6
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoinsPaid
4
+ class QrCode
5
+ include Dry::Initializer.define -> do
6
+ param :player_id
7
+ option :currency
8
+ option :label
9
+ option :message
10
+ end
11
+
12
+ def url
13
+ "#{token_type}:#{address}?label=#{encode(label)}&message=#{encode(message)}"
14
+ end
15
+
16
+ def address
17
+ @address ||= CoinsPaid.address(player_id, currency: currency).address
18
+ end
19
+
20
+ def svg
21
+ RQRCode::QRCode.new(url).as_svg(
22
+ offset: 0,
23
+ color: '000',
24
+ shape_rendering: 'crispEdges',
25
+ module_size: 3,
26
+ standalone: true
27
+ )
28
+ end
29
+
30
+ private
31
+
32
+ def token_type
33
+ CRYPTO_CURRENCIES.fetch(currency)
34
+ end
35
+
36
+ def encode(string)
37
+ URI.encode_www_form_component(string)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'coins_paid'
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoinsPaid
4
+ module MigrationData
5
+ module_function
6
+
7
+ def get
8
+ <<RUBY
9
+ create_table :coins_paid_addresses do |t|
10
+ t.string :foreign_id, null: false
11
+ t.string :currency, null: false
12
+ t.string :address, null: false
13
+ t.string :tag
14
+ t.integer :external_id, null: false
15
+
16
+ t.timestamps
17
+ t.index [:foreign_id, :currency], unique: true
18
+ end
19
+ RUBY
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators/active_record'
3
+ require_relative 'migration_data'
4
+
5
+ module CoinsPaid
6
+ module Generators
7
+ class MigrationGenerator < ActiveRecord::Generators::Base
8
+ argument :name, default: 'create_coins_paid_addresses'
9
+ source_root File.expand_path("templates", __dir__)
10
+
11
+ def copy_coins_paid_migration
12
+ migration_template 'migration.rb', "#{db_migrate_path}/#{file_name}.rb"
13
+ end
14
+
15
+ def migration_data
16
+ CoinsPaid::MigrationData.get
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Create<%= table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
+ def change
5
+ <%= migration_data %>
6
+ end
7
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe CoinsPaid, '.address' do
4
+ let(:foreign_key) { 'user-id:2048' }
5
+ let(:currency) { 'BTC' }
6
+ let(:full_address_attributes) do
7
+ {
8
+ foreign_id: foreign_key,
9
+ currency: currency
10
+ }.merge(address_attributes)
11
+ end
12
+ let(:address_attributes) do
13
+ {
14
+ external_id: 1,
15
+ address: '12983h13ro1hrt24it432t',
16
+ tag: 'tag-123',
17
+ }
18
+ end
19
+ subject(:take_address) { described_class.address(foreign_key, currency: currency) }
20
+
21
+ context 'when there is existing record' do
22
+ let!(:address) do
23
+ CoinsPaid::CoinsPaidAddress.create!(full_address_attributes)
24
+ end
25
+
26
+ before do
27
+ allow(CoinsPaid::API).to receive(:take_address)
28
+ end
29
+
30
+ it 'returns existing record' do
31
+ expect(take_address).to eq address
32
+
33
+ expect(CoinsPaid::API).not_to have_received(:take_address)
34
+ end
35
+ end
36
+
37
+ context 'when coins paid api responds with error' do
38
+ before do
39
+ allow(CoinsPaid::API).to receive(:take_address).and_raise(CoinsPaid::API::Error)
40
+ end
41
+
42
+ it 'raises error' do
43
+ expect { take_address }.to raise_error(CoinsPaid::API::Error)
44
+ end
45
+ end
46
+
47
+ context 'when coins paid return valid response' do
48
+ before do
49
+ allow(CoinsPaid::API).to receive(:take_address).and_return(CoinsPaid::API::TakeAddress::Response.new(address_attributes))
50
+ end
51
+
52
+ it 'creates new address' do
53
+ expect(take_address).to have_attributes(full_address_attributes)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe CoinsPaid, '.currency' do
4
+ let(:eth) { instance_double(CoinsPaid::API::Currency, currency: 'ETH') }
5
+
6
+ subject(:currency) { described_class.currency(eth.currency) }
7
+
8
+ context 'when CoinsPaid API responds correctly' do
9
+ before do
10
+ allow(CoinsPaid::API).to receive(:currencies_list) { currencies }
11
+ end
12
+
13
+ context 'and currency exists at CoinsPaid' do
14
+ let(:currencies) do
15
+ [eth, instance_double(CoinsPaid::API::Currency, currency: 'm' + eth.currency)]
16
+ end
17
+
18
+ it 'returns requested currency details' do
19
+ expect(currency).to eq eth
20
+ end
21
+ end
22
+
23
+ context 'and currency does not exist at CoinsPaid' do
24
+ let(:currencies) do
25
+ [instance_double(CoinsPaid::API::Currency, currency: 'm' + eth.currency)]
26
+ end
27
+
28
+ it 'errors' do
29
+ expect { currency }.to raise_error(CoinsPaid::UnknownCurrency)
30
+ end
31
+ end
32
+ end
33
+
34
+ context 'when coins paid api errors' do
35
+ before do
36
+ allow(CoinsPaid::API).to receive(:currencies_list).and_raise(CoinsPaid::API::Error)
37
+ end
38
+
39
+ it 're-raises error' do
40
+ expect { currency }.to raise_error(CoinsPaid::API::Error)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe CoinsPaid, '.qr_code' do
4
+ let(:foreign_id) { 123 }
5
+ let(:coins_paid_address) do
6
+ instance_double CoinsPaid::CoinsPaidAddress,
7
+ currency: 'BTC',
8
+ address: 'abc123'
9
+ end
10
+ subject(:qr_code) do
11
+ described_class.qr_code(
12
+ foreign_id,
13
+ currency: 'BTC',
14
+ label: 'RedStar deposit',
15
+ message: 'Make a deposit to RedStar'
16
+ )
17
+ end
18
+
19
+ before do
20
+ allow(CoinsPaid).to receive(:address).with(foreign_id, currency: 'BTC').and_return(coins_paid_address)
21
+ end
22
+
23
+ describe '#payment_url' do
24
+ its(:url) { is_expected.to eq 'bitcoin:abc123?label=RedStar+deposit&message=Make+a+deposit+to+RedStar' }
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ ENV['COINS_PAID_CURRENCY'] = 'EUR'
2
+
3
+ if ENV['CIRCLE_ARTIFACTS']
4
+ require 'simplecov'
5
+ SimpleCov.start
6
+ end
7
+
8
+ require 'active_record'
9
+ require "active_record/railtie"
10
+ require 'rspec/rails'
11
+ require 'rspec/its'
12
+
13
+ require 'coins_paid_api'
14
+ require 'coins_paid_rails'
15
+
16
+ Dir['./spec/support/**/*.rb'].each { |f| require f }
17
+
18
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'spec/test.db')
19
+
20
+ RSpec.configure do |config|
21
+ config.use_transactional_fixtures = true
22
+
23
+ config.before :suite do
24
+ CreateTable.migrate(:up)
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ require_relative '../../../lib/generators/coins_paid/migration_data'
3
+
4
+ class CreateTable < ActiveRecord::Migration[ActiveRecord::Migration.current_version]
5
+ def up
6
+ drop_table :coins_paid_addresses if table_exists?(:coins_paid_addresses)
7
+
8
+ migration_data
9
+ end
10
+
11
+ def migration_data
12
+ instance_eval CoinsPaid::MigrationData.get
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: coins_paid_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Artem Biserov(artembiserov)
8
+ - Oleg Ivanov(morhekil)
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-11-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: coins_paid_api
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: activerecord
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 4.2.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 4.2.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: dry-initializer
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: dry-struct
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec-rails
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '3.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '3.0'
84
+ description:
85
+ email:
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".circleci/config.yml"
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - Gemfile
94
+ - coins_paid_rails.gemspec
95
+ - lib/coins_paid.rb
96
+ - lib/coins_paid/address.rb
97
+ - lib/coins_paid/coins_paid_address.rb
98
+ - lib/coins_paid/qr_code.rb
99
+ - lib/coins_paid_rails.rb
100
+ - lib/generators/coins_paid/migration_data.rb
101
+ - lib/generators/coins_paid/migration_generator.rb
102
+ - lib/generators/coins_paid/templates/migration.rb
103
+ - spec/address_spec.rb
104
+ - spec/currency_spec.rb
105
+ - spec/qr_code_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/support/database/create_table.rb
108
+ homepage:
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.7.6
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: CoinsPaid Rails Integration
132
+ test_files: []