arctic-vendor 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +51 -0
  3. data/CHANGELOG.md +12 -0
  4. data/Gemfile.lock +2 -3
  5. data/documentation/CHANGELOG.md +137 -0
  6. data/documentation/CODE_OF_CONDUCT.md +46 -0
  7. data/documentation/Gemfile +11 -0
  8. data/documentation/Gemfile.lock +130 -0
  9. data/documentation/LICENSE +13 -0
  10. data/documentation/Procfile +1 -0
  11. data/documentation/README.md +118 -0
  12. data/documentation/build/fonts/slate.eot +0 -0
  13. data/documentation/build/fonts/slate.svg +14 -0
  14. data/documentation/build/fonts/slate.ttf +0 -0
  15. data/documentation/build/fonts/slate.woff +0 -0
  16. data/documentation/build/fonts/slate.woff2 +0 -0
  17. data/documentation/build/images/logo.png +0 -0
  18. data/documentation/build/images/navbar.png +0 -0
  19. data/documentation/build/index.html +564 -0
  20. data/documentation/build/javascripts/all.js +131 -0
  21. data/documentation/build/javascripts/all_nosearch.js +31 -0
  22. data/documentation/build/stylesheets/print.css +1 -0
  23. data/documentation/build/stylesheets/screen.css +1 -0
  24. data/documentation/config.rb +57 -0
  25. data/documentation/deploy.sh +215 -0
  26. data/documentation/font-selection.json +148 -0
  27. data/documentation/lib/multilang.rb +16 -0
  28. data/documentation/lib/nesting_unique_head.rb +22 -0
  29. data/documentation/lib/toc_data.rb +30 -0
  30. data/documentation/lib/unique_head.rb +24 -0
  31. data/documentation/source/fonts/slate.eot +0 -0
  32. data/documentation/source/fonts/slate.svg +14 -0
  33. data/documentation/source/fonts/slate.ttf +0 -0
  34. data/documentation/source/fonts/slate.woff +0 -0
  35. data/documentation/source/fonts/slate.woff2 +0 -0
  36. data/documentation/source/images/logo.png +0 -0
  37. data/documentation/source/images/navbar.png +0 -0
  38. data/documentation/source/includes/_errors.md +17 -0
  39. data/documentation/source/index.html.md +150 -0
  40. data/documentation/source/javascripts/all.js +2 -0
  41. data/documentation/source/javascripts/all_nosearch.js +16 -0
  42. data/documentation/source/javascripts/app/_lang.js +164 -0
  43. data/documentation/source/javascripts/app/_search.js +98 -0
  44. data/documentation/source/javascripts/app/_toc.js +114 -0
  45. data/documentation/source/javascripts/lib/_energize.js +169 -0
  46. data/documentation/source/javascripts/lib/_imagesloaded.min.js +7 -0
  47. data/documentation/source/javascripts/lib/_jquery.highlight.js +108 -0
  48. data/documentation/source/javascripts/lib/_jquery.js +9831 -0
  49. data/documentation/source/javascripts/lib/_lunr.js +1910 -0
  50. data/documentation/source/layouts/layout.erb +116 -0
  51. data/documentation/source/stylesheets/_icon-font.scss +38 -0
  52. data/documentation/source/stylesheets/_normalize.scss +427 -0
  53. data/documentation/source/stylesheets/_rtl.scss +140 -0
  54. data/documentation/source/stylesheets/_variables.scss +103 -0
  55. data/documentation/source/stylesheets/_variables2.scss +147 -0
  56. data/documentation/source/stylesheets/print.css.scss +148 -0
  57. data/documentation/source/stylesheets/screen.css.scss +712 -0
  58. data/lib/arctic/vendor/api.rb +38 -4
  59. data/lib/arctic/vendor/product.rb +47 -0
  60. data/lib/arctic/vendor/vendor.rb +7 -6
  61. data/lib/arctic/vendor/version.rb +1 -1
  62. data/vendor.gemspec +1 -1
  63. metadata +57 -16
