cloudrider 0.3.0 → 0.3.20

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.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -1
  3. data/cloudrider.gemspec +1 -0
  4. data/generica/.gitignore +18 -0
  5. data/generica/Gemfile +8 -1
  6. data/generica/Gemfile.lock +3 -0
  7. data/generica/app/assets/javascripts/apiv1.js.ls +6 -1
  8. data/generica/app/assets/javascripts/components/offers-summary.js.em +2 -0
  9. data/generica/app/assets/javascripts/components/picture-chunk.js.em +17 -0
  10. data/generica/app/assets/javascripts/components/pictures-group.js.em +21 -0
  11. data/generica/app/assets/javascripts/components/search-and-filter.js.em +4 -0
  12. data/generica/app/assets/javascripts/components/site-nav.js.em +5 -1
  13. data/generica/app/assets/javascripts/components/taggable-field.js.em +28 -0
  14. data/generica/app/assets/javascripts/components/tree/taxon-li.js.em +6 -2
  15. data/generica/app/assets/javascripts/controllers/index_controller.js.em +19 -2
  16. data/generica/app/assets/javascripts/controllers/modals/login_controller.js.em +23 -9
  17. data/generica/app/assets/javascripts/controllers/modals/register_controller.js.em +24 -0
  18. data/generica/app/assets/javascripts/controllers/products/index_controller.js.em +23 -13
  19. data/generica/app/assets/javascripts/controllers/products/product/offers/new_controller.js.em +17 -0
  20. data/generica/app/assets/javascripts/controllers/users/offers/index_controller.js.em +10 -0
  21. data/generica/app/assets/javascripts/controllers/users/product/edit_controller.js.em +31 -0
  22. data/generica/app/assets/javascripts/controllers/users/products/index_controller.js.em +8 -0
  23. data/generica/app/assets/javascripts/controllers/users/products/new_controller.js.em +22 -0
  24. data/generica/app/assets/javascripts/controllers/users/products/slice_controller.js.em +4 -0
  25. data/generica/app/assets/javascripts/helpers/filte_previewer.js.ls +21 -0
  26. data/generica/app/assets/javascripts/helpers/listing_picture.js.em +17 -0
  27. data/generica/app/assets/javascripts/models/offer.js.em +9 -8
  28. data/generica/app/assets/javascripts/models/user.js.em +12 -0
  29. data/generica/app/assets/javascripts/models/users/product.js.em +12 -0
  30. data/generica/app/assets/javascripts/routes/application_route.js.em +10 -2
  31. data/generica/app/assets/javascripts/routes/products/index_route.js.em +23 -2
  32. data/generica/app/assets/javascripts/routes/products/product/offers/new_route.js.em +18 -0
  33. data/generica/app/assets/javascripts/routes/users/offers/index_route.js.em +1 -0
  34. data/generica/app/assets/javascripts/routes/users/product_route.js.em +3 -0
  35. data/generica/app/assets/javascripts/routes/users/products/index_route.js.em +3 -0
  36. data/generica/app/assets/javascripts/routes/users/products/new_route.js.em +3 -0
  37. data/generica/app/assets/javascripts/templates/admin/product/edit.emblem +2 -0
  38. data/generica/app/assets/javascripts/templates/admin/products/_form-core.emblem +44 -0
  39. data/generica/app/assets/javascripts/templates/admin/products/new.emblem +4 -42
  40. data/generica/app/assets/javascripts/templates/components/offers-summary.emblem +9 -0
  41. data/generica/app/assets/javascripts/templates/components/picture-chunk.emblem +9 -0
  42. data/generica/app/assets/javascripts/templates/components/pictures-group.emblem +6 -0
  43. data/generica/app/assets/javascripts/templates/components/search-and-filter.emblem +5 -1
  44. data/generica/app/assets/javascripts/templates/components/taggable-field.emblem +1 -0
  45. data/generica/app/assets/javascripts/templates/modals/register.emblem +57 -0
  46. data/generica/app/assets/javascripts/templates/products/product/offers/_anonymous-form.emblem +11 -0
  47. data/generica/app/assets/javascripts/templates/products/product/offers/_offer-form.emblem +55 -0
  48. data/generica/app/assets/javascripts/templates/products/product/offers/new.emblem +37 -0
  49. data/generica/app/assets/javascripts/templates/products/product/show.emblem +26 -1
  50. data/generica/app/assets/javascripts/templates/users.emblem +24 -0
  51. data/generica/app/assets/javascripts/templates/users/index.emblem +3 -0
  52. data/generica/app/assets/javascripts/templates/users/offers/index.emblem +25 -0
  53. data/generica/app/assets/javascripts/templates/users/offers/slice.emblem +31 -0
  54. data/generica/app/assets/javascripts/templates/users/product/edit.emblem +82 -0
  55. data/generica/app/assets/javascripts/templates/users/products/index.emblem +22 -0
  56. data/generica/app/assets/javascripts/templates/users/products/new.emblem +28 -0
  57. data/generica/app/assets/javascripts/templates/users/products/slice.emblem +27 -0
  58. data/generica/app/assets/stylesheets/apiv1/_application.css.scss +4 -0
  59. data/generica/app/assets/stylesheets/apiv1/components/_offers-summary.css.scss +20 -0
  60. data/generica/app/assets/stylesheets/apiv1/components/_pictures-group.css.scss +32 -0
  61. data/generica/app/assets/stylesheets/apiv1/components/_taggable-field.css.scss +32 -0
  62. data/generica/app/assets/stylesheets/apiv1/products/product/offers/_new.css.scss +8 -0
  63. data/generica/app/controllers/admin/base_controller.rb +1 -1
  64. data/generica/app/controllers/admin/sessions/destroy_controller.rb +16 -0
  65. data/generica/app/controllers/apiv1/offers/create_controller.rb +30 -0
  66. data/generica/app/controllers/apiv1/offers/index_controller.rb +22 -0
  67. data/generica/app/controllers/apiv1/offers/show_controller.rb +12 -0
  68. data/generica/app/controllers/apiv1/products/destroy_controller.rb +6 -0
  69. data/generica/app/controllers/apiv1/products/index_controller.rb +8 -2
  70. data/generica/app/controllers/apiv1/products/show_controller.rb +7 -3
  71. data/generica/app/controllers/apiv1/taxons/index_controller.rb +5 -1
  72. data/generica/app/controllers/apiv1/users/create_controller.rb +17 -0
  73. data/generica/app/controllers/apiv1/users/show_controller.rb +12 -0
  74. data/generica/app/controllers/apiv1/users_controller.rb +9 -0
  75. data/generica/app/controllers/application_controller.rb +3 -0
  76. data/generica/app/controllers/users/offers/create_controller.rb +26 -0
  77. data/generica/app/controllers/users/products/create_controller.rb +26 -0
  78. data/generica/app/controllers/users/products/update_controller.rb +35 -0
  79. data/generica/app/mailers/apiv1/aggregate_mailer.rb +13 -0
  80. data/generica/app/mailers/apiv1/aggregate_mailer/summary_context.rb +121 -0
  81. data/generica/app/mailers/apiv1/notifications_mailer.rb +19 -0
  82. data/generica/app/mailers/apiv1/notifications_mailer/new_offer_context.rb +53 -0
  83. data/generica/app/models/admin/user.rb +43 -2
  84. data/generica/app/models/apiv1/attachment.rb +2 -0
  85. data/generica/app/models/apiv1/email_object.rb +35 -0
  86. data/generica/app/models/apiv1/email_request.rb +107 -0
  87. data/generica/app/models/apiv1/offer_message.rb +53 -0
  88. data/generica/app/models/apiv1/offer_postboy.rb +33 -0
  89. data/generica/app/models/apiv1/picture.rb +2 -0
  90. data/generica/app/models/apiv1/product.rb +28 -6
  91. data/generica/app/models/apiv1/products/offer_message_factory.rb +13 -0
  92. data/generica/app/models/apiv1/products_machine.rb +8 -2
  93. data/generica/app/models/apiv1/taxon.rb +1 -1
  94. data/generica/app/models/apiv1/users/product_factory.rb +22 -0
  95. data/generica/app/models/apiv1/users/product_relationship.rb +19 -0
  96. data/generica/app/models/users/products/offer_factory.rb +40 -0
  97. data/generica/app/varissets/javascripts/templates/application.emblem.erb +2 -2
  98. data/generica/app/varissets/javascripts/templates/components/offers-overview.emblem.erb +1 -0
  99. data/generica/app/varissets/javascripts/templates/components/search-and-filter.emblem.erb +33 -0
  100. data/generica/app/varissets/javascripts/templates/components/site-nav.emblem.erb +8 -0
  101. data/generica/app/varissets/javascripts/templates/components/taggable-field.emblem.erb +11 -0
  102. data/generica/app/varissets/javascripts/templates/modals/login.emblem.erb +36 -0
  103. data/generica/app/varissets/javascripts/templates/products.emblem.erb +4 -0
  104. data/generica/app/varissets/javascripts/templates/products/index.emblem.erb +17 -0
  105. data/generica/app/varissets/javascripts/templates/products/product/offers/_anonymous-form.emblem.erb +11 -0
  106. data/generica/app/varissets/javascripts/templates/products/product/offers/_offer-form.emblem.erb +55 -0
  107. data/generica/app/varissets/javascripts/templates/products/product/offers/new.emblem.erb +37 -0
  108. data/generica/app/varissets/javascripts/templates/products/product/show.emblem.erb +108 -0
  109. data/generica/app/varissets/stylesheets/apiv1/components/_offers-overview.css.scss.erb +3 -0
  110. data/generica/app/varissets/stylesheets/apiv1/components/_offers_overview.css.scss.erb +3 -0
  111. data/generica/app/varissets/stylesheets/apiv1/components/_search-and-filter.css.scss.erb +15 -0
  112. data/generica/app/varissets/stylesheets/apiv1/components/_site-footer.css.scss.erb +23 -0
  113. data/generica/app/varissets/stylesheets/apiv1/components/_taggable-field.css.scss.erb +32 -0
  114. data/generica/app/views/apiv1/home/index.html.haml +3 -1
  115. data/generica/app/views/apiv1/layouts/application.html.haml +37 -2
  116. data/generica/config/{database.yml.erb → database.yml.str} +3 -3
  117. data/generica/config/email.yml +11 -0
  118. data/generica/config/email_slave.god +9 -0
  119. data/generica/config/initializers/premailer.rb +1 -0
  120. data/generica/config/initializers/squash.rb.erb +3 -0
  121. data/generica/config/nginx.conf.erb +4 -4
  122. data/generica/config/routes.rb +14 -0
  123. data/generica/db/migrate/20141114213427_add_user_rank_to_admin_users.rb +9 -0
  124. data/generica/db/migrate/20141114225019_create_apiv1_users_products.rb +9 -0
  125. data/generica/db/migrate/20141116053522_create_apiv1_offer_messages.rb +16 -0
  126. data/generica/db/migrate/20141116235011_add_deleted_at_to_apiv1_products.rb +5 -0
  127. data/generica/db/migrate/20141116235209_add_deleted_at_to_apiv1_offer_messages.rb +5 -0
  128. data/generica/db/migrate/20141116235651_add_deleted_at_to_apiv1_pictures.rb +5 -0
  129. data/generica/db/migrate/20141116235808_add_deleted_at_to_apiv1_attachments.rb +5 -0
  130. data/generica/db/migrate/20141127230304_create_apiv1_email_requests.rb +16 -0
  131. data/generica/db/migrate/20141127230455_create_apiv1_email_objects.rb +11 -0
  132. data/generica/lib/generica/assets_unretardifier.rb +32 -0
  133. data/generica/lib/generica/email_slave.rb +92 -0
  134. data/generica/lib/tasks/email_slave.rake +11 -0
  135. data/generica/lib/tasks/production.rake +1 -1
  136. data/generica/public/tests/bermese.jpg +0 -0
  137. data/generica/public/tests/chow.jpg +0 -0
  138. data/generica/public/tests/malamute.jpg +0 -0
  139. data/generica/public/tests/malamute2.JPG +0 -0
  140. data/generica/spec/controllers/apiv1/users/create_controller_spec.rb +17 -0
  141. data/generica/spec/controllers/users/products/create_controller_spec.rb +31 -0
  142. data/generica/spec/mailers/apiv1/aggregate_mailer_spec.rb +29 -0
  143. data/generica/spec/models/apiv1/email_request_spec.rb +4 -0
  144. data/generica/spec/models/apiv1/offer_postboy_spec.rb +22 -0
  145. data/generica/spec/models/apiv1/product_spec.rb +1 -0
  146. data/generica/spec/models/apiv1/products/offer_message_factory_spec.rb +37 -0
  147. data/generica/spec/models/apiv1/products_machine_spec.rb +77 -0
  148. data/generica/spec/models/apiv1/users/product_factory_spec.rb +47 -0
  149. data/generica/spec/models/users/products/offer_factory_spec.rb +38 -0
  150. data/generica/test/mailers/.keep +0 -0
  151. data/generica/test/mailers/previews/apiv1/aggregate_preview.rb +6 -0
  152. data/generica/test/mailers/previews/apiv1/notifications_preview.rb +5 -0
  153. data/lib/cloudrider.rb +1 -1
  154. data/lib/cloudrider/apiv1/base.rb +2 -2
  155. data/lib/cloudrider/apiv1/login_modal_emblem.rb +25 -0
  156. data/lib/cloudrider/apiv1/offers_anonymous_form_partial_emblem.rb +12 -0
  157. data/lib/cloudrider/apiv1/offers_new_emblem.rb +15 -0
  158. data/lib/cloudrider/apiv1/offers_overview_component.rb +8 -0
  159. data/lib/cloudrider/apiv1/offers_overview_sass.rb +8 -0
  160. data/lib/cloudrider/apiv1/product_show_emblem.rb +31 -0
  161. data/lib/cloudrider/apiv1/products_emblem.rb +11 -0
  162. data/lib/cloudrider/apiv1/products_index_emblem.rb +14 -0
  163. data/lib/cloudrider/apiv1/search_and_filter_component.rb +11 -0
  164. data/lib/cloudrider/apiv1/search_and_filter_sass.rb +11 -0
  165. data/lib/cloudrider/apiv1/site_footer_component.rb +7 -7
  166. data/lib/cloudrider/apiv1/site_footer_sass.rb +9 -0
  167. data/lib/cloudrider/application_commander.rb +46 -34
  168. data/lib/cloudrider/backend_commander.rb +15 -9
  169. data/lib/cloudrider/protofile.rb +18 -2
  170. data/lib/cloudrider/protosite.example.json +26 -0
  171. data/lib/cloudrider/protosite.rb +66 -0
  172. data/lib/cloudrider/serverside/base.rb +2 -2
  173. data/lib/cloudrider/serverside/database_yaml.rb +9 -4
  174. data/lib/cloudrider/serverside/nginx_conf.rb +7 -2
  175. data/lib/cloudrider/serverside/squash_ruby.rb +14 -0
  176. data/lib/cloudrider/serverside/unicorn_conf_ruby.rb +2 -1
  177. data/lib/cloudrider/version.rb +1 -1
  178. data/lib/cloudrider/web_firm.rb +16 -0
  179. data/lib/cloudrider/web_firm/component_architect.rb +23 -0
  180. data/lib/cloudrider/web_firm/page_designer.rb +13 -0
  181. data/lib/cloudrider/web_firm/project_lead.rb +30 -0
  182. data/lib/cloudrider/web_firm/scumbag_engineer.rb +40 -0
  183. data/lib/cloudrider/web_firm/support_intern.rb +113 -0
  184. data/lib/generators/cloudrider/server/server_generator.rb +4 -8
  185. data/lib/generators/cloudrider/website/website_generator.rb +25 -0
  186. data/spec/cloudrider/protosite_spec.rb +63 -0
  187. data/vanilla/.bowerrc +4 -0
  188. data/vanilla/.editorconfig +33 -0
  189. data/vanilla/.ember-cli +9 -0
  190. data/vanilla/.gitignore +17 -0
  191. data/vanilla/.jshintrc +32 -0
  192. data/vanilla/.travis.yml +16 -0
  193. data/vanilla/Brocfile.js +20 -0
  194. data/vanilla/README.md +51 -0
  195. data/vanilla/app/app.js +16 -0
  196. data/vanilla/app/components/.gitkeep +0 -0
  197. data/vanilla/app/controllers/.gitkeep +0 -0
  198. data/vanilla/app/controllers/admin.coffee +5 -0
  199. data/vanilla/app/helpers/.gitkeep +0 -0
  200. data/vanilla/app/index.html +21 -0
  201. data/vanilla/app/models/.gitkeep +0 -0
  202. data/vanilla/app/router.js +11 -0
  203. data/vanilla/app/routes/.gitkeep +0 -0
  204. data/vanilla/app/styles/.gitkeep +0 -0
  205. data/vanilla/app/styles/app.css +3 -0
  206. data/vanilla/app/templates/.gitkeep +0 -0
  207. data/vanilla/app/templates/application.hbs +3 -0
  208. data/vanilla/app/templates/components/.gitkeep +0 -0
  209. data/vanilla/app/views/.gitkeep +0 -0
  210. data/vanilla/bower.json +17 -0
  211. data/vanilla/config/environment.js +47 -0
  212. data/vanilla/package.json +39 -0
  213. data/vanilla/public/.gitkeep +0 -0
  214. data/vanilla/public/crossdomain.xml +15 -0
  215. data/vanilla/public/robots.txt +3 -0
  216. data/vanilla/testem.json +11 -0
  217. data/vanilla/tests/.jshintrc +74 -0
  218. data/vanilla/tests/helpers/resolver.js +11 -0
  219. data/vanilla/tests/helpers/start-app.js +25 -0
  220. data/vanilla/tests/index.html +45 -0
  221. data/vanilla/tests/test-helper.js +12 -0
  222. data/vanilla/tests/unit/.gitkeep +0 -0
  223. data/vanilla/tests/unit/controllers/admin-test.coffee +12 -0
  224. data/vanilla/vendor/.gitkeep +0 -0
  225. metadata +189 -5
  226. data/generica/app/views/layouts/application.html.erb +0 -14
  227. data/lib/cloudrider/master_context.rb +0 -105
