pcloud_api 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5ea6aab35912a377555ea6ee45e36ec29dbc797e620b4d738ea2665f2679e79
4
- data.tar.gz: 5bf4514161d144db50fbbd919e8886e1adc3144e9df7381db23a7594170c1cca
3
+ metadata.gz: 0bc6a66525cb7bfd47085851a95dbc1656759f92960611d1d66e5f466025c800
4
+ data.tar.gz: 3eb54b53ab7c2c97ece4db9a074cbf75d6aa602ba727c917a6f88dbc97997c92
5
5
  SHA512:
6
- metadata.gz: 23121677b95b60944d49d59623466841d08a7c1e1833013f6eaf6ca8e011799a26bc6bfadeb28b6c7c65e178cb51f5632e78ed76a2cd547a6d2d875dbbb4d1b8
7
- data.tar.gz: f1900eaf066f7dba20e6b8ef9b0bfa3554e070d5f0ca2b3bbd7cb5d858cbbcb405e60c144ace91048c3635658752fd4ab232af068f058e835b7ac0e2fd23db83
6
+ metadata.gz: 0ce986fc8cdedaed9773209c26afbaf08091d4285abbb40126a0fcc0fcac99d77bd1ce1250bed6cdce4dd79e445076ca49469f6ce0c2e3ccfb597a36bf41f79f
7
+ data.tar.gz: 5aa4fb9d5dd96227b61c18c2bc537ad4b73338509e8a0e6b710cc06415228c41f67efb7719258ae954eb0fe9f36fae55d9151622021fb1f4d8116767aae1cad8
data/CHANGELOG.md CHANGED
@@ -1,4 +1,13 @@
1
+ ## 0.2.0 2021-09-26
2
+
3
+ New
4
+ * An `.exists?` method has been added to `Pcloud::Folder` and `Pcloud::File`
5
+ * The `.find_by` method on `Pcloud::Folder` and `Pcloud::File` can now be called with either `:id` or `:path`. NOTE: pCloud treats `:id` with precedence, so an error will be raised if the method is called with both parameters at once. _(Allowing precedence in a method like this would likely feel like unexpected behavior, so my intention was to make it immediately obvious to the end user.)_
6
+
7
+ Change
8
+ * `Pcloud::Folder` and `Pcloud::File` `created_at` and `modified_at` timestamps are now returned as Ruby `Time` objects
9
+ * Some error class names and messages have been cleaned up for additional clarity and consistency.
10
+
1
11
  ## 0.1.0 2021-09-26
2
12
 
3
- * 1 major enhancement:
4
- * Initial release
13
+ Initial release
data/README.md CHANGED
@@ -25,8 +25,8 @@ Or install it yourself as:
25
25
  The `Pcloud::Client` can be configured by directly calling the `Pcloud::Client.configure` method in an initializer or somewhere else in your code at startup:
26
26
  ```ruby
27
27
  Pcloud::Client.configure(
28
- access_token: "your-pcloud-app-access-token",
29
- data_region: "EU"
28
+ access_token: "your-pcloud-app-access-token",
29
+ data_region: "EU"
30
30
  )
31
31
  ```
32
32
 
@@ -44,9 +44,9 @@ Pcloud::File.find_by(path: "/images/jack_the_cat.jpg")
44
44
 
45
45
  # Upload a new file, rename if already existing:
46
46
  Pcloud::File.upload(
47
- folder_id: 1,
48
- filename: "jack_goes_swimming.mp4",
49
- file: File.open("/Users/joshua/Downloads/jack_goes_swimming.mp4")
47
+ folder_id: 1,
48
+ filename: "jack_goes_swimming.mp4",
49
+ file: File.open("/Users/joshua/Downloads/jack_goes_swimming.mp4")
50
50
  )
51
51
  # NOTE: the upload method will allow you to specify either the `path` or the
52
52
  # `folder_id`, or you can choose to pass neither paramenter and your files will
@@ -54,9 +54,9 @@ Pcloud::File.upload(
54
54
 
55
55
  # Upload a file, force overwrite of existing file:
56
56
  Pcloud::File.upload!(
57
- folder_id: 1,
58
- filename: "jack_goes_swimming.mp4",
59
- file: File.open("/Users/joshua/Downloads/jack_goes_swimming.mp4")
57
+ folder_id: 1,
58
+ filename: "jack_goes_swimming.mp4",
59
+ file: File.open("/Users/joshua/Downloads/jack_goes_swimming.mp4")
60
60
  )
61
61
 
62
62
  # Rename a file:
@@ -106,16 +106,18 @@ jack_images.parent_folder
106
106
  jack_images.contents
107
107
  ```
108
108
 
109
- **Aside: path vs id:**
109
+ **Aside: path vs id**
110
+
110
111
  pCloud recommends using the `folder_id`, `parent_folder_id` or `file_id` params for API calls whenever possible, rather using an exact path. Folder and file ids are static, so this will make your code less brittle to changes in the file/folder tree. You can simply look up the id for a folder in the console ahead of time and then set it in your code, similar to how you would specify an AWS S3 bucket.
111
112
 
112
113
 
113
- **Aside: off-label client use:**
114
+ **Aside: off-label client use**
115
+
114
116
  The `Pcloud::File` and `Pcloud::Folder` APIs cover the most important, common functionality developers will want to access in a way that is easy to use without much onboarding. If you find that you still need to access other parts of the pCloud API that are not included in this gem yet, you can try calling other methods specified in [the pCloud API docs](https://docs.pcloud.com/) by interacting directly with the `Pcloud::Client`:
115
117
  ```ruby
116
118
  Pcloud::Client.execute("listrevisions", query: { fileid: 90000 })
117
119
  ```
118
- _(There are a few methods on the raw pCloud API that require manual login, which this gem does not yet support. If you find that you need access to these methods you may wish to look at using the [`pcloud`](https://github.com/7urkm3n/pcloud) gem instead.)
120
+ _(There are a few methods on the raw pCloud API that require manual login, which this gem does not yet support. If you find that you need access to these methods you may wish to look at using the [`pcloud`](https://github.com/7urkm3n/pcloud) gem instead.)_
119
121
 
120
122
  ### Generating an access token
121
123
 
data/lib/pcloud/file.rb CHANGED
@@ -1,10 +1,13 @@
1
1
  module Pcloud
2
2
  class File
3
- class UnsuportedUpdateParams < StandardError; end
4
3
  class ManformedUpdateParams < StandardError; end
5
4
  class InvalidParameter < StandardError; end
5
+ class InvalidParameters < StandardError; end
6
+ class MissingParameter < StandardError; end
6
7
  class UploadFailed < StandardError; end
8
+
7
9
  include Parser
10
+ include Pcloud::TimeHelper
8
11
 
9
12
  SUPPORTED_UPDATE_PARAMS = [:name, :parent_folder_id, :path].freeze
10
13
  FILE_CATAGORIES = {
@@ -28,16 +31,16 @@ module Pcloud
28
31
  @size = params.fetch(:size) # bytes
29
32
  @parent_folder_id = params.fetch(:parent_folder_id)
30
33
  @is_deleted = params.fetch(:is_deleted) || false
31
- @created_at = params.fetch(:created_at)
32
- @modified_at = params.fetch(:modified_at)
34
+ @created_at = time_from(params.fetch(:created_at))
35
+ @modified_at = time_from(params.fetch(:modified_at))
33
36
  end
34
37
 
35
38
  def update(params)
36
39
  unless (params.keys - SUPPORTED_UPDATE_PARAMS).empty?
37
- raise UnsuportedUpdateParams.new("Must be one of #{SUPPORTED_UPDATE_PARAMS}")
40
+ raise InvalidParameters.new("Must be one of #{SUPPORTED_UPDATE_PARAMS}")
38
41
  end
39
42
  if params[:path] && is_invalid_path_param?(params[:path])
40
- raise ManformedUpdateParams.new("`path` param must start and end with `/`")
43
+ raise ManformedUpdateParams.new(":path param must start and end with `/`")
41
44
  end
42
45
  query = {
43
46
  fileid: id,
@@ -73,41 +76,46 @@ module Pcloud
73
76
  private
74
77
 
75
78
  def is_invalid_path_param?(path_param)
76
- # Path params have to start and end with `/``
79
+ # Path params have to start and end with `/`
77
80
  [path_param[0], path_param[-1]] != ["/", "/"]
78
81
  end
79
82
 
80
83
  class << self
84
+ def exists?(id)
85
+ find(id)
86
+ true
87
+ rescue Pcloud::Client::ErrorResponse => e
88
+ return false if e.message == "File not found."
89
+ raise e
90
+ end
91
+
81
92
  def find(id)
82
93
  parse_one(Client.execute("stat", query: { fileid: id }))
83
94
  end
84
95
 
85
- def find_by(path:)
86
- parse_one(Client.execute("stat", query: { path: path }))
96
+ def find_by(params)
97
+ raise MissingParameter.new(":path or :id is required") unless params[:path] || params[:id]
98
+ raise InvalidParameters.new(":id takes precedent over :path, please only use one or the other") if params[:path] && params[:id]
99
+ parse_one(
100
+ Client.execute(
101
+ "stat",
102
+ query: { path: params[:path], fileid: params[:id] }.compact
103
+ )
104
+ )
87
105
  end
88
106
 
89
- def upload(filename:, file:, path: nil, folder_id: nil)
90
- process_upload(
91
- filename: filename,
92
- file: file,
93
- path: path,
94
- folder_id: folder_id
95
- )
107
+ def upload(params)
108
+ process_upload(params)
96
109
  end
97
110
 
98
- def upload!(filename:, file:, path: nil, folder_id: nil)
99
- process_upload(
100
- filename: filename,
101
- file: file,
102
- path: path,
103
- folder_id: folder_id,
104
- overwrite: true
105
- )
111
+ def upload!(params)
112
+ process_upload(params.merge({ overwrite: true }))
106
113
  end
107
114
 
108
115
  private
109
116
 
110
- def process_upload(filename:, file:, path: nil, folder_id: nil, overwrite: false)
117
+ def process_upload(params)
118
+ file = params.fetch(:file)
111
119
  raise InvalidParameter.new("The `file` parameter must be an instance of Ruby `File`") unless file.is_a?(::File)
112
120
 
113
121
  # === pCloud API behavior notes: ===
@@ -118,11 +126,11 @@ module Pcloud
118
126
  response = Client.execute(
119
127
  "uploadfile",
120
128
  body: {
121
- renameifexists: overwrite ? 0 : 1,
122
- path: path,
123
- folderid: folder_id,
124
- filename: filename,
125
- file: file
129
+ renameifexists: params[:overwrite] ? 0 : 1,
130
+ path: params[:path],
131
+ folderid: params[:folder_id],
132
+ filename: params.fetch(:filename),
133
+ file: file,
126
134
  }.compact,
127
135
  )
128
136
  # This method on the pCloud API can accept multiple uploads at once.
@@ -131,6 +139,9 @@ module Pcloud
131
139
  uploaded_file = parse_many(response).first
132
140
  raise UploadFailed if uploaded_file.nil?
133
141
  return uploaded_file
142
+ rescue KeyError => e
143
+ missing_param = e.message.gsub("key not found: ", "")
144
+ raise MissingParameter.new("#{missing_param} is required")
134
145
  end
135
146
  end
136
147
  end
data/lib/pcloud/folder.rb CHANGED
@@ -2,8 +2,11 @@ module Pcloud
2
2
  class Folder
3
3
  class UnsuportedUpdateParams < StandardError; end
4
4
  class ManformedUpdateParams < StandardError; end
5
- class InvalidCreateParams < StandardError; end
5
+ class InvalidParameters < StandardError; end
6
+ class MissingParameter < StandardError; end
7
+
6
8
  include Parser
9
+ include Pcloud::TimeHelper
7
10
 
8
11
  SUPPORTED_UPDATE_PARAMS = [:name, :parent_folder_id, :path].freeze
9
12
 
@@ -23,8 +26,8 @@ module Pcloud
23
26
  # have any contents set yet.
24
27
  @contents_are_confirmed = @contents && @contents.size > 0
25
28
  @is_deleted = params.fetch(:is_deleted) || false
26
- @created_at = params.fetch(:created_at)
27
- @modified_at = params.fetch(:modified_at)
29
+ @created_at = time_from(params.fetch(:created_at))
30
+ @modified_at = time_from(params.fetch(:modified_at))
28
31
  end
29
32
 
30
33
  def update(params)
@@ -32,7 +35,7 @@ module Pcloud
32
35
  raise UnsuportedUpdateParams.new("Must be one of #{SUPPORTED_UPDATE_PARAMS}")
33
36
  end
34
37
  if params[:path] && is_invalid_path_param?(params[:path])
35
- raise ManformedUpdateParams.new("`path` param must start and end with `/`")
38
+ raise ManformedUpdateParams.new(":path param must start and end with `/`")
36
39
  end
37
40
  query = {
38
41
  folderid: id,
@@ -72,7 +75,7 @@ module Pcloud
72
75
  private
73
76
 
74
77
  def is_invalid_path_param?(path_param)
75
- # Path params have to start and end with `/``
78
+ # Path params have to start and end with `/`
76
79
  [path_param[0], path_param[-1]] != ["/", "/"]
77
80
  end
78
81
 
@@ -83,16 +86,31 @@ module Pcloud
83
86
  elsif params[:path]
84
87
  parse_one(Client.execute("createfolderifnotexists", query: { path: params[:path] }))
85
88
  else
86
- raise InvalidCreateParams.new("first_or_create must be called with either `path` or both `parent_folder_id` and `name` params")
89
+ raise InvalidParameters.new("either :path or a combination of :parent_folder_id and :name params are required")
87
90
  end
88
91
  end
89
92
 
93
+ def exists?(id)
94
+ find(id)
95
+ true
96
+ rescue Pcloud::Client::ErrorResponse => e
97
+ return false if e.message == "Directory does not exist."
98
+ raise e
99
+ end
100
+
90
101
  def find(id)
91
102
  parse_one(Client.execute("listfolder", query: { folderid: id }))
92
103
  end
93
104
 
94
- def find_by(path:)
95
- parse_one(Client.execute("listfolder", query: { path: path }))
105
+ def find_by(params)
106
+ raise MissingParameter.new(":path or :id is required") unless params[:path] || params[:id]
107
+ raise InvalidParameters.new(":id takes precedent over :path, please only use one or the other") if params[:path] && params[:id]
108
+ parse_one(
109
+ Client.execute(
110
+ "listfolder",
111
+ query: { path: params[:path], folderid: params[:id] }.compact
112
+ )
113
+ )
96
114
  end
97
115
  end
98
116
  end
@@ -0,0 +1,26 @@
1
+ module Pcloud
2
+ module TimeHelper
3
+ class UnrecognizedTimeFormat < StandardError; end
4
+
5
+ TIMEZONE = TZInfo::Timezone.get(ENV.fetch("TZ", "UTC")).freeze
6
+
7
+ protected
8
+
9
+ def time_from(time)
10
+ time_object =
11
+ if time.is_a?(String)
12
+ Time.parse(time)
13
+ elsif time.is_a?(Integer)
14
+ return Time.at(time) if time.digits.size < 13
15
+ milliseconds = time.to_s[-3..-1].to_i
16
+ seconds = time.to_s[0..-4].to_i
17
+ Time.at(seconds, milliseconds, :millisecond)
18
+ elsif time.is_a?(Time)
19
+ time
20
+ else
21
+ raise Pcloud::TimeHelper::UnrecognizedTimeFormat.new(time.inspect)
22
+ end
23
+ TIMEZONE.to_local(time_object)
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module Pcloud
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/pcloud_api.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require "httparty"
2
+ require "tzinfo"
2
3
  require "json"
3
4
 
4
5
  require "pcloud/version"
6
+ require "pcloud/time_helper"
5
7
  require "pcloud/file/parser"
6
8
  require "pcloud/file"
7
9
  require "pcloud/folder/parser"
data/pcloud_api.gemspec CHANGED
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "pry", "~> 0.13"
31
31
 
32
32
  spec.add_dependency "httparty", "~> 0.16"
33
+ spec.add_dependency "tzinfo"
33
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pcloud_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Hunsche Jones
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-27 00:00:00.000000000 Z
11
+ date: 2021-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,6 +86,20 @@ dependencies:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
88
  version: '0.16'
89
+ - !ruby/object:Gem::Dependency
90
+ name: tzinfo
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
89
103
  description:
90
104
  email:
91
105
  - joshua@hunschejones.com
@@ -110,6 +124,7 @@ files:
110
124
  - lib/pcloud/file/parser.rb
111
125
  - lib/pcloud/folder.rb
112
126
  - lib/pcloud/folder/parser.rb
127
+ - lib/pcloud/time_helper.rb
113
128
  - lib/pcloud/version.rb
114
129
  - lib/pcloud_api.rb
115
130
  - pcloud_api.gemspec