@@ -0,0 +1,16 @@
1
+ module Multilang
2
+ def block_code(code, full_lang_name)
3
+ if full_lang_name
4
+ parts = full_lang_name.split('--')
5
+ rouge_lang_name = (parts) ? parts[0] : "" # just parts[0] here causes null ref exception when no language specified
6
+ super(code, rouge_lang_name).sub("highlight #{rouge_lang_name}") do |match|
7
+ match + " tab-" + full_lang_name
8
+ end
9
+ else
10
+ super(code, full_lang_name)
11
+ end
12
+ end
13
+ end
14
+
15
+ require 'middleman-core/renderers/redcarpet'
16
+ Middleman::Renderers::MiddlemanRedcarpetHTML.send :include, Multilang
@@ -0,0 +1,22 @@
1
+ # Nested unique header generation
2
+ require 'middleman-core/renderers/redcarpet'
3
+
4
+ class NestingUniqueHeadCounter < Middleman::Renderers::MiddlemanRedcarpetHTML
5
+ def initialize
6
+ super
7
+ @@headers_history = {} if !defined?(@@headers_history)
8
+ end
9
+
10
+ def header(text, header_level)
11
+ friendly_text = text.parameterize
12
+ @@headers_history[header_level] = text.parameterize
13
+
14
+ if header_level > 1
15
+ for i in (header_level - 1).downto(1)
16
+ friendly_text.prepend("#{@@headers_history[i]}-") if @@headers_history.key?(i)
17
+ end
18
+ end
19
+
20
+ return "<h#{header_level} id='#{friendly_text}'>#{text}</h#{header_level}>"
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ require 'nokogiri'
2
+
3
+ def toc_data(page_content)
4
+ html_doc = Nokogiri::HTML::DocumentFragment.parse(page_content)
5
+
6
+ # get a flat list of headers
7
+ headers = []
8
+ html_doc.css('h1, h2, h3').each do |header|
9
+ headers.push({
10
+ id: header.attribute('id').to_s,
11
+ content: header.children,
12
+ level: header.name[1].to_i,
13
+ children: []
14
+ })
15
+ end
16
+
17
+ [3,2].each do |header_level|
18
+ header_to_nest = nil
19
+ headers = headers.reject do |header|
20
+ if header[:level] == header_level
21
+ header_to_nest[:children].push header if header_to_nest
22
+ true
23
+ else
24
+ header_to_nest = header if header[:level] < header_level
25
+ false
26
+ end
27
+ end
28
+ end
29
+ headers
30
+ end
@@ -0,0 +1,24 @@
1
+ # Unique header generation
2
+ require 'middleman-core/renderers/redcarpet'
3
+ require 'digest'
4
+ class UniqueHeadCounter < Middleman::Renderers::MiddlemanRedcarpetHTML
5
+ def initialize
6
+ super
7
+ @head_count = {}
8
+ end
9
+ def header(text, header_level)
10
+ friendly_text = text.gsub(/<[^<]+>/,"").parameterize
11
+ if friendly_text.strip.length == 0
12
+ # Looks like parameterize removed the whole thing! It removes many unicode
13
+ # characters like Chinese and Russian. To get a unique URL, let's just
14
+ # URI escape the whole header
15
+ friendly_text = Digest::SHA1.hexdigest(text)[0,10]
16
+ end
17
+ @head_count[friendly_text] ||= 0
18
+ @head_count[friendly_text] += 1
19
+ if @head_count[friendly_text] > 1
20
+ friendly_text += "-#{@head_count[friendly_text]}"
21
+ end
22
+ return "<h#{header_level} id='#{friendly_text}'>#{text}</h#{header_level}>"
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>Generated by IcoMoon</metadata>
5
+ <defs>
6
+ <font id="slate" horiz-adv-x="1024">
7
+ <font-face units-per-em="1024" ascent="960" descent="-64" />
8
+ <missing-glyph horiz-adv-x="1024" />
9
+ <glyph unicode="&#x20;" d="" horiz-adv-x="512" />
10
+ <glyph unicode="&#xe600;" d="M438.857 877.714q119.429 0 220.286-58.857t159.714-159.714 58.857-220.286-58.857-220.286-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857zM512 165.143v108.571q0 8-5.143 13.429t-12.571 5.429h-109.714q-7.429 0-13.143-5.714t-5.714-13.143v-108.571q0-7.429 5.714-13.143t13.143-5.714h109.714q7.429 0 12.571 5.429t5.143 13.429zM510.857 361.714l10.286 354.857q0 6.857-5.714 10.286-5.714 4.571-13.714 4.571h-125.714q-8 0-13.714-4.571-5.714-3.429-5.714-10.286l9.714-354.857q0-5.714 5.714-10t13.714-4.286h105.714q8 0 13.429 4.286t6 10z" />
11
+ <glyph unicode="&#xe602;" d="M585.143 164.571v91.429q0 8-5.143 13.143t-13.143 5.143h-54.857v292.571q0 8-5.143 13.143t-13.143 5.143h-182.857q-8 0-13.143-5.143t-5.143-13.143v-91.429q0-8 5.143-13.143t13.143-5.143h54.857v-182.857h-54.857q-8 0-13.143-5.143t-5.143-13.143v-91.429q0-8 5.143-13.143t13.143-5.143h256q8 0 13.143 5.143t5.143 13.143zM512 676.571v91.429q0 8-5.143 13.143t-13.143 5.143h-109.714q-8 0-13.143-5.143t-5.143-13.143v-91.429q0-8 5.143-13.143t13.143-5.143h109.714q8 0 13.143 5.143t5.143 13.143zM877.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z" />
12
+ <glyph unicode="&#xe606;" d="M733.714 531.428q0 16-10.286 26.286l-52 51.429q-10.857 10.857-25.714 10.857t-25.714-10.857l-233.143-232.571-129.143 129.143q-10.857 10.857-25.714 10.857t-25.714-10.857l-52-51.429q-10.286-10.286-10.286-26.286 0-15.429 10.286-25.714l206.857-206.857q10.857-10.857 25.714-10.857 15.429 0 26.286 10.857l310.286 310.286q10.286 10.286 10.286 25.714zM877.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z" />
13
+ <glyph unicode="&#xe607;" d="M658.286 475.428q0 105.714-75.143 180.857t-180.857 75.143-180.857-75.143-75.143-180.857 75.143-180.857 180.857-75.143 180.857 75.143 75.143 180.857zM950.857 0q0-29.714-21.714-51.429t-51.429-21.714q-30.857 0-51.429 21.714l-196 195.429q-102.286-70.857-228-70.857-81.714 0-156.286 31.714t-128.571 85.714-85.714 128.571-31.714 156.286 31.714 156.286 85.714 128.571 128.571 85.714 156.286 31.714 156.286-31.714 128.571-85.714 85.714-128.571 31.714-156.286q0-125.714-70.857-228l196-196q21.143-21.143 21.143-51.429z" horiz-adv-x="951" />
14
+ </font></defs></svg>
@@ -0,0 +1,17 @@
1
+ # Errors
2
+
3
+ > Example error response
4
+
5
+ ```json
6
+ {
7
+ "error": "Unauthorized",
8
+ "description": "Invalid or missing Bearer token Authentication header"
9
+ }
10
+ ```
11
+
12
+ The Arctic Core API uses the [HTTP status codes](httpstatuses.com) list. Here is some additional explenations for some of the HTTP status codes.
13
+
14
+ Error Code | Meaning
15
+ ---------- | -------
16
+ 401 | Unauthorized -- Your Vendor token is incorrect or missing.
17
+ 403 | Forbidden -- Your Vendor token doesn't have the proper permissions for the action.
@@ -0,0 +1,150 @@
1
+ ---
2
+ title: API Reference
3
+
4
+ language_tabs: # must be one of https://git.io/vQNgJ
5
+ - ruby
6
+
7
+ toc_footers:
8
+ - <a href='https://arctic-project.dk/vendor/register' target="_blank">Register a Vendor</a>
9
+ - <a href='https://arctic-project.io' target="_blank">Core API documentation</a>
10
+ - <a href='https://github.com/YouWeApS/arctic-vendor/issues' target="_blank">Found a bug?</a>
11
+
12
+ includes:
13
+ - errors
14
+
15
+ search: true
16
+ ---
17
+
18
+ # Introduction
19
+
20
+ The Arctic Vendor project is a wrapper around the [Arcic Core API](https://arctic-project.io).
21
+
22
+ An Arctic Vendor is an application that connects a marketplace to the Arctic platform.
23
+
24
+ This project looks to simplify setting up these vendors and thus simplifying the onboarding of new marketplaces for the merchangs on the Arctic platform.
25
+
26
+ An Arctic Vendor has two aspects to it: Collection and distribution.
27
+
28
+ **Collecting products** means tranforming (possibly) unstructured product data
29
+ from the marketplace into structured data.
30
+
31
+ **Distributing products** means sending structured products onto the connected
32
+ marketplace.
33
+
34
+ # Setup
35
+
36
+ > To install in your project
37
+
38
+ ```ruby
39
+ gem 'arctic-vendor', '~> 2.2'
40
+ ```
41
+
42
+ First you must [register your Vendor](https://arctic-project.dk/vendor/register)
43
+ with the Core API to obtain a Vendor Token.
44
+
45
+ In order to connect to the Arctici Core API, you need to have a Vendor Token,
46
+ and you need to store this token in the `ARCTIC_CORE_API_TOKEN` environment
47
+ variable.
48
+
49
+ If you need to run your application against another environment you can override
50
+ the URL by setting the `ARCTIC_CORE_API_URL` environment variable.
51
+
52
+ # Object descriptions
53
+
54
+ ### Shop
55
+
56
+ A single object.
57
+
58
+ Parameter | Description
59
+ --------- | -----------
60
+ id | Shop ID
61
+ name | Human friendly shop name
62
+ synced_at | [ISO 8601 HTTP date](https://en.wikipedia.org/wiki/ISO_8601)
63
+ auth_config | Sensitive marketplace authentication information
64
+ config | Non-sensitive, general configuration set for the shop
65
+ format_config | JSON formatting instructions
66
+
67
+ <aside class="notice">
68
+ All <code>*config</code> fields are filled or enhanced by the merchant when
69
+ configuring the Vendor to distribute products through the Vendor's marketplace.
70
+ When registering the vendor with the Core API, JSON schema definitions for these
71
+ fields must be supplied by the Vendor developer.
72
+ </aside>
73
+
74
+ ### Products
75
+
76
+ An array of product objects.
77
+
78
+ Parameter | Description
79
+ --------- | -----------
80
+ id | Product ID
81
+ characteristics | Normalized product characteristics
82
+ master | Product is master. Will have a Product ID value if this product is a variant of another.
83
+ state | Last known product state. Can be <code>created</code>, <code>updated</code>, or <code>deleted</code>
84
+
85
+ ### Product characteristics
86
+
87
+ Name | Description
88
+ ---- | -----------
89
+ name | Human readable product name
90
+ description | Human readable description of the product
91
+ color | Color
92
+ size | Size
93
+ ean | EAN number
94
+ price | Price without currency
95
+ currency | [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code
96
+ stock | Stock count
97
+ images | Array of image URLs
98
+
99
+ # Collecting products
100
+
101
+ > Collect products from the marketplace
102
+
103
+ ```ruby
104
+ Arctic::Vendor.collect_products do |shop|
105
+ # 1. Connect to the marketplace and retrieve the products for the shop
106
+
107
+ # 2. Format each of the products according to the shop's format_config
108
+ end
109
+ ```
110
+
111
+ First, initialize the `Vendor.collect_products` method to receive each of the
112
+ shops that your vendor should process.
113
+
114
+ Then retrieve the products for that shop, and return them to the block, and the
115
+ Vendor Project will send them to the Core API.
116
+
117
+ The products you return to the block should be a JSON array of products, each
118
+ formatted according to the `shop`s `format_config` block.
119
+
120
+ # Distributing products
121
+
122
+ > Distribute products to the marketplace
123
+
124
+ ```ruby
125
+ Arctic::Vendor.distribute_products(batch_size: 300) do |shop, product_batch|
126
+ # 1. Connect to the marketplace and publish the products to the shop
127
+ product_batch.each do |product|
128
+ # 2. As each of the products are published, update the state
129
+ product.update_state 'created'
130
+ end
131
+ end
132
+ ```
133
+
134
+ First, initialize the `Vendor.distribute_products` method to receive each of the
135
+ shops and batches of related products to distribute to the marketplace.
136
+
137
+ Then connect to the marketplace and distribute the products to the shop.
138
+
139
+ <aside class="notice">
140
+ <code>Arctic::Vendor.distribute_products</code> returns products in batches of 100 by default.
141
+ </aside>
142
+
143
+ # Going live
144
+
145
+ When you have fully developed your Vendor, you will have to go through a
146
+ verification and testing process with the Arctic Team.
147
+
148
+ Once you pass this verification process your Vendor will be released into
149
+ production and merchants can distribute their products through your Vendor to
150
+ the marketplace.
@@ -0,0 +1,2 @@
1
+ //= require ./all_nosearch
2
+ //= require ./app/_search
@@ -0,0 +1,16 @@
1
+ //= require ./lib/_energize
2
+ //= require ./app/_toc
3
+ //= require ./app/_lang
4
+
5
+ $(function() {
6
+ loadToc($('#toc'), '.toc-link', '.toc-list-h2', 10);
7
+ setupLanguages($('body').data('languages'));
8
+ $('.content').imagesLoaded( function() {
9
+ window.recacheHeights();
10
+ window.refreshToc();
11
+ });
12
+ });
13
+
14
+ window.onpopstate = function() {
15
+ activateLanguage(getLanguageFromQueryString());
16
+ };
@@ -0,0 +1,164 @@
1
+ //= require ../lib/_jquery
2
+
3
+ /*
4
+ Copyright 2008-2013 Concur Technologies, Inc.
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
7
+ not use this file except in compliance with the License. You may obtain
8
+ a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ License for the specific language governing permissions and limitations
16
+ under the License.
17
+ */
18
+ ;(function () {
19
+ 'use strict';
20
+
21
+ var languages = [];
22
+
23
+ window.setupLanguages = setupLanguages;
24
+ window.activateLanguage = activateLanguage;
25
+ window.getLanguageFromQueryString = getLanguageFromQueryString;
26
+
27
+ function activateLanguage(language) {
28
+ if (!language) return;
29
+ if (language === "") return;
30
+
31
+ $(".lang-selector a").removeClass('active');
32
+ $(".lang-selector a[data-language-name='" + language + "']").addClass('active');
33
+ for (var i=0; i < languages.length; i++) {
34
+ $(".highlight.tab-" + languages[i]).hide();
35
+ $(".lang-specific." + languages[i]).hide();
36
+ }
37
+ $(".highlight.tab-" + language).show();
38
+ $(".lang-specific." + language).show();
39
+
40
+ window.recacheHeights();
41
+
42
+ // scroll to the new location of the position
43
+ if ($(window.location.hash).get(0)) {
44
+ $(window.location.hash).get(0).scrollIntoView(true);
45
+ }
46
+ }
47
+
48
+ // parseURL and stringifyURL are from https://github.com/sindresorhus/query-string
49
+ // MIT licensed
50
+ // https://github.com/sindresorhus/query-string/blob/7bee64c16f2da1a326579e96977b9227bf6da9e6/license
51
+ function parseURL(str) {
52
+ if (typeof str !== 'string') {
53
+ return {};
54
+ }
55
+
56
+ str = str.trim().replace(/^(\?|#|&)/, '');
57
+
58
+ if (!str) {
59
+ return {};
60
+ }
61
+
62
+ return str.split('&').reduce(function (ret, param) {
63
+ var parts = param.replace(/\+/g, ' ').split('=');
64
+ var key = parts[0];
65
+ var val = parts[1];
66
+
67
+ key = decodeURIComponent(key);
68
+ // missing `=` should be `null`:
69
+ // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
70
+ val = val === undefined ? null : decodeURIComponent(val);
71
+
72
+ if (!ret.hasOwnProperty(key)) {
73
+ ret[key] = val;
74
+ } else if (Array.isArray(ret[key])) {
75
+ ret[key].push(val);
76
+ } else {
77
+ ret[key] = [ret[key], val];
78
+ }
79
+
80
+ return ret;
81
+ }, {});
82
+ };
83
+
84
+ function stringifyURL(obj) {
85
+ return obj ? Object.keys(obj).sort().map(function (key) {
86
+ var val = obj[key];
87
+
88
+ if (Array.isArray(val)) {
89
+ return val.sort().map(function (val2) {
90
+ return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
91
+ }).join('&');
92
+ }
93
+
94
+ return encodeURIComponent(key) + '=' + encodeURIComponent(val);
95
+ }).join('&') : '';
96
+ };
97
+
98
+ // gets the language set in the query string
99
+ function getLanguageFromQueryString() {
100
+ if (location.search.length >= 1) {
101
+ var language = parseURL(location.search).language;
102
+ if (language) {
103
+ return language;
104
+ } else if (jQuery.inArray(location.search.substr(1), languages) != -1) {
105
+ return location.search.substr(1);
106
+ }
107
+ }
108
+
109
+ return false;
110
+ }
111
+
112
+ // returns a new query string with the new language in it
113
+ function generateNewQueryString(language) {
114
+ var url = parseURL(location.search);
115
+ if (url.language) {
116
+ url.language = language;
117
+ return stringifyURL(url);
118
+ }
119
+ return language;
120
+ }
121
+
122
+ // if a button is clicked, add the state to the history
123
+ function pushURL(language) {
124
+ if (!history) { return; }
125
+ var hash = window.location.hash;
126
+ if (hash) {
127
+ hash = hash.replace(/^#+/, '');
128
+ }
129
+ history.pushState({}, '', '?' + generateNewQueryString(language) + '#' + hash);
130
+
131
+ // save language as next default
132
+ localStorage.setItem("language", language);
133
+ }
134
+
135
+ function setupLanguages(l) {
136
+ var defaultLanguage = localStorage.getItem("language");
137
+
138
+ languages = l;
139
+
140
+ var presetLanguage = getLanguageFromQueryString();
141
+ if (presetLanguage) {
142
+ // the language is in the URL, so use that language!
143
+ activateLanguage(presetLanguage);
144
+
145
+ localStorage.setItem("language", presetLanguage);
146
+ } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) {
147
+ // the language was the last selected one saved in localstorage, so use that language!
148
+ activateLanguage(defaultLanguage);
149
+ } else {
150
+ // no language selected, so use the default
151
+ activateLanguage(languages[0]);
152
+ }
153
+ }
154
+
155
+ // if we click on a language tab, activate that language
156
+ $(function() {
157
+ $(".lang-selector a").on("click", function() {
158
+ var language = $(this).data("language-name");
159
+ pushURL(language);
160
+ activateLanguage(language);
161
+ return false;
162
+ });
163
+ });
164
+ })();