@@ -0,0 +1,32 @@
1
+ .taggable-field {
2
+ @include display-flex;
3
+ @include flex-direction(row);
4
+ @include flex-wrap(nowrap);
5
+ @include justify-content(flex-start);
6
+ overflow-x: hidden;
7
+ .taggable-textfield {
8
+ margin-bottom: 0px;
9
+ width: 100%;
10
+ height: 40px;
11
+ }
12
+ .taggable-field-tag {
13
+ @include display-flex;
14
+ @include flex-direction(row);
15
+ @include justify-content(center);
16
+ @include align-items(center);
17
+ border: 1px solid #ddd;
18
+ padding-left: 10px;
19
+ padding-right: 15px;
20
+ min-width: 50px;
21
+ height: 40px;
22
+ background: {
23
+ color: #f2f2f2;
24
+ }
25
+ color: #358753;
26
+ }
27
+ .centered-fully {
28
+ @include display-flex;
29
+ @include flex-wrap(nowrap);
30
+ @include flex-direction(row);
31
+ }
32
+ }
@@ -0,0 +1,8 @@
1
+ .products-product-offers-new {
2
+ .form-legend {
3
+ text-transform: capitalize;
4
+ font-size: 1.2rem;
5
+ padding-bottom: 1rem;
6
+ padding-top: 1rem;
7
+ }
8
+ }
@@ -2,7 +2,7 @@ class Admin::BaseController < ApplicationController
2
2
  before_filter :_respond_with_unauthorized_json
3
3
  private
4
4
  def _respond_with_unauthorized_json
5
- unless logged_in?
5
+ unless logged_in? && current_user.admin?
6
6
  render json: { message: "login required" }, status: 401
7
7
  end
8
8
  end
@@ -0,0 +1,16 @@
1
+ class Admin::Sessions::DestroyController < Apiv1::UsersController
2
+ before_filter :_ensure_correct_sessionism
3
+ def destroy
4
+ logout
5
+ render json: nil
6
+ end
7
+ private
8
+ def _ensure_correct_sessionism
9
+ unless current_user == _user
10
+ render json: { message: "you can't log someone else out" }, status: 401
11
+ end
12
+ end
13
+ def _user
14
+ @user ||= Admin::User.find params[:id]
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ class Apiv1::Offers::CreateController < Apiv1::HomeController
2
+ def create
3
+ if _offer_creation_success?
4
+ _offer_factory.save!
5
+ _offer_postboy.request_work!
6
+ render json: _offer_hash
7
+ else
8
+ render json: _error_hash, status: :expectation_failed
9
+ end
10
+ end
11
+ private
12
+ def _offer_postboy
13
+ @offer_postboy ||= Apiv1::OfferPostboy.new _offer_factory.offer
14
+ end
15
+ def _offer_creation_success?
16
+ _offer_factory.satisfy_specifications?
17
+ end
18
+ def _offer_hash
19
+ _offer_factory.offer_hash
20
+ end
21
+ def _error_hash
22
+ _offer_factory.error_hash
23
+ end
24
+ def _offer_factory
25
+ @offer_factory ||= Apiv1::Products::OfferMessageFactory.new(_offer_params)
26
+ end
27
+ def _offer_params
28
+ params.require(:offer)
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ class Apiv1::Offers::IndexController < Apiv1::UsersController
2
+ def index
3
+ render json: { offers: _offers.map(&:to_ember_hash), meta: _meta_hash }
4
+ end
5
+ private
6
+ def _meta_hash
7
+ {
8
+ page: _page,
9
+ per: _per,
10
+ count: current_user.offers.count
11
+ }
12
+ end
13
+ def _offers
14
+ @offers ||= current_user.offers.page(_page).per(_per)
15
+ end
16
+ def _page
17
+ params[:page] || 1
18
+ end
19
+ def _per
20
+ params[:per] || 15
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ class Apiv1::Offers::ShowController < Apiv1::HomeController
2
+ def show
3
+ render json: { offer: _offer_hash }
4
+ end
5
+ private
6
+ def _offer_hash
7
+ _offer.to_ember_hash
8
+ end
9
+ def _offer
10
+ @offer ||= Apiv1::OfferMessage.find params[:id]
11
+ end
12
+ end
@@ -1,8 +1,14 @@
1
1
  class Apiv1::Products::DestroyController < Admin::BaseController
