netologiest 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: