parse-stack 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changes.md +21 -0
- data/Gemfile.lock +2 -2
- data/README.md +42 -34
- data/lib/parse/client.rb +41 -1
- data/lib/parse/client/caching.rb +11 -7
- data/lib/parse/client/response.rb +19 -1
- data/lib/parse/model/core/actions.rb +9 -3
- data/lib/parse/model/core/properties.rb +10 -2
- data/lib/parse/model/core/schema.rb +1 -1
- data/lib/parse/model/object.rb +5 -0
- data/lib/parse/query/constraints.rb +4 -0
- data/lib/parse/stack/version.rb +1 -1
- data/lib/parse/webhooks.rb +23 -12
- data/lib/parse/webhooks/payload.rb +10 -3
- data/parse-stack.gemspec +12 -2
- metadata +28 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a515a094fadb46b58f8acbefd80f8188e265b22
|
4
|
+
data.tar.gz: 64702d47c7a395c9ae754374aa9cf8b9fec048a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8402485e10d774c12325542f3a4aabcf24a10f7626a6dc1d32b76f47df9283408a796e5440642d6f84b0a58ebf777637a77fa94cb52e78f5027ae0a625fdd2c8
|
7
|
+
data.tar.gz: e080d1f9665dd80694eb5802162ab67a0b6bd72f8b8c6b9e4b8e0aa1ed348ce5c5dbceb21c89f1355b5769c4021fe7067458bef624e34caeb388da67da15e1c3
|
data/Changes.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Parse-Stack Changes
|
2
2
|
|
3
|
+
1.3.0
|
4
|
+
-----------
|
5
|
+
- **IMPORTANT**: __Raising an error no longer sends an error response back to
|
6
|
+
the client in a Webhook trigger. You must now call `error!('...')` instead of
|
7
|
+
calling `raise '...'`.__ The webhook block is now binded to the Parse::Payload
|
8
|
+
instance, removing the need to pass `payload` object; use the instance methods directly.
|
9
|
+
See updated README.md for more details.
|
10
|
+
- **Parse-Stack will throw new exceptions** depending on the error code returned by Parse. These
|
11
|
+
are of type AuthenticationError, TimeoutError, ProtocolError, ServerError, ConnectionError and RequestLimitExceededError.
|
12
|
+
- `nil` and Delete operations for `:integers` and `:booleans` are no longer typecast.
|
13
|
+
- Added aliases `before`, `on_or_before`, `after` and `on_or_after` to help with
|
14
|
+
comparing non-integer fields such as dates. These map to `lt`,`lte`, `gt` and `gte`.
|
15
|
+
- Schema API return true is no changes were made to the table on `auto_upgrade!` (success)
|
16
|
+
- Parse::Middleware::Caching no longer caches 404 and 410 responses; and responses
|
17
|
+
with content lengths less than 20 bytes.
|
18
|
+
- FIX: Parse::Payload when applying auth_data in Webhooks. This fixes handing Facebook
|
19
|
+
login with Android devices.
|
20
|
+
- New method `save!` to raise an exception if the save fails.
|
21
|
+
- FIX: Verify Content-Type header field is present for webhooks before checking its value.
|
22
|
+
- FIX: Support `reload!` when using it Padrino.
|
23
|
+
|
3
24
|
1.2.1
|
4
25
|
-----------
|
5
26
|
- Add active support string dependencies.
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
parse-stack (1.
|
4
|
+
parse-stack (1.3.0)
|
5
5
|
active_model_serializers (>= 0.9, < 1)
|
6
6
|
activemodel (>= 4.2.1, < 5)
|
7
7
|
activesupport (>= 4.2.1, < 5)
|
@@ -114,4 +114,4 @@ DEPENDENCIES
|
|
114
114
|
rake (~> 10)
|
115
115
|
|
116
116
|
BUNDLED WITH
|
117
|
-
1.
|
117
|
+
1.12.5
|
data/README.md
CHANGED
@@ -116,7 +116,7 @@ song.likes.add Parse::User.first(username: "persaud")
|
|
116
116
|
song.save
|
117
117
|
|
118
118
|
# find songs
|
119
|
-
songs = Song.all(artist: artist, :plays.gt => 100, :released.
|
119
|
+
songs = Song.all(artist: artist, :plays.gt => 100, :released.on_or_after => 30.days.ago)
|
120
120
|
|
121
121
|
songs.each { |s| s.tags.add "awesome" }
|
122
122
|
# batch saves
|
@@ -125,9 +125,6 @@ songs.save
|
|
125
125
|
# Call Cloud Code functions
|
126
126
|
result = Parse.call_function :myFunctionName, {param: value}
|
127
127
|
|
128
|
-
# Trigger a Parse Job
|
129
|
-
Parse.trigger_job :myBackgroundJob, {param: value}
|
130
|
-
|
131
128
|
```
|
132
129
|
|
133
130
|
## Main Features
|
@@ -138,7 +135,7 @@ While there are many additional features of the framework, these are the main po
|
|
138
135
|
- Queries support with caching middleware. (Reduces API usage)
|
139
136
|
- Support for all Parse data types.
|
140
137
|
- One-to-One, One-to-Many and Many-to-Many relations.
|
141
|
-
-
|
138
|
+
- Integration with Parse Cloud Code Webhooks.
|
142
139
|
- Send Push notifications with advanced targeting.
|
143
140
|
- Schema upgrades and migrations.
|
144
141
|
|
@@ -565,12 +562,15 @@ end
|
|
565
562
|
```
|
566
563
|
|
567
564
|
#### Raising an exception when save fails
|
568
|
-
By default, we return `true` or `false` for save and destroy operations. If you prefer to have `Parse::Object` raise an exception instead, you can tell to do so either globally or on a per-model basis.
|
565
|
+
By default, we return `true` or `false` for save and destroy operations. If you prefer to have `Parse::Object` raise an exception instead, you can tell to do so either globally or on a per-model basis. When a save fails, it will raise a `Parse::SaveFailureError`.
|
569
566
|
|
570
567
|
```ruby
|
571
568
|
Parse::Model.raise_on_save_failure = true # globally across all models
|
572
569
|
Song.raise_on_save_failure = true # per-model
|
573
570
|
|
571
|
+
# or per-instance raise on failure
|
572
|
+
song.save!
|
573
|
+
|
574
574
|
```
|
575
575
|
|
576
576
|
When enabled, if an error is returned by Parse due to saving or destroying a record, due to your `before_save` or `before_delete` validation cloud code triggers, `Parse::Object` will return the a `Parse::SaveFailureError` exception type. This exception has an instance method of `#object` which contains the object that failed to save.
|
@@ -579,7 +579,7 @@ When enabled, if an error is returned by Parse due to saving or destroying a rec
|
|
579
579
|
To create a new object you can call `#new` while passing a hash of attributes you want to set. You can then use the property accessors to also modify individual properties. As you modify properties, you can access dirty tracking state and data using the generated [`ActiveModel::Dirty`](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html) features. When you are ready to commit the new object to Parse, you can call `#save`.
|
580
580
|
|
581
581
|
```ruby
|
582
|
-
song = Song.new
|
582
|
+
song = Song.new name: "My Old Song"
|
583
583
|
song.new? # true
|
584
584
|
song.id # nil
|
585
585
|
song.released = DateTime.now
|
@@ -744,7 +744,7 @@ You can destroy a Parse record, just call the `#destroy` method. It will return
|
|
744
744
|
song.destroy
|
745
745
|
|
746
746
|
# or in a batch
|
747
|
-
songs = Song.all
|
747
|
+
songs = Song.all :limit => 10
|
748
748
|
songs.destroy # uses batch operation
|
749
749
|
```
|
750
750
|
|
@@ -973,15 +973,23 @@ Most of the constraints supported by Parse are available to `Parse::Query`. Assu
|
|
973
973
|
|
974
974
|
# less than
|
975
975
|
q.where :field.lt => value
|
976
|
+
# alias to `lt`; useful when dealing with dates
|
977
|
+
q.where :field.before => value
|
976
978
|
|
977
979
|
# less than or equal to
|
978
980
|
q.where :field.lte => value
|
981
|
+
# alias to `lte`; useful when dealing with dates
|
982
|
+
q.where :field.on_or_before => value
|
979
983
|
|
980
984
|
# greater than
|
981
985
|
q.where :field.gt => value
|
986
|
+
# alias to `gt`; useful when dealing with dates
|
987
|
+
q.where :field.after => value
|
982
988
|
|
983
989
|
# greater than or equal to
|
984
990
|
q.where :field.gte => value
|
991
|
+
# alias to `gte`; useful when dealing with dates
|
992
|
+
q.where :field.on_or_after => value
|
985
993
|
|
986
994
|
# Not equal to
|
987
995
|
q.where :field.not => value
|
@@ -1109,19 +1117,17 @@ Push notifications are implemented through the `Parse::Push` class. To send push
|
|
1109
1117
|
Parse Parse allows you to receive Cloud Code webhooks on your own hosted server. The `Parse::Webhooks` class is a lightweight Rack application that routes incoming Cloud Code webhook requests and payloads to locally registered handlers. The payloads are `Parse::Payload` type of objects that represent that data that Parse sends webhook handlers. You can register any of the Cloud Code webhook trigger hooks (`beforeSave`, `afterSave`, `beforeDelete`, `afterDelete`) and function hooks.
|
1110
1118
|
|
1111
1119
|
### Setup Cloud Code functions
|
1112
|
-
You can use the `route()` method to register handler blocks.
|
1113
|
-
|
1114
|
-
If a function block returns any value that is true for `blank?`, we will automatically return `true` as part of the response to the webhook. If an exception is raised inside the block, we will return the correct Parse error response with the value you provided.
|
1120
|
+
You can use the `route()` method to register handler blocks. The last value returned by the block will be returned back to the client in a success response. If `error!(value)` is called inside the block, we will return the correct Parse error response with the value you provided.
|
1115
1121
|
|
1116
1122
|
```ruby
|
1117
1123
|
# Register handling the 'helloWorld' function.
|
1118
|
-
Parse::Webhooks.route(:function, :helloWorld) do
|
1119
|
-
# use the Parse::Payload
|
1120
|
-
|
1124
|
+
Parse::Webhooks.route(:function, :helloWorld) do
|
1125
|
+
# use the Parse::Payload instance methods in this block
|
1126
|
+
incoming_params = params #function params
|
1121
1127
|
name = params['name'].to_s
|
1122
1128
|
|
1123
1129
|
# will return proper error response
|
1124
|
-
|
1130
|
+
error!("Missing argument 'name'.") unless name.present?
|
1125
1131
|
# return early
|
1126
1132
|
"Hello #{name}!"
|
1127
1133
|
end
|
@@ -1135,9 +1141,9 @@ If you are creating `Parse::Object` subclasses, you may also register them there
|
|
1135
1141
|
```ruby
|
1136
1142
|
class Song < Parse::Object
|
1137
1143
|
|
1138
|
-
webhook :function, :mySongFunction do
|
1139
|
-
|
1140
|
-
params =
|
1144
|
+
webhook :function, :mySongFunction do
|
1145
|
+
the_user = user # available if a Parse user made the call
|
1146
|
+
params = params
|
1141
1147
|
# ... do stuff ...
|
1142
1148
|
true
|
1143
1149
|
end
|
@@ -1147,7 +1153,7 @@ end
|
|
1147
1153
|
```
|
1148
1154
|
|
1149
1155
|
### Setup Cloud Code Triggers
|
1150
|
-
You can register webhooks to handle the different object triggers: `:before_save`, `:after_save`, `:before_delete` and `:after_delete`.
|
1156
|
+
You can register webhooks to handle the different object triggers: `:before_save`, `:after_save`, `:before_delete` and `:after_delete`. The `payload` object, which is an instance of `Parse::Payload`, contains several properties that represent the payload. One of the most important ones is `parse_object`, which will provide you with the instance of your specific Parse object. In `:before_save` triggers, this object already contains dirty tracking information of what has been changed.
|
1151
1157
|
|
1152
1158
|
```ruby
|
1153
1159
|
# recommended way
|
@@ -1155,23 +1161,25 @@ You can register webhooks to handle the different object triggers: `:before_save
|
|
1155
1161
|
# ... properties ...
|
1156
1162
|
|
1157
1163
|
# setup after save for Artist
|
1158
|
-
webhook :after_save do
|
1159
|
-
user
|
1160
|
-
artist =
|
1164
|
+
webhook :after_save do
|
1165
|
+
puts "User: #{user.username}" if user.present? # Parse::User
|
1166
|
+
artist = parse_object # Artist
|
1167
|
+
# no need for return in after save
|
1161
1168
|
end
|
1162
1169
|
|
1163
1170
|
end
|
1164
1171
|
|
1165
1172
|
# or the explicit way
|
1166
|
-
Parse::Webhooks.route :after_save, "Artist" do
|
1167
|
-
user
|
1168
|
-
artist =
|
1173
|
+
Parse::Webhooks.route :after_save, "Artist" do
|
1174
|
+
puts "User: #{user.username}" if user.present? # Parse::User
|
1175
|
+
artist = parse_object # Artist
|
1176
|
+
# no need for return in after save
|
1169
1177
|
end
|
1170
1178
|
```
|
1171
1179
|
|
1172
1180
|
For any `after_*` hook, return values are not needed since Parse does not utilize them. You may also register as many `after_save` or `after_delete` handlers as you prefer, all of them will be called.
|
1173
1181
|
|
1174
|
-
`before_save` and `before_delete` hooks have special functionality. When
|
1182
|
+
`before_save` and `before_delete` hooks have special functionality. When the `error!` method is called by the provided block, the framework will return the correct error response to Parse with value provided. Returning an error will prevent Parse from saving the object in the case of `before_save` and will prevent Parse from deleting the object when in a `before_delete`. In addition, for a `before_save`, the last value returned by the block will be the value returned in the success response. If the block returns nil or an `empty?` value, it will return `true` as the default response. You can also return a JSON object in a hash format to override the values that will be saved for the object. For this, we recommend using the `payload_update` method. For more details, see [Cloud Code BeforeSave Webhooks](https://parse.com/docs/cloudcode/guide#cloud-code-advanced-beforesave-webhooks)
|
1175
1183
|
|
1176
1184
|
```ruby
|
1177
1185
|
# recommended way
|
@@ -1180,9 +1188,9 @@ class Artist < Parse::Object
|
|
1180
1188
|
property :location, :geopoint
|
1181
1189
|
|
1182
1190
|
# setup after save for Artist
|
1183
|
-
webhook :before_save do
|
1184
|
-
|
1185
|
-
artist =
|
1191
|
+
webhook :before_save do
|
1192
|
+
the_user = user # Parse::User
|
1193
|
+
artist = parse_object # Artist
|
1186
1194
|
# artist object will have dirty tracking information
|
1187
1195
|
|
1188
1196
|
artist.new? # true if this is a new object
|
@@ -1191,19 +1199,19 @@ class Artist < Parse::Object
|
|
1191
1199
|
artist.location ||= Parse::GeoPoint.new(32.82, -117.23)
|
1192
1200
|
|
1193
1201
|
# raise to fail the save
|
1194
|
-
|
1202
|
+
error!("Name cannot be empty") if artist.name.blank?
|
1195
1203
|
|
1196
1204
|
if artist.name_changed?
|
1197
1205
|
# .. do something if `name` has changed
|
1198
1206
|
end
|
1199
1207
|
|
1200
|
-
#
|
1208
|
+
# *important* returns a special hash of changed values
|
1201
1209
|
artist.payload_update
|
1202
1210
|
end
|
1203
1211
|
|
1204
|
-
webhook :before_delete do
|
1212
|
+
webhook :before_delete do
|
1205
1213
|
# prevent deleting Artist records
|
1206
|
-
|
1214
|
+
error!("You can't delete an Artist")
|
1207
1215
|
end
|
1208
1216
|
|
1209
1217
|
end
|
@@ -1323,7 +1331,7 @@ same_user = Parse::User.first # cached result
|
|
1323
1331
|
Add this line to your application's Gemfile:
|
1324
1332
|
|
1325
1333
|
```ruby
|
1326
|
-
gem 'parse-stack'
|
1334
|
+
gem 'parse-stack', require: 'parse/stack'
|
1327
1335
|
```
|
1328
1336
|
|
1329
1337
|
or install it locally
|
data/lib/parse/client.rb
CHANGED
@@ -12,6 +12,11 @@ module Parse
|
|
12
12
|
|
13
13
|
# This is an exception that is thrown if there is a client connectivity issue
|
14
14
|
class ConnectionError < Exception; end;
|
15
|
+
class TimeoutError < Exception; end;
|
16
|
+
class ProtocolError < Exception; end;
|
17
|
+
class ServerError < Exception; end;
|
18
|
+
class AuthenticationError < Exception; end;
|
19
|
+
class RequestLimitExceededError < Exception; end;
|
15
20
|
|
16
21
|
# Main class for the client. The client class is based on a Faraday stack.
|
17
22
|
# The Faraday stack is similar to a Rack-style application in which you can define middlewares
|
@@ -153,7 +158,42 @@ module Parse
|
|
153
158
|
params = (method == :get ? query : body) || {}
|
154
159
|
# if the path does not start with the '/1/' prefix, then add it to be nice.
|
155
160
|
# actually send the request and return the body
|
156
|
-
@session.send(method, uri, params, headers)
|
161
|
+
response = @session.send(method, uri, params, headers)
|
162
|
+
body = response.body
|
163
|
+
|
164
|
+
case response.status
|
165
|
+
when 401, 403
|
166
|
+
puts "[ParseError] #{body}"
|
167
|
+
raise Parse::AuthenticationError, body
|
168
|
+
when 400, 408
|
169
|
+
puts "[ParseError] #{body}"
|
170
|
+
if body.code == 124 || body.code == 143 #"net/http: timeout awaiting response headers"
|
171
|
+
raise Parse::TimeoutError, body
|
172
|
+
end
|
173
|
+
when 404
|
174
|
+
unless body.object_not_found?
|
175
|
+
puts "[ParseError] #{body}"
|
176
|
+
raise Parse::ConnectionError, body
|
177
|
+
end
|
178
|
+
when 405, 406
|
179
|
+
puts "[ParseError] #{body}"
|
180
|
+
raise Parse::ProtocolError, body
|
181
|
+
when 500
|
182
|
+
puts "[ParseError] #{body}"
|
183
|
+
raise Parse::ServerError, body
|
184
|
+
end
|
185
|
+
|
186
|
+
if body.error?
|
187
|
+
if body.code <= 100
|
188
|
+
puts "[ParseError] #{body}"
|
189
|
+
raise Parse::ServerError, body
|
190
|
+
elsif body.code == 155
|
191
|
+
puts "[ParseError] #{body}"
|
192
|
+
raise Parse::RequestLimitExceededError, body
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
body
|
157
197
|
rescue Faraday::Error::ClientError => e
|
158
198
|
raise Parse::ConnectionError, e.message
|
159
199
|
end
|
data/lib/parse/client/caching.rb
CHANGED
@@ -13,9 +13,9 @@ module Parse
|
|
13
13
|
# * 300 - 'Multiple Choices'
|
14
14
|
# * 301 - 'Moved Permanently'
|
15
15
|
# * 302 - 'Found'
|
16
|
-
# * 404 - 'Not Found'
|
17
|
-
# * 410 - 'Gone'
|
18
|
-
CACHEABLE_HTTP_CODES = [200, 203, 300, 301, 302
|
16
|
+
# * 404 - 'Not Found' - removed
|
17
|
+
# * 410 - 'Gone' - removed
|
18
|
+
CACHEABLE_HTTP_CODES = [200, 203, 300, 301, 302].freeze
|
19
19
|
|
20
20
|
class << self
|
21
21
|
attr_accessor :enabled, :logging
|
@@ -88,10 +88,14 @@ module Parse
|
|
88
88
|
|
89
89
|
|
90
90
|
@app.call(env).on_complete do |response_env|
|
91
|
-
# Only cache GET requests with valid HTTP status codes
|
92
|
-
|
93
|
-
|
94
|
-
|
91
|
+
# Only cache GET requests with valid HTTP status codes whose content-length
|
92
|
+
# is greater than 20. Otherwise they could be errors, successes and empty result sets.
|
93
|
+
if cache_enabled && method == :get && CACHEABLE_HTTP_CODES.include?(response_env.status) &&
|
94
|
+
response_env.present? && response_env.response_headers["content-length".freeze].to_i > 20
|
95
|
+
|
96
|
+
@store.store(url, response_env, expires: @expires) # ||= response_env.body
|
97
|
+
|
98
|
+
end # if
|
95
99
|
# do something with the response
|
96
100
|
# response_env[:response_headers].merge!(...)
|
97
101
|
end
|
@@ -3,13 +3,14 @@ require 'active_support/json'
|
|
3
3
|
# be a set of responses (from a Batch response).
|
4
4
|
module Parse
|
5
5
|
|
6
|
+
|
6
7
|
class Response
|
7
8
|
include Enumerable
|
8
9
|
|
9
10
|
ERROR_INTERNAL = 1
|
10
11
|
ERROR_TIMEOUT = 124
|
11
12
|
ERROR_EXCEEDED_BURST_LIMIT = 155
|
12
|
-
|
13
|
+
ERROR_OBJECT_NOT_FOUND = 101
|
13
14
|
|
14
15
|
ERROR = "error".freeze
|
15
16
|
CODE = "code".freeze
|
@@ -95,6 +96,10 @@ module Parse
|
|
95
96
|
! success?
|
96
97
|
end
|
97
98
|
|
99
|
+
def object_not_found?
|
100
|
+
@code == ERROR_OBJECT_NOT_FOUND
|
101
|
+
end
|
102
|
+
|
98
103
|
# returns the result data from the response. Always returns an array.
|
99
104
|
def results
|
100
105
|
return [] if @result.nil?
|
@@ -112,5 +117,18 @@ module Parse
|
|
112
117
|
self
|
113
118
|
end
|
114
119
|
|
120
|
+
def inspect
|
121
|
+
if error?
|
122
|
+
"#<#{self.class} @code=#{code} @error='#{error}'>"
|
123
|
+
else
|
124
|
+
"#<#{self.class} @result='#{@result}'>"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_s
|
129
|
+
return "E-#{@code}: #{@error}" if error?
|
130
|
+
@result
|
131
|
+
end
|
132
|
+
|
115
133
|
end
|
116
134
|
end
|
@@ -280,7 +280,8 @@ module Parse
|
|
280
280
|
# saves the object. If the object has not changed, it is a noop. If it is new,
|
281
281
|
# we will create the object. If the object has an id, we will update the record.
|
282
282
|
# You can define before and after :save callbacks
|
283
|
-
|
283
|
+
# autoraise: set to true will automatically raise an exception if the save fails
|
284
|
+
def save(autoraise: false)
|
284
285
|
return true unless changed?
|
285
286
|
success = false
|
286
287
|
run_callbacks :save do
|
@@ -298,13 +299,13 @@ module Parse
|
|
298
299
|
success = update_relations
|
299
300
|
if success
|
300
301
|
changes_applied!
|
301
|
-
elsif self.class.raise_on_save_failure
|
302
|
+
elsif self.class.raise_on_save_failure || autoraise.present?
|
302
303
|
raise Parse::SaveFailureError.new(self), "Failed updating relations. #{self.parse_class} partially saved."
|
303
304
|
end
|
304
305
|
else
|
305
306
|
changes_applied!
|
306
307
|
end
|
307
|
-
elsif self.class.raise_on_save_failure
|
308
|
+
elsif self.class.raise_on_save_failure || autoraise.present?
|
308
309
|
raise Parse::SaveFailureError.new(self), "Failed to create or save attributes. #{self.parse_class} was not saved."
|
309
310
|
end
|
310
311
|
|
@@ -312,6 +313,11 @@ module Parse
|
|
312
313
|
success
|
313
314
|
end
|
314
315
|
|
316
|
+
# shortcut for raising an exception of saving this object failed.
|
317
|
+
def save!
|
318
|
+
save(autoraise: true)
|
319
|
+
end
|
320
|
+
|
315
321
|
# only destroy the object if it has an id. You can setup before and after
|
316
322
|
#callback hooks on :destroy
|
317
323
|
def destroy
|
@@ -374,9 +374,17 @@ module Parse
|
|
374
374
|
when :bytes
|
375
375
|
val = Parse::Bytes.new(val) unless val.blank?
|
376
376
|
when :integer
|
377
|
-
val
|
377
|
+
if val.nil? || val.respond_to?(:to_i) == false
|
378
|
+
val = nil
|
379
|
+
else
|
380
|
+
val = val.to_i
|
381
|
+
end
|
378
382
|
when :boolean
|
379
|
-
|
383
|
+
if val.nil?
|
384
|
+
val = nil
|
385
|
+
else
|
386
|
+
val = val ? true : false
|
387
|
+
end
|
380
388
|
when :string
|
381
389
|
val = val.to_s unless val.blank?
|
382
390
|
when :float
|
data/lib/parse/model/object.rb
CHANGED
@@ -78,6 +78,11 @@ module Parse
|
|
78
78
|
def self.registered_classes
|
79
79
|
Parse::Object.descendants.map { |m| m.parse_class }.uniq
|
80
80
|
end
|
81
|
+
|
82
|
+
# Find a corresponding class for this string or symbol
|
83
|
+
def self.classify(className)
|
84
|
+
Parse::Model.find_class className.to_parse_class
|
85
|
+
end
|
81
86
|
|
82
87
|
class Object < Pointer
|
83
88
|
include Properties
|
@@ -24,21 +24,25 @@ module Parse
|
|
24
24
|
class LessOrEqualConstraint < Constraint
|
25
25
|
contraint_keyword :$lte
|
26
26
|
register :lte
|
27
|
+
register :on_or_before
|
27
28
|
end
|
28
29
|
|
29
30
|
class LessThanConstraint < Constraint
|
30
31
|
contraint_keyword :$lt
|
31
32
|
register :lt
|
33
|
+
register :before
|
32
34
|
end
|
33
35
|
|
34
36
|
class GreaterThanConstraint < Constraint
|
35
37
|
contraint_keyword :$gt
|
36
38
|
register :gt
|
39
|
+
register :after
|
37
40
|
end
|
38
41
|
|
39
42
|
class GreaterOrEqualConstraint < Constraint
|
40
43
|
contraint_keyword :$gte
|
41
44
|
register :gte
|
45
|
+
register :on_or_after
|
42
46
|
end
|
43
47
|
|
44
48
|
class NotEqualConstraint < Constraint
|
data/lib/parse/stack/version.rb
CHANGED
data/lib/parse/webhooks.rb
CHANGED
@@ -80,18 +80,29 @@ module Parse
|
|
80
80
|
|
81
81
|
end
|
82
82
|
|
83
|
+
class Payload
|
84
|
+
def error!(msg = "")
|
85
|
+
raise WebhookErrorResponse, msg
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class WebhookErrorResponse < Exception; end;
|
83
90
|
class Webhooks
|
84
91
|
|
92
|
+
def self.reload!(args = {})
|
93
|
+
|
94
|
+
end
|
95
|
+
|
85
96
|
include Client::Connectable
|
86
97
|
extend Webhook::Registration
|
87
98
|
|
88
99
|
HTTP_PARSE_WEBHOOK = "HTTP_X_PARSE_WEBHOOK_KEY".freeze
|
89
100
|
HTTP_PARSE_APPLICATION_ID = "HTTP_X_PARSE_APPLICATION_ID".freeze
|
90
101
|
CONTENT_TYPE = "application/json".freeze
|
91
|
-
|
92
102
|
attr_accessor :key
|
93
103
|
class << self
|
94
104
|
attr_accessor :logging
|
105
|
+
|
95
106
|
def routes
|
96
107
|
@routes ||= OpenStruct.new( {
|
97
108
|
before_save: {}, after_save: {},
|
@@ -136,13 +147,10 @@ module Parse
|
|
136
147
|
return unless routes[type].present? && routes[type][className].present?
|
137
148
|
registry = routes[type][className]
|
138
149
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
return registry.call(payload)
|
144
|
-
end
|
145
|
-
nil
|
150
|
+
return payload.instance_exec(payload, ®istry) unless registry.is_a?(Array)
|
151
|
+
results = registry.map { |hook| payload.instance_exec(payload, &hook) }
|
152
|
+
return results.last
|
153
|
+
|
146
154
|
end
|
147
155
|
|
148
156
|
def success(data = true)
|
@@ -167,7 +175,7 @@ module Parse
|
|
167
175
|
return response.finish
|
168
176
|
end
|
169
177
|
|
170
|
-
unless request.content_type.include?(CONTENT_TYPE)
|
178
|
+
unless request.content_type.present? && request.content_type.include?(CONTENT_TYPE)
|
171
179
|
response.write error("Invalid content-type format. Should be application/json.")
|
172
180
|
return response.finish
|
173
181
|
end
|
@@ -217,9 +225,12 @@ module Parse
|
|
217
225
|
end
|
218
226
|
response.write success(result)
|
219
227
|
return response.finish
|
220
|
-
rescue
|
221
|
-
|
222
|
-
|
228
|
+
rescue Parse::WebhookErrorResponse => e
|
229
|
+
if payload.trigger?
|
230
|
+
puts "[Webhook ResponseError] >> #{payload.trigger_name} #{payload.parse_class}:#{payload.parse_id}: #{e}"
|
231
|
+
elsif payload.function?
|
232
|
+
puts "[Webhook ResponseError] >> #{payload.function_name}: #{e}"
|
233
|
+
end
|
223
234
|
response.write error( e.to_s )
|
224
235
|
return response.finish
|
225
236
|
end
|
@@ -102,9 +102,16 @@ module Parse
|
|
102
102
|
klass = Parse::Object.find_class parse_class
|
103
103
|
# if we have a class, return that with updated changes, otherwise
|
104
104
|
# default to regular object
|
105
|
-
|
106
|
-
|
107
|
-
|
105
|
+
if klass.present?
|
106
|
+
o = klass.new(@object || {})
|
107
|
+
if o.is_a?(Parse::User) && @update.present? && @update["authData"].present?
|
108
|
+
o.auth_data = @update["authData"]
|
109
|
+
end
|
110
|
+
return o
|
111
|
+
end # if klass.present?
|
112
|
+
end # if we have original
|
113
|
+
|
114
|
+
end # if before_trigger?
|
108
115
|
Parse::Object.build(@object)
|
109
116
|
end
|
110
117
|
|
data/parse-stack.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Anthony Persaud", "Mark Storch"]
|
10
10
|
spec.email = ["persaud@modernistik.com", "mark_storch@yahoo.com"]
|
11
11
|
|
12
|
-
spec.summary = %q{Parse Ruby Client
|
13
|
-
spec.description = %q{A Parse Ruby Client, ORM, and Query engine to manage larger scale Parse applications}
|
12
|
+
spec.summary = %q{Parse SDK Ruby Client and Object Relational Mapping stack}
|
13
|
+
spec.description = %q{A Parse SDK Ruby Client, ORM, and Query engine to manage larger scale Parse applications}
|
14
14
|
spec.homepage = "https://github.com/modernistik/parse-stack"
|
15
15
|
spec.license = "MIT"
|
16
16
|
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.bindir = "exe"
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ["lib"]
|
28
|
+
spec.required_ruby_version = '>= 2.2'
|
28
29
|
|
29
30
|
spec.add_runtime_dependency "activemodel", [">= 4.2.1", "< 5"]
|
30
31
|
spec.add_runtime_dependency "activesupport", [">= 4.2.1", "< 5"]
|
@@ -41,5 +42,14 @@ Gem::Specification.new do |spec|
|
|
41
42
|
spec.add_development_dependency "pry", "< 1"
|
42
43
|
spec.add_development_dependency 'pry-stack_explorer', "< 1"
|
43
44
|
spec.add_development_dependency 'pry-nav', "< 1"
|
45
|
+
spec.add_development_dependency 'dotenv', "< 3"
|
46
|
+
spec.post_install_message = <<UPGRADE
|
44
47
|
|
48
|
+
** IMPORTANT **
|
49
|
+
Parse::Webhook exception handling has changed in 1.3.0. Please review Changes.md
|
50
|
+
and README.md for changes in webhooks functions and triggers.
|
51
|
+
|
52
|
+
See guide: https://github.com/modernistik/parse-stack/wiki/Webhook-Migration-1.2.x-to-1.3.0
|
53
|
+
|
54
|
+
UPGRADE
|
45
55
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parse-stack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anthony Persaud
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-07-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -249,8 +249,22 @@ dependencies:
|
|
249
249
|
- - "<"
|
250
250
|
- !ruby/object:Gem::Version
|
251
251
|
version: '1'
|
252
|
-
|
253
|
-
|
252
|
+
- !ruby/object:Gem::Dependency
|
253
|
+
name: dotenv
|
254
|
+
requirement: !ruby/object:Gem::Requirement
|
255
|
+
requirements:
|
256
|
+
- - "<"
|
257
|
+
- !ruby/object:Gem::Version
|
258
|
+
version: '3'
|
259
|
+
type: :development
|
260
|
+
prerelease: false
|
261
|
+
version_requirements: !ruby/object:Gem::Requirement
|
262
|
+
requirements:
|
263
|
+
- - "<"
|
264
|
+
- !ruby/object:Gem::Version
|
265
|
+
version: '3'
|
266
|
+
description: A Parse SDK Ruby Client, ORM, and Query engine to manage larger scale
|
267
|
+
Parse applications
|
254
268
|
email:
|
255
269
|
- persaud@modernistik.com
|
256
270
|
- mark_storch@yahoo.com
|
@@ -322,7 +336,14 @@ homepage: https://github.com/modernistik/parse-stack
|
|
322
336
|
licenses:
|
323
337
|
- MIT
|
324
338
|
metadata: {}
|
325
|
-
post_install_message:
|
339
|
+
post_install_message: |2+
|
340
|
+
|
341
|
+
** IMPORTANT **
|
342
|
+
Parse::Webhook exception handling has changed in 1.3.0. Please review Changes.md
|
343
|
+
and README.md for changes in webhooks functions and triggers.
|
344
|
+
|
345
|
+
See guide: https://github.com/modernistik/parse-stack/wiki/Webhook-Migration-1.2.x-to-1.3.0
|
346
|
+
|
326
347
|
rdoc_options: []
|
327
348
|
require_paths:
|
328
349
|
- lib
|
@@ -330,7 +351,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
330
351
|
requirements:
|
331
352
|
- - ">="
|
332
353
|
- !ruby/object:Gem::Version
|
333
|
-
version: '
|
354
|
+
version: '2.2'
|
334
355
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
335
356
|
requirements:
|
336
357
|
- - ">="
|
@@ -341,5 +362,5 @@ rubyforge_project:
|
|
341
362
|
rubygems_version: 2.5.1
|
342
363
|
signing_key:
|
343
364
|
specification_version: 4
|
344
|
-
summary: Parse Ruby Client
|
365
|
+
summary: Parse SDK Ruby Client and Object Relational Mapping stack
|
345
366
|
test_files: []
|