2
+ before_filter :_ensure_product_ownership
2
3
  def destroy
3
4
  render json: { product: _product.destroy }
4
5
  end
5
6
  private
7
+ def _ensure_product_ownership
8
+ unless current_user.admin? || current_user.owns?(_product)
9
+ render json: { message: "This isn't your listing" }, status: 401
10
+ end
11
+ end
6
12
  def _product
7
13
  @product ||= Apiv1::Product.find params[:id]
8
14
  end
@@ -1,8 +1,14 @@
1
1
  class Apiv1::Products::IndexController < Apiv1::HomeController
2
2
  def index
3
- render json: { products: _products_hash, meta: _meta_hash }
3
+ render json: { products: _products_hash, meta: _meta_hash, pictures: _pictures_hash, taxons: _taxons_hash }
4
4
  end
5
5
  private
6
+ def _pictures_hash
7
+ _products.map(&:pictures).flatten.map(&:to_ember_hash)
8
+ end
9
+ def _taxons_hash
10
+ _products.map(&:taxons).flatten.map(&:to_ember_hash)
11
+ end
6
12
  def _products_hash
7
13
  _products.map &:to_ember_hash
8
14
  end
@@ -16,6 +22,6 @@ class Apiv1::Products::IndexController < Apiv1::HomeController
16
22
  @products_machine ||= Apiv1::ProductsMachine.new _query_params
17
23
  end
18
24
  def _query_params
19
- params.permit(:page, :per, :query, :order).merge taxons: params[:taxons]
25
+ params.permit(:page, :per, :query, :order, :user_id, :taxons, taxons: [])
20
26
  end
21
27
  end
@@ -1,10 +1,14 @@
1
1
  class Apiv1::Products::ShowController < Apiv1::HomeController
2
2
  def show
3
- render json: { product: _product_hash, pictures: _product.pictures.map(&:to_ember_hash) }
3
+ render json: _output_hash
4
4
  end
5
5
  private
6
- def _product_hash
7
- _product.to_ember_hash
6
+ def _output_hash
7
+ {
8
+ product: _product.to_ember_hash,
9
+ pictures: _product.pictures.map(&:to_ember_hash),
10
+ offers: _product.offers.map(&:to_ember_hash)
11
+ }
8
12
  end
9
13
  def _product
10
14
  @product ||= Apiv1::Product.find_by_permalink_or_id! params[:id]
@@ -1,12 +1,16 @@
1
1
  class Apiv1::Taxons::IndexController < Apiv1::HomeController
2
2
  def index
3
- render json: { taxons: _taxons }
3
+ render json: { taxons: _taxons_hash }
4
4
  end
5
5
  private
6
+ def _taxons_hash
7
+ _taxons.map(&:to_ember_hash)
8
+ end
6
9
  def _taxons
