parse-stack 1.5.2 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changes.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +40 -80
- data/lib/parse/api/all.rb +7 -0
- data/lib/parse/api/analytics.rb +8 -3
- data/lib/parse/api/apps.rb +29 -1
- data/lib/parse/api/batch.rb +14 -129
- data/lib/parse/api/cloud_functions.rb +9 -0
- data/lib/parse/api/config.rb +10 -1
- data/lib/parse/api/files.rb +7 -2
- data/lib/parse/api/hooks.rb +45 -2
- data/lib/parse/api/objects.rb +43 -6
- data/lib/parse/api/push.rb +6 -1
- data/lib/parse/api/schemas.rb +15 -1
- data/lib/parse/api/sessions.rb +5 -0
- data/lib/parse/api/users.rb +64 -5
- data/lib/parse/client/authentication.rb +25 -8
- data/lib/parse/client/batch.rb +206 -0
- data/lib/parse/client/body_builder.rb +12 -6
- data/lib/parse/client/caching.rb +42 -10
- data/lib/parse/client/protocol.rb +51 -46
- data/lib/parse/client/response.rb +1 -47
- data/lib/parse/client.rb +171 -42
- data/lib/parse/model/acl.rb +184 -39
- data/lib/parse/model/associations/belongs_to.rb +1 -0
- data/lib/parse/model/classes/role.rb +7 -1
- data/lib/parse/model/classes/session.rb +7 -3
- data/lib/parse/model/classes/user.rb +107 -0
- data/lib/parse/model/core/actions.rb +166 -115
- data/lib/parse/model/core/fetching.rb +105 -0
- data/lib/parse/model/core/properties.rb +40 -13
- data/lib/parse/model/core/querying.rb +123 -39
- data/lib/parse/model/core/schema.rb +22 -32
- data/lib/parse/model/object.rb +26 -20
- data/lib/parse/model/pointer.rb +1 -0
- data/lib/parse/query/constraint.rb +65 -27
- data/lib/parse/query/constraints.rb +0 -3
- data/lib/parse/query/operation.rb +33 -22
- data/lib/parse/query/ordering.rb +10 -5
- data/lib/parse/stack/generators/rails.rb +5 -1
- data/lib/parse/stack/generators/templates/model_installation.rb +1 -1
- data/lib/parse/stack/generators/templates/model_role.rb +1 -1
- data/lib/parse/stack/generators/templates/model_session.rb +2 -2
- data/lib/parse/stack/generators/templates/model_user.rb +1 -1
- data/lib/parse/stack/generators/templates/parse.rb +0 -1
- data/lib/parse/stack/railtie.rb +1 -0
- data/lib/parse/stack/tasks.rb +3 -1
- data/lib/parse/stack/version.rb +3 -1
- data/lib/parse/webhooks/registration.rb +3 -3
- data/lib/parse/webhooks.rb +88 -7
- metadata +5 -3
data/lib/parse/api/hooks.rb
CHANGED
@@ -5,58 +5,101 @@ module Parse
|
|
5
5
|
|
6
6
|
|
7
7
|
module API
|
8
|
+
# Defines the Parse webhooks interface for the Parse REST API
|
8
9
|
module Hooks
|
9
10
|
HOOKS_PREFIX = "hooks/"
|
11
|
+
# The allowed set of Parse triggers.
|
10
12
|
TRIGGER_NAMES = [:beforeSave, :afterSave, :beforeDelete, :afterDelete].freeze
|
13
|
+
|
14
|
+
# @!visibility private
|
11
15
|
def _verify_trigger(triggerName)
|
12
16
|
triggerName = triggerName.to_s.camelize(:lower).to_sym
|
13
17
|
raise ArgumentError, "Invalid trigger name #{triggerName}" unless TRIGGER_NAMES.include?(triggerName)
|
14
18
|
triggerName
|
15
19
|
end
|
16
20
|
|
21
|
+
# Fetch all defined cloud code functions.
|
22
|
+
# @return [Parse::Response]
|
17
23
|
def functions
|
18
24
|
request :get, "#{HOOKS_PREFIX}functions"
|
19
25
|
end
|
20
26
|
|
27
|
+
# Fetch information about a specific registered cloud function.
|
28
|
+
# @param functionName [String] the name of the cloud code function.
|
29
|
+
# @return [Parse::Response]
|
21
30
|
def fetch_function(functionName)
|
22
31
|
request :get, "#{HOOKS_PREFIX}functions/#{functionName}"
|
23
32
|
end
|
24
33
|
|
34
|
+
# Register a cloud code webhook function pointing to a endpoint url.
|
35
|
+
# @param functionName [String] the name of the cloud code function.
|
36
|
+
# @param url [String] the url endpoint for this cloud code function.
|
37
|
+
# @return [Parse::Response]
|
25
38
|
def create_function(functionName, url)
|
26
39
|
request :post, "#{HOOKS_PREFIX}functions", body: {functionName: functionName, url: url}
|
27
40
|
end
|
28
41
|
|
42
|
+
# Updated the endpoint url for a registered cloud code webhook function.
|
43
|
+
# @param functionName [String] the name of the cloud code function.
|
44
|
+
# @param url [String] the new url endpoint for this cloud code function.
|
45
|
+
# @return [Parse::Response]
|
29
46
|
def update_function(functionName, url)
|
30
|
-
#
|
47
|
+
# If you add _method => "PUT" to the JSON body,
|
31
48
|
# and send it as a POST request and parse will accept it as a PUT.
|
32
|
-
# They must do this because it is easier to send POST with Ajax.
|
33
49
|
request :put, "#{HOOKS_PREFIX}functions/#{functionName}", body: { url: url }
|
34
50
|
end
|
35
51
|
|
52
|
+
# Remove a registered cloud code webhook function.
|
53
|
+
# @param functionName [String] the name of the cloud code function.
|
54
|
+
# @return [Parse::Response]
|
36
55
|
def delete_function(functionName)
|
37
56
|
request :put, "#{HOOKS_PREFIX}functions/#{functionName}", body: { __op: "Delete" }
|
38
57
|
end
|
39
58
|
|
59
|
+
# Get the set of registered triggers.
|
60
|
+
# @return [Parse::Response]
|
40
61
|
def triggers
|
41
62
|
request :get, "#{HOOKS_PREFIX}triggers"
|
42
63
|
end
|
43
64
|
|
65
|
+
# Fetch information about a registered webhook trigger.
|
66
|
+
# @param triggerName [String] the name of the trigger. (ex. beforeSave, afterSave)
|
67
|
+
# @param className [String] the name of the Parse collection for the trigger.
|
68
|
+
# @return [Parse::Response]
|
69
|
+
# @see TRIGGER_NAMES
|
44
70
|
def fetch_trigger(triggerName, className)
|
45
71
|
triggerName = _verify_trigger(triggerName)
|
46
72
|
request :get, "#{HOOKS_PREFIX}triggers/#{className}/#{triggerName}"
|
47
73
|
end
|
48
74
|
|
75
|
+
# Register a new cloud code webhook trigger with an endpoint url.
|
76
|
+
# @param triggerName [String] the name of the trigger. (ex. beforeSave, afterSave)
|
77
|
+
# @param className [String] the name of the Parse collection for the trigger.
|
78
|
+
# @param url [String] the url endpoint for this webhook trigger.
|
79
|
+
# @return [Parse::Response]
|
80
|
+
# @see Parse::API::Hooks::TRIGGER_NAMES
|
49
81
|
def create_trigger(triggerName, className, url)
|
50
82
|
triggerName = _verify_trigger(triggerName)
|
51
83
|
body = {className: className, triggerName: triggerName, url: url }
|
52
84
|
request :post, "#{HOOKS_PREFIX}triggers", body: body
|
53
85
|
end
|
54
86
|
|
87
|
+
# Updated the registered endpoint for this cloud code webhook trigger.
|
88
|
+
# @param triggerName [String] the name of the trigger. (ex. beforeSave, afterSave)
|
89
|
+
# @param className [String] the name of the Parse collection for the trigger.
|
90
|
+
# @param url [String] the new url endpoint for this webhook trigger.
|
91
|
+
# @return [Parse::Response]
|
92
|
+
# @see Parse::API::Hooks::TRIGGER_NAMES
|
55
93
|
def update_trigger(triggerName, className, url)
|
56
94
|
triggerName = _verify_trigger(triggerName)
|
57
95
|
request :put, "#{HOOKS_PREFIX}triggers/#{className}/#{triggerName}", body: { url: url }
|
58
96
|
end
|
59
97
|
|
98
|
+
# Remove a registered cloud code webhook trigger.
|
99
|
+
# @param triggerName [String] the name of the trigger. (ex. beforeSave, afterSave)
|
100
|
+
# @param className [String] the name of the Parse collection for the trigger.
|
101
|
+
# @return [Parse::Response]
|
102
|
+
# @see Parse::API::Hooks::TRIGGER_NAMES
|
60
103
|
def delete_trigger(triggerName, className)
|
61
104
|
triggerName = _verify_trigger(triggerName)
|
62
105
|
request :put, "#{HOOKS_PREFIX}triggers/#{className}/#{triggerName}", body: { __op: "Delete" }
|
data/lib/parse/api/objects.rb
CHANGED
@@ -9,19 +9,25 @@ module Parse
|
|
9
9
|
module API
|
10
10
|
# REST API methods for fetching CRUD operations on Parse objects.
|
11
11
|
module Objects
|
12
|
-
|
12
|
+
# The class prefix for fetching objects.
|
13
13
|
CLASS_PATH_PREFIX = "classes/"
|
14
|
+
# The class prefix mapping for fetching objects.
|
14
15
|
PREFIX_MAP = { installation: "installations", _installation: "installations",
|
15
16
|
user: "users", _user: "users",
|
16
17
|
role: "roles", _role: "roles",
|
17
18
|
session: "sessions", _session: "sessions"
|
18
19
|
}.freeze
|
19
20
|
|
21
|
+
# @!visibility private
|
20
22
|
def self.included(base)
|
21
23
|
base.extend(ClassMethods)
|
22
24
|
end
|
23
25
|
|
24
26
|
module ClassMethods
|
27
|
+
# Get the API path for this class.
|
28
|
+
# @param className [String] the name of the Parse collection.
|
29
|
+
# @param id [String] optional objectId to add at the end of the path.
|
30
|
+
# @return [String] the API uri path
|
25
31
|
def uri_path(className, id = nil)
|
26
32
|
if className.is_a?(Parse::Pointer)
|
27
33
|
id = className.id
|
@@ -37,39 +43,70 @@ module Parse
|
|
37
43
|
|
38
44
|
end
|
39
45
|
|
46
|
+
# Get the API path for this class.
|
47
|
+
# @param className [String] the name of the Parse collection.
|
48
|
+
# @param id [String] optional objectId to add at the end of the path.
|
49
|
+
# @return [String] the API uri path
|
40
50
|
def uri_path(className, id = nil)
|
41
51
|
self.class.uri_path(className, id)
|
42
52
|
end
|
43
53
|
|
44
|
-
#
|
54
|
+
# Create an object in a collection.
|
55
|
+
# @param className [String] the name of the Parse collection.
|
56
|
+
# @param body [Hash] the body of the request.
|
57
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
58
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
59
|
+
# @return [Parse::Response]
|
45
60
|
def create_object(className, body = {}, headers: {}, **opts)
|
46
61
|
response = request :post, uri_path(className) , body: body, headers: headers, opts: opts
|
47
62
|
response.parse_class = className if response.present?
|
48
63
|
response
|
49
64
|
end
|
50
65
|
|
51
|
-
#
|
66
|
+
# Delete an object in a collection.
|
67
|
+
# @param className [String] the name of the Parse collection.
|
68
|
+
# @param id [String] The objectId of the record in the collection.
|
69
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
70
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
71
|
+
# @return [Parse::Response]
|
52
72
|
def delete_object(className, id, headers: {}, **opts)
|
53
73
|
response = request :delete, uri_path(className, id), headers: headers, opts: opts
|
54
74
|
response.parse_class = className if response.present?
|
55
75
|
response
|
56
76
|
end
|
57
77
|
|
58
|
-
#
|
78
|
+
# Fetch a specific object from a collection.
|
79
|
+
# @param className [String] the name of the Parse collection.
|
80
|
+
# @param id [String] The objectId of the record in the collection.
|
81
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
82
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
83
|
+
# @return [Parse::Response]
|
59
84
|
def fetch_object(className, id, headers: {}, **opts)
|
60
85
|
response = request :get, uri_path(className, id), headers: headers, opts: opts
|
61
86
|
response.parse_class = className if response.present?
|
62
87
|
response
|
63
88
|
end
|
64
89
|
|
65
|
-
#
|
90
|
+
# Fetch a set of matching objects for a query.
|
91
|
+
# @param className [String] the name of the Parse collection.
|
92
|
+
# @param query [Hash] The set of query constraints.
|
93
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
94
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
95
|
+
# @return [Parse::Response]
|
96
|
+
# @see Parse::Query
|
66
97
|
def find_objects(className, query = {}, headers: {}, **opts)
|
67
98
|
response = request :get, uri_path(className), query: query, headers: headers, opts: opts
|
68
99
|
response.parse_class = className if response.present?
|
69
100
|
response
|
70
101
|
end
|
71
102
|
|
72
|
-
#
|
103
|
+
# Update an object in a collection.
|
104
|
+
# @param className [String] the name of the Parse collection.
|
105
|
+
# @param id [String] The objectId of the record in the collection.
|
106
|
+
# @param body [Hash] The key value pairs to update.
|
107
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
108
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
109
|
+
# @return [Parse::Response]
|
73
110
|
def update_object(className, id, body = {}, headers: {}, **opts)
|
74
111
|
response = request :put, uri_path(className,id) , body: body, headers: headers, opts: opts
|
75
112
|
response.parse_class = className if response.present?
|
data/lib/parse/api/push.rb
CHANGED
@@ -4,9 +4,14 @@
|
|
4
4
|
module Parse
|
5
5
|
|
6
6
|
module API
|
7
|
-
#
|
7
|
+
# Defines the Parse Push notification service interface for the Parse REST API
|
8
8
|
module Push
|
9
9
|
PUSH_PATH = "push"
|
10
|
+
|
11
|
+
# Update the schema for a collection.
|
12
|
+
# @param payload [Hash] the paylod for the Push notification.
|
13
|
+
# @return [Parse::Response]
|
14
|
+
# @see https://parseplatform.github.io/docs/rest/guide/#sending-pushes Sending Pushes
|
10
15
|
def push(payload = {})
|
11
16
|
request :post, PUSH_PATH, body: payload.as_json
|
12
17
|
end
|
data/lib/parse/api/schemas.rb
CHANGED
@@ -4,17 +4,31 @@
|
|
4
4
|
module Parse
|
5
5
|
|
6
6
|
module API
|
7
|
-
#
|
7
|
+
# Defines the Schema interface for the Parse REST API
|
8
8
|
module Schema
|
9
9
|
SCHEMAS_PATH = "schemas"
|
10
|
+
|
11
|
+
# Get the schema for a collection.
|
12
|
+
# @param className [String] the name of the remote Parse collection.
|
13
|
+
# @return [Parse::Response]
|
10
14
|
def schema(className)
|
11
15
|
request :get, "#{SCHEMAS_PATH}/#{className}"
|
12
16
|
end
|
13
17
|
|
18
|
+
# Create a new collection with the specific schema.
|
19
|
+
# @param className [String] the name of the remote Parse collection.
|
20
|
+
# @param schema [Hash] the schema hash. This is a specific format specified by
|
21
|
+
# Parse.
|
22
|
+
# @return [Parse::Response]
|
14
23
|
def create_schema(className, schema)
|
15
24
|
request :post, "#{SCHEMAS_PATH}/#{className}", body: schema
|
16
25
|
end
|
17
26
|
|
27
|
+
# Update the schema for a collection.
|
28
|
+
# @param className [String] the name of the remote Parse collection.
|
29
|
+
# @param schema [Hash] the schema hash. This is a specific format specified by
|
30
|
+
# Parse.
|
31
|
+
# @return [Parse::Response]
|
18
32
|
def update_schema(className, schema)
|
19
33
|
request :put, "#{SCHEMAS_PATH}/#{className}", body: schema
|
20
34
|
end
|
data/lib/parse/api/sessions.rb
CHANGED
@@ -4,9 +4,14 @@
|
|
4
4
|
module Parse
|
5
5
|
|
6
6
|
module API
|
7
|
+
# Defines the Session class interface for the Parse REST API
|
7
8
|
module Sessions
|
8
9
|
SESSION_PATH_PREFIX = "sessions"
|
9
10
|
|
11
|
+
# Fetch a session record for a given session token.
|
12
|
+
# @param session_token [String] an active session token.
|
13
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
14
|
+
# @return [Parse::Response]
|
10
15
|
def fetch_session(session_token, **opts)
|
11
16
|
opts.merge!({use_master_key: false, cache: false})
|
12
17
|
headers = {Parse::Protocol::SESSION_TOKEN => session_token}
|
data/lib/parse/api/users.rb
CHANGED
@@ -6,24 +6,38 @@ require 'open-uri'
|
|
6
6
|
module Parse
|
7
7
|
|
8
8
|
module API
|
9
|
+
# Defines the User class interface for the Parse REST API
|
9
10
|
module Users
|
10
|
-
|
11
|
-
# detect class names to proper URI handlers
|
11
|
+
|
12
12
|
USER_PATH_PREFIX = "users"
|
13
13
|
LOGOUT_PATH = "logout"
|
14
14
|
LOGIN_PATH = "login"
|
15
15
|
REQUEST_PASSWORD_RESET = "requestPasswordReset"
|
16
16
|
|
17
|
+
# Fetch a {Parse::User} for a given objectId.
|
18
|
+
# @param id [String] the user objectid
|
19
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
20
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
21
|
+
# @return [Parse::Response]
|
17
22
|
def fetch_user(id, headers: {}, **opts)
|
18
23
|
request :get, "#{USER_PATH_PREFIX}/#{id}", headers: headers, opts: opts
|
19
24
|
end
|
20
25
|
|
26
|
+
# Find users matching a set of constraints.
|
27
|
+
# @param query [Hash] query parameters.
|
28
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
29
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
30
|
+
# @return [Parse::Response]
|
21
31
|
def find_users(query = {}, headers: {}, **opts)
|
22
32
|
response = request :get, USER_PATH_PREFIX, query: query, headers: headers, opts: opts
|
23
33
|
response.parse_class = Parse::Model::CLASS_USER
|
24
34
|
response
|
25
35
|
end
|
26
36
|
|
37
|
+
# Find user matching this active session token.
|
38
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
39
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
40
|
+
# @return [Parse::Response]
|
27
41
|
def current_user(session_token, headers: {}, **opts)
|
28
42
|
headers.merge!({Parse::Protocol::SESSION_TOKEN => session_token})
|
29
43
|
response = request :get, "#{USER_PATH_PREFIX}/me", headers: headers, opts: opts
|
@@ -31,6 +45,11 @@ module Parse
|
|
31
45
|
response
|
32
46
|
end
|
33
47
|
|
48
|
+
# Create a new user.
|
49
|
+
# @param body [Hash] a hash of values related to your _User schema.
|
50
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
51
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
52
|
+
# @return [Parse::Response]
|
34
53
|
def create_user(body, headers: {}, **opts)
|
35
54
|
headers.merge!({ Parse::Protocol::REVOCABLE_SESSION => '1'})
|
36
55
|
if opts[:session_token].present?
|
@@ -41,27 +60,56 @@ module Parse
|
|
41
60
|
response
|
42
61
|
end
|
43
62
|
|
63
|
+
# Update a {Parse::User} record given an objectId.
|
64
|
+
# @param id [String] the Parse user objectId.
|
65
|
+
# @param body [Hash] the body of the API request.
|
66
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
67
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
68
|
+
# @return [Parse::Response]
|
44
69
|
def update_user(id, body = {}, headers: {}, **opts)
|
45
70
|
response = request :put, "#{USER_PATH_PREFIX}/#{id}", body: body, opts: opts
|
46
71
|
response.parse_class = Parse::Model::CLASS_USER
|
47
72
|
response
|
48
73
|
end
|
49
74
|
|
50
|
-
#
|
75
|
+
# Set the authentication service OAUth data for a user. Deleting or unlinking
|
76
|
+
# is done by setting the authData of the service name to nil.
|
77
|
+
# @param id [String] the Parse user objectId.
|
78
|
+
# @param service_name [Symbol] the name of the OAuth service.
|
79
|
+
# @param auth_data [Hash] the hash data related to the third-party service.
|
80
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
81
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
82
|
+
# @return [Parse::Response]
|
51
83
|
def set_service_auth_data(id, service_name, auth_data, headers: {}, **opts)
|
52
84
|
body = { authData: { service_name => auth_data } }
|
53
85
|
update_user(id, body, opts)
|
54
86
|
end
|
55
87
|
|
88
|
+
# Delete a {Parse::User} record given an objectId.
|
89
|
+
# @param id [String] the Parse user objectId.
|
90
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
91
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
92
|
+
# @return [Parse::Response]
|
56
93
|
def delete_user(id, headers: {}, **opts)
|
57
94
|
request :delete, "#{USER_PATH_PREFIX}/#{id}", headers: headers, opts: opts
|
58
95
|
end
|
59
96
|
|
60
|
-
|
97
|
+
# Request a password reset for a registered email.
|
98
|
+
# @param email [String] the Parse user email.
|
99
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
100
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
101
|
+
# @return [Parse::Response]
|
102
|
+
def request_password_reset(email, headers: {}, **opts)
|
61
103
|
body = {email: email}
|
62
|
-
request :post, REQUEST_PASSWORD_RESET, body: body, opts: opts
|
104
|
+
request :post, REQUEST_PASSWORD_RESET, body: body, opts: opts, headers: headers
|
63
105
|
end
|
64
106
|
|
107
|
+
# Login a user.
|
108
|
+
# @param username [String] the Parse user username.
|
109
|
+
# @param password [String] the Parse user's associated password.
|
110
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
111
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
112
|
+
# @return [Parse::Response]
|
65
113
|
def login(username, password, headers: {}, **opts)
|
66
114
|
# Probably pass Installation-ID as header
|
67
115
|
query = { username: username, password: password }
|
@@ -72,6 +120,11 @@ module Parse
|
|
72
120
|
response
|
73
121
|
end
|
74
122
|
|
123
|
+
# Logout a user by deleting the associated session.
|
124
|
+
# @param session_token [String] the Parse user session token to delete.
|
125
|
+
# @param headers [Hash] additional HTTP headers to send with the request.
|
126
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
127
|
+
# @return [Parse::Response]
|
75
128
|
def logout(session_token, headers: {}, **opts)
|
76
129
|
headers.merge!({ Parse::Protocol::SESSION_TOKEN => session_token})
|
77
130
|
opts.merge!({use_master_key: false, session_token: session_token})
|
@@ -79,6 +132,12 @@ module Parse
|
|
79
132
|
end
|
80
133
|
|
81
134
|
# Signup a user given a username, password and, optionally, their email.
|
135
|
+
# @param username [String] the Parse user username.
|
136
|
+
# @param password [String] the Parse user's associated password.
|
137
|
+
# @param email [String] the desired Parse user's email.
|
138
|
+
# @param body [Hash] additional property values to pass when creating the user record.
|
139
|
+
# @param opts [Hash] additional options to pass to the {Parse::Client} request.
|
140
|
+
# @return [Parse::Response]
|
82
141
|
def signup(username, password, email = nil, body: {}, **opts)
|
83
142
|
body = body.merge({ username: username, password: password })
|
84
143
|
body[:email] = email || body[:email]
|
@@ -7,22 +7,37 @@ require 'active_support'
|
|
7
7
|
require 'active_support/core_ext'
|
8
8
|
|
9
9
|
require_relative 'protocol'
|
10
|
-
|
11
|
-
# This middleware takes all outgoing requests and adds the proper header values
|
12
|
-
# base on the client configuration.
|
10
|
+
|
13
11
|
module Parse
|
14
12
|
|
15
13
|
module Middleware
|
16
|
-
|
14
|
+
# This middleware handles sending the proper authentication headers to the
|
15
|
+
# Parse REST API endpoint.
|
17
16
|
class Authentication < Faraday::Middleware
|
18
17
|
include Parse::Protocol
|
19
|
-
DISABLE_MASTER_KEY = "X-Disable-Parse-Master-Key"
|
18
|
+
DISABLE_MASTER_KEY = "X-Disable-Parse-Master-Key".freeze
|
19
|
+
# @return [String] the application id for this Parse endpoint.
|
20
20
|
attr_accessor :application_id
|
21
|
+
# @return [String] the REST API Key for this Parse endpoint.
|
21
22
|
attr_accessor :api_key
|
23
|
+
# The Master key API Key for this Parse endpoint. This is optional. If
|
24
|
+
# provided, it will be sent in every request.
|
25
|
+
# @return [String]
|
22
26
|
attr_accessor :master_key
|
23
|
-
|
24
|
-
|
25
|
-
|
27
|
+
|
28
|
+
#
|
29
|
+
# @param adapter [Faraday::Adapter] An instance of the Faraday adapter
|
30
|
+
# used for the connection. Defaults Faraday::Adapter::NetHttp.
|
31
|
+
# @param options [Hash] the options containing Parse authentication data.
|
32
|
+
# @option options [String] :application_id the application id.
|
33
|
+
# @option options [String] :api_key the REST API key.
|
34
|
+
# @option options [String] :master_key the Master Key for this application.
|
35
|
+
# If it is set, it will be sent on every request unless this middleware sees
|
36
|
+
# {DISABLE_MASTER_KEY} as an entry in the headers section.
|
37
|
+
# @option options [String] :content_type the content type format header. Defaults to
|
38
|
+
# {Parse::Protocol::CONTENT_TYPE_FORMAT}.
|
39
|
+
def initialize(adapter, options = {})
|
40
|
+
super(adapter)
|
26
41
|
@application_id = options[:application_id]
|
27
42
|
@api_key = options[:api_key]
|
28
43
|
@master_key = options[:master_key]
|
@@ -30,10 +45,12 @@ module Parse
|
|
30
45
|
end
|
31
46
|
|
32
47
|
# we dup the call for thread-safety
|
48
|
+
# @!visibility private
|
33
49
|
def call(env)
|
34
50
|
dup.call!(env)
|
35
51
|
end
|
36
52
|
|
53
|
+
# @!visibility private
|
37
54
|
def call!(env)
|
38
55
|
# We add the main Parse protocol headers
|
39
56
|
headers = {}
|
@@ -0,0 +1,206 @@
|
|
1
|
+
|
2
|
+
require_relative 'request'
|
3
|
+
require_relative 'response'
|
4
|
+
|
5
|
+
|
6
|
+
module Parse
|
7
|
+
# Create a new batch operation.
|
8
|
+
# @param reqs [Array<Parse::Request>] a set of requests to batch.
|
9
|
+
# @return [BatchOperation] a new {BatchOperation} with the given change requests.
|
10
|
+
def self.batch(reqs = nil)
|
11
|
+
BatchOperation.new(reqs)
|
12
|
+
end
|
13
|
+
|
14
|
+
# This class provides a standard way to submit, manage and process batch operations
|
15
|
+
# for Parse::Objects and associations.
|
16
|
+
#
|
17
|
+
# Batch requests are supported implicitly and intelligently through an
|
18
|
+
# extension of array. When an array of Parse::Object subclasses is saved,
|
19
|
+
# Parse-Stack will batch all possible save operations for the objects in the
|
20
|
+
# array that have changed. It will also batch save 50 at a time until all items
|
21
|
+
# in the array are saved. Note: Parse does not allow batch saving Parse::User objects.
|
22
|
+
#
|
23
|
+
# songs = Songs.first 1000 #first 1000 songs
|
24
|
+
# songs.each do |song|
|
25
|
+
# # ... modify song ...
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # will batch save 50 items at a time until all are saved.
|
29
|
+
# songs.save
|
30
|
+
#
|
31
|
+
# The objects do not have to be of the same collection in order to be supported in the
|
32
|
+
# batch request.
|
33
|
+
# @see Array.save
|
34
|
+
# @see Array.destroy
|
35
|
+
class BatchOperation
|
36
|
+
|
37
|
+
attr_accessor :requests, :responses
|
38
|
+
include Enumerable
|
39
|
+
|
40
|
+
# @return [Parse::Client] the client to be used for the request.
|
41
|
+
def client
|
42
|
+
@client ||= Parse::Client.client
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param reqs [Array<Parse::Request>] an array of requests.
|
46
|
+
def initialize(reqs = nil)
|
47
|
+
@requests = []
|
48
|
+
@responses = []
|
49
|
+
reqs = [reqs] unless reqs.is_a?(Enumerable)
|
50
|
+
reqs.each { |r| add(r) } if reqs.is_a?(Enumerable)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Add an additional request to this batch.
|
54
|
+
# @overload add(req)
|
55
|
+
# @param req [Parse::Request] the request to append.
|
56
|
+
# @return [Array<Parse::Request>] the set of requests.
|
57
|
+
# @overload add(batch)
|
58
|
+
# @param req [Parse::BatchOperation] add all the requests from this batch operation.
|
59
|
+
# @return [Array<Parse::Request>] the set of requests.
|
60
|
+
def add(req)
|
61
|
+
if req.respond_to?(:change_requests)
|
62
|
+
requests = req.change_requests.select { |r| r.is_a?(Parse::Request) }
|
63
|
+
@requests += requests
|
64
|
+
elsif req.is_a?(Array)
|
65
|
+
requests = req.select { |r| r.is_a?(Parse::Request) }
|
66
|
+
@requests += requests
|
67
|
+
elsif req.is_a?(BatchOperation)
|
68
|
+
@requests += req.requests if req.is_a?(BatchOperation)
|
69
|
+
else
|
70
|
+
@requests.push(req) if req.is_a?(Parse::Request)
|
71
|
+
end
|
72
|
+
@requests
|
73
|
+
end
|
74
|
+
|
75
|
+
# This method is for interoperability with Parse::Object instances.
|
76
|
+
# @see Parse::Object#change_requests
|
77
|
+
def change_requests
|
78
|
+
@requests
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [Array]
|
82
|
+
def each
|
83
|
+
return enum_for(:each) unless block_given?
|
84
|
+
@requests.each(&Proc.new)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Hash] a formatted payload for the batch request.
|
88
|
+
def as_json(*args)
|
89
|
+
{ requests: requests }.as_json
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [Integer] the number of requests in the batch.
|
93
|
+
def count
|
94
|
+
@requests.count
|
95
|
+
end
|
96
|
+
|
97
|
+
# Remove all requests in this batch.
|
98
|
+
# @return [Array]
|
99
|
+
def clear!
|
100
|
+
@requests.clear
|
101
|
+
end
|
102
|
+
|
103
|
+
# @return [Boolean] true if the request was successful.
|
104
|
+
def success?
|
105
|
+
return false if @responses.empty?
|
106
|
+
@responses.compact.all?(&:success?)
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [Boolean] true if the request had an error.
|
110
|
+
def error?
|
111
|
+
return false if @responses.empty?
|
112
|
+
! success?
|
113
|
+
end
|
114
|
+
|
115
|
+
# Submit the batch operation in chunks until they are all complete. In general,
|
116
|
+
# Parse limits requests in each batch to 50 and it is possible that a {BatchOperation}
|
117
|
+
# instance contains more than 50 requests. This method will slice up the array of
|
118
|
+
# request and send them based on the `segment` amount until they have all been submitted.
|
119
|
+
# @param segment [Integer] the number of requests to send in each batch. Default 50.
|
120
|
+
# @return [Array<Parse::Response>] the corresponding set of responses for
|
121
|
+
# each request in the batch.
|
122
|
+
def submit(segment = 50)
|
123
|
+
@responses = []
|
124
|
+
@requests.uniq!(&:signature)
|
125
|
+
@requests.each_slice(segment) do |slice|
|
126
|
+
@responses << client.batch_request( BatchOperation.new(slice) )
|
127
|
+
#throttle
|
128
|
+
# sleep (slice.count.to_f / MAX_REQ_SEC.to_f )
|
129
|
+
end
|
130
|
+
@responses.flatten!
|
131
|
+
#puts "Requests: #{@requests.count} == Response: #{@responses.count}"
|
132
|
+
@requests.zip(@responses).each(&Proc.new) if block_given?
|
133
|
+
@responses
|
134
|
+
end
|
135
|
+
alias_method :save, :submit
|
136
|
+
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class Array
|
142
|
+
|
143
|
+
# Submit a batch request for deleting a set of Parse::Objects.
|
144
|
+
# @example
|
145
|
+
# # assume Post and Author are Parse models
|
146
|
+
# author = Author.first
|
147
|
+
# posts = Post.all author: author
|
148
|
+
# posts.destroy # batch destroy request
|
149
|
+
# @return [Parse::BatchOperation] the batch operation performed.
|
150
|
+
# @see Parse::BatchOperation
|
151
|
+
def destroy
|
152
|
+
batch = Parse::BatchOperation.new
|
153
|
+
each do |o|
|
154
|
+
next unless o.respond_to?(:destroy_request)
|
155
|
+
r = o.destroy_request
|
156
|
+
batch.add(r) unless r.nil?
|
157
|
+
end
|
158
|
+
batch.submit
|
159
|
+
batch
|
160
|
+
end
|
161
|
+
|
162
|
+
# Submit a batch request for deleting a set of Parse::Objects.
|
163
|
+
# Batch requests are supported implicitly and intelligently through an
|
164
|
+
# extension of array. When an array of Parse::Object subclasses is saved,
|
165
|
+
# Parse-Stack will batch all possible save operations for the objects in the
|
166
|
+
# array that have changed. It will also batch save 50 at a time until all items
|
167
|
+
# in the array are saved. Note: Parse does not allow batch saving Parse::User objects.
|
168
|
+
# @note The objects of the array to be saved do not all have to be of the same collection.
|
169
|
+
# @param merge [Boolean] whether to merge the updated changes to the series of
|
170
|
+
# objects back to the original ones submitted. If you don't need the original objects
|
171
|
+
# to be updated with the changes, set this to false for improved performance.
|
172
|
+
# @param force [Boolean] Do not skip objects that do not have pending changes (dirty tracking).
|
173
|
+
# @example
|
174
|
+
# # assume Post and Author are Parse models
|
175
|
+
# author = Author.first
|
176
|
+
# posts = Post.first 100
|
177
|
+
# posts.each { |post| post.author = author }
|
178
|
+
# posts.save # batch save
|
179
|
+
# @return [Parse::BatchOperation] the batch operation performed.
|
180
|
+
# @see Parse::BatchOperation
|
181
|
+
def save(merge: true, force: false)
|
182
|
+
batch = Parse::BatchOperation.new
|
183
|
+
objects = {}
|
184
|
+
each do |o|
|
185
|
+
next unless o.is_a?(Parse::Object)
|
186
|
+
objects[o.object_id] = o
|
187
|
+
batch.add o.change_requests(force)
|
188
|
+
end
|
189
|
+
if merge == false
|
190
|
+
batch.submit
|
191
|
+
return batch
|
192
|
+
end
|
193
|
+
#rebind updates
|
194
|
+
batch.submit do |request, response|
|
195
|
+
next unless request.tag.present? && response.present? && response.success?
|
196
|
+
o = objects[request.tag]
|
197
|
+
next unless o.is_a?(Parse::Object)
|
198
|
+
result = response.result
|
199
|
+
o.id = result['objectId'] if o.id.blank?
|
200
|
+
o.set_attributes!(result)
|
201
|
+
o.clear_changes!
|
202
|
+
end
|
203
|
+
batch
|
204
|
+
end #save!
|
205
|
+
|
206
|
+
end
|