admincredible 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/Gemfile +12 -0
  2. data/Gemfile.lock +86 -0
  3. data/Rakefile +24 -0
  4. data/Readme.md +121 -0
  5. data/TODOS +1 -0
  6. data/admincredible.gemspec +35 -0
  7. data/developer_notes/README.md +2 -0
  8. data/developer_notes/TODOS.md +0 -0
  9. data/lib/admincredible.rb +1 -0
  10. data/lib/admincredible/client.rb +60 -0
  11. data/lib/admincredible/configuration.rb +125 -0
  12. data/lib/admincredible/connection.rb +30 -0
  13. data/lib/admincredible/core_ext/string.rb +16 -0
  14. data/lib/admincredible/joomla_request.rb +22 -0
  15. data/lib/admincredible/middleware/logger.rb +51 -0
  16. data/lib/admincredible/middleware/step.rb +44 -0
  17. data/lib/admincredible/request.rb +47 -0
  18. data/lib/admincredible/resource.rb +20 -0
  19. data/lib/admincredible/resources/Backup.rb +34 -0
  20. data/lib/admincredible/resources/Compatibility.rb +13 -0
  21. data/lib/admincredible/resources/Extension.rb +37 -0
  22. data/lib/admincredible/resources/Oauth.rb +53 -0
  23. data/lib/admincredible/resources/Setting.rb +21 -0
  24. data/lib/admincredible/resources/Site.rb +9 -0
  25. data/lib/admincredible/resources/Upgrade.rb +64 -0
  26. data/spec/core/client_spec.rb +24 -0
  27. data/spec/core/resource_spec.rb +13 -0
  28. data/spec/fixtures/cassettes/backups/create.yml +73 -0
  29. data/spec/fixtures/cassettes/backups/start.yml +38 -0
  30. data/spec/fixtures/cassettes/backups/step.yml +38 -0
  31. data/spec/fixtures/cassettes/compatibility/added_exceptions.yml +38 -0
  32. data/spec/fixtures/cassettes/compatibility/status.yml +38 -0
  33. data/spec/fixtures/cassettes/extensions/all.yml +38 -0
  34. data/spec/fixtures/cassettes/extensions/update.yml +38 -0
  35. data/spec/fixtures/cassettes/settings/all.yml +38 -0
  36. data/spec/fixtures/cassettes/settings/created.yml +39 -0
  37. data/spec/fixtures/cassettes/settings/first.yml +38 -0
  38. data/spec/fixtures/cassettes/settings/updated.yml +39 -0
  39. data/spec/fixtures/cassettes/site/configuration.yml +41 -0
  40. data/spec/fixtures/cassettes/upgrade/cleanup.yml +38 -0
  41. data/spec/fixtures/cassettes/upgrade/create.yml +249 -0
  42. data/spec/fixtures/cassettes/upgrade/create_restoration_file.yml +38 -0
  43. data/spec/fixtures/cassettes/upgrade/download.yml +38 -0
  44. data/spec/fixtures/cassettes/upgrade/finalize.yml +38 -0
  45. data/spec/fixtures/cassettes/upgrade/info.yml +38 -0
  46. data/spec/fixtures/cassettes/upgrade/start.yml +39 -0
  47. data/spec/fixtures/cassettes/upgrade/step.yml +38 -0
  48. data/spec/resources/backups_spec.rb +36 -0
  49. data/spec/resources/compatibility_spec.rb +25 -0
  50. data/spec/resources/extensions_spec.rb +25 -0
  51. data/spec/resources/setting_spec.rb +47 -0
  52. data/spec/resources/site_spec.rb +14 -0
  53. data/spec/resources/upgrade_spec.rb +91 -0
  54. data/spec/spec_helper.rb +38 -0
  55. 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,9 @@
1
+ module Admincredible
2
+ module Resources
3
+ class Site < Resource
4
+ def configuration
5
+ client.jget('site', 'configuration')['data']
6
+ end
7
+ end
8
+ end
9
+ 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