7
10
  Apiv1::Taxon.pipeline -> (t) { t.by_root_genus(params[:root_genus]) if params[:root_genus].present? },
8
11
  -> (t) { t.children_of_parent(params[:parent_id]) if params[:parent_id].present? },
9
12
  -> (t) { t.root_generation if params.has_key?(:parent_id) && params[:parent_id].blank? },
13
+ -> (t) { t.where id: params[:ids].to_a if params[:ids].present? },
10
14
  -> (t) { t.all }
11
15
  end
12
16
  end
@@ -0,0 +1,17 @@
1
+ class Apiv1::Users::CreateController < Apiv1::HomeController
2
+ def create
3
+ if _user.valid?
4
+ _user.save! && auto_login(_user)
5
+ render json: { user: _user.to_ember_hash }
6
+ else
7
+ render json: _user.errors.to_h, status: :expectation_failed
8
+ end
9
+ end
10
+ private
11
+ def _user
12
+ @user ||= Admin::User.new _user_params
13
+ end
14
+ def _user_params
15
+ params.require(:user).permit :email, :company_name, :phone_number, :password, :password_confirmation, :address
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ class Apiv1::Users::ShowController < Apiv1::HomeController
2
+ def show
3
+ render json: { user: _user_hash }
4
+ end
5
+ private
6
+ def _user_hash
7
+ _user.to_ember_hash
8
+ end
9
+ def _user
10
+ @user ||= Admin::User.find params[:id]
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ class Apiv1::UsersController < ApplicationController
2
+ before_filter :_respond_with_unauthorized_json
3
+ private
4
+ def _respond_with_unauthorized_json
5
+ unless logged_in?
6
+ render json: { message: "login required" }, status: 401
7
+ end
8
+ end
9
+ end
@@ -2,4 +2,7 @@ class ApplicationController < ActionController::Base
2
2
  # Prevent CSRF attacks by raising an exception.
