clash_of_clans_api 0.1.1
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.
- checksums.yaml +7 -0
- data/README.adoc +67 -0
- data/lib/clash_of_clans_api/api.rb +57 -0
- data/lib/clash_of_clans_api/client.rb +46 -0
- data/lib/clash_of_clans_api/endpoint_methods.rb +68 -0
- data/lib/clash_of_clans_api/models/base.rb +71 -0
- data/lib/clash_of_clans_api/models/icon_set.rb +12 -0
- data/lib/clash_of_clans_api/models/invalid_data_error.rb +13 -0
- data/lib/clash_of_clans_api/models/league.rb +12 -0
- data/lib/clash_of_clans_api/models/token.rb +32 -0
- data/lib/clash_of_clans_api/no_success_error.rb +9 -0
- data/lib/clash_of_clans_api/tags.rb +21 -0
- data/lib/clash_of_clans_api/token_api.rb +37 -0
- data/lib/clash_of_clans_api/token_client.rb +61 -0
- data/lib/clash_of_clans_api/utils.rb +34 -0
- data/lib/clash_of_clans_api/version.rb +5 -0
- data/lib/clash_of_clans_api.rb +7 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a2b63aa46b4c6536b5c3c86729addc9e5dfa9c8071fdc890d24eed29d8768010
|
4
|
+
data.tar.gz: 4c2a7bf252282acd7f5254b22eab7fe5f273dd740c0179fb04926af0d8295fef
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b9735602b7013aa396f555b1aca1d7dfc560cd6a46b27fd290275195f1a759c3789d116076ff10fe5ef5c8762371dfa2fdbebebc8f60930adf686c80b460aafe
|
7
|
+
data.tar.gz: ccdb84b96e9c4db19c6e1bb89cd142fdd200c22b953d3f4ed6e45051bc13b137d7e23d247487842dcc915fe7c97f07550813fcbb834657add06799e967a7563f
|
data/README.adoc
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
== ClashOfClansApi
|
2
|
+
|
3
|
+
`clash_of_clans_api` is a gem to communicate with the Clash of Clans API at https://developer.clashofclans.com/.
|
4
|
+
It contains low-level methods to communicate with all existing API endpoints and aims to provide higher-level abstractions for them.
|
5
|
+
|
6
|
+
=== Installation
|
7
|
+
|
8
|
+
Add this line to your application’s Gemfile:
|
9
|
+
|
10
|
+
[source,ruby]
|
11
|
+
----
|
12
|
+
gem 'clash_of_clans_api'
|
13
|
+
----
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
....
|
18
|
+
$ bundle install
|
19
|
+
....
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
....
|
24
|
+
$ gem install clash_of_clans_api
|
25
|
+
....
|
26
|
+
|
27
|
+
=== Usage
|
28
|
+
|
29
|
+
==== API Communication
|
30
|
+
|
31
|
+
To communicate with the Clash of Clans API, an API access token is required.
|
32
|
+
Currently, the gem is not able to create tokens itself.
|
33
|
+
|
34
|
+
The gem provides two classes for communication.
|
35
|
+
`ClashOfClansApi::Api` is a low-level interface that implements methods for all API endpoints.
|
36
|
+
If the request is successful, the API’s JSON response is parsed and returned, otherwise a `ClashOfClans::NoSucessError` is raised.
|
37
|
+
`ClashOfClansApi::Client` is a higher-level interface that exposes its `ClashOfClansApi::Api` instance through `ClashOfClansApi::Client#api`.
|
38
|
+
Both classes’ initializers take a single argument, the API token.
|
39
|
+
|
40
|
+
The method names for the endpoints are the same in both classes.
|
41
|
+
They are derived from the https://developer.clashofclans.com/#/documentation[API documentation] by the following steps.
|
42
|
+
|
43
|
+
. Take the path name from the documentation (e.g. `/clans/{clanTag}/currentwar/leaguegroup`).
|
44
|
+
. Replace slashes (`/`) with underscores (`\_`) and keep only inner ones (`clans_{clanTag}_currentwar_leaguegroup`).
|
45
|
+
. In case of path arguments, singularize the path segment referenced by the argument (`clan_{clanTag}_currentwar_leaguegroup`).
|
46
|
+
. Remove path argument segments (`clan_currentwar_leaguegroup`).
|
47
|
+
|
48
|
+
Path arguments are converted to positional arguments in the order of definition in the original path name.
|
49
|
+
Path arguments will automatically be URL-escaped.
|
50
|
+
A URL query in the form of a `Hash` can be passed as the named parameter `query:`.
|
51
|
+
|
52
|
+
==== Clan and player tags
|
53
|
+
|
54
|
+
Tags in Clash of Clans are subject to format restrictions.
|
55
|
+
Since those restrictions are well known, `ClashOfClansApi::Tags` provides class methods for checking the format (`.sanitizable?`) and sanitizing ill-formatted tags up to a certain degree (`.sanitize`).
|
56
|
+
|
57
|
+
Even though the API seems to ignore some mistakes, e.g. using `O` (upper case letter o) instead of `0` (number zero), it also does not seem to correct them.
|
58
|
+
If a player with tag `#PY0` existed, the API would return the same information for both `#PY0` and `#PYO`, except using the tag that was requested.
|
59
|
+
This could lead to unforeseen errors like multiple database entries for the same player or clan.
|
60
|
+
Therefore, those mistakes should be catched before sending a request.
|
61
|
+
|
62
|
+
|
63
|
+
=== Development
|
64
|
+
|
65
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
66
|
+
Then, run `rake spec` to run the tests.
|
67
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative 'endpoint_methods'
|
2
|
+
require_relative 'no_success_error'
|
3
|
+
require_relative 'utils'
|
4
|
+
|
5
|
+
module ClashOfClansApi
|
6
|
+
class Api
|
7
|
+
include EndpointMethods
|
8
|
+
|
9
|
+
BASE_URI = URI('https://api.clashofclans.com/v1/')
|
10
|
+
|
11
|
+
def base_uri
|
12
|
+
BASE_URI
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :api_token
|
16
|
+
|
17
|
+
def initialize(api_token)
|
18
|
+
@api_token = api_token
|
19
|
+
end
|
20
|
+
|
21
|
+
def endpoint_headers
|
22
|
+
{
|
23
|
+
'Authorization' => "Bearer #{api_token}",
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
define_endpoint :clan_currentwar_leaguegroup, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}/currentwar/leaguegroup" }
|
28
|
+
define_endpoint :clanwarleagues_war, method: :get, endpoint: proc { | war_tag | "clanwarleagues/wars/#{Utils.url_escape(war_tag)}" }
|
29
|
+
define_endpoint :clan_warlog, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}/warlog" }
|
30
|
+
define_endpoint :clans, method: :get, endpoint: 'clans'
|
31
|
+
define_endpoint :clan_currentwar, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}/currentwar" }
|
32
|
+
define_endpoint :clan, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}" }
|
33
|
+
define_endpoint :clan_members, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}/members" }
|
34
|
+
|
35
|
+
define_endpoint :player, method: :get, endpoint: proc { |player_tag | "players/#{Utils.url_escape(player_tag)}" }
|
36
|
+
define_endpoint :player_verifytoken, method: :post, endpoint: proc { |player_tag | "players/#{Utils.url_escape(player_tag)}/verifytoken" }, body: proc { |token:| %Q[{"token":"#{token.to_s}"}] }
|
37
|
+
|
38
|
+
define_endpoint :leagues, method: :get, endpoint: 'leagues'
|
39
|
+
define_endpoint :league_season, method: :get, endpoint: proc { | league_id, season_id| "leagues/#{Utils.url_escape( league_id)}/seasons/#{Utils.url_escape(season_id)}" }
|
40
|
+
define_endpoint :league, method: :get, endpoint: proc { | league_id | "leagues/#{Utils.url_escape( league_id)}" }
|
41
|
+
define_endpoint :league_seasons, method: :get, endpoint: proc { | league_id | "leagues/#{Utils.url_escape( league_id)}/seasons" }
|
42
|
+
define_endpoint :warleague, method: :get, endpoint: proc { |warleague_id | "warleagues/#{Utils.url_escape(warleague_id)}" }
|
43
|
+
define_endpoint :warleagues, method: :get, endpoint: 'warleagues'
|
44
|
+
|
45
|
+
define_endpoint :location_rankings_clans, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}/rankings/clans" }
|
46
|
+
define_endpoint :location_rankings_players, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}/rankings/players" }
|
47
|
+
define_endpoint :location_rankings_clansversus, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}/rankings/clans-versus" }
|
48
|
+
define_endpoint :location_rankings_playersversus, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}/rankings/players-versus" }
|
49
|
+
define_endpoint :locations, method: :get, endpoint: 'locations'
|
50
|
+
define_endpoint :location, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}" }
|
51
|
+
|
52
|
+
define_endpoint :goldpass_seasons_current, method: :get, endpoint: 'goldpass/seasons/current'
|
53
|
+
|
54
|
+
define_endpoint :labels_players, method: :get, endpoint: 'labels/players'
|
55
|
+
define_endpoint :labels_clans, method: :get, endpoint: 'labels/clans'
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative 'api'
|
2
|
+
require_relative 'models/league'
|
3
|
+
|
4
|
+
module ClashOfClansApi
|
5
|
+
class Client
|
6
|
+
attr_reader :api
|
7
|
+
|
8
|
+
def initialize(api_token)
|
9
|
+
@api = Api.new(api_token)
|
10
|
+
end
|
11
|
+
|
12
|
+
def authorized?
|
13
|
+
api.perform_get('test').code == '404'
|
14
|
+
end
|
15
|
+
|
16
|
+
def player_verifytoken(player_tag, token)
|
17
|
+
response = api.player_verifytoken(player_tag, token: token)
|
18
|
+
|
19
|
+
raise "Sent player tag #{player_tag.inspect} but received #{response['tag' ].inspect}." unless player_tag == response['tag' ]
|
20
|
+
raise "Sent token #{ token .inspect} but received #{response['token'].inspect}." unless token == response['token']
|
21
|
+
|
22
|
+
case response['status']
|
23
|
+
when 'ok'
|
24
|
+
true
|
25
|
+
when 'invalid'
|
26
|
+
false
|
27
|
+
else
|
28
|
+
raise "Unknown status #{response['status'].inspect}."
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def leagues
|
33
|
+
response = api.leagues
|
34
|
+
|
35
|
+
raise NotImplementedError, "Found a paging cursor but handling it is not implemented yet." if response['paging']['cursors'].any?
|
36
|
+
|
37
|
+
response['items'].map do |league|
|
38
|
+
Models::League.new(league)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def league(id)
|
43
|
+
Models::League.new(api.league(id))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'json'
|
3
|
+
require 'net/https'
|
4
|
+
|
5
|
+
module ClashOfClansApi
|
6
|
+
module EndpointMethods
|
7
|
+
def endpoint_headers
|
8
|
+
{}
|
9
|
+
end
|
10
|
+
|
11
|
+
def perform_request(method, api_path, query: nil, body: nil, headers: nil)
|
12
|
+
uri = self.base_uri+api_path
|
13
|
+
uri.query = URI.encode_www_form(query) if query
|
14
|
+
|
15
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme=='https') do |http|
|
16
|
+
case method
|
17
|
+
when :get
|
18
|
+
Net::HTTP::Get
|
19
|
+
when :post
|
20
|
+
Net::HTTP::Post
|
21
|
+
else
|
22
|
+
raise ArgumentError, "Invalid method #{method.inspect}."
|
23
|
+
end.new(uri).tap do |request|
|
24
|
+
endpoint_headers.merge(headers || {}).each do |name, value|
|
25
|
+
request[name] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
if body
|
29
|
+
request['Content-Type'] = 'application/json'
|
30
|
+
request.body = body
|
31
|
+
end
|
32
|
+
end.then do |request|
|
33
|
+
http.request(request)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def transform_response(response)
|
39
|
+
if response.is_a?(Net::HTTPSuccess)
|
40
|
+
JSON.parse(response.body)
|
41
|
+
else
|
42
|
+
raise NoSuccessError.new(response)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def self.included(klass)
|
48
|
+
klass.extend(ClassMethods)
|
49
|
+
end
|
50
|
+
|
51
|
+
module ClassMethods
|
52
|
+
def define_endpoint(name, method:, endpoint:, body: nil)
|
53
|
+
define_method(name) do |*args, **kwargs|
|
54
|
+
uri = endpoint.respond_to?(:call) ? ClashOfClansApi::Utils.call_proc_without_unknown_keywords(endpoint, *args, **kwargs) : endpoint
|
55
|
+
request_body = body .respond_to?(:call) ? ClashOfClansApi::Utils.call_proc_without_unknown_keywords(body, *args, **kwargs) : body
|
56
|
+
|
57
|
+
perform_request(method, uri, body: request_body, query: kwargs.dig(:query), headers: kwargs.dig(:headers)).then do |response|
|
58
|
+
if !kwargs.key?(:plain_response) || !kwargs.fetch(:plain_response)
|
59
|
+
transform_response(response)
|
60
|
+
else
|
61
|
+
response
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative 'invalid_data_error'
|
2
|
+
|
3
|
+
module ClashOfClansApi
|
4
|
+
module Models
|
5
|
+
class Base
|
6
|
+
def initialize(hash)
|
7
|
+
@hash = hash
|
8
|
+
|
9
|
+
validate!
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h
|
13
|
+
@hash
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](key)
|
17
|
+
@hash[key]
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
attr_reader :required_fields
|
22
|
+
|
23
|
+
def property(name, key, type: nil, required: false)
|
24
|
+
define_method(name) do
|
25
|
+
if type.nil?
|
26
|
+
self[key]
|
27
|
+
else
|
28
|
+
if property_cached?(name)
|
29
|
+
property_from_cache(name)
|
30
|
+
else
|
31
|
+
cache_property(name, self[key].then do |prop|
|
32
|
+
prop.is_a?(Array) ? prop.map {|item| type.new(item) } : type.new(prop)
|
33
|
+
end)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if required
|
39
|
+
@required_fields = (@required_fields || [])+[key]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def property_cached?(name)
|
45
|
+
@property_cache && @property_cache.key?(name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def cache_property(name, obj)
|
49
|
+
@property_cache ||= {}
|
50
|
+
|
51
|
+
@property_cache[name] = obj
|
52
|
+
end
|
53
|
+
|
54
|
+
def property_from_cache(name)
|
55
|
+
@property_cache[name]
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate!
|
59
|
+
if self.class.required_fields
|
60
|
+
missing = self.class.required_fields.reject do |required_field|
|
61
|
+
@hash.key?(required_field)
|
62
|
+
end
|
63
|
+
|
64
|
+
if missing.any?
|
65
|
+
raise InvalidDataError, "The following keys are required, but missing from the model data: #{missing.map(&:inspect).join(', ')}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
require_relative 'icon_set'
|
3
|
+
|
4
|
+
module ClashOfClansApi
|
5
|
+
module Models
|
6
|
+
class League < Base
|
7
|
+
property :id, 'id', required: true
|
8
|
+
property :name, 'name', required: true
|
9
|
+
property :icon_urls, 'iconUrls', type: IconSet
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module ClashOfClansApi
|
4
|
+
module Models
|
5
|
+
class Token < Base
|
6
|
+
property :id, 'id', required: true
|
7
|
+
property :developer_id, 'developerId'
|
8
|
+
property :tier, 'tier'
|
9
|
+
property :name, 'name', required: true
|
10
|
+
property :description, 'description', required: true
|
11
|
+
property :origins, 'origins'
|
12
|
+
property :scopes, 'scopes'
|
13
|
+
property :cidr_ranges, 'cidrRanges', required: true
|
14
|
+
property :valid_until, 'validUntil'
|
15
|
+
property :key, 'key', required: true
|
16
|
+
|
17
|
+
def initialize(hash, token_client:)
|
18
|
+
super(hash)
|
19
|
+
|
20
|
+
@token_client = token_client
|
21
|
+
end
|
22
|
+
|
23
|
+
def revoke
|
24
|
+
@token_client.revoke_api_key(self.id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def client_from_token
|
28
|
+
ClashOfClansApi::Client.new(self.key)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ClashOfClansApi
|
2
|
+
module Tags
|
3
|
+
def self.tag_regex
|
4
|
+
/\A#[PYLQGRJCUV0289]+\z/
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.sanitizable_tag_regex
|
8
|
+
/\A\s*#?[PYLQGRJCUVO0289]+\s*\z/i
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.sanitizable?(tag)
|
12
|
+
sanitizable_tag_regex.match?(tag)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.sanitize(tag)
|
16
|
+
tag.strip.upcase.gsub('O', '0').then do |t|
|
17
|
+
t.start_with?('#') ? t : "##{t}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative 'endpoint_methods'
|
2
|
+
|
3
|
+
module ClashOfClansApi
|
4
|
+
module TokenApi
|
5
|
+
BASE_URI = URI('https://developer.clashofclans.com/api/')
|
6
|
+
|
7
|
+
class << self
|
8
|
+
include EndpointMethods
|
9
|
+
|
10
|
+
def base_uri
|
11
|
+
BASE_URI
|
12
|
+
end
|
13
|
+
|
14
|
+
define_endpoint :login, method: :post, endpoint: 'login', body: proc { |email:, password:|
|
15
|
+
{
|
16
|
+
email: email.to_s,
|
17
|
+
password: password.to_s,
|
18
|
+
}.to_json
|
19
|
+
}
|
20
|
+
define_endpoint :logout, method: :post, endpoint: 'logout', body: proc { '{}' }
|
21
|
+
define_endpoint :apikey_list, method: :post, endpoint: 'apikey/list', body: proc { '{}' }
|
22
|
+
define_endpoint :apikey_create, method: :post, endpoint: 'apikey/create', body: proc { |name:, description:, ip_addresses:|
|
23
|
+
{
|
24
|
+
name: name,
|
25
|
+
description: description,
|
26
|
+
cidrRanges: ip_addresses,
|
27
|
+
scopes: [:clash],
|
28
|
+
}.to_json
|
29
|
+
}
|
30
|
+
define_endpoint :apikey_revoke, method: :post, endpoint: 'apikey/revoke', body: proc { |id:|
|
31
|
+
{
|
32
|
+
id: id,
|
33
|
+
}.to_json
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require_relative 'token_api'
|
3
|
+
require_relative 'models/token'
|
4
|
+
|
5
|
+
module ClashOfClansApi
|
6
|
+
class TokenClient
|
7
|
+
attr_reader :email
|
8
|
+
attr_reader :password
|
9
|
+
|
10
|
+
def initialize(email, password)
|
11
|
+
@email = email
|
12
|
+
@password = password
|
13
|
+
end
|
14
|
+
|
15
|
+
def login!
|
16
|
+
TokenApi.login(email: email, password: password, plain_response: true).tap do |response|
|
17
|
+
if response.is_a?(Net::HTTPSuccess)
|
18
|
+
cookies = CGI::Cookie.parse(response['set-cookie'])
|
19
|
+
|
20
|
+
@session_headers = {
|
21
|
+
'Cookie' => "session=#{cookies['session'][0]}",
|
22
|
+
}
|
23
|
+
else
|
24
|
+
raise NoSuccessError, response
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def logout
|
30
|
+
TokenApi.logout(headers: @session_headers)
|
31
|
+
ensure
|
32
|
+
@session_headers = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def list_api_keys
|
36
|
+
response = TokenApi.apikey_list(headers: @session_headers)
|
37
|
+
|
38
|
+
response['keys'].map do |key|
|
39
|
+
Models::Token.new(key, token_client: self)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_api_key(name, description, ip_addresses)
|
44
|
+
response = TokenApi.apikey_create(name: name, description: description, ip_addresses: (ip_addresses.is_a?(Array) ? ip_addresses : [ip_addresses]), headers: @session_headers)
|
45
|
+
|
46
|
+
Models::Token.new(response['key'], token_client: self)
|
47
|
+
end
|
48
|
+
|
49
|
+
def revoke_api_key(id)
|
50
|
+
TokenApi.apikey_revoke(id: id, headers: @session_headers)
|
51
|
+
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
class << self
|
56
|
+
def create!(email, password)
|
57
|
+
new(email, password).login!
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module ClashOfClansApi
|
4
|
+
module Utils
|
5
|
+
def self.url_escape(string)
|
6
|
+
if !string.nil?
|
7
|
+
CGI.escape(string.to_s)
|
8
|
+
else
|
9
|
+
raise TypeError, 'cannot escape nil'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.call_proc_without_unknown_keywords(proc, *args, **kwargs, &block)
|
14
|
+
params = proc.parameters.group_by(&:first).transform_values! do |m|
|
15
|
+
m.map do |s|
|
16
|
+
s[1]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
proc_keys =
|
21
|
+
if params.key?(:keyrest)
|
22
|
+
kwargs
|
23
|
+
else
|
24
|
+
kwargs.slice(*(params.values_at(:key, :keyreq).compact.flatten))
|
25
|
+
end
|
26
|
+
|
27
|
+
proc.call(*args, **proc_keys, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get_current_ipv4_address
|
31
|
+
IPAddr.new(URI('https://ipv4.icanhazip.com').open.read.strip).to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: clash_of_clans_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- expeehaa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-12-26 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
- expeehaa@outlook.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- README.adoc
|
21
|
+
- lib/clash_of_clans_api.rb
|
22
|
+
- lib/clash_of_clans_api/api.rb
|
23
|
+
- lib/clash_of_clans_api/client.rb
|
24
|
+
- lib/clash_of_clans_api/endpoint_methods.rb
|
25
|
+
- lib/clash_of_clans_api/models/base.rb
|
26
|
+
- lib/clash_of_clans_api/models/icon_set.rb
|
27
|
+
- lib/clash_of_clans_api/models/invalid_data_error.rb
|
28
|
+
- lib/clash_of_clans_api/models/league.rb
|
29
|
+
- lib/clash_of_clans_api/models/token.rb
|
30
|
+
- lib/clash_of_clans_api/no_success_error.rb
|
31
|
+
- lib/clash_of_clans_api/tags.rb
|
32
|
+
- lib/clash_of_clans_api/token_api.rb
|
33
|
+
- lib/clash_of_clans_api/token_client.rb
|
34
|
+
- lib/clash_of_clans_api/utils.rb
|
35
|
+
- lib/clash_of_clans_api/version.rb
|
36
|
+
homepage: https://github.com/expeehaa/clash_of_clans_api
|
37
|
+
licenses: []
|
38
|
+
metadata:
|
39
|
+
allowed_push_host: https://rubygems.org
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 2.6.0
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubygems_version: 3.2.22
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: Client library for interacting with the ClashOfClans API.
|
59
|
+
test_files: []
|