parse-stack 1.3.1 → 1.3.7

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 CHANGED
@@ -6,6 +6,7 @@ require 'rake/testtask'
6
6
  Rake::TestTask.new do |t|
7
7
  t.libs << 'lib/parse/stack'
8
8
  t.test_files = FileList['test/lib/**/*_test.rb']
9
+ t.warning = false
9
10
  t.verbose = true
10
11
  end
11
12
 
@@ -4,6 +4,11 @@ require "bundler/setup"
4
4
  require "parse/stack"
5
5
  require 'dotenv'
6
6
  Dotenv.load
7
+
8
+
9
+ class Song < Parse::Object
10
+ property :name
11
+ end
7
12
  # You can add fixtures and/or initialization code here to make experimenting
8
13
  # with your gem easier. You can also use a different console, if you like.
9
14
 
@@ -0,0 +1,2 @@
1
+ # Useful for some users that require 'parse-stack' manually
2
+ require_relative "./parse/stack.rb"
@@ -1,5 +1,6 @@
1
1
  require 'parallel'
2
-
2
+ require 'active_support'
3
+ require 'active_support/core_ext'
3
4
  class Array
4
5
 
5
6
  def destroy
@@ -1,3 +1,5 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
1
3
 
2
4
  module Parse
3
5
 
@@ -1,3 +1,5 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
1
3
 
2
4
  module Parse
3
5
 
@@ -1,6 +1,14 @@
1
1
  require 'faraday'
2
2
  require 'faraday_middleware'
3
+ require 'active_support'
4
+ require 'active_model_serializers'
5
+ require 'active_support/inflector'
6
+ require 'active_support/core_ext/object'
3
7
  require 'active_support/core_ext/string'
8
+ require 'active_support/core_ext/date/calculations'
9
+ require 'active_support/core_ext/date_time/calculations'
10
+ require 'active_support/core_ext/time/calculations'
11
+ require 'active_support/core_ext'
4
12
  require_relative "client/request"
5
13
  require_relative "client/response"
6
14
  require_relative "client/body_builder"
@@ -17,6 +25,12 @@ module Parse
17
25
  class ServerError < Exception; end;
18
26
  class AuthenticationError < Exception; end;
19
27
  class RequestLimitExceededError < Exception; end;
28
+ class InvalidSessionTokenError < Exception; end;
29
+
30
+ # helper method to get the config variables.
31
+ def self.config(s = :default)
32
+ Parse::Client.session(s).config
33
+ end
20
34
 
21
35
  # Main class for the client. The client class is based on a Faraday stack.
22
36
  # The Faraday stack is similar to a Rack-style application in which you can define middlewares
@@ -42,6 +56,9 @@ module Parse
42
56
  # by the other classes including Parse::Query and Parse::Objects
43
57
  @@sessions = { default: nil }
44
58
 
59
+ def self.session?(v = :default)
60
+ @@sessions[v].present?
61
+ end
45
62
  # get a session for a given tag. This will also create a new one for the tag if not specified.
46
63
  def self.session(connection = :default)
47
64
  #warn "Please call Parse::Client.setup() to initialize your parse session" if @@sessions.empty? || @@sessions[:default].nil?
@@ -72,7 +89,7 @@ module Parse
72
89
  # :host - defaults to Parse::Protocol::SERVER_URL (https://api.parse.com/1/)
73
90
  def initialize(opts = {})
74
91
  @server_url = opts[:server_url] || ENV["PARSE_SERVER_URL"] || Parse::Protocol::SERVER_URL
75
- @application_id = opts[:application_id] || ENV["PARSE_APP_ID"]
92
+ @application_id = opts[:app_id] || opts[:application_id] || ENV["PARSE_APP_ID"]
76
93
  @api_key = opts[:api_key] || ENV["PARSE_API_KEY"]
77
94
  @master_key = opts[:master_key] || ENV["PARSE_MASTER_KEY"]
78
95
  opts[:adapter] ||= Faraday.default_adapter
@@ -104,6 +121,10 @@ module Parse
104
121
  # We place it after the Authentication middleware in case we need to use then
