netologiest 0.0.0 → 0.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7c751c650af9ea57817189c2cdd91f41fe33cfdc
4
- data.tar.gz: 47057e79318e7b265021d61cc48dc6d7917b5ddb
3
+ metadata.gz: 8b6e1d7e36a3857d851d1bcc54007f3aeddfe753
4
+ data.tar.gz: 7b0f8a1fc72547248c13c4f9a93ddf485af85131
5
5
  SHA512:
6
- metadata.gz: 857d813bdb77a95bfc406b97e6fc80f9484375f10ff6f6aa9d1d552bbbf62d2b17cbcce6e63983650255891cd34d999b965f5b242bc1692b7bde140bb81e2bb2
7
- data.tar.gz: 72a5553cf6929fdc97a7685a3c93e4e79e392bcb61bf14ab03dfc9b8d9bef01c0a3497f78e8b473afc9035b0a8d132cc47403bcb6b72a27c84848e0e2e8041c6
6
+ metadata.gz: dddf7b03ca6142c6b97ded47c1f8472ec8e534c7163a22edf2f17a8c214f01e00af1b782078dc2aa11301c614c380faf9a79886066f01c8bf6370e8a055d1892
7
+ data.tar.gz: 371b2fdab4d38087abe607cfa3c2fbd90a659d80090b89a53a2a887e508134ceadfbf125546ccf9628dd17b732020c5b0097e01ebc6767d5966df779509fbd78
data/README.md CHANGED
@@ -1,2 +1,87 @@
1
+ [![Build Status](https://travis-ci.org/teachbase/netologiest.svg?branch=master)](https://travis-ci.org/teachbase/netologiest)
2
+
1
3
  # Netologiest
2
4
  Netology Ruby API client
5
+
6
+ API for Netology (http://netology.ru/) e-learning intergration.
7
+
8
+ ## Configuration
9
+
10
+ Netologiest uses [anyway_config](https://github.com/palkan/anyway_config) to configure client.
11
+
12
+ It has two configuration attributes:
13
+ - `api_key`;
14
+ - `api_url`.
15
+
16
+ For example (in your `secrets.yml`):
17
+
18
+ ```ruby
19
+ ....
20
+ netologiest:
21
+ api_key: "your_api_key_here"
22
+ api_url: "http://dev.netology.ru/content_api"
23
+ ....
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ Netologiest having only one resource at moment (Course).
29
+
30
+ To get a list of courses
31
+
32
+ ```ruby
33
+ Netologiest::Course.list
34
+
35
+ #=>
36
+ [
37
+ {
38
+ "id" => "1",
39
+ "name" => "Direct marketing. Basics.",
40
+ "last_updated_at" => "1387176082"
41
+ },
42
+ {
43
+ "id" => "2",
44
+ "name" => "Test course #1",
45
+ "last_updated_at" => "1386236837"
46
+ },
47
+ {
48
+ "id" => "3",
49
+ "name" => "How to make course.",
50
+ "last_updated_at" => "1387176130"
51
+ }
52
+ ]
53
+ ```
54
+
55
+ Also you can get detailed information about any course:
56
+
57
+ ```ruby
58
+ # argument is Course ID
59
+ Netologiest::Course.detail(1)
60
+
61
+ #=>
62
+ {
63
+ "id" => 931,
64
+ "name" => "Name of course",
65
+ "description" => "Description of course",
66
+ "progress" => 0,
67
+ "duration" => 47,
68
+ "level" => { ... },
69
+ "tags" => [{..}, {..}, {..}]
70
+ ....
71
+ "blocks" => [
72
+ ...
73
+ {
74
+ "lessons" => []
75
+ }
76
+ ...
77
+ ]
78
+ }
79
+ ```
80
+
81
+ ## Contributing
82
+
83
+ 1. Fork it ( https://github.com/[my-github-username]/netologiest/fork )
84
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
85
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
86
+ 4. Push to the branch (`git push origin my-new-feature`)
87
+ 5. Create a new Pull Request
data/lib/netologiest.rb CHANGED
@@ -1,5 +1,12 @@
1
+ require 'netologiest/resource'
2
+ require 'netologiest/resources/course'
3
+ require 'netologiest/config'
4
+ require 'netologiest/exceptions'
1
5
  require 'netologiest/version'
2
6
 
3
7
  # Ruby client for Netology API
4
8
  module Netologiest
9
+ def self.config
10
+ @config ||= Config.new
11
+ end
5
12
  end
@@ -0,0 +1,9 @@
1
+ require 'anyway'
2
+
3
+ module Netologiest
4
+ # :nodoc:
5
+ class Config < Anyway::Config
6
+ attr_config :api_key,
7
+ api_url: "http://dev.netology.ru/content_api"
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Netologiest
2
+ class Unauthorized < StandardError; end
3
+ end
@@ -0,0 +1,97 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+ require 'active_support'
4
+
5
+ module Netologiest
6
+ # This class describe client for
7
+ # Netology API. It contains finder actions
8
+ # and special handlers methods
9
+ class Resource
10
+ class << self
11
+ attr_accessor :resource_name
12
+ end
13
+
14
+ attr_reader :token, :token_expire
15
+
16
+ def initialize
17
+ authorize!
18
+ end
19
+
20
+ def self.list
21
+ new.list
22
+ end
23
+
24
+ def self.detail(id)
25
+ new.detail(id)
26
+ end
27
+
28
+ def list
29
+ handle_list(
30
+ get(
31
+ build_url(self.class.resource_name)
32
+ )
33
+ )
34
+ end
35
+
36
+ def detail(id)
37
+ handle_detail(
38
+ get(
39
+ build_url(self.class.resource_name, id)
40
+ )
41
+ )
42
+ end
43
+
44
+ # rubocop:disable Metrics/AbcSize, Metrics//MethodLength
45
+ def authorize!
46
+ url = build_url('gettoken')
47
+ params = { client_secret: Netologiest.config.api_key }
48
+ RestClient.get(url, params: params) do |response, _request, _result|
49
+ case response.code
50
+ when 200
51
+ body = JSON.parse(response.body)
52
+ @token_expire = Time.now.to_i + body.fetch('expires_in').to_i
53
+ @token = body['access_token']
54
+ when 401
55
+ fail Netologiest::Unauthorized, response.body
56
+ else
57
+ response
58
+ end
59
+ end
60
+ end
61
+ # rubocop:enable Metrics/AbcSize, Metrics//MethodLength
62
+
63
+ def token_expired?
64
+ return true unless token_expire.present?
65
+ token_expire < Time.now.to_i
66
+ end
67
+
68
+ def handle_list(_response); end
69
+
70
+ def handle_detail(_response); end
71
+
72
+ protected
73
+
74
+ def build_url(*args)
75
+ File.join(Netologiest.config.api_url, *args.map(&:to_s))
76
+ end
77
+
78
+ # rubocop:disable Metrics/MethodLength
79
+ def get(url, options = {})
80
+ params = { token: token }.merge!(options)
81
+
82
+ RestClient.get(url, params: params) do |response, _request, _result|
83
+ if response.code == 401
84
+ begin
85
+ authorize!
86
+ params[:token] = token
87
+ return RestClient.get(url, params: params)
88
+ rescue RestClient::Unauthorized
89
+ raise Netologiest::Unauthorized, response.body
90
+ end
91
+ end
92
+ response
93
+ end
94
+ end
95
+ # rubocop:enable Metrics/MethodLength
96
+ end
97
+ end
@@ -0,0 +1,28 @@
1
+ module Netologiest
2
+ # Child class for Resource
3
+ # describe rules for parsing Netology response
4
+ class Course < Netologiest::Resource
5
+ self.resource_name = 'courses'
6
+
7
+ # Methods for parsing JSON response
8
+ # it returns Array of Hash instances
9
+ def handle_list(response)
10
+ parse_json(response)
11
+ end
12
+
13
+ # it returns a Hash instance
14
+ # it contains deep elements:
15
+ # => blocks: [{lessons: [{questions: []}]]
16
+ def handle_detail(response)
17
+ parse_json(response)
18
+ end
19
+
20
+ private
21
+
22
+ def parse_json(response)
23
+ data = JSON.parse(response)
24
+ return unless data.present? || data.any?
25
+ data
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,4 @@
1
- module Netologiest # :nodoc:
2
- VERSION = "0.0.0"
1
+ # :nodoc:
2
+ module Netologiest
3
+ VERSION = "0.0.1"
3
4
  end
data/netologiest.gemspec CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "webmock"
25
25
  spec.add_development_dependency 'pry'
26
26
  spec.add_dependency "anyway_config", "~> 0", ">= 0.3"
27
- spec.add_dependency 'activemodel'
27
+ spec.add_dependency "rest-client"
28
+ spec.add_dependency 'activesupport'
28
29
  spec.add_dependency 'json'
29
30
  end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ describe Netologiest::Course do
4
+ describe "valid response" do
5
+ before(:each) do
6
+ mock_api
7
+ courses_stub
8
+ end
9
+
10
+ it "return list of courses" do
11
+ courses = described_class.list
12
+ expect(courses.count).to eq 11
13
+ expect(courses.first["id"]).to eq "426"
14
+ end
15
+
16
+ it "return detail hash of course" do
17
+ detail_course_stub(931)
18
+ course = described_class.detail(931)
19
+ expect(course["id"]).to eq 931
20
+ expect(course["name"]).to eq "Контекстная реклама в Google AdWords"
21
+ expect(course["blocks"].size).to eq 1
22
+ expect(course["blocks"][0]["lessons"].size).to eq 11
23
+ end
24
+
25
+ it "return nil if course not found" do
26
+ empty_course_stub(1)
27
+ course = described_class.detail(1)
28
+ expect(course).to be_nil
29
+ end
30
+
31
+ it "many authorize requests" do
32
+ many_requests_stub(931)
33
+ course = described_class.detail(931)
34
+ expect(course["id"]).to eq 931
35
+ end
36
+ end
37
+
38
+ describe "errors" do
39
+ it "raise error if token is bad" do
40
+ mock_api
41
+ bad_token_stub(1)
42
+ expect { described_class.detail(1) }
43
+ .to raise_error(Netologiest::Unauthorized, /Need token/)
44
+ end
45
+
46
+ it "raise error if secret key is bad" do
47
+ auth_url = "#{Netologiest.config.api_url}/gettoken"
48
+ url = "#{auth_url}?client_secret=#{Netologiest.config.api_key}"
49
+ auth_failed_stub(url)
50
+ expect { described_class.detail(931) }
51
+ .to raise_error(Netologiest::Unauthorized, /Need correct client_secret/)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,4 @@
1
+ {
2
+ "access_token": "S3PBVG38O1209Y01X5LEK0PYH0MT3YDZ",
3
+ "expires_in": 600
4
+ }
@@ -0,0 +1,422 @@
1
+ {
2
+ "id": 931,
3
+ "name": "Контекстная реклама в Google AdWords",
4
+ "description": "<p>Почему Google AdWords обходится дешевле, чем &laquo;Яндекс. Директ&raquo;? Как сберечь деньги на контекстной рекламе и привлечь целевой трафик на сайт?<br />\r\n&nbsp;<br />\r\nКурс адресован начинающим специалистам по контекстной рекламе и интернет-маркетологам, которые знают основы медиапланирования.</p>\r\n\r\n<p>Полина Аверина расскажет, как создавать рекламные кампании в Google AdWords для поисковой и контекстно-медийной сети. Вы научитесь работать со ссылками, составлять эффективные объявления, подбирать ключевые фразы и минус-слова. Узнаете, как с помощью ремаркетинга вернуть заинтересованных пользователей.</p>\r\n",
5
+ "progress": 0,
6
+ "duration": 47,
7
+ "level": {
8
+ "id": 1,
9
+ "name": "Базовый"
10
+ },
11
+ "tags": [
12
+ {
13
+ "id": 4,
14
+ "name": "Интернет-маркетинг"
15
+ }
16
+ ],
17
+ "authors": [
18
+ {
19
+ "id": 2426656,
20
+ "organization_post": "Руководитель отдела контекстной рекламы сервиса 1PS",
21
+ "full_name": "Полина Аверина",
22
+ "image": "http://netology.ru/content/u7/7049.jpeg",
23
+ "description": ""
24
+ }
25
+ ],
26
+ "blocks": [
27
+ {
28
+ "id": 931,
29
+ "name": "Блок по умолчанию",
30
+ "position": 1,
31
+ "lessons": [
32
+ {
33
+ "id": 2268,
34
+ "name": "Вступление и знакомство с автором курса",
35
+ "position": 1,
36
+ "human_type": "video_lesson",
37
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
38
+ "video_url": "/courses/931/lessons/2268/iframe"
39
+ },
40
+ {
41
+ "id": 2269,
42
+ "name": "Сравнение Google AdWords и «Яндекс.Директа»",
43
+ "position": 2,
44
+ "human_type": "video_lesson",
45
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
46
+ "video_url": "/courses/931/lessons/2269/iframe"
47
+ },
48
+ {
49
+ "id": 2270,
50
+ "name": "Настройки поисковой кампании",
51
+ "position": 3,
52
+ "human_type": "video_lesson",
53
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
54
+ "video_url": "/courses/931/lessons/2270/iframe"
55
+ },
56
+ {
57
+ "id": 2271,
58
+ "name": "Работа с ключевыми словами",
59
+ "position": 4,
60
+ "human_type": "video_lesson",
61
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
62
+ "video_url": "/courses/931/lessons/2271/iframe"
63
+ },
64
+ {
65
+ "id": 2272,
66
+ "name": "Составление объявлений и работа со ссылками",
67
+ "position": 5,
68
+ "human_type": "video_lesson",
69
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
70
+ "video_url": "/courses/931/lessons/2272/iframe"
71
+ },
72
+ {
73
+ "id": 2273,
74
+ "name": "Загрузка кампании через редактор AdWords",
75
+ "position": 6,
76
+ "human_type": "video_lesson",
77
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
78
+ "video_url": "/courses/931/lessons/2273/iframe"
79
+ },
80
+ {
81
+ "id": 2274,
82
+ "name": "Расширения объявлений",
83
+ "position": 7,
84
+ "human_type": "video_lesson",
85
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
86
+ "video_url": "/courses/931/lessons/2274/iframe"
87
+ },
88
+ {
89
+ "id": 2275,
90
+ "name": "Эффективная кампания для КМС",
91
+ "position": 8,
92
+ "human_type": "video_lesson",
93
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
94
+ "video_url": "/courses/931/lessons/2275/iframe"
95
+ },
96
+ {
97
+ "id": 2276,
98
+ "name": "Ремаркетинг в КМС",
99
+ "position": 9,
100
+ "human_type": "video_lesson",
101
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
102
+ "video_url": "/courses/931/lessons/2276/iframe"
103
+ },
104
+ {
105
+ "id": 2277,
106
+ "name": "Подведение итогов курса",
107
+ "position": 10,
108
+ "human_type": "video_lesson",
109
+ "poster": "http://netology.ru/content/p3/3375@2x.png",
110
+ "video_url": "/courses/931/lessons/2277/iframe"
111
+ },
112
+ {
113
+ "id": 2547,
114
+ "name": "Контекстная реклама в Google AdWords: итоговый тест",
115
+ "position": 11,
116
+ "human_type": "test_final",
117
+ "questions": [
118
+ {
119
+ "id": "65953",
120
+ "position": 1,
121
+ "content": "При определении позиции объявления в блоке Google AdWords учитывается:",
122
+ "type": "radio",
123
+ "answers": [
124
+ {
125
+ "id": 1,
126
+ "content": "только ставка рекламодателя",
127
+ "is_correct": false
128
+ },
129
+ {
130
+ "id": 2,
131
+ "content": "ставка рекламодателя и прогнозируемый CTR объявления",
132
+ "is_correct": false
133
+ },
134
+ {
135
+ "id": 3,
136
+ "content": "показатель качества объявления и ставка рекламодателя",
137
+ "is_correct": true
138
+ }
139
+ ]
140
+ },
141
+ {
142
+ "id": "65954",
143
+ "position": 2,
144
+ "content": "Вы предоставляете услуги выездной техпомощи на дорогах. Как лучше настроить ставки в объявлениях на мобильных устройствах?",
145
+ "type": "radio",
146
+ "answers": [
147
+ {
148
+ "id": 1,
149
+ "content": "снизить на 50%",
150
+ "is_correct": false
151
+ },
152
+ {
153
+ "id": 2,
154
+ "content": "повысить на 50−100%",
155
+ "is_correct": true
156
+ },
157
+ {
158
+ "id": 3,
159
+ "content": "снизить на 20%",
160
+ "is_correct": false
161
+ }
162
+ ]
163
+ },
164
+ {
165
+ "id": "65955",
166
+ "position": 3,
167
+ "content": "Как лучше всего настроить геотаргетинг?",
168
+ "type": "radio",
169
+ "answers": [
170
+ {
171
+ "id": 1,
172
+ "content": "установить в настройках кампании таргетинг на Москву, затем по очереди добавить все остальные города",
173
+ "is_correct": false
174
+ },
175
+ {
176
+ "id": 2,
177
+ "content": "настроить на каждый город отдельную кампанию, где название города будет присутствовать в текстах объявлений",
178
+ "is_correct": true
179
+ },
180
+ {
181
+ "id": 3,
182
+ "content": "выбрать в настройках местоположений вариант «Дополнительно» и отметить все нужные точки на карте",
183
+ "is_correct": false
184
+ }
185
+ ]
186
+ },
187
+ {
188
+ "id": "65956",
189
+ "position": 4,
190
+ "content": "Дневной бюджет в кампании можно задать:",
191
+ "type": "radio",
192
+ "answers": [
193
+ {
194
+ "id": 1,
195
+ "content": "на уровне аккаунта",
196
+ "is_correct": false
197
+ },
198
+ {
199
+ "id": 2,
200
+ "content": "на уровне рекламной кампании",
201
+ "is_correct": true
202
+ },
203
+ {
204
+ "id": 3,
205
+ "content": "на уровне группы объявлений",
206
+ "is_correct": false
207
+ }
208
+ ]
209
+ },
210
+ {
211
+ "id": "65957",
212
+ "position": 5,
213
+ "content": "По какому запросу пользователя не будет показов?",
214
+ "type": "radio",
215
+ "answers": [
216
+ {
217
+ "id": 1,
218
+ "content": "купить мультиварку в интернет-магазине",
219
+ "is_correct": false
220
+ },
221
+ {
222
+ "id": 2,
223
+ "content": "где купить мультиварку в Самаре",
224
+ "is_correct": false
225
+ },
226
+ {
227
+ "id": 3,
228
+ "content": "мультиварки со скидкой в Москве",
229
+ "is_correct": true
230
+ }
231
+ ]
232
+ },
233
+ {
234
+ "id": "65958",
235
+ "position": 6,
236
+ "content": "Как добавить словосочетание «своими руками» в качестве минус-слова на уровне кампании в Google AdWord?",
237
+ "type": "radio",
238
+ "answers": [
239
+ {
240
+ "id": 1,
241
+ "content": "на вкладке «Ключевые слова» добавить в минус-слова [своими руками]",
242
+ "is_correct": true
243
+ },
244
+ {
245
+ "id": 2,
246
+ "content": "на вкладке «Ключевые слова» добавить в минус-слова «свой» и «рука»",
247
+ "is_correct": false
248
+ },
249
+ {
250
+ "id": 3,
251
+ "content": "в настройках кампании вписать словосочетание «своими руками» в раздел «минус-слова на кампанию»",
252
+ "is_correct": false
253
+ }
254
+ ]
255
+ },
256
+ {
257
+ "id": "65959",
258
+ "position": 7,
259
+ "content": "Группы объявлений помогают:",
260
+ "type": "radio",
261
+ "answers": [
262
+ {
263
+ "id": 1,
264
+ "content": "сгруппировать в кампании объявления по тематикам",
265
+ "is_correct": false
266
+ },
267
+ {
268
+ "id": 2,
269
+ "content": "выявить наиболее эффективные тексты объявлений",
270
+ "is_correct": true
271
+ },
272
+ {
273
+ "id": 3,
274
+ "content": "выявить новые ключевые слова для кампании",
275
+ "is_correct": false
276
+ }
277
+ ]
278
+ },
279
+ {
280
+ "id": "65960",
281
+ "position": 8,
282
+ "content": "Как будет выглядеть заголовок объявления?",
283
+ "type": "radio",
284
+ "answers": [
285
+ {
286
+ "id": 1,
287
+ "content": "скидки на карнавальные костюмы",
288
+ "is_correct": false
289
+ },
290
+ {
291
+ "id": 2,
292
+ "content": "скидки на костюмы для детского сада",
293
+ "is_correct": false
294
+ },
295
+ {
296
+ "id": 3,
297
+ "content": "скидки на костюмы",
298
+ "is_correct": true
299
+ }
300
+ ]
301
+ },
302
+ {
303
+ "id": "65961",
304
+ "position": 9,
305
+ "content": "Как будут отбираться дополнительные ссылки для каждого объявления?",
306
+ "type": "radio",
307
+ "answers": [
308
+ {
309
+ "id": 1,
310
+ "content": "нужно отметить приоритетные ссылки в каждой группе объявлений, тогда система покажет именно их",
311
+ "is_correct": false
312
+ },
313
+ {
314
+ "id": 2,
315
+ "content": "система выберет для показа те ссылки, которые будут наиболее релевантны конкретному объявлению",
316
+ "is_correct": true
317
+ },
318
+ {
319
+ "id": 3,
320
+ "content": "все ссылки будут показываться поочередно",
321
+ "is_correct": false
322
+ }
323
+ ]
324
+ },
325
+ {
326
+ "id": "65962",
327
+ "position": 10,
328
+ "content": "Какие размеры баннеров лучше использовать для показов на сайтах КМС Google AdWords?",
329
+ "type": "radio",
330
+ "answers": [
331
+ {
332
+ "id": 1,
333
+ "content": "240x400, 250x250, 300x250, 970x250",
334
+ "is_correct": false
335
+ },
336
+ {
337
+ "id": 2,
338
+ "content": "300x250, 300x600, 970x250, 970x90",
339
+ "is_correct": false
340
+ },
341
+ {
342
+ "id": 3,
343
+ "content": "все допустимые размеры",
344
+ "is_correct": true
345
+ }
346
+ ]
347
+ },
348
+ {
349
+ "id": "65963",
350
+ "position": 11,
351
+ "content": "Как лучше настроить ремаркетинг?",
352
+ "type": "radio",
353
+ "answers": [
354
+ {
355
+ "id": 1,
356
+ "content": "показывать объявления ремаркетинга всем посетителям сайта",
357
+ "is_correct": false
358
+ },
359
+ {
360
+ "id": 2,
361
+ "content": "создать список ремаркетинга для тех пользователей, которые смотрели страницу «Все услуги», но не переходили на страницу нужной услуги",
362
+ "is_correct": false
363
+ },
364
+ {
365
+ "id": 3,
366
+ "content": "создать отдельный список ремаркетинга для тех, кто посещал страницу с нужной услугой, и предлагать им специальные условия по данной услуге, которые описаны на отдельной странице сайта",
367
+ "is_correct": true
368
+ }
369
+ ]
370
+ },
371
+ {
372
+ "id": "65964",
373
+ "position": 12,
374
+ "content": "Откуда Google AdWords берет данные для разделения аудитории по полу, возрасту и родительскому статусу?",
375
+ "type": "radio",
376
+ "answers": [
377
+ {
378
+ "id": 1,
379
+ "content": "выводы делаются на основе посещенных пользователем сайтов",
380
+ "is_correct": false
381
+ },
382
+ {
383
+ "id": 2,
384
+ "content": "из профилей пользователей в социальных сетях",
385
+ "is_correct": false
386
+ },
387
+ {
388
+ "id": 3,
389
+ "content": "из регистрационных данных в сервисах Google",
390
+ "is_correct": true
391
+ }
392
+ ]
393
+ },
394
+ {
395
+ "id": "65965",
396
+ "position": 13,
397
+ "content": "Как лучше настроить демографические данные для показов объявлений в КМС?",
398
+ "type": "radio",
399
+ "answers": [
400
+ {
401
+ "id": 1,
402
+ "content": "включить показы женщинам от 25 до 34 лет, все остальные половые и возрастные категории отключить ",
403
+ "is_correct": false
404
+ },
405
+ {
406
+ "id": 2,
407
+ "content": "на вкладке «Пол» оставить включенными категории «Женщины» и «Неизвестно», на вкладке «Возраст» — «25−34» и «Неизвестно»",
408
+ "is_correct": true
409
+ },
410
+ {
411
+ "id": 3,
412
+ "content": "включить показы женщинам от 18 до 45 лет, чтобы немного расширить аудиторию",
413
+ "is_correct": false
414
+ }
415
+ ]
416
+ }
417
+ ]
418
+ }
419
+ ]
420
+ }
421
+ ]
422
+ }
@@ -0,0 +1,57 @@
1
+ [
2
+ {
3
+ "id": "426",
4
+ "name": "Основы email-маркетинга",
5
+ "last_updated_at": "1387176082"
6
+ },
7
+ {
8
+ "id": "429",
9
+ "name": "Основы контекстной рекламы",
10
+ "last_updated_at": "1386236837"
11
+ },
12
+ {
13
+ "id": "430",
14
+ "name": "Юзабилити в электронной коммерции",
15
+ "last_updated_at": "1387176130"
16
+ },
17
+ {
18
+ "id": "431",
19
+ "name": "Как писать продающие тексты: свод правил для копирайтера",
20
+ "last_updated_at": "1387176102"
21
+ },
22
+ {
23
+ "id": "432",
24
+ "name": "Баннерная реклама и RTB-технологии",
25
+ "last_updated_at": "1387105068"
26
+ },
27
+ {
28
+ "id": "433",
29
+ "name": "Реклама и маркетинг в интернет-среде",
30
+ "last_updated_at": "1387176111"
31
+ },
32
+ {
33
+ "id": "435",
34
+ "name": "Основы веб-аналитики",
35
+ "last_updated_at": "1387176094"
36
+ },
37
+ {
38
+ "id": "436",
39
+ "name": "Конкурентный анализ и исследование целевой аудитории",
40
+ "last_updated_at": "1387176072"
41
+ },
42
+ {
43
+ "id": "439",
44
+ "name": "Основы маркетинга в социальных сетях (SMM)",
45
+ "last_updated_at": "1385968453"
46
+ },
47
+ {
48
+ "id": "441",
49
+ "name": "Продающие тексты для интернет-магазинов",
50
+ "last_updated_at": "1385968536"
51
+ },
52
+ {
53
+ "id": "444",
54
+ "name": "Запись и распространение аудиоподкастов",
55
+ "last_updated_at": "1386846925"
56
+ }
57
+ ]
@@ -0,0 +1,2 @@
1
+ api_key: "test_api_key_9190132"
2
+ api_url: "http://dev.netology.ru/content_api"
@@ -0,0 +1,79 @@
1
+ module NetologiestWebMock
2
+ def mock_api
3
+ auth_url = "#{Netologiest.config.api_url}/gettoken"
4
+ url = "#{auth_url}?client_secret=#{Netologiest.config.api_key}"
5
+ authorize_stub(url)
6
+ end
7
+
8
+ def authorize_stub(url)
9
+ stub_request(:get, url)
10
+ .to_return(
11
+ headers: { 'Content-Type' => 'application/json' },
12
+ status: 200,
13
+ body: File.read("spec/fixtures/auth.json")
14
+ )
15
+ end
16
+
17
+ def courses_stub
18
+ token = "S3PBVG38O1209Y01X5LEK0PYH0MT3YDZ"
19
+ url = Netologiest.config.api_url + "/courses?token=#{token}"
20
+ stub_request(:get, url).to_return(
21
+ headers: { 'Content-Type' => 'application/json' },
22
+ status: 200,
23
+ body: File.read("spec/fixtures/courses.json")
24
+ )
25
+ end
26
+
27
+ def empty_course_stub(id)
28
+ token = "S3PBVG38O1209Y01X5LEK0PYH0MT3YDZ"
29
+ url = Netologiest.config.api_url + "/courses/#{id}?token=#{token}"
30
+ stub_request(:get, url).to_return(
31
+ headers: { 'Content-Type' => 'application/json' },
32
+ status: 200,
33
+ body: "[]"
34
+ )
35
+ end
36
+
37
+ def detail_course_stub(id)
38
+ token = "S3PBVG38O1209Y01X5LEK0PYH0MT3YDZ"
39
+ url = Netologiest.config.api_url + "/courses/#{id}?token=#{token}"
40
+ stub_request(:get, url).to_return(
41
+ headers: { 'Content-Type' => 'application/json' },
42
+ status: 200,
43
+ body: File.read("spec/fixtures/course.json")
44
+ )
45
+ end
46
+
47
+ def bad_token_stub(id)
48
+ url = Netologiest.config.api_url + "/courses/#{id}?token=S3PBVG38O1209Y01X5LEK0PYH0MT3YDZ"
49
+ stub_request(:get, url).to_return(
50
+ headers: { 'Content-Type' => 'application/json' },
51
+ status: 401,
52
+ body: "Need token"
53
+ )
54
+ end
55
+
56
+ def auth_failed_stub(url)
57
+ stub_request(:get, url)
58
+ .to_return(
59
+ headers: { 'Content-Type' => 'application/json' },
60
+ status: 401,
61
+ body: "Need correct client_secret"
62
+ )
63
+ end
64
+
65
+ def many_requests_stub(id)
66
+ token = "S3PBVG38O1209Y01X5LEK0PYH0MT3YDZ"
67
+ url = Netologiest.config.api_url + "/courses/#{id}?token=#{token}"
68
+ stub_request(:get, url).to_return(
69
+ {
70
+ headers: { 'Content-Type' => 'application/json' },
71
+ status: 401,
72
+ body: "Need token"
73
+ },
74
+ headers: { 'Content-Type' => 'application/json' },
75
+ status: 200,
76
+ body: File.read("spec/fixtures/course.json")
77
+ )
78
+ end
79
+ end
@@ -0,0 +1,11 @@
1
+ require "spec_helper"
2
+
3
+ describe Netologiest::Resource do
4
+ before(:each) { mock_api }
5
+
6
+ it "get authorization token automaticaly" do
7
+ res = described_class.new
8
+ expect(res.token).to eq "S3PBVG38O1209Y01X5LEK0PYH0MT3YDZ"
9
+ expect(res.token_expire.present?).to be_truthy
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ require 'rspec'
2
+ require 'netologiest'
3
+ require 'webmock/rspec'
4
+ require 'helpers/webmock_helpers'
5
+
6
+ begin
7
+ require "pry-byebug"
8
+ rescue LoadError
9
+ end
10
+
11
+ ENV["NETOLOGIEST_CONF"] = File.expand_path("../fixtures/netologiest_test.yml", __FILE__)
12
+
13
+ RSpec.configure do |config|
14
+ config.mock_with :rspec
15
+ include NetologiestWebMock
16
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: netologiest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vlad Dem
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-24 00:00:00.000000000 Z
11
+ date: 2015-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -101,7 +101,21 @@ dependencies:
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0.3'
103
103
  - !ruby/object:Gem::Dependency
104
- name: activemodel
104
+ name: rest-client
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: activesupport
105
119
  requirement: !ruby/object:Gem::Requirement
106
120
  requirements:
107
121
  - - ">="
@@ -143,8 +157,20 @@ files:
143
157
  - README.md
144
158
  - Rakefile
145
159
  - lib/netologiest.rb
160
+ - lib/netologiest/config.rb
161
+ - lib/netologiest/exceptions.rb
162
+ - lib/netologiest/resource.rb
163
+ - lib/netologiest/resources/course.rb
146
164
  - lib/netologiest/version.rb
147
165
  - netologiest.gemspec
166
+ - spec/course_spec.rb
167
+ - spec/fixtures/auth.json
168
+ - spec/fixtures/course.json
169
+ - spec/fixtures/courses.json
170
+ - spec/fixtures/netologiest_test.yml
171
+ - spec/helpers/webmock_helpers.rb
172
+ - spec/resource_spec.rb
173
+ - spec/spec_helper.rb
148
174
  homepage: ''
149
175
  licenses:
150
176
  - MIT
@@ -169,5 +195,13 @@ rubygems_version: 2.4.5
169
195
  signing_key:
170
196
  specification_version: 4
171
197
  summary: Ruby API client for Netology
172
- test_files: []
198
+ test_files:
199
+ - spec/course_spec.rb
200
+ - spec/fixtures/auth.json
201
+ - spec/fixtures/course.json
202
+ - spec/fixtures/courses.json
203
+ - spec/fixtures/netologiest_test.yml
204
+ - spec/helpers/webmock_helpers.rb
205
+ - spec/resource_spec.rb
206
+ - spec/spec_helper.rb
173
207
  has_rdoc: