admincredible 0.0.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.
- data/Gemfile +12 -0
- data/Gemfile.lock +86 -0
- data/Rakefile +24 -0
- data/Readme.md +121 -0
- data/TODOS +1 -0
- data/admincredible.gemspec +35 -0
- data/developer_notes/README.md +2 -0
- data/developer_notes/TODOS.md +0 -0
- data/lib/admincredible.rb +1 -0
- data/lib/admincredible/client.rb +60 -0
- data/lib/admincredible/configuration.rb +125 -0
- data/lib/admincredible/connection.rb +30 -0
- data/lib/admincredible/core_ext/string.rb +16 -0
- data/lib/admincredible/joomla_request.rb +22 -0
- data/lib/admincredible/middleware/logger.rb +51 -0
- data/lib/admincredible/middleware/step.rb +44 -0
- data/lib/admincredible/request.rb +47 -0
- data/lib/admincredible/resource.rb +20 -0
- data/lib/admincredible/resources/Backup.rb +34 -0
- data/lib/admincredible/resources/Compatibility.rb +13 -0
- data/lib/admincredible/resources/Extension.rb +37 -0
- data/lib/admincredible/resources/Oauth.rb +53 -0
- data/lib/admincredible/resources/Setting.rb +21 -0
- data/lib/admincredible/resources/Site.rb +9 -0
- data/lib/admincredible/resources/Upgrade.rb +64 -0
- data/spec/core/client_spec.rb +24 -0
- data/spec/core/resource_spec.rb +13 -0
- data/spec/fixtures/cassettes/backups/create.yml +73 -0
- data/spec/fixtures/cassettes/backups/start.yml +38 -0
- data/spec/fixtures/cassettes/backups/step.yml +38 -0
- data/spec/fixtures/cassettes/compatibility/added_exceptions.yml +38 -0
- data/spec/fixtures/cassettes/compatibility/status.yml +38 -0
- data/spec/fixtures/cassettes/extensions/all.yml +38 -0
- data/spec/fixtures/cassettes/extensions/update.yml +38 -0
- data/spec/fixtures/cassettes/settings/all.yml +38 -0
- data/spec/fixtures/cassettes/settings/created.yml +39 -0
- data/spec/fixtures/cassettes/settings/first.yml +38 -0
- data/spec/fixtures/cassettes/settings/updated.yml +39 -0
- data/spec/fixtures/cassettes/site/configuration.yml +41 -0
- data/spec/fixtures/cassettes/upgrade/cleanup.yml +38 -0
- data/spec/fixtures/cassettes/upgrade/create.yml +249 -0
- data/spec/fixtures/cassettes/upgrade/create_restoration_file.yml +38 -0
- data/spec/fixtures/cassettes/upgrade/download.yml +38 -0
- data/spec/fixtures/cassettes/upgrade/finalize.yml +38 -0
- data/spec/fixtures/cassettes/upgrade/info.yml +38 -0
- data/spec/fixtures/cassettes/upgrade/start.yml +39 -0
- data/spec/fixtures/cassettes/upgrade/step.yml +38 -0
- data/spec/resources/backups_spec.rb +36 -0
- data/spec/resources/compatibility_spec.rb +25 -0
- data/spec/resources/extensions_spec.rb +25 -0
- data/spec/resources/setting_spec.rb +47 -0
- data/spec/resources/site_spec.rb +14 -0
- data/spec/resources/upgrade_spec.rb +91 -0
- data/spec/spec_helper.rb +38 -0
- metadata +353 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
module Admincredible
|
2
|
+
module Connection
|
3
|
+
def connection
|
4
|
+
@connection ||= build_connection
|
5
|
+
return @connection
|
6
|
+
end
|
7
|
+
|
8
|
+
def rebuild_connection
|
9
|
+
@connection = build_connection
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_connection
|
13
|
+
Faraday.new(config.connection_options) do |builder|
|
14
|
+
# Response
|
15
|
+
builder.use Faraday::Response::RaiseError
|
16
|
+
builder.use Admincredible::Middleware::Response::Logger, config.logger if config.logger
|
17
|
+
builder.response :json, :content_type => 'application/json'
|
18
|
+
|
19
|
+
# Request
|
20
|
+
builder.use Faraday::Request::OAuth, config.oauth_options if config.oauth?
|
21
|
+
builder.request :multipart
|
22
|
+
builder.request :json
|
23
|
+
builder.request :retry, 2 unless config.oauth?
|
24
|
+
builder.request :step unless config.oauth?
|
25
|
+
|
26
|
+
builder.adapter config.adapter || Faraday.default_adapter
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class String
|
2
|
+
##
|
3
|
+
# Transforms a string into a module name.
|
4
|
+
#
|
5
|
+
# We at String Transforming Enterprise, Inc, TM, LLC, Corp, believe in three things;
|
6
|
+
# 1. All strings should be allowed to be whatever string they like.
|
7
|
+
# 2. ??
|
8
|
+
# 3. Profit
|
9
|
+
#
|
10
|
+
def modulize
|
11
|
+
self.gsub(/__(.?)/){ "::#{$1.upcase}" }.
|
12
|
+
gsub(/\/(.?)/){ "::#{$1.upcase}" }.
|
13
|
+
gsub(/(?:_+|-+)([a-z])/){ $1.upcase }.
|
14
|
+
gsub(/(\A|\s)([a-z])/){ $1 + $2.upcase }
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Due to the fact Joomla cant handle decent URLs (at least not out of the box)
|
2
|
+
# we abstract the requests further. all these methods take a resource + task and then any other
|
3
|
+
# has GET request vars, finally it takes normal options.
|
4
|
+
module Admincredible
|
5
|
+
module JoomlaRequest
|
6
|
+
def jget(resource, task, options={})
|
7
|
+
get('', {:resource => resource, :task => task}.merge(options))
|
8
|
+
end
|
9
|
+
|
10
|
+
def jpost(resource, task, options={})
|
11
|
+
post('', options, {:resource => resource, :task => task})
|
12
|
+
end
|
13
|
+
|
14
|
+
def jput(resource, task, options={})
|
15
|
+
put('', options, {:resource => resource, :task => task})
|
16
|
+
end
|
17
|
+
|
18
|
+
def jdelete(resource, task, options={})
|
19
|
+
delete('', {:resource => resource, :task => task}.merge(options))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'faraday_middleware/response_middleware'
|
2
|
+
|
3
|
+
module Admincredible
|
4
|
+
module Middleware
|
5
|
+
module Response
|
6
|
+
##
|
7
|
+
# So you're sitting there and you're staring off into the abyss of your terminal,
|
8
|
+
# the solarized green color scheme begins to sink into your retinas and the anger begins to build.
|
9
|
+
# This class prevents hulk moments from occurring and automagically logs requests in when enable via config.
|
10
|
+
#
|
11
|
+
class Logger < Faraday::Response::Middleware
|
12
|
+
def initialize(app, logger = nil)
|
13
|
+
super(app)
|
14
|
+
@logger = logger || begin
|
15
|
+
require 'logger'
|
16
|
+
::Logger.new(STDOUT)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
@logger.info "#{env[:method]} #{env[:url].to_s}"
|
22
|
+
@logger.debug dump_debug(env, :request_headers)
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def on_complete(env)
|
27
|
+
@logger.info("Status #{env[:status].to_s}")
|
28
|
+
@logger.debug dump_debug(env, :response_headers)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
##
|
34
|
+
# Dumps things, but safely, like a cat diligently using the litter box.
|
35
|
+
# It won't dump things that are nil and will make sure to inspect the objects first,
|
36
|
+
# if they are found to be carrying in countraband they'll be mapped and joined; which is probably code for
|
37
|
+
# something rather sinister.
|
38
|
+
# Remember cats, sand irst (safety), dump second,
|
39
|
+
#
|
40
|
+
def dump_debug(env, headers_key)
|
41
|
+
info = env[headers_key].map { |k, v| " #{k}: #{v.inspect}" }.join("\n")
|
42
|
+
unless env[:body].nil?
|
43
|
+
info.concat("\n")
|
44
|
+
info.concat(env[:body].inspect)
|
45
|
+
end
|
46
|
+
info
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'faraday/middleware'
|
2
|
+
|
3
|
+
module Admincredible
|
4
|
+
module Middleware
|
5
|
+
module Request
|
6
|
+
##
|
7
|
+
# Akeeba powered restoration scripts use a step/ping methodology that avoids timing out servers.
|
8
|
+
# This will automatically send more requests when a step response is received.
|
9
|
+
#
|
10
|
+
# It sadly doesn't work with OAuth yet because the re-signing requests problem was too difficult for this dev too
|
11
|
+
# solve at the time of this writing.
|
12
|
+
#
|
13
|
+
# @todo Fix this for OAuth
|
14
|
+
#
|
15
|
+
# If many months pass before this is resolved you can blame the developer's intense devotion to getting other things
|
16
|
+
# done. You can probably motivate him to fix it for oauth by bribing him with books.
|
17
|
+
#
|
18
|
+
class Step < Faraday::Middleware
|
19
|
+
DEFAULT_RETRY_AFTER = 1
|
20
|
+
|
21
|
+
def initialize(app, options={})
|
22
|
+
super(app)
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(env)
|
26
|
+
response = @app.call(env)
|
27
|
+
|
28
|
+
if response.env[:status] == 202
|
29
|
+
seconds_left = DEFAULT_RETRY_AFTER
|
30
|
+
|
31
|
+
seconds_left.times do |i|
|
32
|
+
sleep 1
|
33
|
+
end
|
34
|
+
|
35
|
+
call(env)
|
36
|
+
else
|
37
|
+
response
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
Faraday.register_middleware :request, :step => Admincredible::Middleware::Request::Step
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Admincredible
|
2
|
+
module Request
|
3
|
+
# Perform an HTTP GET request
|
4
|
+
def get(path, options={})
|
5
|
+
request(:get, path, options)
|
6
|
+
end
|
7
|
+
|
8
|
+
# Perform an HTTP POST request
|
9
|
+
def post(path, options={}, path_options={})
|
10
|
+
request(:post, path, options, path_options)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Perform an HTTP PUT request
|
14
|
+
def put(path, options={}, path_options={})
|
15
|
+
request(:put, path, options, path_options)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Perform an HTTP DELETE request
|
19
|
+
def delete(path, options={})
|
20
|
+
request(:delete, path, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def request(method, path, options={}, path_options={})
|
26
|
+
response = false
|
27
|
+
begin
|
28
|
+
response = connection.send(method) do |request|
|
29
|
+
case method
|
30
|
+
when :get, :delete
|
31
|
+
request.url(path, options)
|
32
|
+
when :post, :put
|
33
|
+
request.path = path
|
34
|
+
request.params = path_options
|
35
|
+
request.body = options unless options.empty?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rescue Faraday::Error::ClientError => e
|
39
|
+
response = e.response
|
40
|
+
end
|
41
|
+
|
42
|
+
return response.body if response.respond_to?(:body)
|
43
|
+
return response[:body] if response.is_a?(Hash)
|
44
|
+
return response
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Admincredible
|
2
|
+
class Resource
|
3
|
+
attr_reader :client
|
4
|
+
|
5
|
+
##
|
6
|
+
# Initializes with a client. You can use resource classes directly by passing and instance of Admincredible::Client
|
7
|
+
#
|
8
|
+
def initialize(client, options={})
|
9
|
+
@client = client
|
10
|
+
end
|
11
|
+
|
12
|
+
def connection
|
13
|
+
return client.connection
|
14
|
+
end
|
15
|
+
|
16
|
+
def config
|
17
|
+
return client.config
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Admincredible
|
2
|
+
module Resources
|
3
|
+
class Backup < Resource
|
4
|
+
def start
|
5
|
+
client.jget('backups', 'start')
|
6
|
+
end
|
7
|
+
|
8
|
+
def step(repeat_until_done=true)
|
9
|
+
response = client.jget('backups', 'step')
|
10
|
+
|
11
|
+
if response['status'] == 'working' && repeat_until_done
|
12
|
+
seconds_left = config.step_after_seconds
|
13
|
+
|
14
|
+
seconds_left.times do |i|
|
15
|
+
sleep 1
|
16
|
+
end
|
17
|
+
|
18
|
+
return step
|
19
|
+
end
|
20
|
+
|
21
|
+
response
|
22
|
+
end
|
23
|
+
|
24
|
+
def create
|
25
|
+
response = start
|
26
|
+
if response['status'] == 302
|
27
|
+
return step
|
28
|
+
else
|
29
|
+
return response
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Admincredible
|
2
|
+
module Resources
|
3
|
+
class Compatibility < Resource
|
4
|
+
def status
|
5
|
+
client.jget('compatibility', 'status')['data']
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_exceptions
|
9
|
+
client.jget('compatibility', 'add_exceptions', {:accept_terms => true})
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Admincredible
|
2
|
+
module Resources
|
3
|
+
class Extension < Resource
|
4
|
+
def all
|
5
|
+
client.jget('extensions', 'index')['data']['extensions']
|
6
|
+
end
|
7
|
+
alias :index :all
|
8
|
+
|
9
|
+
def update(extension_ids=[], repeat_until_response=true)
|
10
|
+
unless config.oauth?
|
11
|
+
client.rebuild_connection
|
12
|
+
connection.builder.request :retry, 18
|
13
|
+
end
|
14
|
+
|
15
|
+
response = nil
|
16
|
+
begin
|
17
|
+
response = client.jget('extensions', 'update', :extension_ids => extension_ids)
|
18
|
+
rescue Faraday::Error::TimeoutError => e
|
19
|
+
if repeat_until_response && config.oauth?
|
20
|
+
seconds_left = config.step_after_seconds
|
21
|
+
|
22
|
+
seconds_left.times do |i|
|
23
|
+
sleep 1
|
24
|
+
end
|
25
|
+
|
26
|
+
return update(extension_ids)
|
27
|
+
else
|
28
|
+
response = false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
client.rebuild_connection unless config.oauth?
|
33
|
+
response
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Admincredible
|
2
|
+
module Resources
|
3
|
+
class Oauth < Resource
|
4
|
+
def register
|
5
|
+
response = client.jget('oauth', 'register')
|
6
|
+
return response unless response['status'] == 200
|
7
|
+
|
8
|
+
config.consumer_key = response['data']['osr_consumer_key']
|
9
|
+
config.consumer_secret = response['data']['osr_consumer_secret']
|
10
|
+
|
11
|
+
client.rebuild_connection
|
12
|
+
return response['data']
|
13
|
+
end
|
14
|
+
|
15
|
+
def request_token
|
16
|
+
response = client.jget('oauth', 'request_token')
|
17
|
+
return response unless response['status'] == 200
|
18
|
+
|
19
|
+
config.token = response['data']['request_token']['oauth_token']
|
20
|
+
config.token_secret = response['data']['request_token']['oauth_token_secret']
|
21
|
+
|
22
|
+
client.rebuild_connection
|
23
|
+
return response['data']['request_token']
|
24
|
+
end
|
25
|
+
|
26
|
+
def authorization_url
|
27
|
+
url = config.url.gsub(config.direct_endpoint, config.main_endpoint)
|
28
|
+
url = URI.parse(url)
|
29
|
+
params = CGI.parse(url.query)
|
30
|
+
|
31
|
+
return ROAuth.sign_url(config.oauth_options, url.scheme + '://' + url.host + url.path, params.merge({:oauth_callback => config.oauth_callback}))
|
32
|
+
end
|
33
|
+
|
34
|
+
def access_token(oauth_verifier)
|
35
|
+
params = {
|
36
|
+
:resource => 'oauth',
|
37
|
+
:task => 'access_token',
|
38
|
+
:oauth_token => config.token,
|
39
|
+
:oauth_verifier => oauth_verifier
|
40
|
+
}
|
41
|
+
oauth_header = ROAuth.header(config.oauth_options, config.url, params)
|
42
|
+
response = JSON.parse(Nestful.get(config.url, :params => params, :headers => {'Accept' => 'application/json', 'Authorization' => oauth_header}))
|
43
|
+
return response unless response['status'] == 200
|
44
|
+
|
45
|
+
config.token = response['data']['access_token']['oauth_token']
|
46
|
+
config.token_secret = response['data']['access_token']['oauth_token_secret']
|
47
|
+
|
48
|
+
client.rebuild_connection
|
49
|
+
return response['data']['access_token']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Admincredible
|
2
|
+
module Resources
|
3
|
+
class Setting < Resource
|
4
|
+
def all
|
5
|
+
client.jget('settings', 'index')['data']
|
6
|
+
end
|
7
|
+
|
8
|
+
def first
|
9
|
+
client.jget('settings', 'read')['data']
|
10
|
+
end
|
11
|
+
|
12
|
+
def create(*args)
|
13
|
+
client.jpost('settings', 'create', args.extract_options!)['data']
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(*args)
|
17
|
+
client.jpost('settings', 'update', args.extract_options!)['data']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Admincredible
|
2
|
+
module Resources
|
3
|
+
class Upgrade < Resource
|
4
|
+
def info
|
5
|
+
client.jget('upgrade', 'info')['data']
|
6
|
+
end
|
7
|
+
|
8
|
+
def download
|
9
|
+
client.jget('upgrade', 'download')
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_restoration_file
|
13
|
+
client.jget('upgrade', 'create_restoration_file')
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
client.jget('upgrade', 'start')
|
18
|
+
end
|
19
|
+
|
20
|
+
def step(repeat_until_done=true)
|
21
|
+
response = client.jget('upgrade', 'step')
|
22
|
+
|
23
|
+
if response['status'] == 'working' && repeat_until_done
|
24
|
+
seconds_left = config.step_after_seconds
|
25
|
+
|
26
|
+
seconds_left.times do |i|
|
27
|
+
sleep 1
|
28
|
+
end
|
29
|
+
|
30
|
+
return step
|
31
|
+
end
|
32
|
+
|
33
|
+
response
|
34
|
+
end
|
35
|
+
|
36
|
+
def finalize
|
37
|
+
client.jget('upgrade', 'finalize')
|
38
|
+
end
|
39
|
+
|
40
|
+
def cleanup
|
41
|
+
client.jget('upgrade', 'cleanup')
|
42
|
+
end
|
43
|
+
|
44
|
+
def create
|
45
|
+
response = download
|
46
|
+
return response unless response['status'] == 200
|
47
|
+
|
48
|
+
response = create_restoration_file
|
49
|
+
return response unless response['status'] == 200
|
50
|
+
|
51
|
+
response = start
|
52
|
+
return response unless response['status'] == 302
|
53
|
+
|
54
|
+
response = step
|
55
|
+
return response unless response['status'] == 200
|
56
|
+
|
57
|
+
response = finalize
|
58
|
+
return response unless response['status'] == 200
|
59
|
+
|
60
|
+
return cleanup
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|