105
122
  # authentication information when building request and responses.
106
123
  conn.use Parse::Middleware::BodyBuilder
124
+ if opts[:logging].present? && opts[:logging] == :debug
125
+ Parse::Middleware::BodyBuilder.logging = true
126
+ end
127
+
107
128
  if opts[:cache].present? && opts[:expires].to_i > 0
108
129
  unless opts[:cache].is_a?(Moneta::Transformer)
109
130
  raise "Parse::Client option :cache needs to be a type of Moneta::Transformer store."
@@ -165,7 +186,12 @@ module Parse
165
186
  if opts[:use_master_key] == false
166
187
  headers[Parse::Middleware::Authentication::DISABLE_MASTER_KEY] = "true"
167
188
  end
168
-
189
+
190
+ if opts[:session_token].present?
191
+ headers[Parse::Middleware::Authentication::DISABLE_MASTER_KEY] = "true"
192
+ headers[Parse::Protocol::SESSION_TOKEN] = opts[:session_token]
193
+ end
194
+
169
195
  #if it is a :get request, then use query params, otherwise body.
170
196
  params = (method == :get ? query : body) || {}
171
197
  # if the path does not start with the '/1/' prefix, then add it to be nice.
@@ -202,6 +228,9 @@ module Parse
202
228
  elsif body.code == 155
203
229
  puts "[ParseError] #{body}"
204
230
  raise Parse::RequestLimitExceededError, body
231
+ elsif body.code == 209 #Error 209: invalid session token
232
+ puts "[ParseError] #{body}"
233
+ raise Parse::InvalidSessionTokenError, body
205
234
  end
206
235
  end
207
236
 
@@ -1,5 +1,8 @@
1
1
  require 'faraday'
2
2
  require 'faraday_middleware'
3
+ require 'active_support'
4
+ require 'active_support/core_ext'
5
+
3
6
  require_relative 'protocol'
4
7
  # All Parse requests require authentication with specific header values.
5
8
  # This middleware takes all outgoing requests and adds the proper header values
@@ -38,6 +41,13 @@ module Parse
38
41
  unless @master_key.blank? || env[:request_headers][DISABLE_MASTER_KEY].present?
39
42
  headers[MASTER_KEY] = @master_key
40
43
  end
44
+
45
+ env[:request_headers].delete(DISABLE_MASTER_KEY)
46
+
47
+ # delete the use of master key if we are using session token.
48
+ if env[:request_headers].key?(Parse::Protocol::SESSION_TOKEN)
49
+ headers.delete(MASTER_KEY)
50
+ end
41
51
  # merge the headers with the current provided headers
42
52
  env[:request_headers].merge! headers
43
53
  # set the content type of the request if it was not provided already.
@@ -2,6 +2,9 @@ require 'faraday'
2
2
  require 'faraday_middleware'
3
3
  require_relative 'response'
4
4
  require_relative 'protocol'
5
+ require 'active_support'
6
+ require 'active_support/core_ext'
7
+ require 'active_model_serializers'
5
8
  # This middleware takes an incoming response (after an outgoing request)
6
9
  # and creates a Parse::Response object.
7
10
  module Parse
@@ -1,4 +1,4 @@
1
-
1
+ require 'active_support'
2
2
  require 'active_support/json'
3
3
 
4
4
  module Parse
@@ -1,3 +1,4 @@
1
+ require 'active_support'
1
2
  require 'active_support/json'
2
3
  # This is the model that represents a response from Parse. A Response can also
3
4
  # be a set of responses (from a Batch response).
@@ -54,11 +54,11 @@ module Parse
54
54
  # them in parallel.
55
55
 
56
56
  def fetch!
57
- collection.fetch!
57
+ collection.fetch_objects!
58
58
  end
59
59
 
60
60
  def fetch
61
- collection.fetch
61
+ collection.fetch_objects
62
62
  end
63
63
  # Even though we may have full Parse Objects in the collection, when updating
64
64
  # or storing them in Parse, we actually just want Parse::Pointer objects.
