nextcloud-client 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/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "nextcloud-client"
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(__FILE__)
data/bin/patch_gems.sh ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ clear
3
+ rm -rf nextcloud-1.3.3.gem Gemfile.lock
4
+ bundle config set mirror.http://rubygems.org https://nexus.mahillmann.de/repository/Ruby/
5
+ RAILS_ENV=development bundle install 2>&1 | grep "activesupport\|json\|nokogiri\|net-http-report"
6
+ rspec && \
7
+ /usr/local/bundle/bin/rubocop && \
8
+ gem build nextcloud
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
@@ -0,0 +1,63 @@
1
+ module NextcloudClient
2
+ class Api
3
+ attr_reader :url, :username, :password
4
+ protected :url
5
+ protected :username
6
+ protected :password
7
+
8
+ # Gathers credentials for communicating with Nextcloud instance
9
+ #
10
+ # @param [Hash] args authentication credentials.
11
+ # @option args [String] :url Nextcloud instance URL
12
+ # @option args [String] :username Nextcloud instance administrator username
13
+ # @option args [String] :password Nextcloud instance administrator password
14
+ def initialize(args)
15
+ @url = URI(args[:url] + "/ocs/v2.php/cloud/")
16
+ @username = args[:username]
17
+ @password = args[:password]
18
+ end
19
+
20
+ # Sends API request to Nextcloud
21
+ #
22
+ # @param method [Symbol] Request type. Can be :get, :post, :put, etc.
23
+ # @param path [String] Nextcloud OCS API request path
24
+ # @param params [Hash, nil] Parameters to send
25
+ # @return [Object] Nokogiri::XML::Document
26
+ def request(method, path, params = nil, body = nil, depth = nil, destination = nil, raw = false)
27
+ response = Net::HTTP.start(@url.host, @url.port,
28
+ use_ssl: @url.scheme == "https") do |http|
29
+ req = Kernel.const_get("Net::HTTP::#{method.capitalize}").new(@url.request_uri + path)
30
+ req["OCS-APIRequest"] = true
31
+ req.basic_auth @username, @password
32
+ req["Content-Type"] = "application/x-www-form-urlencoded"
33
+
34
+ req["Depth"] = 0 if depth
35
+ req["Destination"] = destination if destination
36
+
37
+ req.set_form_data(params) if params
38
+ req.body = body if body
39
+
40
+ http.request(req)
41
+ end
42
+
43
+ # if ![201, 204, 207].include? response.code
44
+ # raise Errors::Error.new("Nextcloud received invalid status code")
45
+ # end
46
+ raw ? response.body : Nokogiri::XML.parse(response.body)
47
+ end
48
+
49
+ # Creates Ocs API instance
50
+ #
51
+ # @return [Object] OcsApi
52
+ def ocs
53
+ OcsApi.new(url: @url, username: @username, password: @password)
54
+ end
55
+
56
+ # Create WebDav API instance
57
+ #
58
+ # @return [Object] WebdavApi
59
+ def webdav
60
+ WebdavApi.new(url: @url, username: @username, password: @password)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,5 @@
1
+ module NextcloudClient
2
+ module Errors
3
+ class Error < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,102 @@
1
+ require "active_support"
2
+ require "active_support/core_ext/hash"
3
+ require "json"
4
+
5
+ module NextcloudClient
6
+ # Helper methods that are used through lib
7
+ module Helpers
8
+ # Makes an array out of repeated elements
9
+ #
10
+ # @param doc [Object] Nokogiri::XML::Document
11
+ # @param xpath [String] Path to element that is being repeated
12
+ # @return [Array] Parsed array
13
+ def parse_with_meta(doc, xpath)
14
+ groups = []
15
+ doc.xpath(xpath).each do |prop|
16
+ groups << prop.text
17
+ end
18
+ meta = get_meta(doc)
19
+ groups.send(:define_singleton_method, :meta) do
20
+ meta
21
+ end
22
+ groups
23
+ end
24
+
25
+ # Parses meta information returned by API, may include a status, status code and a message
26
+ #
27
+ # @param doc [Object] Nokogiri::XML::Document
28
+ # @return [Hash] Parsed hash
29
+ def get_meta(doc)
30
+ meta = doc.xpath("//meta/*").each_with_object({}) do |node, meta|
31
+ meta[node.name] = node.text
32
+ end
33
+ end
34
+
35
+ # Converts document to hash
36
+ #
37
+ # @param doc [Object] Nokogiri::XML::Document
38
+ # @param xpath [String] Document path to convert to hash
39
+ # @return [Hash] Hash that was produced from XML document
40
+ def doc_to_hash(doc, xpath = "/")
41
+ h = Hash.from_xml(doc.xpath(xpath).to_xml)
42
+ h
43
+ end
44
+
45
+ # Adds meta method to an object
46
+ #
47
+ # @param doc [Object] Nokogiri::XML::Document to take meta information from
48
+ # @param obj [#define_singleton_method] Object to add meta method to
49
+ # @return [#define_singleton_method] Object with meta method defined
50
+ def add_meta(doc, obj)
51
+ meta = get_meta(doc)
52
+ obj.define_singleton_method(:meta) { meta } && obj
53
+ end
54
+
55
+ # Extracts remaining part of url
56
+ #
57
+ # @param href [String] Full url
58
+ # @param url [String] Part to give away
59
+ # @return [String] "Right" part of string
60
+ def path_from_href(href, url)
61
+ href.match(/#{url}(.*)/)[1]
62
+ end
63
+
64
+ # Shows errors, or success message
65
+ #
66
+ # @param doc [Object] Nokogiri::XML::Document
67
+ # @return [Hash] State response
68
+ def parse_dav_response(doc)
69
+ doc.remove_namespaces!
70
+ if doc.at_xpath("//error")
71
+ {
72
+ exception: doc.xpath("//exception").text,
73
+ message: doc.xpath("//message").text
74
+ }
75
+ elsif doc.at_xpath("//status")
76
+ {
77
+ status: doc.xpath("//status").text
78
+ }
79
+ else
80
+ {
81
+ status: "ok"
82
+ }
83
+ end
84
+ end
85
+
86
+ # Shows error or returns false
87
+ #
88
+ # @param doc [Object] Nokogiri::XML::Document
89
+ # @return [Hash,Boolean] Returns error message if found, false otherwise
90
+ def has_dav_errors(doc)
91
+ doc.remove_namespaces!
92
+ if doc.at_xpath("//error")
93
+ {
94
+ exception: doc.xpath("//exception").text,
95
+ message: doc.xpath("//message").text
96
+ }
97
+ else
98
+ false
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,76 @@
1
+ module NextcloudClient
2
+ module Helpers
3
+ module Properties
4
+ # Body to send to receive item properties
5
+ RESOURCE = '<?xml version="1.0"?>
6
+ <d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
7
+ <d:prop>
8
+ <d:displayname />
9
+ <d:creationdate />
10
+ <d:getlastmodified />
11
+ <d:getetag />
12
+ <d:resourcetype />
13
+ <d:getcontenttype />
14
+ <d:getcontentlength />
15
+ <oc:id />
16
+ <oc:fileid />
17
+ <oc:permissions />
18
+ <oc:size />
19
+ <nc:has-preview />
20
+ <oc:favorite />
21
+ <oc:comments-href />
22
+ <oc:comments-count />
23
+ <oc:comments-unread />
24
+ <oc:owner-id />
25
+ <oc:owner-display-name />
26
+ <oc:share-types />
27
+ <nc:has-preview />
28
+ <oc:downloadURL />
29
+ </d:prop>
30
+ </d:propfind>'.freeze
31
+
32
+ # Body to send to add an item to favorites
33
+ MAKE_FAVORITE = '<?xml version="1.0"?>
34
+ <d:propertyupdate xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
35
+ <d:set>
36
+ <d:prop>
37
+ <oc:favorite>1</oc:favorite>
38
+ </d:prop>
39
+ </d:set>
40
+ </d:propertyupdate>'.freeze
41
+
42
+ # Body to send to unfavorite an item
43
+ UNFAVORITE = '<?xml version="1.0"?>
44
+ <d:propertyupdate xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
45
+ <d:set>
46
+ <d:prop>
47
+ <oc:favorite>0</oc:favorite>
48
+ </d:prop>
49
+ </d:set>
50
+ </d:propertyupdate>'.freeze
51
+
52
+ # Body to send for receiving favorites
53
+ FAVORITE = '<?xml version="1.0"?>
54
+ <oc:filter-files xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
55
+ <oc:filter-rules>
56
+ <oc:favorite>1</oc:favorite>
57
+ </oc:filter-rules>
58
+ <d:prop>
59
+ <d:getlastmodified />
60
+ <d:getetag />
61
+ <d:getcontenttype />
62
+ <d:resourcetype />
63
+ <oc:fileid />
64
+ <oc:permissions />
65
+ <oc:size />
66
+ <d:getcontentlength />
67
+ <nc:has-preview />
68
+ <oc:favorite />
69
+ <oc:comments-unread />
70
+ <oc:owner-display-name />
71
+ <oc:share-types />
72
+ </d:prop>
73
+ </oc:filter-files>'.freeze
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,78 @@
1
+ module NextcloudClient
2
+ module Models
3
+ # Directory model
4
+ #
5
+ # @!attribute [rw] href
6
+ # @return [String] File/directory location
7
+ # @!attribute [rw] creationdate
8
+ # @return [String] Creation date time of file/directory
9
+ # @!attribute [rw] lastmodified
10
+ # @return [String] Last modification time of file/directory
11
+ # @!attribute [rw] tag
12
+ # @return [Hash] Etag
13
+ # @!attribute [rw] resourcetype
14
+ # @return [String] Type of a resource
15
+ # @!attribute [rw] contenttype
16
+ # @return [String] Type of content
17
+ # @!attribute [rw] contentlength
18
+ # @return [String] Length of content
19
+ # @!attribute [rw] id
20
+ # @return [String] ID
21
+ # @!attribute [rw] fileid
22
+ # @return [String] Fileid
23
+ # @!attribute [rw] permissions
24
+ # @return [String] Permissions
25
+ # @!attribute [rw] has_preview
26
+ # @return [String] Has preview or not
27
+ # @!attribute [rw] favorite
28
+ # @return [String] Is favorited or not
29
+ # @!attribute [rw] comments_href
30
+ # @return [String] Address of comments
31
+ # @!attribute [rw] comments_count
32
+ # @return [String] Comments count
33
+ # @!attribute [rw] comments_unread
34
+ # @return [String] Unread comments
35
+ # @!attribute [rw] owner_id
36
+ # @return [String] Id of owner
37
+ # @!attribute [rw] owner_display_name
38
+ # @return [String] Display name of owner
39
+ # @!attribute [rw] displayname
40
+ # @return [String] Display name of file/directory
41
+ # @!attribute [rw] share_types
42
+ # @return [String] Share types
43
+ class Directory
44
+ attr_accessor :meta, :contents
45
+
46
+ # Initiates a model instance
47
+ #
48
+ # @param [Hash]
49
+ def initialize(href: nil, creationdate: nil, lastmodified: nil, tag: nil, resourcetype: nil, contenttype: nil,
50
+ contentlength: nil, id: nil, fileid: nil, permissions: nil, size: nil, has_preview: nil, favorite: nil,
51
+ comments_href: nil, comments_count: nil, comments_unread: nil, owner_id: nil,
52
+ owner_display_name: nil, displayname: nil, share_types: nil, skip_contents: false)
53
+
54
+ self.class.params.each do |v|
55
+ instance_variable_set("@#{v}", instance_eval(v.to_s)) if instance_eval(v.to_s)
56
+ end
57
+
58
+ remove_instance_variable (:@skip_contents) if skip_contents
59
+ end
60
+
61
+ @params = instance_method(:initialize).parameters.map(&:last)
62
+ @params.each { |p| instance_eval("attr_accessor :#{p}") }
63
+
64
+ class << self
65
+ attr_reader :params
66
+ end
67
+
68
+ # Adds content to collection
69
+ #
70
+ # @param [Hash]
71
+ # @return [Array] Contents array
72
+ def add(args)
73
+ @contents = [] if @contents.nil?
74
+ @contents << self.class.new(**args.merge(skip_contents: true))
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,50 @@
1
+ module NextcloudClient
2
+ module Models
3
+ # User model
4
+ #
5
+ # @!attribute [rw] enabled
6
+ # @return [String] Is an user enabled or not
7
+ # @!attribute [rw] id
8
+ # @return [String] Identifier of an user
9
+ # @!attribute [rw] quota
10
+ # @return [Hash] Quota of user
11
+ # @!attribute [rw] email
12
+ # @return [String] E-mail address
13
+ # @!attribute [rw] displayname
14
+ # @return [String] User display name
15
+ # @!attribute [rw] phone
16
+ # @return [String] User phone number
17
+ # @!attribute [rw] address
18
+ # @return [String] User address
19
+ # @!attribute [rw] website
20
+ # @return [String] User web-site address
21
+ # @!attribute [rw] twitter
22
+ # @return [String] User Twitter account
23
+ # @!attribute [rw] groups
24
+ # @return [String] Groups user belongs to
25
+ # @!attribute [rw] language
26
+ # @return [String] Nextcloud version for an user
27
+ class User
28
+ attr_accessor :meta
29
+
30
+ # Initiates a model instance
31
+ #
32
+ # @param [Hash]
33
+ def initialize(enabled: nil, id: nil, quota: nil, email: nil, displayname: nil, phone: nil, address: nil,
34
+ website: nil,
35
+ twitter: nil, groups: nil, language: nil)
36
+
37
+ self.class.params.each do |v|
38
+ instance_variable_set("@#{v}", instance_eval(v.to_s)) if instance_eval(v.to_s)
39
+ end
40
+ end
41
+
42
+ @params = instance_method(:initialize).parameters.map(&:last)
43
+ @params.each { |p| instance_eval("attr_accessor :#{p}") }
44
+
45
+ class << self
46
+ attr_reader :params
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,90 @@
1
+ module NextcloudClient
2
+ module Ocs
3
+ # Application class used for interfering with app specific actions
4
+ #
5
+ # @!attribute [rw] meta
6
+ # @return [Hash] Information about API response
7
+ # @!attribute [rw] appid
8
+ # @return [Integer] Application identifier
9
+ class App < OcsApi
10
+ include Helpers
11
+
12
+ attr_accessor :meta, :appid
13
+
14
+ # Application initializer
15
+ #
16
+ # @param api [Object] Api instance
17
+ # @param appid [Integer,nil] Application identifier
18
+ def initialize(args, appid = nil)
19
+ @appid = appid if appid
20
+
21
+ if args.class == NextcloudClient::OcsApi
22
+ @api = args
23
+ else
24
+ super(args)
25
+ @api = self
26
+ end
27
+ end
28
+
29
+ # Sets app (useful if class is initiated without OcsApi.app)
30
+ #
31
+ # @param appid [String] App identifier
32
+ # @return [Obeject] self
33
+ def set(appid)
34
+ @appid = appid
35
+ self
36
+ end
37
+
38
+ # List enabled applications
39
+ #
40
+ # @return [Array] List of applications that are enabled on an instance
41
+ def enabled
42
+ filter("enabled")
43
+ end
44
+
45
+ # List disabled applications
46
+ #
47
+ # @return [Array] List of applications that are disabled on an instance
48
+ def disabled
49
+ filter("disabled")
50
+ end
51
+
52
+ # Get information about an applicaiton
53
+ #
54
+ # @param appid [Integer] Application identifier
55
+ # @return [Hash] Application information
56
+ def find(appid)
57
+ response = @api.request(:get, "apps/#{appid}")
58
+ h = doc_to_hash(response, "//data")["data"]
59
+ add_meta(response, h)
60
+ end
61
+
62
+ # Enable an application
63
+ #
64
+ # @return [Object] Instance with meta response
65
+ def enable
66
+ response = @api.request(:post, "apps/#{@appid}")
67
+ (@meta = get_meta(response)) && self
68
+ end
69
+
70
+ # Disable an application
71
+ #
72
+ # @return [Object] Instance with meta response
73
+ def disable
74
+ response = @api.request(:delete, "apps/#{@appid}")
75
+ (@meta = get_meta(response)) && self
76
+ end
77
+
78
+ private
79
+
80
+ # Retrieve enabled or disabled applications
81
+ #
82
+ # @param filter [String] Either enabled or disabled
83
+ # @return [Array] List of applications with meta method
84
+ def filter(filter)
85
+ response = @api.request(:get, "apps?filter=#{filter}")
86
+ parse_with_meta(response, "//data/apps/element")
87
+ end
88
+ end
89
+ end
90
+ end