paystack 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5498e1e46aa43b8b36bbe6717e67705e645dfe2e
4
+ data.tar.gz: 762398e50ef02e69410a777931d4c5038b41f80f
5
+ SHA512:
6
+ metadata.gz: e7d36bf5bac98d6770532a75079d8a9a7feec251a39c111093061877a55c841635dadee56fa9db034b9320b380622159823eead2cc267fa8894181b0d2a74777
7
+ data.tar.gz: db2befad8679043461b539842ef684b76d18eab920d4c38fca96405b6a7bcdf3ab2344477f4c0af64769656a40029b5d4c4920e68d7f948aabffee007d0b0cc0
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at ikoro.victor@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in paystack.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Victor Ikoro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # Paystack
2
+
3
+
4
+ A ruby gem for easy integration of Paystack with your Ruby / Rails application.
5
+
6
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/paystack`. To experiment with that code, run `bin/console` for an interactive prompt.
7
+
8
+ TODO: Delete this and the text above, and describe your gem
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'paystack'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install paystack
25
+
26
+ ## Usage
27
+
28
+ ### 1. Instantiate Paystack Object
29
+
30
+ paystack = Paystack.new(public_key, secret_key)
31
+
32
+ A more secure way is to set your public and private keys as environmental variables `PAYSTACK_PUBLIC_KEY` and `PAYSTACK_PRIVATE_KEY` respectively. Then you instantiate without parameters
33
+
34
+ ```ruby
35
+
36
+ paystack = Paystack.new
37
+
38
+ ```
39
+
40
+ Methods available in the Paystack class include
41
+
42
+
43
+
44
+ ### 2. Instantiate a Card object
45
+
46
+ ```ruby
47
+ card = new PaystackCard(
48
+ :number => "304402040400400022",
49
+ :cvc => "888",
50
+ :expiryMonth => "07",
51
+ :expiryYear => "19"
52
+ )
53
+ ```
54
+
55
+
56
+
57
+
58
+ ## Development
59
+
60
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
61
+
62
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
63
+
64
+ ## Contributing
65
+
66
+ Bug reports and pull requests are welcome on GitHub at https://github.com/IkoroVictor/paystack-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
67
+
68
+
69
+ ## License
70
+
71
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
72
+
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "paystack"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/key.pem ADDED
File without changes
data/lib/paystack.rb ADDED
@@ -0,0 +1,84 @@
1
+ require 'rest-client'
2
+ require 'paystack/modules/tokenmanager.rb'
3
+ require 'paystack/error.rb'
4
+ require 'paystack/utils/utils.rb'
5
+
6
+ require 'paystack/objects/card.rb'
7
+ require 'paystack/objects/customers.rb'
8
+ require 'paystack/objects/plans.rb'
9
+ require 'paystack/objects/transactions.rb'
10
+
11
+
12
+ class Paystack
13
+ attr_reader :public_key, :private_key
14
+
15
+ def initialize paystack_public_key=nil, paystack_private_key=nil
16
+ if(paystack_public_key.nil?)
17
+ @public_key = ENV['PAYSTACK_PUBLIC_KEY']
18
+
19
+ else
20
+ @public_key = paystack_public_key
21
+ end
22
+
23
+ if(paystack_private_key.nil?)
24
+ @private_key = ENV['PAYSTACK_PRIVATE_KEY']
25
+ else
26
+ @private_key = paystack_private_key
27
+ end
28
+
29
+ unless !@public_key.nil?
30
+ raise PaystackBadKeyError, "No public key supplied and couldn't find any in environment variables. Make sure to set public key as an environment variable PAYSTACK_PUBLIC_KEY"
31
+ end
32
+ unless @public_key[0..2] == 'pk_'
33
+ raise PaystackBadKeyError, "Invalid public key #{@public_key}"
34
+ end
35
+
36
+ unless !@private_key.nil?
37
+ raise PaystackBadKeyError, "No private key supplied and couldn't find any in environment variables. Make sure to set private key as an environment variable PAYSTACK_PRIVATE_KEY"
38
+ end
39
+ unless @private_key[0..2] == 'sk_'
40
+ raise PaystackBadKeyError, "Invalid private key #{@private_key}"
41
+ end
42
+
43
+
44
+ end
45
+
46
+ def getToken card
47
+ return TokenManager.create(card, @public_key)
48
+ end
49
+
50
+ def setPublicKey public_key
51
+ @public_key = public_key
52
+ end
53
+
54
+ def setPrivateKey public_key
55
+ @public_key = public_key
56
+ end
57
+
58
+ # def chargeToken(token, amount,args = {})
59
+ # token = token;
60
+ # amount = amount
61
+ # email = args[:email]
62
+ # reference = args[:reference]
63
+ # result = nil;
64
+ #
65
+ # begin
66
+ # response = RestClient.post "#{API::BASE_URL}#{API::TRANSACTION_PATH}/charge_token", {:token => token, :amount => amount, :email => email, :reference => reference}.to_json, :Authorization => "Bearer #{@private_key}", :content_type => :json, :accept => :json
67
+ # unless (response.code == 200 || response.code == 201)
68
+ # raise PaystackServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
69
+ # end
70
+ # result = JSON.parse(response.body)
71
+ # unless(result['status'] != 0 )
72
+ # raise PaystackServerError.new(response), "Server Message: #{result['message']}"
73
+ # end
74
+ #
75
+ # rescue JSON::ParserError => jsonerr
76
+ # raise PaystackServerError.new(response) , "Invalid result data. Could not parse JSON response body \n #{jsonerr.message}"
77
+ #
78
+ # rescue PaystackServerError => e
79
+ # Utils.serverErrorHandler(e)
80
+ # end
81
+ # return result
82
+ # end
83
+
84
+ end
@@ -0,0 +1,13 @@
1
+
2
+ class PaystackServerError < StandardError
3
+ attr_reader :response
4
+ def initialize(response=nil)
5
+ @response = response
6
+ end
7
+ end
8
+
9
+ class PaystackCardError < StandardError
10
+ end
11
+
12
+ class PaystackBadKeyError < StandardError
13
+ end
@@ -0,0 +1,7 @@
1
+ module API
2
+ BASE_URL = "https://api.paystack.co"
3
+ TOKEN_URL ='https://standard.paystack.co/bosco/createmobiletoken'
4
+ TRANSACTION_PATH = "/transaction"
5
+ PLAN_PATH = "/plan"
6
+ CUSTOMER_PATH = "/customer"
7
+ end
@@ -0,0 +1,11 @@
1
+ require "Base64"
2
+ require "openssl"
3
+
4
+ module Crypto
5
+
6
+ def Crypto.encrypt_string(message, public_key)
7
+
8
+ rsa = OpenSSL::PKey::RSA.new public_key
9
+ return Base64::encode64(rsa.public_encrypt(message)).rstrip
10
+ end
11
+ end
@@ -0,0 +1,60 @@
1
+ require 'rest-client'
2
+ require 'paystack/modules/crypto.rb'
3
+ require 'paystack/modules/api.rb'
4
+ require 'paystack/objects/card.rb'
5
+
6
+ module TokenManager
7
+
8
+ CONCATENATOR = '*'
9
+ RSA_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANIsL+RHqfkBiKGn/D1y1QnNrMkKzxWP\n2wkeSokw2OJrCI+d6YGJPrHHx+nmb/Qn885/R01Gw6d7M824qofmCvkCAwEAAQ==\n-----END PUBLIC KEY-----\n"
10
+
11
+ def TokenManager.create(card, publishableKey)
12
+ if(card == nil)
13
+ raise PayStackCardError, "Card cannot be null"
14
+ elsif !card.isValidCard()
15
+ raise PayStackCardError, "Invalid card details"
16
+ end
17
+
18
+ card_str = concatCardFields(card)
19
+ enc_card_str = Crypto.encrypt_string(card_str, RSA_PUBLIC_KEY)
20
+ return createServerToken enc_card_str, publishableKey
21
+ end
22
+
23
+ def TokenManager.concatCardFields(card)
24
+ raise PayStackCardError, 'Invalid Card' unless (!card.nil? && card.instance_of?(PaystackCard))
25
+
26
+ number = Utils.nullifyString(card.number)
27
+ cvc = card.cvc
28
+ expiryMonth = card.expiryMonth
29
+ expiryYear = card.expiryYear
30
+
31
+ raise PayStackCardError, 'Card number cannot be empty or null' unless (!number.nil?)
32
+
33
+ return "#{number}#{CONCATENATOR}#{cvc}#{CONCATENATOR}#{expiryMonth}#{CONCATENATOR}#{expiryYear}"
34
+
35
+ end
36
+
37
+ def TokenManager.createServerToken(encrypted_card, publishableKey)
38
+ token = nil;
39
+ begin
40
+ response = RestClient.post "#{API::TOKEN_URL}", :clientdata => encrypted_card, :publishablekey => publishableKey
41
+ unless (response.code == 200 || response.code == 201)
42
+ raise PayStackServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
43
+ end
44
+ result = JSON.parse(response.body)
45
+ unless(result['status'] != '0' )
46
+ raise PayStackServerError.new(response), "Server Message: #{result['message']}"
47
+ end
48
+ token = {:token => result['token'], :last4 => result['last4']}
49
+ rescue JSON::ParserError => jsonerr
50
+ raise PayStackServerError.new(response) , "Invalid result data. Could not parse JSON response body \n #{jsonerr.message}"
51
+
52
+ rescue PayStackServerError => e
53
+ puts e.response.code
54
+ Utils.serverErrorHandler(e)
55
+ end
56
+ return token
57
+
58
+ end
59
+ end
60
+
@@ -0,0 +1,102 @@
1
+ class PaystackBaseObject
2
+
3
+ attr_reader :paystack
4
+
5
+ def initialize(paystackObj)
6
+ unless !paystackObj.nil?
7
+ raise ArgumentError, "Paystack object cannot be nil!!"
8
+ end
9
+ @paystack = paystackObj
10
+ end
11
+
12
+ protected
13
+ # =>Static methods
14
+ def self.initGetRequest(paystackObj, url)
15
+ result = nil
16
+ begin
17
+ response = RestClient.get "#{API::BASE_URL}#{url}" , :Authorization => "Bearer #{paystackObj.private_key}", :content_type => :json, :accept => :json
18
+ unless (response.code == 200 || response.code == 201)
19
+ raise PaystackServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
20
+ end
21
+ result = JSON.parse(response.body)
22
+ unless(result['status'] != 0 )
23
+ raise PaystackServerError.new(response), "Server Message: #{result['message']}"
24
+ end
25
+
26
+ rescue JSON::ParserError => jsonerr
27
+ raise PaystackServerError.new(response) , "Invalid result data. Could not parse JSON response body \n #{jsonerr.message}"
28
+
29
+ rescue PayStackServerError => e
30
+ Utils.serverErrorHandler(e)
31
+ end
32
+ return result
33
+ end
34
+
35
+ def self.initPostRequest(paystackObj, url, data = {}, json=false )
36
+ result = nil
37
+ begin
38
+ if !json
39
+ response = RestClient.post "#{API::BASE_URL}#{url}" , data, :Authorization => "Bearer #{paystackObj.private_key}"
40
+ else
41
+ response = RestClient.post "#{API::BASE_URL}#{url}" , data.to_json, :Authorization => "Bearer #{paystackObj.private_key}", :content_type => :json, :accept => :json
42
+
43
+ end
44
+ unless (response.code == 200 || response.code == 201)
45
+ raise PaystackServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
46
+ end
47
+ result = JSON.parse(response.body)
48
+ unless(result['status'] != 0 )
49
+ raise PaystackServerError.new(response), "Server Message: #{result['message']}"
50
+ end
51
+
52
+ rescue JSON::ParserError => jsonerr
53
+ raise PaystackServerError.new(response) , "Invalid result data. Could not parse JSON response body \n #{jsonerr.message}"
54
+
55
+ rescue PayStackServerError => e
56
+ Utils.serverErrorHandler(e)
57
+ end
58
+ return result
59
+ end
60
+
61
+ def self.initPutRequest(paystackObj, url, data = {} )
62
+ result = nil
63
+ begin
64
+ response = RestClient.put "#{API::BASE_URL}#{url}" , data, :Authorization => "Bearer #{paystackObj.private_key}"
65
+ unless (response.code == 200 || response.code == 201)
66
+ raise PaystackServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
67
+ end
68
+ result = JSON.parse(response.body)
69
+ unless(result['status'] != 0 )
70
+ raise PaystackServerError.new(response), "Server Message: #{result['message']}"
71
+ end
72
+
73
+ rescue JSON::ParserError => jsonerr
74
+ raise PaystackServerError.new(response) , "Invalid result data. Could not parse JSON response body \n #{jsonerr.message}"
75
+
76
+ rescue PayStackServerError => e
77
+ Utils.serverErrorHandler(e)
78
+ end
79
+ return result
80
+ end
81
+
82
+ def self.initDeleteRequest(paystackObj, url)
83
+ result = nil
84
+ begin
85
+ response = RestClient.delete "#{API::BASE_URL}#{url}" , :Authorization => "Bearer #{paystackObj.private_key}"
86
+ unless (response.code == 200 || response.code == 201)
87
+ raise PaystackServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
88
+ end
89
+ result = JSON.parse(response.body)
90
+ unless(result['status'] != 0 )
91
+ raise PaystackServerError.new(response), "Server Message: #{result['message']}"
92
+ end
93
+
94
+ rescue JSON::ParserError => jsonerr
95
+ raise PaystackServerError.new(response) , "Invalid result data. Could not parse JSON response body \n #{jsonerr.message}"
96
+
97
+ rescue PayStackServerError => e
98
+ Utils.serverErrorHandler(e)
99
+ end
100
+ return result
101
+ end
102
+ end
@@ -0,0 +1,106 @@
1
+ require 'paystack/utils/utils.rb'
2
+
3
+ class PaystackCard
4
+ attr_reader :name, :number,:cvc,:expiryMonth,:expiryYear, :addressLine1,:addressLine2, :addressLine3, :addressLine4, :addressCountry, :addressPostalCode, :email, :cardCountry, :cardIssuer
5
+
6
+ MAX_DINERS_CARD_LENGTH = 14
7
+ MAX_AMERICAN_EXPRESS_CARD_LENGTH = 15
8
+ MAX_NORMAL_CARD_LENGTH = 16
9
+
10
+ PATTERN_VISA = /^4[0-9]{6,}$/
11
+ PATTERN_MASTERCARD = /^5[1-5][0-9]{5,}$/
12
+ PATTERN_AMERICAN_EXPRESS = /^3[47][0-9]{5,}$/
13
+ PATTERN_DINERS_CLUB = /^3(?:0[0-5]|[68][0-9])[0-9]{4,}$/
14
+ PATTERN_DISCOVER = /^6(?:011|5[0-9]{2})[0-9]{3,}$/
15
+ PATTERN_JCB = /^(?:2131|1800|35[0-9]{3})[0-9]{3,}/
16
+
17
+ def initialize(args = {})
18
+ @name = Utils.nullifyString(args[:name])
19
+ @number = Utils.nullifyString(args[:number])
20
+ @cvc = Utils.nullifyString(args[:cvc])
21
+ @expiryMonth = Utils.nullifyString(args[:expiryMonth])
22
+ @expiryYear = Utils.nullifyString(args[:expiryYear])
23
+ @cardIssuer = PaystackCard.getCardType(@number)
24
+ end
25
+
26
+ def isValidCard()
27
+ if (@cvc != nil)
28
+ return isValidNumber() && isValidExpiryDate() && isValidCVC()
29
+ else
30
+ return isValidNumber() && isValidExpiryDate()
31
+ end
32
+
33
+ end
34
+
35
+ def PaystackCard.getCardType(number)
36
+ if(number == nil)
37
+ return 'invalid'
38
+ end
39
+ if(number =~ PATTERN_VISA) != nil
40
+ return 'visa'
41
+ end
42
+
43
+ if(number =~ PATTERN_MASTERCARD) != nil
44
+ return 'mastercard'
45
+ end
46
+
47
+ if(number =~ PATTERN_AMERICAN_EXPRESS) != nil
48
+ return 'american_express'
49
+ end
50
+
51
+ if(number =~ PATTERN_DINERS_CLUB)
52
+ return 'diners'
53
+ end
54
+ if(number =~ PATTERN_DISCOVER)
55
+ return 'discover'
56
+ end
57
+ if(number =~ PATTERN_JCB)
58
+ return 'jcb'
59
+ end
60
+ return 'unknown'
61
+ end
62
+
63
+
64
+
65
+
66
+
67
+
68
+ def isValidNumber
69
+ if(Utils.isEmpty(@number))
70
+ return false
71
+ end
72
+ formatted_number = @number.gsub(/\s+|-/) {|s| '' }.strip
73
+
74
+ if(Utils.isEmpty(formatted_number) || !Utils.isWholePositiveNumber(formatted_number) || !Utils.isLuthValidNumber(formatted_number))
75
+
76
+ return false
77
+ end
78
+ if PaystackCard.getCardType(formatted_number).eql?('diners')
79
+ return (formatted_number.length == MAX_DINERS_CARD_LENGTH)
80
+ end
81
+
82
+ if PaystackCard.getCardType(formatted_number).eql?('american_express')
83
+ return (formatted_number.length == MAX_AMERICAN_EXPRESS_CARD_LENGTH)
84
+ end
85
+
86
+ return (formatted_number.length == MAX_NORMAL_CARD_LENGTH)
87
+
88
+ end
89
+
90
+ def isValidCVC
91
+ if(@cvc.eql?(""))
92
+ return false
93
+ end
94
+ cvc = @cvc.strip
95
+ cvc_len = cvc.length
96
+
97
+ validLength = ((cvc_len >= 3 && cvc_len <= 4) || (@cardIssuer.eql?('american_express') && cvc_len == 4) ||(!@cardIssuer.eql?('american_express') && cvc_len == 3))
98
+
99
+ end
100
+
101
+ def isValidExpiryDate()
102
+ return !(@expiryMonth == nil || @expiryYear == nil) && Utils.hasCardExpired(@expiryYear, @expiryMonth);
103
+ end
104
+
105
+
106
+ end
@@ -0,0 +1,37 @@
1
+ require 'paystack/objects/base.rb'
2
+
3
+ class PaystackCustomers < PaystackBaseObject
4
+ def create(data={})
5
+ return PaystackCustomers.create(@paystack, data)
6
+ end
7
+
8
+ def get(customer_id)
9
+ return PaystackCustomers.get(@paystack, customer_id)
10
+ end
11
+
12
+
13
+ def update(customer_id, data={})
14
+ return PaystackCustomers.update(@paystack, customer_id, data)
15
+ end
16
+
17
+ def list(page=1)
18
+ return PaystackCustomers.list(@paystack, page)
19
+ end
20
+
21
+
22
+ def PaystackCustomers.create(paystackObj, data)
23
+ initPostRequest(paystackObj,"#{API::CUSTOMER_PATH}", data)
24
+ end
25
+
26
+ def PaystackCustomers.update(paystackObj, customer_id, data)
27
+ initPutRequest(paystackObj,"#{API::CUSTOMER_PATH}/#{customer_id}", data)
28
+ end
29
+
30
+ def PaystackCustomers.get(paystackObj, customer_id)
31
+ initGetRequest(paystackObj, "#{API::CUSTOMER_PATH}/#{customer_id}")
32
+ end
33
+
34
+ def PaystackCustomers.list(paystackObj, page=1)
35
+ initGetRequest(paystackObj, "#{API::CUSTOMER_PATH}?page=#{page}")
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+ require 'paystack/objects/base.rb'
2
+
3
+ class PaystackPlans < PaystackBaseObject
4
+
5
+ def create(data={})
6
+ return PaystackPlans.create(@paystack, data)
7
+ end
8
+
9
+ def get(plan_id)
10
+ return PaystackPlans.get(@paystack, plan_id)
11
+ end
12
+
13
+
14
+ def update(plan_id, data={})
15
+ return PaystackPlans.update(@paystack, plan_id, data)
16
+ end
17
+
18
+ def list(page=1)
19
+ return PaystackPlans.list(@paystack, page)
20
+ end
21
+
22
+
23
+ def PaystackPlans.create(paystackObj, data)
24
+ initPostRequest(paystackObj,"#{API::PLAN_PATH}", data)
25
+ end
26
+
27
+ def PaystackPlans.update(paystackObj, plan_id, data)
28
+ initPutRequest(paystackObj,"#{API::PLAN_PATH}/#{plan_id}", data)
29
+ end
30
+
31
+ def PaystackPlans.get(paystackObj, plan_id)
32
+ initGetRequest(paystackObj, "#{API::PLAN_PATH}/#{plan_id}")
33
+ end
34
+
35
+ def PaystackPlans.list(paystackObj, page=1)
36
+ initGetRequest(paystackObj, "#{API::PLAN_PATH}?page=#{page}")
37
+ end
38
+
39
+
40
+
41
+
42
+ end
@@ -0,0 +1,70 @@
1
+ require 'paystack/objects/base.rb'
2
+
3
+ class PaystackTransactions < PaystackBaseObject
4
+
5
+ def initializeTransaction(args={})
6
+ return PaystackTransactions.initializeTransaction(@paystack, args)
7
+ end
8
+
9
+ def list(page=1)
10
+ return PaystackTransactions.list(@paystack, page)
11
+ end
12
+
13
+ def get(transaction_id)
14
+ return PaystackTransactions.get(@paystack, transaction_id)
15
+ end
16
+
17
+ def verify transaction_reference
18
+ return PaystackTransactions.verify(@paystack, transaction_reference)
19
+ end
20
+
21
+ def totals page=1
22
+ return PaystackTransactions.totals(@paystack, page)
23
+ end
24
+
25
+ def chargeToken(token, amount,args = {})
26
+ return PaystackTransactions.chargeToken(@paystack,token, amount, args)
27
+ end
28
+
29
+ def chargeAuthorization(authorization_code, email, amount,args = {})
30
+ return PaystackTransactions.chargeAuthorization(@paystack,authorization_code,email, amount, args)
31
+ end
32
+
33
+
34
+ # => Public Static methods
35
+
36
+
37
+ def PaystackTransactions.initializeTransaction(paystackObj, args)
38
+ initPostRequest(paystackObj,"#{API::TRANSACTION_PATH}/initialize", args,true)
39
+ end
40
+
41
+ def PaystackTransactions.list(paystackObj, page=1)
42
+
43
+ initGetRequest(paystackObj, "#{API::TRANSACTION_PATH}?page=#{page}")
44
+ end
45
+
46
+ def PaystackTransactions.get(paystackObj, transaction_id)
47
+ initGetRequest(paystackObj, "#{API::TRANSACTION_PATH}/#{transaction_id}")
48
+ end
49
+
50
+
51
+ def PaystackTransactions.verify(paystackObj, transaction_reference)
52
+ initGetRequest(paystackObj, "#{API::TRANSACTION_PATH}/verify/#{transaction_reference}")
53
+ end
54
+
55
+ def PaystackTransactions.totals(paystackObj, page=1)
56
+ initGetRequest(paystackObj, "#{API::TRANSACTION_PATH}/totals?page=#{page}")
57
+ end
58
+
59
+ def PaystackTransactions.chargeToken(paystackObj,token, amount,args = {})
60
+ hash = {:token => token, :amount => amount}.merge(args)
61
+ initPostRequest(paystackObj,"#{API::TRANSACTION_PATH}/charge_token", hash, true)
62
+ end
63
+ def PaystackTransactions.chargeAuthorization(paystackObj,authorization_code,email, amount,args = {})
64
+ hash = {:authorization_code => authorization_code, :amount => amount, :email => email}.merge(args)
65
+ initPostRequest(paystackObj,"#{API::TRANSACTION_PATH}/charge_authorization", hash, true)
66
+ end
67
+
68
+
69
+
70
+ end
@@ -0,0 +1,101 @@
1
+
2
+ require 'paystack/error.rb'
3
+
4
+ module Utils
5
+
6
+ def Utils.nullifyString(value)
7
+ if(value.strip.eql? "" || value.nil?)
8
+ return nil
9
+ end
10
+ return value;
11
+ end
12
+
13
+ def Utils.isWholePositiveNumber(value)
14
+ if(value == nil)
15
+ return false
16
+ end
17
+ length = value.length;
18
+
19
+ for i in 0..(length-1)
20
+ c = value[i]
21
+
22
+ if((c =~ /[[:digit:]]/) == nil)
23
+ return false
24
+ end
25
+ end
26
+ return true
27
+ end
28
+
29
+ def Utils.isLuthValidNumber(number)
30
+ sum = 0
31
+ length = number.strip.length;
32
+
33
+ for i in 0..(length-1)
34
+ c = number[length - 1 -i]
35
+
36
+ if((c =~ /[[:digit:]]/) == nil)
37
+ return false
38
+ end
39
+ digit = c.to_i
40
+ if (i % 2 == 1)
41
+ digit *= 2
42
+ end
43
+ sum += digit > 9 ? digit - 9 : digit
44
+ end
45
+
46
+ return (sum % 10 == 0)
47
+ end
48
+
49
+ def Utils.isEmpty(value)
50
+ return (value.nil? || value.strip.eql?(""))
51
+ end
52
+
53
+ def Utils.hasYearPassed(year)
54
+ return year < Time.new.year
55
+ end
56
+ def Utils.hasMonthPassed(year, month)
57
+ t = Time.new
58
+ return hasYearPassed(year) || year == t.year && month < (t.month)
59
+ end
60
+
61
+ def Utils.hasCardExpired(year, month)
62
+ # Normalize Year value e.g 14 becomes 2014 or 2114 etc.
63
+ year_int = year.strip.to_i
64
+ if(year_int < 100 && year_int >= 0)
65
+ cal_year = Time.new.year.to_s
66
+ year_int = ("#{cal_year[0..1]}#{year.strip}").to_i
67
+ end
68
+
69
+ # Check for expiration
70
+ return !hasYearPassed(year_int) && !hasMonthPassed(year_int, month.to_i)
71
+
72
+ end
73
+
74
+
75
+
76
+
77
+
78
+ def Utils.serverErrorHandler(e)
79
+
80
+ if(e.response == nil)
81
+ raise e
82
+ return
83
+ end
84
+ error = PaystackServerError.new(e.response);
85
+ case e.response.code
86
+ when 400
87
+ raise error, "HTTP Code 400: A validation or client side error occurred and the request was not fulfilled. "
88
+ when 401
89
+ raise error, "HTTP Code 401: The request was not authorized. This can be triggered by passing an invalid secret key in the authorization header or the lack of one"
90
+ when 404
91
+ raise error, "HTTP Code 404: Request could not be fulfilled as the request resource does not exist."
92
+ when 500, 501,502,503,504
93
+ raise error, "HTTP Code #{e.response.code}: Request could not be fulfilled due to an error on Paystack's end. This shouldn't happen so please report as soon as you encounter any instance of this."
94
+ else
95
+ raise error, "HTTP Code #{e.response.code}: #{e.response.body}"
96
+
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,3 @@
1
+ module Paystack
2
+ VERSION = "0.1.2"
3
+ end
data/paystack.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'paystack/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "paystack"
8
+ spec.version = Paystack::VERSION
9
+ spec.authors = ["Victor"]
10
+ spec.email = ["ikoro.victor@gmail.com"]
11
+
12
+ spec.summary = %q{PayStack.co gem for Ruby/Rails}
13
+ spec.description = %q{Client Library Gem for PayStack.co}
14
+ spec.homepage = "https://github.com/IkoroVictor/paystack-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ #Dev dependencies
23
+ spec.add_development_dependency "bundler", "~> 1.11"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec"
26
+
27
+ #Dependencies
28
+ spec.add_dependency "rest-client", '~> 1.8'
29
+
30
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paystack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Victor
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-02-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rest-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.8'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.8'
69
+ description: Client Library Gem for PayStack.co
70
+ email:
71
+ - ikoro.victor@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - CODE_OF_CONDUCT.md
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/console
84
+ - bin/setup
85
+ - key.pem
86
+ - lib/paystack.rb
87
+ - lib/paystack/error.rb
88
+ - lib/paystack/modules/api.rb
89
+ - lib/paystack/modules/crypto.rb
90
+ - lib/paystack/modules/tokenmanager.rb
91
+ - lib/paystack/objects/base.rb
92
+ - lib/paystack/objects/card.rb
93
+ - lib/paystack/objects/customers.rb
94
+ - lib/paystack/objects/plans.rb
95
+ - lib/paystack/objects/transactions.rb
96
+ - lib/paystack/utils/utils.rb
97
+ - lib/paystack/version.rb
98
+ - paystack.gemspec
99
+ homepage: https://github.com/IkoroVictor/paystack-ruby
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.4.5
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: PayStack.co gem for Ruby/Rails
123
+ test_files: []