disco_app 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +37 -0
  3. data/app/assets/images/disco_app/icon.svg +1 -0
  4. data/app/assets/javascripts/disco_app/disco_app.js +7 -0
  5. data/app/assets/stylesheets/disco_app/bootstrap/_custom.scss +54 -0
  6. data/app/assets/stylesheets/disco_app/bootstrap/_variables.scss +872 -0
  7. data/app/assets/stylesheets/disco_app/disco/_buttons.scss +31 -0
  8. data/app/assets/stylesheets/disco_app/disco/_cards.scss +43 -0
  9. data/app/assets/stylesheets/disco_app/disco/_forms.scss +23 -0
  10. data/app/assets/stylesheets/disco_app/disco/_sections.scss +61 -0
  11. data/app/assets/stylesheets/disco_app/disco/_type.scss +21 -0
  12. data/app/assets/stylesheets/disco_app/disco/mixins/_flexbox.scss +394 -0
  13. data/app/assets/stylesheets/disco_app/disco_app.scss +13 -0
  14. data/app/controllers/disco_app/app_proxy_controller.rb +41 -0
  15. data/app/controllers/disco_app/authenticated_controller.rb +44 -0
  16. data/app/controllers/disco_app/carrier_request_controller.rb +28 -0
  17. data/app/controllers/disco_app/charges_controller.rb +30 -0
  18. data/app/controllers/disco_app/install_controller.rb +26 -0
  19. data/app/controllers/disco_app/webhooks_controller.rb +42 -0
  20. data/app/helpers/disco_app/application_helper.rb +4 -0
  21. data/app/jobs/disco_app/app_installed_job.rb +41 -0
  22. data/app/jobs/disco_app/app_uninstalled_job.rb +3 -0
  23. data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +19 -0
  24. data/app/jobs/disco_app/shop_job.rb +29 -0
  25. data/app/jobs/disco_app/shop_update_job.rb +16 -0
  26. data/app/models/disco_app/concerns/plan.rb +14 -0
  27. data/app/models/disco_app/concerns/shop.rb +62 -0
  28. data/app/models/disco_app/concerns/subscription.rb +14 -0
  29. data/app/models/disco_app/plan.rb +3 -0
  30. data/app/models/disco_app/session_storage.rb +18 -0
  31. data/app/models/disco_app/shop.rb +3 -0
  32. data/app/models/disco_app/subscription.rb +3 -0
  33. data/app/services/disco_app/charges_service.rb +73 -0
  34. data/app/services/disco_app/subscription_service.rb +25 -0
  35. data/app/services/disco_app/webhook_service.rb +30 -0
  36. data/app/views/disco_app/charges/activate.html.erb +1 -0
  37. data/app/views/disco_app/charges/create.html.erb +1 -0
  38. data/app/views/disco_app/charges/new.html.erb +45 -0
  39. data/app/views/disco_app/install/installing.html.erb +7 -0
  40. data/app/views/disco_app/install/uninstalling.html.erb +1 -0
  41. data/app/views/disco_app/proxy_errors/404.html.erb +1 -0
  42. data/app/views/disco_app/shared/_card.html.erb +16 -0
  43. data/app/views/disco_app/shared/_section.html.erb +17 -0
  44. data/app/views/layouts/application.html.erb +18 -0
  45. data/app/views/layouts/embedded_app.html.erb +41 -0
  46. data/app/views/sessions/new.html.erb +26 -0
  47. data/config/routes.rb +19 -0
  48. data/db/migrate/20150525000000_create_shops_if_not_existent.rb +15 -0
  49. data/db/migrate/20150525162112_add_status_to_shops.rb +5 -0
  50. data/db/migrate/20150525171422_add_meta_to_shops.rb +11 -0
  51. data/db/migrate/20150629210346_add_charge_status_to_shop.rb +5 -0
  52. data/db/migrate/20150814214025_add_more_meta_to_shops.rb +15 -0
  53. data/db/migrate/20151017231302_create_disco_app_plans.rb +13 -0
  54. data/db/migrate/20151017232027_create_disco_app_subscriptions.rb +15 -0
  55. data/db/migrate/20151017234409_move_shop_to_disco_app_engine.rb +5 -0
  56. data/lib/disco_app/engine.rb +11 -0
  57. data/lib/disco_app/version.rb +3 -0
  58. data/lib/disco_app.rb +4 -0
  59. data/lib/generators/disco_app/USAGE +5 -0
  60. data/lib/generators/disco_app/disco_app_generator.rb +159 -0
  61. data/lib/generators/disco_app/mailify/mailify_generator.rb +55 -0
  62. data/lib/generators/disco_app/reactify/reactify_generator.rb +31 -0
  63. data/lib/generators/disco_app/templates/assets/javascripts/application.js +17 -0
  64. data/lib/generators/disco_app/templates/assets/stylesheets/application.scss +5 -0
  65. data/lib/generators/disco_app/templates/config/puma.rb +15 -0
  66. data/lib/generators/disco_app/templates/controllers/home_controller.rb +7 -0
  67. data/lib/generators/disco_app/templates/initializers/disco_app.rb +1 -0
  68. data/lib/generators/disco_app/templates/initializers/shopify_app.rb +7 -0
  69. data/lib/generators/disco_app/templates/initializers/shopify_session_repository.rb +7 -0
  70. data/lib/generators/disco_app/templates/root/Procfile +2 -0
  71. data/lib/generators/disco_app/templates/views/home/index.html.erb +2 -0
  72. data/test/controllers/disco_app/install_controller_test.rb +50 -0
  73. data/test/controllers/disco_app/webhooks_controller_test.rb +58 -0
  74. data/test/controllers/home_controller_test.rb +61 -0
  75. data/test/disco_app_test.rb +7 -0
  76. data/test/dummy/Rakefile +6 -0
  77. data/test/dummy/app/assets/javascripts/application.js +17 -0
  78. data/test/dummy/app/assets/stylesheets/application.scss +5 -0
  79. data/test/dummy/app/controllers/application_controller.rb +6 -0
  80. data/test/dummy/app/controllers/home_controller.rb +7 -0
  81. data/test/dummy/app/helpers/application_helper.rb +2 -0
  82. data/test/dummy/app/jobs/disco_app/app_uninstalled_job.rb +11 -0
  83. data/test/dummy/app/models/disco_app/shop.rb +15 -0
  84. data/test/dummy/app/views/home/index.html.erb +2 -0
  85. data/test/dummy/bin/bundle +3 -0
  86. data/test/dummy/bin/rails +4 -0
  87. data/test/dummy/bin/rake +4 -0
  88. data/test/dummy/bin/setup +29 -0
  89. data/test/dummy/config/application.rb +37 -0
  90. data/test/dummy/config/boot.rb +5 -0
  91. data/test/dummy/config/database.yml +25 -0
  92. data/test/dummy/config/environment.rb +5 -0
  93. data/test/dummy/config/environments/development.rb +41 -0
  94. data/test/dummy/config/environments/production.rb +85 -0
  95. data/test/dummy/config/environments/test.rb +42 -0
  96. data/test/dummy/config/initializers/assets.rb +11 -0
  97. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  98. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  99. data/test/dummy/config/initializers/disco_app.rb +1 -0
  100. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  101. data/test/dummy/config/initializers/inflections.rb +16 -0
  102. data/test/dummy/config/initializers/mime_types.rb +4 -0
  103. data/test/dummy/config/initializers/omniauth.rb +9 -0
  104. data/test/dummy/config/initializers/session_store.rb +3 -0
  105. data/test/dummy/config/initializers/shopify_app.rb +7 -0
  106. data/test/dummy/config/initializers/shopify_session_repository.rb +7 -0
  107. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  108. data/test/dummy/config/locales/en.yml +23 -0
  109. data/test/dummy/config/routes.rb +8 -0
  110. data/test/dummy/config/secrets.yml +22 -0
  111. data/test/dummy/config.ru +4 -0
  112. data/test/dummy/db/schema.rb +70 -0
  113. data/test/dummy/public/404.html +67 -0
  114. data/test/dummy/public/422.html +67 -0
  115. data/test/dummy/public/500.html +66 -0
  116. data/test/dummy/public/favicon.ico +0 -0
  117. data/test/fixtures/api/widget_store/shop.json +46 -0
  118. data/test/fixtures/disco_app/plans.yml +32 -0
  119. data/test/fixtures/disco_app/shops.yml +10 -0
  120. data/test/fixtures/disco_app/subscriptions.yml +26 -0
  121. data/test/fixtures/webhooks/app_uninstalled.json +46 -0
  122. data/test/integration/navigation_test.rb +10 -0
  123. data/test/jobs/disco_app/app_installed_job_test.rb +29 -0
  124. data/test/jobs/disco_app/app_uninstalled_job_test.rb +32 -0
  125. data/test/models/disco_app/plan_test.rb +5 -0
  126. data/test/models/disco_app/shop_test.rb +26 -0
  127. data/test/models/disco_app/subscription_test.rb +6 -0
  128. data/test/services/disco_app/subscription_service_test.rb +28 -0
  129. data/test/support/test_file_fixtures.rb +29 -0
  130. data/test/test_helper.rb +51 -0
  131. metadata +456 -0