3
3
  # For APIs, you may want to use :null_session instead.
4
4
  protect_from_forgery with: :exception
5
+
6
+ include Squash::Ruby::ControllerMethods
7
+ enable_squash_client
5
8
  end
@@ -0,0 +1,26 @@
1
+ class Users::Offers::CreateController < Apiv1::UsersController
2
+ def create
3
+ if _offer_creation_success?
4
+ _offer_factory.save!
5
+ render json: _offer_hash
6
+ else
7
+ render json: _error_hash, status: :expectation_failed
8
+ end
9
+ end
10
+ private
11
+ def _offer_creation_success?
12
+ _offer_factory.satisfy_specifications?
13
+ end
14
+ def _offer_hash
15
+ _offer_factory.offer_hash
16
+ end
17
+ def _error_hash
18
+ _offer_factory.error_hash
19
+ end
20
+ def _offer_factory
21
+ @offer_factory ||= Users::Products::OfferFactory.new(current_user, _offer_params)
22
+ end
23
+ def _offer_params
24
+ params.require(:users_offer)
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ class Users::Products::CreateController < Apiv1::UsersController
2
+ def create
3
+ if _product_creation_success?
4
+ _product_factory.save!
5
+ render json: _product_hash
6
+ else
7
+ render json: _error_hash, status: :expectation_failed
8
+ end
9
+ end
10
+ private
11
+ def _product_creation_success?
12
+ _product_factory.satisfy_specifications?
13
+ end
14
+ def _product_hash
15
+ _product_factory.product_hash
16
+ end
17
+ def _error_hash
18
+ _product_factory.error_hash
19
+ end
20
+ def _product_factory
21
+ @product_factory ||= Apiv1::Users::ProductFactory.new(current_user, _product_params)
22
+ end
23
+ def _product_params
24
+ params.require(:users_product)
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ class Users::Products::UpdateController < Apiv1::UsersController
2
+ before_filter :_ensure_product_ownership
3
+ def update
4
+ if _product_modification_success?
5
+ _product_modifier.update!
6
+ render json: { product: _product_hash }
7
+ else
8
+ render json: _error_hash, status: :expectation_failed
9
+ end
10
+ end
11
+ private
12
+ def _ensure_product_ownership
13
+ unless current_user.owns? _product
14
+ render json: { message: "This isn't your listing" }, status: 401
15
+ end
16
+ end
17
+ def _product_modification_success?
18
+ _product_modifier.satisfy_specifications?
19
+ end
20
+ def _product_hash
21
+ _product_modifier.product_hash
22
+ end
23
+ def _error_hash
24
+ _product_modifier.error_hash
25
+ end
26
+ def _product_modifier
27
+ @product_modifier ||= Admin::ProductModifier.new _product, _product_params
28
+ end
29
+ def _product
30
+ @product ||= Apiv1::Product.find params[:id]
31
+ end
32
+ def _product_params
33
+ params.require(:users_product)
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ class Apiv1::AggregateMailer < ActionMailer::Base
2
+ default from: "from@example.com"
3
+ layout "apiv1/layouts/email"
4
+ def summary(emails)
5
+ @ctx = Apiv1::AggregateMailer::SummaryContext.new emails
6
+
7
+ mail to: @ctx.to,
8
+ from: @ctx.from,
9
+ cc: @ctx.cc,
10
+ bcc: @ctx.bcc,
11
+ subject: @ctx.subject
12
+ end
13
+ end
@@ -0,0 +1,121 @@
1
+ class Apiv1::AggregateMailer::SummaryContext
2
+ class NoEmailsToAggregate < StandardError; end
3
+ delegate :to,
4
+ :from,
5
+ :cc,
6
+ :bcc,
7
+ to: :_first_email
8
+ def initialize(emails)
9
+ @emails = emails
10
+ raise NoEmailsToAggregate, "no emails to aggregate" if @emails.blank?
11
+ end
12
+ def subject
13
+ [_preamble, _email_type_and_counts.join(", ")].join(" ").strip
14
+ end
15
+ def html_bodies
16
+ @emails.map do |email|
17
+ CoreHtmlFinder.html_body_gist email
18
+ end
19
+ end
20
+ def plain_bodies
21
+ @emails.map do |email|
22
+ CorePlainFinder.plain_body_gist email
23
+ end
24
+ end
25
+ def whoever_this_is_sent_to
26
+ FormalTitleFinder.formal_title _first_email
27
+ end
28
+ private
29
+ def _preamble
30
+ "Update:"
31
+ end
32
+ def _email_type_and_counts
33
+ _email_groups.map do |type_name, emails|
34
+ _that_pluralize_thing noun: type_name, count: emails.count
35
+ end
36
+ end
37
+ def _that_pluralize_thing(noun: noun, count: count)
38
+ if count > 1 || count == 0
39
+ "#{count} #{noun.pluralize}"
40
+ else
41
+ "#{count} #{noun.singularize}"
42
+ end
43
+ end
44
+ def _first_email
45
+ @emails.first
46
+ end
47
+ def _email_groups
48
+ @emails.reduce({}) do |hash, email|
49
+ s = _simplify_subject email.subject
50
+ hash[s] ||= []
51
+ hash[s].push email
52
+ hash
53
+ end
54
+ end
55
+ def _simplify_subject(subject)
56
+ subject.split("-").first.to_s.strip
57
+ end
58
+ end
59
+
60
+ class Apiv1::AggregateMailer::SummaryContext::CoreHtmlFinder
61
+ class << self
62
+ def html_body_gist(mail)
63
+ _process.call mail
64
+ end
65
+ private
66
+ def _process
67
+ _get_html_part >> _parse_by_nokogiri >> _find_via_css >> _return_html
68
+ end
69
+ def _get_html_part
70
+ -> (mail) { mail.html_part.to_s }
71
+ end
72
+ def _parse_by_nokogiri
73
+ -> (string) { Nokogiri::HTML(string) }
74
+ end
75
+ def _find_via_css
76
+ -> (nokodoc) { nokodoc.css "table.the-gist" }
77
+ end
78
+ def _return_html
79
+ -> (nokoel) { nokoel.map(&:to_s).join("\n") }
80
+ end
81
+ end
82
+ end
83
+
84
+ class Apiv1::AggregateMailer::SummaryContext::FormalTitleFinder
85
+ class << self
86
+ def formal_title(mail)
87
+ _process.call mail
88
+ end
89
+ private
90
+ def _process
91
+ _get_html_part >> _parse_by_nokogiri >> _find_via_css >> _return_html
92
+ end
93
+ def _get_html_part
94
+ -> (mail) { mail.html_part.to_s }
95
+ end
96
+ def _parse_by_nokogiri
97
+ -> (string) { Nokogiri::HTML(string) }
98
+ end
99
+ def _find_via_css
100
+ -> (nokodoc) { nokodoc.css "span.product-owner" }
101
+ end
102
+ def _return_html
103
+ -> (nokoel) { nokoel.first.text }
104
+ end
105
+ end
106
+ end
107
+
108
+ class Apiv1::AggregateMailer::SummaryContext::CorePlainFinder
109
+ class << self
110
+ def plain_body_gist(mail)
111
+ _process.call mail
112
+ end
113
+ private
114
+ def _process
115
+ _get_plain_part
116
+ end
117
+ def _get_plain_part
118
+ -> (mail) { mail.text_part.to_s }
119
+ end
120
+ end
121
+ end