quintype 0.0.2 → 0.0.3

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: 0b6eaa40ec0c1992393a079355cd4ef4e4a0345f
4
- data.tar.gz: 3fd24dbc3782ead2833bfbd7b84d98fbd272cf12
3
+ metadata.gz: fefb62987388a3665a201c7b5516bb4b16207319
4
+ data.tar.gz: f2f0d1d2a058b4f884b9fd9848bc836d31022bdb
5
5
  SHA512:
6
- metadata.gz: 1be78480a44db61e2067c9b3b779df58a7cc4063ccc864ed2f7a93ad6fed41f93b9a5dd472191c39d5320054de1dd917875316e5f13ba6ebb5aece20ed86b5aa
7
- data.tar.gz: 4ad1e0588190e7b54929e5d49fe2b3bcc829251736b7dd9332b65574dc8c698f00ca7b0a088b0f2f087a94d46ac055e8e5c5a9f903a6042b745ef624f0d2005b
6
+ metadata.gz: 6c1d743109ee6717b5d3ba473c93601387d0ff9f3b91085cdef31c81b0f9e8a5eda044b3defd55450b1d278a726c56656c2bf62c358927a51b7eb76e6c70b590
7
+ data.tar.gz: 676ec05fe4c62ca5a8ac93e1a54de6c9cd721ee1496b514f1c4cb8dd7056d53c843f864a1dcd8853d0eee0a03afa27e2dab138f66ef32f6b14cc3c13dd7f6151
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore all logfiles and tempfiles.
11
+ /log/*
12
+ !/log/.keep
13
+ /tmp
14
+ .DS_Store
15
+ .sass-cache/
16
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rspec', '~> 3.4'
7
+ end
8
+
9
+ group :development, :test do
10
+ gem 'pry'
11
+ gem 'byebug'
12
+ end
13
+
14
+ group :test do
15
+ gem 'vcr'
16
+ gem 'webmock'
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ quintype (0.0.0)
5
+ activesupport (~> 4.2)
6
+ faraday (~> 0.9)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (4.2.5.1)
12
+ i18n (~> 0.7)
13
+ json (~> 1.7, >= 1.7.7)
14
+ minitest (~> 5.1)
15
+ thread_safe (~> 0.3, >= 0.3.4)
16
+ tzinfo (~> 1.1)
17
+ addressable (2.4.0)
18
+ byebug (8.2.2)
19
+ coderay (1.1.1)
20
+ crack (0.4.3)
21
+ safe_yaml (~> 1.0.0)
22
+ diff-lcs (1.2.5)
23
+ faraday (0.9.2)
24
+ multipart-post (>= 1.2, < 3)
25
+ hashdiff (0.3.0)
26
+ i18n (0.7.0)
27
+ json (1.8.3)
28
+ method_source (0.8.2)
29
+ minitest (5.8.4)
30
+ multipart-post (2.0.0)
31
+ pry (0.10.3)
32
+ coderay (~> 1.1.0)
33
+ method_source (~> 0.8.1)
34
+ slop (~> 3.4)
35
+ rspec (3.4.0)
36
+ rspec-core (~> 3.4.0)
37
+ rspec-expectations (~> 3.4.0)
38
+ rspec-mocks (~> 3.4.0)
39
+ rspec-core (3.4.3)
40
+ rspec-support (~> 3.4.0)
41
+ rspec-expectations (3.4.0)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.4.0)
44
+ rspec-mocks (3.4.1)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.4.0)
47
+ rspec-support (3.4.1)
48
+ safe_yaml (1.0.4)
49
+ slop (3.6.0)
50
+ thread_safe (0.3.5)
51
+ tzinfo (1.2.2)
52
+ thread_safe (~> 0.1)
53
+ vcr (3.0.1)
54
+ webmock (1.24.2)
55
+ addressable (>= 2.3.6)
56
+ crack (>= 0.3.2)
57
+ hashdiff
58
+
59
+ PLATFORMS
60
+ ruby
61
+
62
+ DEPENDENCIES
63
+ byebug
64
+ pry
65
+ quintype!
66
+ rspec (~> 3.4)
67
+ vcr
68
+ webmock
@@ -0,0 +1,224 @@
1
+ require 'faraday'
2
+ require 'json'
3
+ require 'active_support/all'
4
+
5
+ # API models
6
+ require_relative './api/story'
7
+ require_relative './api/stack'
8
+ require_relative './api/url'
9
+
10
+ class API
11
+ class << self
12
+ def establish_connection(host, conn = Faraday.new(url: host))
13
+ @@host = host
14
+ @@api_base = host + '/api/'
15
+ @@conn = conn
16
+ end
17
+
18
+ def conn
19
+ @@conn
20
+ end
21
+
22
+ def bulk_post(params)
23
+ _post("bulk", params)
24
+ end
25
+
26
+ def config
27
+ _get("config")
28
+ end
29
+
30
+ def story(story_id)
31
+ _get("stories/#{story_id}")
32
+ end
33
+
34
+ def story_by_slug(slug, params = {})
35
+ _get("stories-by-slug", params.merge({ slug: slug }))
36
+ end
37
+
38
+ def related_stories(story_id, section, fields = [])
39
+ _get("related-stories?", {
40
+ "story-id" => story_id,
41
+ section: section,
42
+ fields: make_fields(fields)
43
+ })
44
+ end
45
+
46
+ def stories(params, options = {})
47
+ url = options[:facets] ? "stories-with-facets" : "stories"
48
+ _get(url, params)
49
+ end
50
+
51
+ def comments_and_likes(story_ids)
52
+ if story_ids.present?
53
+ _get("comments-and-votes/" + story_ids.join('|'))
54
+ end
55
+ end
56
+
57
+ def videos
58
+ _get("stories-by-template", {
59
+ template: "video",
60
+ limit: 12,
61
+ fields: "hero-image-s3-key,hero-image-metadata,hero-image-caption,headline,slug"
62
+ })
63
+ end
64
+
65
+ def search_story_collection(name, options)
66
+ _get("story-collection", {
67
+ name: name,
68
+ type: "search",
69
+ fields: "author-name,hero-image-s3-key,hero-image-metadata,hero-image-caption,headline,slug,sections,metadata"
70
+ }.merge(options))
71
+ end
72
+
73
+ def story_collection(options)
74
+ _get("story-collection", options)
75
+ end
76
+
77
+ def story_collection_by_tag(options)
78
+ _get("story-collection/find-by-tag", options)
79
+ end
80
+
81
+ def post_comment(story_content_id, text, parent_comment_id=nil, session_cookie)
82
+ hash = {
83
+ "story-content-id" => story_content_id,
84
+ "text" => text
85
+ }
86
+ hash.merge!("parent-comment-id" => parent_comment_id.to_i) if parent_comment_id
87
+ _post("comment", hash, session_cookie)
88
+ end
89
+
90
+ def invite_users(emails, from_email, from_name)
91
+ params = { emails: emails }
92
+ params['from-email'] = from_email if from_email.present?
93
+ params['from-name'] = from_name if from_name.present?
94
+
95
+ _post("emails/invite", params)
96
+ end
97
+
98
+ def contact_publisher(params)
99
+ _post("emails/contact", params)
100
+ end
101
+
102
+ def unsubscribe_publisher(params)
103
+ _post("emails/unsubscribe", params)
104
+ end
105
+
106
+ def authors(params)
107
+ _get("authors", params)
108
+ end
109
+
110
+ def author_profile(author_id)
111
+ _get("author/#{author_id}")
112
+ end
113
+
114
+ def search(options)
115
+ _get("search", options)
116
+ end
117
+
118
+ def subscribe(member, profile, payment)
119
+ _post("subscribe", {
120
+ member: member,
121
+ profile: profile,
122
+ payment: payment
123
+ })
124
+ end
125
+
126
+ def unsubscribe(options)
127
+ _post("unsubscribe", { options: options })
128
+ end
129
+
130
+ def save_member_metadata(metadata)
131
+ _post("member/metadata", { metadata: metadata })
132
+ end
133
+
134
+ def check_email(email)
135
+ _get("member/check", { email: email })
136
+ end
137
+
138
+ def signup_member(member)
139
+ _post("member", member)
140
+ end
141
+
142
+ def login_member(auth)
143
+ _post("member/login", auth)
144
+ end
145
+
146
+ def login(provider, data)
147
+ user, headers = _post_returning_headers("login/#{provider}", data)
148
+ user['auth_token'] = headers['X-QT-AUTH']
149
+ user['member'].merge(user.except('member'))
150
+ end
151
+
152
+ def logout
153
+ _get("logout")
154
+ end
155
+
156
+ def forgot_password(member)
157
+ _post("member/forgot-password", member)
158
+ end
159
+
160
+ def reset_password(params)
161
+ _post("member/password", params)
162
+ end
163
+
164
+ def vote_on_story (data)
165
+ _post("stories/#{data[:story_id]}/votes", data)
166
+ end
167
+
168
+ def votes_on_story (options = {})
169
+ _get("stories/#{story_id}/votes", options)
170
+ end
171
+
172
+ private
173
+
174
+ def _post(url_path, body, session_cookie=nil)
175
+ body, headers = _post_returning_headers(url_path, body, session_cookie)
176
+
177
+ body
178
+ end
179
+
180
+ def _post_returning_headers(url_path, body, session_cookie=nil)
181
+ response = @@conn.post(@@api_base + url_path) do |request|
182
+ request.headers['Content-Type'] = 'application/json'
183
+ request.headers['X-QT-AUTH'] = session_cookie if session_cookie
184
+
185
+ request.body = body.to_json
186
+ end
187
+
188
+ if response.body.present?
189
+ body = case body = JSON.parse(response.body)
190
+ when Array
191
+ body.map { |i| keywordize(i) }
192
+ when Object
193
+ keywordize body
194
+ end
195
+
196
+ [body, response.headers]
197
+ end
198
+ end
199
+
200
+ def _get(url_path, *args)
201
+ response = @@conn.get(@@api_base + url_path, *args)
202
+ return nil if response.status >= 400
203
+
204
+ if response.body.present?
205
+ body = JSON.parse(response.body)
206
+
207
+ case body
208
+ when Array
209
+ body.map { |i| keywordize(i) }
210
+ when Object
211
+ keywordize body
212
+ end
213
+ end
214
+ end
215
+
216
+ def keywordize(obj)
217
+ obj.deep_transform_keys { |k| k.gsub('-', '_') }
218
+ end
219
+
220
+ def make_fields(arr)
221
+ arr.join(',') if arr.present?
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,42 @@
1
+ class API
2
+ class Author
3
+ attr_reader :author
4
+ class << self
5
+ def wrap_all(authors)
6
+ authors ||= []
7
+ authors.is_a?(Array) ?
8
+ authors.map { |a| wrap(a) } :
9
+ wrap(authors)
10
+ end
11
+
12
+ def wrap(author)
13
+ new(author) if author
14
+ end
15
+
16
+ def where(params)
17
+ if params['ids'].kind_of? Array
18
+ params['ids'] = params['ids'].join ","
19
+ end
20
+ authors = API.authors(params)
21
+ wrap_all(authors)
22
+ end
23
+
24
+ def find(params)
25
+ if authors = API.authors({ids: params}).presence
26
+ author = authors.first
27
+ wrap(author)
28
+ end
29
+ end
30
+ end
31
+
32
+ def initialize(author)
33
+ @author = author
34
+ end
35
+
36
+ def to_h(config={})
37
+ author
38
+ end
39
+
40
+ private
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ class API
2
+ class Stack
3
+ class << self
4
+ def all
5
+ API.config['layout']['stacks']
6
+ end
7
+ #TODO filter by stacks
8
+ def with_stories(params={}, config={})
9
+ stories_with_stacks = API::Story.find_by_stacks(all, params)
10
+ stacks = all.map do |stack|
11
+ stories = stories_with_stacks[stack['story_group'].gsub('-', '_')]
12
+ stack['stories'] = stories
13
+ stack
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,119 @@
1
+ require_relative './story/reading_time'
2
+
3
+ class API
4
+ class Story
5
+ attr_reader :story
6
+ include ReadingTime
7
+ class << self
8
+ def wrap_all(stories)
9
+ stories ||= []
10
+ stories.is_a?(Array) ?
11
+ stories.map { |s| wrap(s) } :
12
+ wrap(stories)
13
+ end
14
+
15
+ def wrap(story)
16
+ new(story) if story
17
+ end
18
+
19
+ def where(params, opts={})
20
+ stories = API.stories(params, opts)
21
+ wrap_all(stories)
22
+ end
23
+
24
+ def find(params, opts={})
25
+ if stories = API.stories(params, opts).presence
26
+ story = stories.first
27
+ wrap(story)
28
+ end
29
+ end
30
+
31
+ def find_by_stacks(stacks, options={})
32
+ if stacks.present?
33
+ requests = stacks.inject({}) do |hash, stack|
34
+ options.reject! {|k,v| k == 'section' }
35
+ hash[stack['story_group']] = { 'story_group' => stack['story_group'] }.merge(options)
36
+ hash
37
+ end
38
+
39
+ stories = find_in_bulk(requests)
40
+ stories
41
+ end
42
+ end
43
+
44
+ def find_in_bulk(params)
45
+ if params.present?
46
+ params = params.inject({}) do |hash, param|
47
+ hash[param.first] = param.last.merge(_type: 'stories')
48
+ hash
49
+ end
50
+ response = API.bulk_post(requests: params)
51
+ response['results']
52
+ else
53
+ []
54
+ end
55
+ end
56
+
57
+ def find_by_slug(slug, params = {})
58
+ if story = API.story_by_slug(slug, params).presence
59
+ wrap(story['story'])
60
+ end
61
+ end
62
+
63
+ def all_video_stories
64
+ stories = API.videos
65
+ wrap_all(stories['stories'])
66
+ end
67
+
68
+ def all
69
+ stories = API.stories({})
70
+ wrap_all(stories)
71
+ end
72
+ end
73
+
74
+ def initialize(story)
75
+ @story = story
76
+ end
77
+
78
+ def cards
79
+ @cards = story['cards'] || []
80
+ end
81
+
82
+ def to_h(config={})
83
+ hash = story.merge({
84
+ 'url' => URL.story(story),
85
+ 'time_in_minutes' => time_in_minutes,
86
+ 'tags' => add_urls_to_tags
87
+ })
88
+ if config.present?
89
+ hash.merge!({ 'sections' => add_display_names_to_sections(config),
90
+ 'canonical_url' => URL.story_canonical(config['root_url'], story)
91
+ })
92
+ end
93
+ hash
94
+ end
95
+
96
+ private
97
+ def add_display_names_to_sections(config)
98
+ return story unless story['sections'].present?
99
+
100
+ sections = story['sections'].map do |section|
101
+ display_section = config['sections'].find { |s| s['id'] == section['id'] } || {}
102
+
103
+ display_name = display_section['display_name'] || display_section['name'] || section['name']
104
+
105
+ section.merge({ 'display_name' => display_name })
106
+ end
107
+ end
108
+
109
+ def add_urls_to_tags
110
+ if story['tags'].present?
111
+ tags = story['tags'].map do |tag|
112
+ tag.merge('url' => URL.topic(tag['name']))
113
+ end
114
+ else
115
+ story['tags']
116
+ end
117
+ end
118
+ end
119
+ end