@@ -1,3 +1,4 @@
1
+ require 'active_support'
1
2
  require 'active_support/inflector'
2
3
  require 'active_support/core_ext/object'
3
4
  require_relative 'pointer_collection_proxy'
@@ -1,7 +1,7 @@
1
1
  require 'active_model'
2
2
  require 'active_support'
3
3
  require 'active_support/inflector'
4
- require 'active_support/core_ext/object'
4
+ require 'active_support/core_ext'
5
5
  require 'time'
6
6
  require 'parallel'
7
7
  require_relative '../../client/request'
@@ -95,11 +95,11 @@ module Parse
95
95
  # updated_comparison_block = Proc.new { |x| x.updated_at }
96
96
 
97
97
  anchor_date = Parse::Date.now
98
- constraints.merge! :updated_at.lte => anchor_date
98
+ constraints.merge! :updated_at.on_or_before => anchor_date
99
99
  # oldest first, so we create a reduction-cycle
100
100
  constraints.merge! order: :updated_at.asc, limit: 100
101
101
  update_query = query(constraints)
102
- puts "Setting Anchor Date: #{anchor_date}"
102
+ #puts "Setting Anchor Date: #{anchor_date}"
103
103
  cursor = nil
104
104
  has_errors = false
105
105
  loop do
@@ -109,7 +109,7 @@ module Parse
109
109
 
110
110
  # verify we didn't get duplicates fetches
111
111
  if cursor.is_a?(Parse::Object) && results.any? { |x| x.id == cursor.id }
112
- warn "Unbounded update detected - stopping."
112
+ warn "[Parse::SaveAll] Unbounded update detected with id #{cursor.id}."
113
113
  has_errors = true
114
114
  break cursor
115
115
  end
@@ -124,13 +124,13 @@ module Parse
124
124
  cursor = results.last
125
125
  # slower version, but more accurate
126
126
  # cursor_item = results.max_by(&updated_comparison_block).updated_at
127
- puts "Updated #{results.count} records updated <= #{cursor.updated_at}"
127
+ # puts "[Parse::SaveAll] Updated #{results.count} records updated <= #{cursor.updated_at}"
128
128
 
129
129
  if cursor.is_a?(Parse::Object)
130
130
  update_query.where :updated_at.gte => cursor.updated_at
131
131
 
132
132
  if cursor.updated_at.present? && cursor.updated_at > anchor_date
133
- warn "Reached anchor date limit - stopping."
133
+ warn "[Parse::SaveAll] Reached anchor date #{anchor_date} < #{cursor.updated_at}"
134
134
  break cursor
135
135
  end
136
136
 
@@ -479,7 +479,7 @@ class Array
479
479
  # a parameter symbol can be passed indicating the lookup methodology. Default
480
480
  # is parallel which fetches all objects in parallel HTTP requests.
481
481
  # If nil is passed in, then all the fetching happens sequentially.
482
- def fetch!(lookup = :parallel)
482
+ def fetch_objects!(lookup = :parallel)
483
483
  # this gets all valid parse objects from the array
484
484
  items = valid_parse_objects
485
485
 
@@ -497,7 +497,7 @@ class Array
497
497
  # fetches all pointer objects in the array. You can pass a symbol argument
498
498
  # that provides the lookup methodology, default is :parallel. Objects that have
499
499
  # already been fetched (not in a pointer state) are skipped.
500
- def fetch(lookup = :parallel)
500
+ def fetch_objects(lookup = :parallel)
501
501
  items = valid_parse_objects
502
502
  if lookup == :parallel
503
503
  items.threaded_each { |o| o.fetch }
@@ -1,4 +1,10 @@
1
1
  require 'active_model'
2
+ require 'active_support'
3
+ require 'active_support/inflector'
4
+ require 'active_support/core_ext'
5
+ require 'active_support/core_ext/object'
6
+ require 'active_support/inflector'
7
+ require 'active_model_serializers'
2
8
  require 'active_support/inflector'
3
9
  require 'active_model_serializers'
4
10
  require 'time'
@@ -94,6 +100,9 @@ module Parse
94
100
  opts.merge!(data_type)
95
101
  data_type = :string
96
102
  end
103
+
104
+ # allow :bool for :boolean
105
+ data_type = :boolean if data_type == :bool
97
106
  # set defaults
98
107
  opts = { required: false,
99
108
  alias: true,
@@ -2,6 +2,15 @@ require_relative "properties"
2
2
  # This class adds methods to Parse::Objects in order to create a JSON Parse schema
3
3
  # in order to support table creation and table alterations.
4
4
  module Parse
5
+
6
+ def self.auto_upgrade!
7
+ klassModels = Parse::Object.descendants - [Parse::User, Parse::Installation, Parse::Role, Parse::Session]
8
+ klassModels.sort_by { |c| c.parse_class }.each do |klass|
9
+ yield(klass) if block_given?
10
+ klass.auto_upgrade!
11
+ end
12
+ end
13
+
5
14
  module Schema
6
15
 
7
16
  def self.included(base)
@@ -1,8 +1,12 @@
1
1
  require 'time'
2
+ require 'date'
2
3
  require 'active_model'
3
4
  require 'active_support'
4
5
  require 'active_support/inflector'
5
6
  require 'active_support/core_ext/object'
7
+ require 'active_support/core_ext/date/calculations'
8
+ require 'active_support/core_ext/date_time/calculations'
9
+ require 'active_support/core_ext/time/calculations'
6
10
  require 'active_model_serializers'
7
11
  require_relative 'model'
8
12
 
@@ -20,14 +20,21 @@ module Parse
20
20
  alias_method :__type, :parse_class
21
21
  FIELD_NAME = "name".freeze
22
22
  FIELD_URL = "url".freeze
23
+ class << self
24
+ attr_accessor :default_mime_type
23
25
 
26
+ def default_mime_type
27
+ @default_mime_type ||= "image/jpeg"
28
+ end
29
+ end
24
30
  # The initializer to create a new file supports different inputs.
25
31
  # If the first paramter is a string which starts with 'http', we then download
26
32
  # the content of the file (and use the detected mime-type) to set the content and mime_type fields.
27
33
  # If the first parameter is a hash, we assume it might be the Parse File hash format which contains url and name fields only.
28
34
  # If the first paramter is a Parse::File, then we copy fields over
29
35
  # Otherwise, creating a new file requires a name, the actual contents (usually from a File.open("local.jpg").read ) and the mime-type
30
- def initialize(name, contents = nil, mime_type = "application/octet-stream".freeze)
36
+ def initialize(name, contents = nil, mime_type = nil)
37
+ mime_type ||= Parse::File.default_mime_type
31
38
 
32
39
  if name.is_a?(String) && name.start_with?("http".freeze) #could be url string
33
40
  file = open( name )
@@ -39,7 +46,7 @@ module Parse
39
46
  elsif name.is_a?(::File)
40
47
  @contents = contents || name.read
41
48
  @name = File.basename name.to_path
42
- elsif name.is_a?(File)
49
+ elsif name.is_a?(Parse::File)
43
50
  @name = name.name
44
51
  @url = name.url
45
52
  else
@@ -109,6 +116,14 @@ module Parse
109
116
  saved?
110
117
  end
111
118
 
119
+ def inspect
120
+ "<Parse::File @name='#{@name}' @mime_type='#{@mime_type}' @contents=#{@contents.nil?} @url='#{@url}'>"
121
+ end
122
+
123
+ def to_s
124
+ @url
125
+ end
126
+
112
127
  end
113
128
 
114
129
  end
@@ -10,15 +10,24 @@ module Parse
10
10
  attr_accessor :latitude, :longitude
11
11
  FIELD_LAT = "latitude".freeze
12
12
  FIELD_LNG = "longitude".freeze
13
+ # Latitude should not be -90.0 or 90.0.
14
+ # Longitude should not be -180.0 or 180.0.
15
+ LAT_MIN = -90.0
16
+ LAT_MAX = 90.0
17
+ LNG_MIN = -180.0
18
+ LNG_MAX = 180.0
13
19
  alias_method :lat, :latitude
14
20
  alias_method :lng, :longitude
15
21
  def self.parse_class; TYPE_GEOPOINT; end;
16
22
  def parse_class; self.class.parse_class; end;
17
23
  alias_method :__type, :parse_class
18
- # TODO: Validate the ranges of the geo point for valid lat and lng numbers.
19
24
  # To create a GeoPoint, you can either pass a hash (ex. {latitude: 32, longitue: -117})
20
25
  # or an array (ex. [32,-117]) as the first parameter.
21
26
  # You may also pass a GeoPoint object or both a lat/lng pair (Ex. GeoPoint.new(32, -117) )
27
+ # Points should not equal or exceed the extreme ends of the ranges.
28
+
29
+ # Attempting to use GeoPoint’s with latitude and/or longitude outside these ranges will cause an error.
30
+
22
31
  def initialize(latitude = nil, longitude = nil)
23
32
  @latitude = @longitude = 0.0
24
33
  if latitude.is_a?(Hash) || latitude.is_a?(Array)
@@ -30,6 +39,22 @@ module Parse
30
39
  @latitude = latitude.latitude
31
40
  @longitude = latitude.longitude
32
41
  end
42
+
43
+ _validate_point
44
+ end
45
+
46
+ def _validate_point
47
+
48
+ unless @latitude.nil? || @latitude.between?(LAT_MIN, LAT_MAX)
49
+ warn "[Parse::GeoPoint] Latitude (#{@latitude}) is not between #{LAT_MIN}, #{LAT_MAX}!"
50
+ warn "Attempting to use GeoPoint’s with latitudes outside these ranges will raise an exception in a future release."
51
+ end
52
+
53
+ unless @longitude.nil? || @longitude.between?(LNG_MIN, LNG_MAX)
54
+ warn "[Parse::GeoPoint] Longitude (#{@longitude}) is not between #{LNG_MIN}, #{LNG_MAX}!"
55
+ warn "Attempting to use GeoPoint’s with longitude outside these ranges will raise an exception in a future release."
56
+ end
57
+
33
58
  end
34
59
 
35
60
  def attributes
@@ -37,9 +62,20 @@ module Parse
37
62
  end
38
63
 
39
64
  def max_miles(m)
65
+ m = 0 if m.nil?
40
66
  [@latitude,@longitude,m]
41
67
  end
42
68
 
69
+ def latitude=(l)
70
+ @latitude = l
71
+ _validate_point
72
+ end
73
+
74
+ def longitude=(l)
75
+ @longitude = l
76
+ _validate_point
77
+ end
78
+
43
79
  # Setting lat and lng for an GeoPoint can be done using a hash with the attributes set
44
80
  # or with an array of two items where the first is the lat and the second is the lng (ex. [32.22,-118.81])
45
81
  def attributes=(h)
@@ -51,6 +87,7 @@ module Parse
51
87
  @latitude = h.first.to_f
52
88
  @longitude = h.last.to_f
53
89
  end
90
+ _validate_point
54
91
  end
55
92
 
56
93
  def ==(g)
@@ -75,7 +112,7 @@ module Parse
75
112
  unless geopoint.is_a?(Parse::GeoPoint)
76
113
  geopoint = Parse::GeoPoint.new(geopoint, lng)
77
114
  end
78
-
115
+
79
116
  dtor = Math::PI/180
80
117
  r = 6378.14
81
118
  r_lat1 = self.latitude * dtor
@@ -1,6 +1,7 @@
1
1
  require 'active_model'
2
2
  require 'active_support'
3
3
  require 'active_support/inflector'
4
+ require 'active_support/core_ext'
4
5
  require 'active_support/core_ext/object'
5
6
  require 'active_support/core_ext/string'
6
7
  require 'active_model_serializers'
@@ -78,7 +79,7 @@ module Parse
78
79
  def self.registered_classes
79
80
  Parse::Object.descendants.map { |m| m.parse_class }.uniq
80
81
  end
81
-
82
+
82
83
  # Find a corresponding class for this string or symbol
83
84
  def self.classify(className)
84
85
  Parse::Model.find_class className.to_parse_class