@@ -0,0 +1,31 @@
1
+ //
2
+ // Replicate the styles for Shopify Admin buttons.
3
+ // --------------------------------------------------
4
+
5
+ .btn {
6
+ line-height: 1;
7
+ padding: 8.5px 15px;
8
+ }
9
+
10
+ .btn-default {
11
+ &:hover, &:focus, &:active, &.active {
12
+ border-color: #d3dbe2;
13
+ background-color: #f5f6f7;
14
+ }
15
+ }
16
+
17
+ .btn-primary {
18
+ &:hover, &:focus, &:active, &.active {
19
+ border-color: #4293c2;
20
+ background-color: #4293c2;
21
+ }
22
+ }
23
+
24
+ .btn-disabled {
25
+ &, &:hover, &:focus, &:active {
26
+ cursor: default;
27
+ background: #fafbfc;
28
+ color: #c3cfd8;
29
+ border: 1px solid #d3dbe2;
30
+ }
31
+ }
@@ -0,0 +1,43 @@
1
+ //
2
+ // Replicate the styles for Shopify Admin cards.
3
+ // --------------------------------------------------
4
+
5
+ .next-card {
6
+ background-color: #ffffff;
7
+ border-radius: 3px;
8
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
9
+ }
10
+
11
+ .next-card ~ .next-card {
12
+ margin-top: 20px;
13
+ }
14
+
15
+ .next-card__header {
16
+ padding: 20px 20px 0;
17
+
18
+ h1, h2, h3 {
19
+ margin-bottom: 0;
20
+ font-size: 18px;
21
+ line-height: 1.2em;
22
+ }
23
+ }
24
+
25
+ .next-card__footer {
26
+ padding: 0 20px 20px;
27
+ }
28
+
29
+ .next-card__section {
30
+ padding: 20px;
31
+ }
32
+
33
+ .next-card--aside,
34
+ .next-card--disabled {
35
+ background-color: #f5f6f7;
36
+ }
37
+
38
+ .next-card--disabled {
39
+ .next-card__header,
40
+ .next-card__section {
41
+ color: #777777;
42
+ }
43
+ }
@@ -0,0 +1,23 @@
1
+ //
2
+ // Replicate the styles for Shopify Admin forms.
3
+ // --------------------------------------------------
4
+
5
+ .form-control {
6
+ -webkit-box-shadow: none;
7
+ box-shadow: none;
8
+
9
+ font-size: 15px;
10
+ line-height: 20px;
11
+
12
+ &:focus {
13
+ -webkit-box-shadow: none;
14
+ box-shadow: none;
15
+ }
16
+ }
17
+
18
+ .help-block {
19
+ font-style: italic;
20
+ font-size: 13px;
21
+ color: #95a7b7;
22
+ margin-top: 5px;
23
+ }
@@ -0,0 +1,61 @@
1
+ //
2
+ // Replicate the styles for Shopify Admin sections
3
+ // and flexbox layout.
4
+ // --------------------------------------------------
5
+
6
+
7
+ //== Layout
8
+ //
9
+ //## Simple Flexbox layout utilities.
10
+
11
+ .layout-content {
12
+ display: flex;
13
+ }
14
+
15
+ .layout-content__sidebar {
16
+ padding: 20px;
17
+ @include flex(1, 1, 25%);
18
+ max-width: 25%
19
+ }
20
+
21
+ .layout-content__main {
22
+ padding: 20px;
23
+ @include flex(1, 1, 0%);
24
+ }
25
+
26
+ .layout-content__first {
27
+ padding-right: 0;
28
+ }
29
+
30
+
31
+ //== Section
32
+ //
33
+ //## Simple Flexbox layout utilities.
34
+
35
+ //** Main section wrapper.
36
+ .section {
37
+ margin: 0;
38
+ padding: 0;
39
+ border-bottom: 1px solid #e6e6e6;
40
+ }
41
+
42
+ //** Section "summary" to the left of the section.
43
+ .section-summary {
44
+ padding: 20px 20px 20px 30px;
45
+
46
+ h1, h2 {
47
+ line-height: 1.325;
48
+ margin-top: -4px;
49
+ font-size: 18px;
50
+ margin-bottom: 10px;
51
+ }
52
+
53
+ p {
54
+ color: #798c9c;
55
+ margin-bottom: 15px;
56
+
57
+ &:last-child {
58
+ margin-bottom: 0;
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,21 @@
1
+ //
2
+ // Replicate the styles for Shopify Admin typography.
3
+ // --------------------------------------------------
4
+
5
+
6
+ //== Headings
7
+ //
8
+ //## Heading styles.
9
+
10
+ h1, .h1,
11
+ h2, .h2,
12
+ h3, .h3,
13
+ h4, .h4,
14
+ h5, .h5,
15
+ h6, .h6 {
16
+ margin: 0 0 20px 0;
17
+ }
18
+
19
+ p {
20
+ margin: 0;
21
+ }
@@ -0,0 +1,394 @@
1
+ // Flexbox Mixins
2
+ // http://philipwalton.github.io/solved-by-flexbox/
3
+ // https://github.com/philipwalton/solved-by-flexbox
4
+ //
5
+ // Copyright (c) 2013 Brian Franco
6
+ //
7
+ // Permission is hereby granted, free of charge, to any person obtaining a
8
+ // copy of this software and associated documentation files (the
9
+ // "Software"), to deal in the Software without restriction, including
10
+ // without limitation the rights to use, copy, modify, merge, publish,
11
+ // distribute, sublicense, and/or sell copies of the Software, and to
12
+ // permit persons to whom the Software is furnished to do so, subject to
13
+ // the following conditions:
14
+ // The above copyright notice and this permission notice shall be included
15
+ // in all copies or substantial portions of the Software.
16
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ //
24
+ // This is a set of mixins for those who want to mess around with flexbox
25
+ // using the native support of current browsers. For full support table
26
+ // check: http://caniuse.com/flexbox
27
+ //
28
+ // Basically this will use:
29
+ //
30
+ // * Fallback, old syntax (IE10, mobile webkit browsers - no wrapping)
31
+ // * Final standards syntax (FF, Safari, Chrome, IE11, Opera)
32
+ //
33
+ // This was inspired by:
34
+ //
35
+ // * http://dev.opera.com/articles/view/advanced-cross-browser-flexbox/
36
+ //
37
+ // With help from:
38
+ //
39
+ // * http://w3.org/tr/css3-flexbox/
40
+ // * http://the-echoplex.net/flexyboxes/
41
+ // * http://msdn.microsoft.com/en-us/library/ie/hh772069(v=vs.85).aspx
42
+ // * http://css-tricks.com/using-flexbox/
43
+ // * http://dev.opera.com/articles/view/advanced-cross-browser-flexbox/
44
+ // * https://developer.mozilla.org/en-us/docs/web/guide/css/flexible_boxes
45
+
46
+ //----------------------------------------------------------------------
47
+
48
+ // Flexbox Containers
49
+ //
50
+ // The 'flex' value causes an element to generate a block-level flex
51
+ // container box.
52
+ //
53
+ // The 'inline-flex' value causes an element to generate a inline-level
54
+ // flex container box.
55
+ //
56
+ // display: flex | inline-flex
57
+ //
58
+ // http://w3.org/tr/css3-flexbox/#flex-containers
59
+ //
60
+ // (Placeholder selectors for each type, for those who rather @extend)
61
+
62
+ @mixin flexbox {
63
+ display: -webkit-box;
64
+ display: -webkit-flex;
65
+ display: -moz-flex;
66
+ display: -ms-flexbox;
67
+ display: flex;
68
+ }
69
+
70
+ %flexbox { @include flexbox; }
71
+
72
+ //----------------------------------
73
+
74
+ @mixin inline-flex {
75
+ display: -webkit-inline-box;
76
+ display: -webkit-inline-flex;
77
+ display: -moz-inline-flex;
78
+ display: -ms-inline-flexbox;
79
+ display: inline-flex;
80
+ }
81
+
82
+ %inline-flex { @include inline-flex; }
83
+
84
+ //----------------------------------------------------------------------
85
+
86
+ // Flexbox Direction
87
+ //
88
+ // The 'flex-direction' property specifies how flex items are placed in
89
+ // the flex container, by setting the direction of the flex container's
90
+ // main axis. This determines the direction that flex items are laid out in.
91
+ //
92
+ // Values: row | row-reverse | column | column-reverse
93
+ // Default: row
94
+ //
95
+ // http://w3.org/tr/css3-flexbox/#flex-direction-property
96
+
97
+ @mixin flex-direction($value: row) {
98
+ @if $value == row-reverse {
99
+ -webkit-box-direction: reverse;
100
+ -webkit-box-orient: horizontal;
101
+ } @else if $value == column {
102
+ -webkit-box-direction: normal;
103
+ -webkit-box-orient: vertical;
104
+ } @else if $value == column-reverse {
105
+ -webkit-box-direction: reverse;
106
+ -webkit-box-orient: vertical;
107
+ } @else {
108
+ -webkit-box-direction: normal;
109
+ -webkit-box-orient: horizontal;
110
+ }
111
+ -webkit-flex-direction: $value;
112
+ -moz-flex-direction: $value;
113
+ -ms-flex-direction: $value;
114
+ flex-direction: $value;
115
+ }
116
+ // Shorter version:
117
+ @mixin flex-dir($args...) { @include flex-direction($args...); }
118
+
119
+ //----------------------------------------------------------------------
120
+
121
+ // Flexbox Wrap
122
+ //
123
+ // The 'flex-wrap' property controls whether the flex container is single-line
124
+ // or multi-line, and the direction of the cross-axis, which determines
125
+ // the direction new lines are stacked in.
126
+ //
127
+ // Values: nowrap | wrap | wrap-reverse
128
+ // Default: nowrap
129
+ //
130
+ // http://w3.org/tr/css3-flexbox/#flex-wrap-property
131
+
132
+ @mixin flex-wrap($value: nowrap) {
133
+ // No Webkit Box fallback.
134
+ -webkit-flex-wrap: $value;
135
+ -moz-flex-wrap: $value;
136
+ @if $value == nowrap {
137
+ -ms-flex-wrap: none;
138
+ } @else {
139
+ -ms-flex-wrap: $value;
140
+ }
141
+ flex-wrap: $value;
142
+ }
143
+
144
+ //----------------------------------------------------------------------
145
+
146
+ // Flexbox Flow (shorthand)
147
+ //
148
+ // The 'flex-flow' property is a shorthand for setting the 'flex-direction'
149
+ // and 'flex-wrap' properties, which together define the flex container's
150
+ // main and cross axes.
151
+ //
152
+ // Values: <flex-direction> | <flex-wrap>
153
+ // Default: row nowrap
154
+ //
155
+ // http://w3.org/tr/css3-flexbox/#flex-flow-property
156
+
157
+ @mixin flex-flow($values: (row nowrap)) {
158
+ // No Webkit Box fallback.
159
+ -webkit-flex-flow: $values;
160
+ -moz-flex-flow: $values;
161
+ -ms-flex-flow: $values;
162
+ flex-flow: $values;
163
+ }
164
+
165
+ //----------------------------------------------------------------------
166
+
167
+ // Flexbox Order
168
+ //
169
+ // The 'order' property controls the order in which flex items appear within
170
+ // their flex container, by assigning them to ordinal groups.
171
+ //
172
+ // Default: 0
173
+ //
174
+ // http://w3.org/tr/css3-flexbox/#order-property
175
+
176
+ @mixin order($int: 0) {
177
+ -webkit-box-ordinal-group: $int + 1;
178
+ -webkit-order: $int;
179
+ -moz-order: $int;
180
+ -ms-flex-order: $int;
181
+ order: $int;
182
+ }
183
+
184
+ //----------------------------------------------------------------------
185
+
186
+ // Flexbox Grow
187
+ //
188
+ // The 'flex-grow' property sets the flex grow factor. Negative numbers
189
+ // are invalid.
190
+ //
191
+ // Default: 0
192
+ //
193
+ // http://w3.org/tr/css3-flexbox/#flex-grow-property
194
+
195
+ @mixin flex-grow($int: 0) {
196
+ -webkit-box-flex: $int;
197
+ -webkit-flex-grow: $int;
198
+ -moz-flex-grow: $int;
199
+ -ms-flex-positive: $int;
200
+ flex-grow: $int;
201
+ }
202
+
203
+ //----------------------------------------------------------------------
204
+
205
+ // Flexbox Shrink
206
+ //
207
+ // The 'flex-shrink' property sets the flex shrink factor. Negative numbers
208
+ // are invalid.
209
+ //
210
+ // Default: 1
211
+ //
212
+ // http://w3.org/tr/css3-flexbox/#flex-shrink-property
213
+
214
+ @mixin flex-shrink($int: 1) {
215
+ -webkit-flex-shrink: $int;
216
+ -moz-flex-shrink: $int;
217
+ -ms-flex-negative: $int;
218
+ flex-shrink: $int;
219
+ }
220
+
221
+ //----------------------------------------------------------------------
222
+
223
+ // Flexbox Basis
224
+ //
225
+ // The 'flex-basis' property sets the flex basis. Negative lengths are invalid.
226
+ //
227
+ // Values: Like "width"
228
+ // Default: auto
229
+ //
230
+ // http://www.w3.org/TR/css3-flexbox/#flex-basis-property
231
+
232
+ @mixin flex-basis($value: auto) {
233
+ -webkit-flex-basis: $value;
234
+ -moz-flex-basis: $value;
235
+ -ms-flex-preferred-size: $value;
236
+ flex-basis: $value;
237
+ }
238
+
239
+ //----------------------------------------------------------------------
240
+
241
+ // Flexbox "Flex" (shorthand)
242
+ //
243
+ // The 'flex' property specifies the components of a flexible length: the
244
+ // flex grow factor and flex shrink factor, and the flex basis. When an
245
+ // element is a flex item, 'flex' is consulted instead of the main size
246
+ // property to determine the main size of the element. If an element is
247
+ // not a flex item, 'flex' has no effect.
248
+ //
249
+ // Values: none | <flex-grow> <flex-shrink> || <flex-basis>
250
+ // Default: See individual properties (1 1 0).
251
+ //
252
+ // http://w3.org/tr/css3-flexbox/#flex-property
253
+
254
+ @mixin flex($fg: 1, $fs: null, $fb: null) {
255
+
256
+ // Set a variable to be used by box-flex properties
257
+ $fg-boxflex: $fg;
258
+
259
+ // Box-Flex only supports a flex-grow value so let's grab the
260
+ // first item in the list and just return that.
261
+ @if type-of($fg) == 'list' {
262
+ $fg-boxflex: nth($fg, 1);
263
+ }
264
+
265
+ -webkit-box-flex: $fg-boxflex;
266
+ -webkit-flex: $fg $fs $fb;
267
+ -moz-box-flex: $fg-boxflex;
268
+ -moz-flex: $fg $fs $fb;
269
+ -ms-flex: $fg $fs $fb;
270
+ flex: $fg $fs $fb;
271
+ }
272
+
273
+ //----------------------------------------------------------------------
274
+
275
+ // Flexbox Justify Content
276
+ //
277
+ // The 'justify-content' property aligns flex items along the main axis
278
+ // of the current line of the flex container. This is done after any flexible
279
+ // lengths and any auto margins have been resolved. Typically it helps distribute
280
+ // extra free space leftover when either all the flex items on a line are
281
+ // inflexible, or are flexible but have reached their maximum size. It also
282
+ // exerts some control over the alignment of items when they overflow the line.
283
+ //
284
+ // Note: 'space-*' values not supported in older syntaxes.
285
+ //
286
+ // Values: flex-start | flex-end | center | space-between | space-around
287
+ // Default: flex-start
288
+ //
289
+ // http://w3.org/tr/css3-flexbox/#justify-content-property
290
+
291
+ @mixin justify-content($value: flex-start) {
292
+ @if $value == flex-start {
293
+ -webkit-box-pack: start;
294
+ -ms-flex-pack: start;
295
+ } @else if $value == flex-end {
296
+ -webkit-box-pack: end;
297
+ -ms-flex-pack: end;
298
+ } @else if $value == space-between {
299
+ -webkit-box-pack: justify;
300
+ -ms-flex-pack: justify;
301
+ } @else if $value == space-around {
302
+ -ms-flex-pack: distribute;
303
+ } @else {
304
+ -webkit-box-pack: $value;
305
+ -ms-flex-pack: $value;
306
+ }
307
+ -webkit-justify-content: $value;
308
+ -moz-justify-content: $value;
309
+ justify-content: $value;
310
+ }
311
+ // Shorter version:
312
+ @mixin flex-just($args...) { @include justify-content($args...); }
313
+
314
+ //----------------------------------------------------------------------
315
+
316
+ // Flexbox Align Items
317
+ //
318
+ // Flex items can be aligned in the cross axis of the current line of the
319
+ // flex container, similar to 'justify-content' but in the perpendicular
320
+ // direction. 'align-items' sets the default alignment for all of the flex
321
+ // container's items, including anonymous flex items. 'align-self' allows
322
+ // this default alignment to be overridden for individual flex items. (For
323
+ // anonymous flex items, 'align-self' always matches the value of 'align-items'
324
+ // on their associated flex container.)
325
+ //
326
+ // Values: flex-start | flex-end | center | baseline | stretch
327
+ // Default: stretch
328
+ //
329
+ // http://w3.org/tr/css3-flexbox/#align-items-property
330
+
331
+ @mixin align-items($value: stretch) {
332
+ @if $value == flex-start {
333
+ -webkit-box-align: start;
334
+ -ms-flex-align: start;
335
+ } @else if $value == flex-end {
336
+ -webkit-box-align: end;
337
+ -ms-flex-align: end;
338
+ } @else {
339
+ -webkit-box-align: $value;
340
+ -ms-flex-align: $value;
341
+ }
342
+ -webkit-align-items: $value;
343
+ -moz-align-items: $value;
344
+ align-items: $value;
345
+ }
346
+
347
+ //----------------------------------
348
+
349
+ // Flexbox Align Self
350
+ //
351
+ // Values: auto | flex-start | flex-end | center | baseline | stretch
352
+ // Default: auto
353
+
354
+ @mixin align-self($value: auto) {
355
+ // No Webkit Box Fallback.
356
+ -webkit-align-self: $value;
357
+ -moz-align-self: $value;
358
+ @if $value == flex-start {
359
+ -ms-flex-item-align: start;
360
+ } @else if $value == flex-end {
361
+ -ms-flex-item-align: end;
362
+ } @else {
363
+ -ms-flex-item-align: $value;
364
+ }
365
+ align-self: $value;
366
+ }
367
+
368
+ //----------------------------------------------------------------------
369
+
370
+ // Flexbox Align Content
371
+ //
372
+ // The 'align-content' property aligns a flex container's lines within the
373
+ // flex container when there is extra space in the cross-axis, similar to
374
+ // how 'justify-content' aligns individual items within the main-axis. Note,
375
+ // this property has no effect when the flexbox has only a single line.
376
+ //
377
+ // Values: flex-start | flex-end | center | space-between | space-around | stretch
378
+ // Default: stretch
379
+ //
380
+ // http://w3.org/tr/css3-flexbox/#align-content-property
381
+
382
+ @mixin align-content($value: stretch) {
383
+ // No Webkit Box Fallback.
384
+ -webkit-align-content: $value;
385
+ -moz-align-content: $value;
386
+ @if $value == flex-start {
387
+ -ms-flex-line-pack: start;
388
+ } @else if $value == flex-end {
389
+ -ms-flex-line-pack: end;
390
+ } @else {
391
+ -ms-flex-line-pack: $value;
392
+ }
393
+ align-content: $value;
394
+ }
@@ -0,0 +1,13 @@
1
+ //
2
+ // Styles for Disco applications.
3
+ // --------------------------------------------------
4
+
5
+ @import 'bootstrap-sprockets';
6
+ @import 'bootstrap/variables';
7
+ @import 'bootstrap/custom';
8
+ @import 'disco/mixins/flexbox';
9
+ @import 'disco/type';
10
+ @import 'disco/sections';
11
+ @import 'disco/cards';
12
+ @import 'disco/buttons';
13
+ @import 'disco/forms';
@@ -0,0 +1,41 @@
1
+ module DiscoApp
2
+ module AppProxyController
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_action :verify_proxy_signature
7
+ after_action :add_liquid_header
8
+
9
+ rescue_from ActiveRecord::RecordNotFound do |exception|
10
+ render_error 404
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def verify_proxy_signature
17
+ unless proxy_signature_is_valid?
18
+ head :unauthorized
19
+ end
20
+ end
21
+
22
+ def proxy_signature_is_valid?
23
+ return true unless Rails.env.production?
24
+ query_hash = Rack::Utils.parse_query(request.query_string)
25
+ signature = query_hash.delete("signature")
26
+ sorted_params = query_hash.collect{ |k, v| "#{k}=#{Array(v).join(',')}" }.sort.join
27
+ calculated_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha256'), ShopifyApp.configuration.secret, sorted_params)
28
+ signature == calculated_signature
29
+ end
30
+
31
+ def add_liquid_header
32
+ response.headers['Content-Type'] = 'application/liquid'
33
+ end
34
+
35
+ def render_error(status)
36
+ add_liquid_header
37
+ render "disco_app/proxy_errors/#{status}", status: status
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ module DiscoApp
2
+ module AuthenticatedController
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_action :login_again_if_different_shop
7
+ before_action :shopify_shop
8
+ before_action :verify_status
9
+ around_filter :shopify_session
10
+ layout 'embedded_app'
11
+ end
12
+
13
+ private
14
+
15
+ def shopify_shop
16
+ if shop_session
17
+ @shop = Shop.find_by!(shopify_domain: @shop_session.url)
18
+ else
19
+ redirect_to_login
20
+ end
21
+ end
22
+
23
+ def verify_status
24
+ if not (@shop.charge_active? or @shop.charge_waived?)
25
+ redirect_if_not_current_path(disco_app.new_charge_path)
26
+ elsif @shop.charge_accepted?
27
+ redirect_if_not_current_path(disco_app.activate_charge_path)
28
+ elsif @shop.never_installed? or @shop.uninstalled?
29
+ redirect_if_not_current_path(disco_app.install_path)
30
+ elsif @shop.awaiting_install? or @shop.installing?
31
+ redirect_if_not_current_path(disco_app.installing_path)
32
+ elsif @shop.awaiting_uninstall? or @shop.uninstalling?
33
+ redirect_if_not_current_path(disco_app.uninstalling_path)
34
+ end
35
+ end
36
+
37
+ def redirect_if_not_current_path(target)
38
+ if request.path != target
39
+ redirect_to target
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,28 @@
1
+ module DiscoApp
2
+ module CarrierRequestController
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_action :verify_carrier_request_signature
7
+ end
8
+
9
+ private
10
+
11
+ def verify_carrier_request_signature
12
+ unless carrier_request_signature_is_valid?
13
+ head :unauthorized
14
+ end
15
+ end
16
+
17
+ def carrier_request_signature_is_valid?
18
+ return true unless Rails.env.production?
19
+ data = request.body.read.to_s
20
+ hmac_header = request.headers['HTTP_X_SHOPIFY_HMAC_SHA256']
21
+ digest = OpenSSL::Digest::Digest.new('sha256')
22
+ calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, ShopifyApp.configuration.secret, data)).strip
23
+ request.body.rewind
24
+ calculated_hmac == hmac_header
25
+ end
26
+
27
+ end
28
+ end