sfrest 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sfrest/collection.rb +159 -0
- data/lib/sfrest/connection.rb +28 -12
- data/lib/sfrest/error.rb +6 -0
- data/lib/sfrest/info.rb +16 -0
- data/lib/sfrest/task.rb +11 -6
- data/lib/sfrest/version.rb +1 -1
- data/lib/sfrest.rb +19 -1
- metadata +19 -4
- data/lib/sfrest/collections.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e5a68209a45ec0dc81e36535e276889ff2f86b6
|
4
|
+
data.tar.gz: 02797d6219680639b0f6669a57af3ffec251839c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 447e1cf3621ca1f9d343a773a2e3ac8a701bdbd0de352421399b859c7388f3fc68c3e5d6f7e0575ddb024faef73ef07056b17b17429c3307b5171981d82a55a7
|
7
|
+
data.tar.gz: f860b23a28e13c26faa939b2b6f44b088a4508d35e5efefd07f81946a8e1413187995b49db57a6c8ec6125d142cb24c6333b59d108d1249fead3b65335f2f47e
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module SFRest
|
2
|
+
# Find colletions, return their data.
|
3
|
+
class Collection
|
4
|
+
# @param [SFRest::Connection] conn
|
5
|
+
def initialize(conn)
|
6
|
+
@conn = conn
|
7
|
+
end
|
8
|
+
|
9
|
+
# gets the site ID for the site named sitename
|
10
|
+
# will page through all the sites available searching for the site
|
11
|
+
# @param [String] name the name of the site
|
12
|
+
# @return [Integer] the id of sitename
|
13
|
+
def get_collection_id(name)
|
14
|
+
pglimit = 100
|
15
|
+
res = @conn.get('/api/v1/collections&limit=' + pglimit.to_s)
|
16
|
+
count = res['count'].to_i
|
17
|
+
id = collection_data_from_results(res, name, 'id')
|
18
|
+
return id if id
|
19
|
+
pages = (count / pglimit) + 1
|
20
|
+
2.upto(pages) do |i|
|
21
|
+
res = @conn.get('/api/v1/collections&limit=' + pglimit.to_s + '?page=' + i.to_s)
|
22
|
+
id = collection_data_from_results(res, name, 'id')
|
23
|
+
return id if id
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Extract the site data for 'key' based on the site result object
|
29
|
+
# @param [Hash] res result from a request to /collections
|
30
|
+
# @param [String] name
|
31
|
+
# @param [String] key one of the user data returned (id, name, domain...)
|
32
|
+
# @return [Object] Integer, String, Array, Hash depending on the collection data
|
33
|
+
def collection_data_from_results(res, name, key)
|
34
|
+
collections = res['collections']
|
35
|
+
collections.each do |collection|
|
36
|
+
return collection[key] if collection['name'] == name
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Gets the site data for a specific id
|
42
|
+
# @param [Integer] id the site id
|
43
|
+
# @return [Hash]
|
44
|
+
def get_collection_data(id)
|
45
|
+
@conn.get('/api/v1/collections/' + id.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
# gets the site id of the 1st one found using the api
|
49
|
+
# @return [Integer] the site id
|
50
|
+
def first_collection_id
|
51
|
+
res = @conn.get('/api/v1/collections')
|
52
|
+
res['collections'].first['id']
|
53
|
+
end
|
54
|
+
|
55
|
+
# Gets the complete list of collections
|
56
|
+
# Makes multiple requests to the factory to get all the collections on the factory
|
57
|
+
# @return [Hash{'count' => Integer, 'sites' => Hash}]
|
58
|
+
def collection_list
|
59
|
+
page = 1
|
60
|
+
not_done = true
|
61
|
+
count = 0
|
62
|
+
while not_done
|
63
|
+
current_path = '/api/v1/collections?page=' << page.to_s
|
64
|
+
res = @conn.get(current_path)
|
65
|
+
if res['collections'] == []
|
66
|
+
not_done = false
|
67
|
+
elsif !res['message'].nil?
|
68
|
+
return { 'message' => res['message'] }
|
69
|
+
elsif page == 1
|
70
|
+
count = res['count']
|
71
|
+
collections = res['collections']
|
72
|
+
else
|
73
|
+
res['collections'].each do |collection|
|
74
|
+
collections << collection
|
75
|
+
end
|
76
|
+
end
|
77
|
+
page += 1
|
78
|
+
end
|
79
|
+
{ 'count' => count, 'collections' => collections }
|
80
|
+
end
|
81
|
+
|
82
|
+
# create a site collection
|
83
|
+
# @param [String] name site collection name
|
84
|
+
# @param [int|Array] sites nid or array of site nids. First nid is primary
|
85
|
+
# @param [int|Array] groups gid or array of group ids.
|
86
|
+
# @param [String] internal_domain_prefix optional the prefix for the internal domain
|
87
|
+
# defaults to name
|
88
|
+
# @return [Hash { "id" => Integer, "name" => String,
|
89
|
+
# "time" => "2016-11-25T13:18:44+00:00",
|
90
|
+
# "internal_domain" => String }]
|
91
|
+
def create(name, sites, groups, internal_domain_prefix = nil)
|
92
|
+
sites = Array(sites)
|
93
|
+
groups = Array(groups)
|
94
|
+
current_path = '/api/v1/collections'
|
95
|
+
payload = { 'name' => name, 'site_ids' => sites, 'group_ids' => groups,
|
96
|
+
'internal_domain_prefix' => internal_domain_prefix }.to_json
|
97
|
+
@conn.post(current_path, payload)
|
98
|
+
end
|
99
|
+
|
100
|
+
# deletes a site collection
|
101
|
+
# performs the same action as deleting in the UI
|
102
|
+
# @param [Integer] id the id of the site collection to delete
|
103
|
+
# @return [Hash{ "id" => Integer,
|
104
|
+
# "time" => "2016-10-28T09:25:26+00:00",
|
105
|
+
# "deleted" => Boolean,
|
106
|
+
# "message" => String }]
|
107
|
+
def delete(id)
|
108
|
+
current_path = "/api/v1/collections/#{id}"
|
109
|
+
@conn.delete(current_path)
|
110
|
+
end
|
111
|
+
|
112
|
+
# adds site(s) to a site collection
|
113
|
+
# @param [int] id of the collection to which to add sites
|
114
|
+
# @param [int|Array] sites nid or array of site nids.
|
115
|
+
# @return [Hash{ "id" => Integer,
|
116
|
+
# "name" => String,
|
117
|
+
# "time" => "2016-10-28T09:25:26+00:00",
|
118
|
+
# "site_ids_added" => Array,
|
119
|
+
# "added" => Boolean,
|
120
|
+
# "message" => String }]
|
121
|
+
def add_sites(id, sites)
|
122
|
+
sites = Array(sites)
|
123
|
+
payload = { 'site_ids' => sites }.to_json
|
124
|
+
current_path = "/api/v1/collections/#{id}/add"
|
125
|
+
@conn.post(current_path, payload)
|
126
|
+
end
|
127
|
+
|
128
|
+
# removes site(s) from a site collection
|
129
|
+
# @param [int] id of the collection from which to remove sites
|
130
|
+
# @param [int|Array] sites nid or array of site nids.
|
131
|
+
# @return [Hash{ "id" => Integer,
|
132
|
+
# "name" => String,
|
133
|
+
# "time" => "2016-10-28T09:25:26+00:00",
|
134
|
+
# "site_ids_removed" => Array,
|
135
|
+
# "removed" => Boolean,
|
136
|
+
# "message" => String }]
|
137
|
+
def remove_sites(id, sites)
|
138
|
+
sites = Array(sites)
|
139
|
+
payload = { 'site_ids' => sites }.to_json
|
140
|
+
current_path = "/api/v1/collections/#{id}/remove"
|
141
|
+
@conn.post(current_path, payload)
|
142
|
+
end
|
143
|
+
|
144
|
+
# sets a site to be a primary site in a site collection
|
145
|
+
# @param [int] id of the collection where the primary site is being changed
|
146
|
+
# @param [int] site nid to become the primary site
|
147
|
+
# @return [Hash{ "id" => Integer,
|
148
|
+
# "name" => String,
|
149
|
+
# "time" => "2016-10-28T09:25:26+00:00",
|
150
|
+
# "primary_site_id": Integer,
|
151
|
+
# "switched" => Boolean,
|
152
|
+
# "message" => String }]
|
153
|
+
def set_primary_site(id, site)
|
154
|
+
payload = { 'site_id' => site }.to_json
|
155
|
+
current_path = "/api/v1/collections/#{id}/set-primary"
|
156
|
+
@conn.post(current_path, payload)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/lib/sfrest/connection.rb
CHANGED
@@ -26,7 +26,7 @@ module SFRest
|
|
26
26
|
password: password,
|
27
27
|
ssl_verify_peer: false)
|
28
28
|
begin
|
29
|
-
access_check JSON(res.body)
|
29
|
+
access_check JSON(res.body), res.status
|
30
30
|
rescue JSON::ParserError
|
31
31
|
res.body
|
32
32
|
end
|
@@ -45,7 +45,7 @@ module SFRest
|
|
45
45
|
password: password,
|
46
46
|
ssl_verify_peer: false)
|
47
47
|
begin
|
48
|
-
data = access_check JSON(res.body)
|
48
|
+
data = access_check JSON(res.body), res.status
|
49
49
|
return res.status, data
|
50
50
|
|
51
51
|
rescue JSON::ParserError
|
@@ -67,7 +67,7 @@ module SFRest
|
|
67
67
|
ssl_verify_peer: false,
|
68
68
|
body: payload)
|
69
69
|
begin
|
70
|
-
access_check JSON(res.body)
|
70
|
+
access_check JSON(res.body), res.status
|
71
71
|
rescue JSON::ParserError
|
72
72
|
res.body
|
73
73
|
end
|
@@ -87,7 +87,7 @@ module SFRest
|
|
87
87
|
ssl_verify_peer: false,
|
88
88
|
body: payload)
|
89
89
|
begin
|
90
|
-
access_check JSON(res.body)
|
90
|
+
access_check JSON(res.body), res.status
|
91
91
|
rescue JSON::ParserError
|
92
92
|
res.body
|
93
93
|
end
|
@@ -106,7 +106,7 @@ module SFRest
|
|
106
106
|
password: password,
|
107
107
|
ssl_verify_peer: false)
|
108
108
|
begin
|
109
|
-
access_check JSON(res.body)
|
109
|
+
access_check JSON(res.body), res.status
|
110
110
|
rescue JSON::ParserError
|
111
111
|
res.body
|
112
112
|
end
|
@@ -114,17 +114,32 @@ module SFRest
|
|
114
114
|
|
115
115
|
# Throws an SFRest exception for requests that have problems
|
116
116
|
# @param [Object] data JSON parsed http reponse of the SFApi
|
117
|
+
# @param [int] http_status the request's HTTP status
|
117
118
|
# @return [Object] the data object if there are no issues
|
118
119
|
# @raise [SFRest::AccessDeniedError] if Authentication fails
|
119
120
|
# @raise [SFRest::ActionForbiddenError] if the users role cannot perform the request
|
120
121
|
# @raise [SFRest::BadRequestError] if there is something malformed in the request
|
122
|
+
# @raise [SFRest::UnprocessableEntity] if there is an unprocessable entity in the request
|
123
|
+
# @raise [SFRest::SFError] if the response HTTP status indicates an error but without the above qualifiers
|
121
124
|
#
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
125
|
+
# The cyclomatic complexity check is being ignored here because we are
|
126
|
+
# collecting all the possible exception raising cases.
|
127
|
+
def access_check(data, http_status) # rubocop:disable Metrics/CyclomaticComplexity
|
128
|
+
if data.is_a?(Hash) && !data['message'].nil?
|
129
|
+
case data['message']
|
130
|
+
when /Access denied|Access Denied/
|
131
|
+
raise SFRest::AccessDeniedError, data['message']
|
132
|
+
when /Forbidden: /
|
133
|
+
raise SFRest::ActionForbiddenError, data['message']
|
134
|
+
when /Bad Request:/
|
135
|
+
raise SFRest::BadRequestError, data['message']
|
136
|
+
when /Unprocessible Entity: |Unprocessable Entity: /
|
137
|
+
raise SFRest::UnprocessableEntity, data['message']
|
138
|
+
end
|
139
|
+
if http_status >= 400 && http_status <= 599
|
140
|
+
sf_err_message = "Status: #{http_status}, Message: #{data['message']}"
|
141
|
+
raise SFRest::SFError, sf_err_message
|
142
|
+
end
|
128
143
|
end
|
129
144
|
data
|
130
145
|
end
|
@@ -151,9 +166,10 @@ module SFRest
|
|
151
166
|
# NOTE: accessor == Class_name.to_lower
|
152
167
|
REST_METHODS = %w(audit
|
153
168
|
backup
|
154
|
-
|
169
|
+
collection
|
155
170
|
domains
|
156
171
|
group
|
172
|
+
info
|
157
173
|
role
|
158
174
|
site
|
159
175
|
stage
|
data/lib/sfrest/error.rb
CHANGED
@@ -14,6 +14,12 @@ module SFRest
|
|
14
14
|
# the factory
|
15
15
|
class BadRequestError < SFRest::SFError; end
|
16
16
|
|
17
|
+
# Throw this when the request contains unprocessable entity.
|
18
|
+
class UnprocessableEntity < SFRest::SFError; end
|
19
|
+
|
17
20
|
# Throw when a task appears to be running too long
|
18
21
|
class TaskNotDoneError < SFRest::SFError; end
|
22
|
+
|
23
|
+
# if you get in valid data
|
24
|
+
class InvalidDataError < SFRest::SFError; end
|
19
25
|
end
|
data/lib/sfrest/info.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module SFRest
|
2
|
+
# Retrieve Site Factory info.
|
3
|
+
class Info
|
4
|
+
# @param [SFRest::Connection] conn
|
5
|
+
def initialize(conn)
|
6
|
+
@conn = conn
|
7
|
+
end
|
8
|
+
|
9
|
+
# Gets information about the Site Factory.
|
10
|
+
# @return [Hash{ "factory_version" => String,
|
11
|
+
# "time" => "2016-10-28T09:25:26+00:00"}]
|
12
|
+
def sfinfo
|
13
|
+
@conn.get('/api/v1/sf-info')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/sfrest/task.rb
CHANGED
@@ -191,12 +191,17 @@ module SFRest
|
|
191
191
|
|
192
192
|
# Gets the value of a vairable
|
193
193
|
# @TODO: this is missnamed becasue it does not check the global paused variable
|
194
|
-
# @
|
195
|
-
|
196
|
-
|
197
|
-
current_path =
|
198
|
-
|
199
|
-
|
194
|
+
# @return [Boolean]
|
195
|
+
def globally_paused?
|
196
|
+
paused = false
|
197
|
+
current_path = '/api/v1/variables?name=wip_pause_global'
|
198
|
+
begin
|
199
|
+
res = @conn.get(current_path)
|
200
|
+
paused = res['wip_pause_global']
|
201
|
+
rescue SFRest::SFError => error
|
202
|
+
paused = false if error.message =~ /Variable not found/
|
203
|
+
end
|
204
|
+
paused
|
200
205
|
end
|
201
206
|
|
202
207
|
# Pauses a specific task identified by its task id.
|
data/lib/sfrest/version.rb
CHANGED
data/lib/sfrest.rb
CHANGED
@@ -8,11 +8,12 @@ require 'json'
|
|
8
8
|
|
9
9
|
require 'sfrest/audit'
|
10
10
|
require 'sfrest/backup'
|
11
|
-
require 'sfrest/
|
11
|
+
require 'sfrest/collection'
|
12
12
|
require 'sfrest/connection'
|
13
13
|
require 'sfrest/domains'
|
14
14
|
require 'sfrest/error'
|
15
15
|
require 'sfrest/group'
|
16
|
+
require 'sfrest/info'
|
16
17
|
require 'sfrest/pathbuilder'
|
17
18
|
require 'sfrest/role'
|
18
19
|
require 'sfrest/site'
|
@@ -42,4 +43,21 @@ module SFRest
|
|
42
43
|
@conn = SFRest::Connection.new(@base_url, @user, @password)
|
43
44
|
end
|
44
45
|
end
|
46
|
+
|
47
|
+
# Extract the return data for 'key' based on the result object
|
48
|
+
# @param [Hash] res result from a request to /collections or /site
|
49
|
+
# @param [String] field data field to search
|
50
|
+
# @param [String] datapat regex-like pattern to match to the data field
|
51
|
+
# @param [String] key one of the user data returned (id, name, domain...)
|
52
|
+
# @return [Object] Integer, String, Array, Hash depending on the collection data
|
53
|
+
def self.find_data_from_results(res, field, datapat, key)
|
54
|
+
data = res.select { |k| !k.to_s.match(/time|count/) }
|
55
|
+
raise InvalidDataError('The data you are searching is not a hash') unless data.is_a?(Hash)
|
56
|
+
data.each_value do |datum|
|
57
|
+
datum.each do |dat|
|
58
|
+
return dat[key] if dat[field].to_s =~ /#{datapat}/
|
59
|
+
end
|
60
|
+
end
|
61
|
+
nil
|
62
|
+
end
|
45
63
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sfrest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ACSF Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: excon
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faker
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rspec
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,11 +103,12 @@ files:
|
|
89
103
|
- lib/sfrest.rb
|
90
104
|
- lib/sfrest/audit.rb
|
91
105
|
- lib/sfrest/backup.rb
|
92
|
-
- lib/sfrest/
|
106
|
+
- lib/sfrest/collection.rb
|
93
107
|
- lib/sfrest/connection.rb
|
94
108
|
- lib/sfrest/domains.rb
|
95
109
|
- lib/sfrest/error.rb
|
96
110
|
- lib/sfrest/group.rb
|
111
|
+
- lib/sfrest/info.rb
|
97
112
|
- lib/sfrest/pathbuilder.rb
|
98
113
|
- lib/sfrest/role.rb
|
99
114
|
- lib/sfrest/site.rb
|
@@ -125,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
140
|
version: '0'
|
126
141
|
requirements: []
|
127
142
|
rubyforge_project:
|
128
|
-
rubygems_version: 2.6.
|
143
|
+
rubygems_version: 2.6.12
|
129
144
|
signing_key:
|
130
145
|
specification_version: 4
|
131
146
|
summary: Acquia Site Factory Rest API.
|
data/lib/sfrest/collections.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
module SFRest
|
2
|
-
# Find colletions, return their data.
|
3
|
-
class Collections
|
4
|
-
# @param [SFRest::Connection] conn
|
5
|
-
def initialize(conn)
|
6
|
-
@conn = conn
|
7
|
-
end
|
8
|
-
|
9
|
-
# gets the site ID for the site named sitename
|
10
|
-
# will page through all the sites available searching for the site
|
11
|
-
# @param [String] name the name of the site
|
12
|
-
# @return [Integer] the id of sitename
|
13
|
-
def get_collection_id(name)
|
14
|
-
pglimit = 100
|
15
|
-
res = @conn.get('/api/v1/collections&limit=' + pglimit.to_s)
|
16
|
-
count = res['count'].to_i
|
17
|
-
id = collection_data_from_results(res, name, 'id')
|
18
|
-
return id if id
|
19
|
-
pages = (count / pglimit) + 1
|
20
|
-
2.upto(pages) do |i|
|
21
|
-
res = @conn.get('/api/v1/collections&limit=' + pglimit.to_s + '?page=' + i.to_s)
|
22
|
-
id = collection_data_from_results(res, name, 'id')
|
23
|
-
return id if id
|
24
|
-
end
|
25
|
-
nil
|
26
|
-
end
|
27
|
-
|
28
|
-
# Extract the site data for 'key' based on the site result object
|
29
|
-
# @param [Hash] res result from a request to /collections
|
30
|
-
# @param [String] name
|
31
|
-
# @param [String] key one of the user data returned (id, name, domain...)
|
32
|
-
# @return [Object] Integer, String, Array, Hash depending on the collection data
|
33
|
-
def collection_data_from_results(res, name, key)
|
34
|
-
collections = res['collections']
|
35
|
-
collections.each do |collection|
|
36
|
-
return collection[key] if collection['name'] == name
|
37
|
-
end
|
38
|
-
nil
|
39
|
-
end
|
40
|
-
|
41
|
-
# Gets the site data for a specific id
|
42
|
-
# @param [Integer] id the site id
|
43
|
-
# @return [Hash]
|
44
|
-
def get_collection_data(id)
|
45
|
-
@conn.get('/api/v1/collections/' + id.to_s)
|
46
|
-
end
|
47
|
-
|
48
|
-
# gets the site id of the 1st one found using the api
|
49
|
-
# @return [Integer] the site id
|
50
|
-
def first_collection_id
|
51
|
-
res = @conn.get('/api/v1/collections')
|
52
|
-
res['collections'].first['id']
|
53
|
-
end
|
54
|
-
|
55
|
-
# Gets the complete list of collections
|
56
|
-
# Makes multiple requests to the factory to get all the collections on the factory
|
57
|
-
# @return [Hash{'count' => Integer, 'sites' => Hash}]
|
58
|
-
def collection_list
|
59
|
-
page = 1
|
60
|
-
not_done = true
|
61
|
-
count = 0
|
62
|
-
while not_done
|
63
|
-
current_path = '/api/v1/collections?page=' << page.to_s
|
64
|
-
res = @conn.get(current_path)
|
65
|
-
if res['collections'] == []
|
66
|
-
not_done = false
|
67
|
-
elsif !res['message'].nil?
|
68
|
-
return { 'message' => res['message'] }
|
69
|
-
elsif page == 1
|
70
|
-
count = res['count']
|
71
|
-
collections = res['collections']
|
72
|
-
else
|
73
|
-
res['collections'].each do |collection|
|
74
|
-
collections << collection
|
75
|
-
end
|
76
|
-
end
|
77
|
-
page += 1
|
78
|
-
end
|
79
|
-
{ 'count' => count, 'collections' => collections }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|