diff --git a/Gemfile b/Gemfile index af4108c9eb..87566eebfa 100644 --- a/Gemfile +++ b/Gemfile @@ -35,6 +35,7 @@ gem 'geocoder' gem 'gmaps4rails' gem 'spinjs-rails' gem 'rack-ssl', :require => 'rack/ssl' +gem 'custom_error_message', :github => 'jeremydurham/custom-err-msg' gem 'foreigner' gem 'immigrant' diff --git a/Gemfile.lock b/Gemfile.lock index 87a0acf967..733ef43572 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,6 +6,12 @@ GIT actionpack (~> 3.0) activemodel (~> 3.0) +GIT + remote: git://github.com/jeremydurham/custom-err-msg.git + revision: 3a8ec9dddc7a5b0aab7c69a6060596de300c68f4 + specs: + custom_error_message (1.1.1) + GIT remote: git://github.com/openfoodfoundation/spree.git revision: da651b40f5c6cdd32e00b060729eb9aefd4f615f @@ -492,6 +498,7 @@ DEPENDENCIES coffee-rails (~> 3.2.1) comfortable_mexican_sofa compass-rails + custom_error_message! database_cleaner (= 0.7.1) db2fog debugger-linecache diff --git a/app/assets/javascripts/admin/admin.js.coffee b/app/assets/javascripts/admin/admin.js.coffee index ba07bb7933..76154e9e20 100644 --- a/app/assets/javascripts/admin/admin.js.coffee +++ b/app/assets/javascripts/admin/admin.js.coffee @@ -1,3 +1,3 @@ -window.Admin = angular.module("ofn.admin", ["ngResource","ofn.dropdown"]).config ($httpProvider) -> +window.Admin = angular.module("ofn.admin", ["ngResource", "ngAnimate", "ofn.dropdown"]).config ($httpProvider) -> $httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content") $httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*" \ No newline at end of file diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js index 3cf4fe97e7..99c936c4d7 100644 --- a/app/assets/javascripts/admin/all.js +++ b/app/assets/javascripts/admin/all.js @@ -11,6 +11,7 @@ //= require shared/jquery-ui-timepicker-addon //= require angular //= require angular-resource +//= require angular-animate //= require admin/spree_core //= require admin/spree_auth //= require admin/spree_promo diff --git a/app/assets/javascripts/admin/controllers/enterprise_relationships_controller.js.coffee b/app/assets/javascripts/admin/controllers/enterprise_relationships_controller.js.coffee new file mode 100644 index 0000000000..c66e79c046 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/enterprise_relationships_controller.js.coffee @@ -0,0 +1,10 @@ +Admin.controller "AdminEnterpriseRelationshipsCtrl", ($scope, EnterpriseRelationships, Enterprises) -> + $scope.EnterpriseRelationships = EnterpriseRelationships + $scope.Enterprises = Enterprises + + $scope.create = -> + $scope.EnterpriseRelationships.create($scope.parent_id, $scope.child_id) + + $scope.delete = (enterprise_relationship) -> + if confirm("Are you sure?") + $scope.EnterpriseRelationships.delete enterprise_relationship diff --git a/app/assets/javascripts/admin/services/enterprise_relationships.js.coffee b/app/assets/javascripts/admin/services/enterprise_relationships.js.coffee new file mode 100644 index 0000000000..0469aa5637 --- /dev/null +++ b/app/assets/javascripts/admin/services/enterprise_relationships.js.coffee @@ -0,0 +1,18 @@ +Admin.factory 'EnterpriseRelationships', ($http, enterprise_relationships) -> + new class EnterpriseRelationships + create_errors: "" + + constructor: -> + @enterprise_relationships = enterprise_relationships + + create: (parent_id, child_id) -> + $http.post('/admin/enterprise_relationships', {enterprise_relationship: {parent_id: parent_id, child_id: child_id}}).success (data, status) => + @enterprise_relationships.unshift(data) + @create_errors = "" + + .error (response, status) => + @create_errors = response.errors + + delete: (er) -> + $http.delete('/admin/enterprise_relationships/' + er.id).success (data) => + @enterprise_relationships.splice @enterprise_relationships.indexOf(er), 1 diff --git a/app/assets/javascripts/admin/services/enterprises.js.coffee b/app/assets/javascripts/admin/services/enterprises.js.coffee new file mode 100644 index 0000000000..199b6294c3 --- /dev/null +++ b/app/assets/javascripts/admin/services/enterprises.js.coffee @@ -0,0 +1,4 @@ +Admin.factory 'Enterprises', (enterprises) -> + new class Enterprises + constructor: -> + @enterprises = enterprises diff --git a/app/assets/javascripts/darkswarm/controllers/authentication/login_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/authentication/login_controller.js.coffee index c2211bc033..da625e3d34 100644 --- a/app/assets/javascripts/darkswarm/controllers/authentication/login_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/authentication/login_controller.js.coffee @@ -1,8 +1,11 @@ -Darkswarm.controller "LoginCtrl", ($scope, $http, $location, AuthenticationService) -> +Darkswarm.controller "LoginCtrl", ($scope, $http, AuthenticationService, Redirections) -> $scope.path = "/login" $scope.submit = -> $http.post("/user/spree_user/sign_in", {spree_user: $scope.spree_user}).success (data)-> - location.href = location.origin + location.pathname # Strips out hash fragments + if Redirections.after_login + location.href = location.origin + Redirections.after_login + else + location.href = location.origin + location.pathname # Strips out hash fragments .error (data) -> $scope.errors = data.message diff --git a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee index 4ec316e65f..959423e3ca 100644 --- a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee @@ -1,4 +1,5 @@ Darkswarm.controller "ProductNodeCtrl", ($scope) -> + $scope.price = -> if $scope.product.variants.length > 0 prices = (v.price for v in $scope.product.variants) @@ -6,4 +7,6 @@ Darkswarm.controller "ProductNodeCtrl", ($scope) -> else $scope.product.price + $scope.producer = $scope.product.supplier + $scope.hasVariants = $scope.product.variants.length > 0 diff --git a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee index 09df18ca38..323df2fc4e 100644 --- a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee @@ -12,5 +12,3 @@ Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle) - code = e.keyCode || e.which if code == 13 e.preventDefault() - - $scope.productPrice = (product) -> diff --git a/app/assets/javascripts/darkswarm/directives/modal.js.coffee b/app/assets/javascripts/darkswarm/directives/modal.js.coffee index 73217b3812..6f62c7cb45 100644 --- a/app/assets/javascripts/darkswarm/directives/modal.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/modal.js.coffee @@ -8,7 +8,10 @@ Darkswarm.directive "ofnModal", ($modal)-> link: (scope, elem, attrs, ctrl, transclude)-> scope.title = attrs.title contents = null - transclude scope, (clone)-> + + # We're using an isolate scope, which is a child of the original scope + # We have to compile the transclude against the original scope, not the isolate + transclude scope.$parent, (clone)-> contents = clone elem.on "click", => diff --git a/app/assets/javascripts/darkswarm/services/authentication_service.js.coffee b/app/assets/javascripts/darkswarm/services/authentication_service.js.coffee index eada8bc44b..820d5bde9c 100644 --- a/app/assets/javascripts/darkswarm/services/authentication_service.js.coffee +++ b/app/assets/javascripts/darkswarm/services/authentication_service.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location)-> +Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redirections)-> new class AuthenticationService selectedPath: "/login" diff --git a/app/assets/javascripts/darkswarm/services/product.js.coffee b/app/assets/javascripts/darkswarm/services/product.js.coffee index ca31d5e9c0..e58b83bacc 100644 --- a/app/assets/javascripts/darkswarm/services/product.js.coffee +++ b/app/assets/javascripts/darkswarm/services/product.js.coffee @@ -2,6 +2,9 @@ Darkswarm.factory 'Product', ($resource) -> new class Product constructor: -> @update() + + # TODO: don't need to scope this into object + # Already on object as far as controller scope is concerned data: products: null loading: true diff --git a/app/assets/javascripts/darkswarm/services/redirections.js.coffee b/app/assets/javascripts/darkswarm/services/redirections.js.coffee new file mode 100644 index 0000000000..a479964e9e --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/redirections.js.coffee @@ -0,0 +1,3 @@ +Darkswarm.factory "Redirections", ($location)-> + new class Redirections + after_login: $location.search().after_login diff --git a/app/assets/stylesheets/admin/enterprise_relationships.css.sass b/app/assets/stylesheets/admin/enterprise_relationships.css.sass new file mode 100644 index 0000000000..cffc0b0623 --- /dev/null +++ b/app/assets/stylesheets/admin/enterprise_relationships.css.sass @@ -0,0 +1,20 @@ +// TODO: Provide -moz- and -o- directives +@-webkit-keyframes alert-flash + 0% + background-color: #f9f1ae + + 100% + background-color: #fff + + +table#enterprise-relationships + th.actions, td.actions + width: 16% + .errors + color: #f00 + + tr.ng-enter + -webkit-animation-name: alert-flash + -webkit-animation-duration: 1200ms + -webkit-animation-iteration-count: 1 + -webkit-animation-timing-function: ease-in-out diff --git a/app/assets/stylesheets/admin/openfoodnetwork.css.scss b/app/assets/stylesheets/admin/openfoodnetwork.css.scss index 92092bd136..87983a6bc7 100644 --- a/app/assets/stylesheets/admin/openfoodnetwork.css.scss +++ b/app/assets/stylesheets/admin/openfoodnetwork.css.scss @@ -19,9 +19,11 @@ table .blank-action { } +input.search { + margin-bottom: 1em; +} #new_enterprise_fee_set input.search { float: right; - margin-bottom: 1em; } .ng .ng-invalid.ng-dirty { diff --git a/app/controllers/admin/enterprise_relationships_controller.rb b/app/controllers/admin/enterprise_relationships_controller.rb new file mode 100644 index 0000000000..46ac45a3e5 --- /dev/null +++ b/app/controllers/admin/enterprise_relationships_controller.rb @@ -0,0 +1,24 @@ +module Admin + class EnterpriseRelationshipsController < ResourceController + def index + @enterprises = Enterprise.managed_by(spree_current_user).by_name + @enterprise_relationships = EnterpriseRelationship.by_name + end + + def create + @enterprise_relationship = EnterpriseRelationship.new params[:enterprise_relationship] + + if @enterprise_relationship.save + render partial: "admin/json/enterprise_relationship", locals: {enterprise_relationship: @enterprise_relationship} + else + render status: 400, json: {errors: @enterprise_relationship.errors.full_messages.join(', ')} + end + end + + def destroy + @enterprise_relationship = EnterpriseRelationship.find params[:id] + @enterprise_relationship.destroy + render nothing: true + end + end +end diff --git a/app/controllers/spree/admin/overview_controller_decorator.rb b/app/controllers/spree/admin/overview_controller_decorator.rb index 5c96901c1d..a6142d26c0 100644 --- a/app/controllers/spree/admin/overview_controller_decorator.rb +++ b/app/controllers/spree/admin/overview_controller_decorator.rb @@ -13,8 +13,7 @@ Spree::Admin::OverviewController.class_eval do redirect_to '/unauthorized' else store_location - url = respond_to?(:spree_login_path) ? spree_login_path : root_path - redirect_to url + redirect_to root_path(anchor: "login?after_login=#{spree.admin_path}") end end end diff --git a/app/controllers/spree/orders_controller_decorator.rb b/app/controllers/spree/orders_controller_decorator.rb index ce20dfd58d..959e51204f 100644 --- a/app/controllers/spree/orders_controller_decorator.rb +++ b/app/controllers/spree/orders_controller_decorator.rb @@ -28,6 +28,7 @@ Spree::OrdersController.class_eval do end populator = Spree::OrderPopulator.new(current_order(true), current_currency) if populator.populate(params.slice(:products, :variants, :quantity)) + fire_event('spree.cart.add') fire_event('spree.order.contents_changed') respond_with(@order) do |format| diff --git a/app/helpers/shared_helper.rb b/app/helpers/shared_helper.rb index be1e0ba0f4..828277cb57 100644 --- a/app/helpers/shared_helper.rb +++ b/app/helpers/shared_helper.rb @@ -1,4 +1,9 @@ module SharedHelper + + def inject_json(name, partial) + render "json/injection", name: name, partial: partial + end + def distributor_link_class(distributor) cart = current_order(true) @active_distributors ||= Enterprise.distributors_with_active_order_cycles diff --git a/app/models/enterprise_relationship.rb b/app/models/enterprise_relationship.rb index 2cbda1511a..09fff8ba03 100644 --- a/app/models/enterprise_relationship.rb +++ b/app/models/enterprise_relationship.rb @@ -3,5 +3,10 @@ class EnterpriseRelationship < ActiveRecord::Base belongs_to :child, class_name: 'Enterprise' validates_presence_of :parent_id, :child_id - validates_uniqueness_of :child_id, scope: :parent_id + validates_uniqueness_of :child_id, scope: :parent_id, message: "^That relationship is already established." + + scope :with_enterprises, + joins('LEFT JOIN enterprises AS parent_enterprises ON parent_enterprises.id = enterprise_relationships.parent_id'). + joins('LEFT JOIN enterprises AS child_enterprises ON child_enterprises.id = enterprise_relationships.child_id') + scope :by_name, with_enterprises.order('parent_enterprises.name, child_enterprises.name') end diff --git a/app/views/admin/enterprise_relationships/_data.html.haml b/app/views/admin/enterprise_relationships/_data.html.haml new file mode 100644 index 0000000000..2361755707 --- /dev/null +++ b/app/views/admin/enterprise_relationships/_data.html.haml @@ -0,0 +1,3 @@ +:javascript + angular.module('ofn.admin').value('enterprise_relationships', #{render partial: "admin/json/enterprise_relationships", object: @enterprise_relationships}); + angular.module('ofn.admin').value('enterprises', #{render partial: "admin/json/enterprises", object: @enterprises}); diff --git a/app/views/admin/enterprise_relationships/_enterprise_relationship.html.haml b/app/views/admin/enterprise_relationships/_enterprise_relationship.html.haml new file mode 100644 index 0000000000..3f93027ca1 --- /dev/null +++ b/app/views/admin/enterprise_relationships/_enterprise_relationship.html.haml @@ -0,0 +1,5 @@ +%td {{ enterprise_relationship.parent_name }} +%td permits +%td {{ enterprise_relationship.child_name }} +%td.actions + %a.delete-enterprise-relationship.icon-trash.no-text{'ng-click' => 'delete(enterprise_relationship)'} diff --git a/app/views/admin/enterprise_relationships/_form.html.haml b/app/views/admin/enterprise_relationships/_form.html.haml new file mode 100644 index 0000000000..5cc10b0fe1 --- /dev/null +++ b/app/views/admin/enterprise_relationships/_form.html.haml @@ -0,0 +1,9 @@ +%tr + %td + %select{name: "enterprise_relationship_parent_name", "ng-model" => "parent_id", "ng-options" => "e.id as e.name for e in Enterprises.enterprises"} + %td permits + %td + %select{name: "enterprise_relationship_child_name", "ng-model" => "child_id", "ng-options" => "e.id as e.name for e in Enterprises.enterprises"} + %td.actions + %input{type: "button", value: "Create", "ng-click" => "create()"} + .errors {{ EnterpriseRelationships.create_errors }} diff --git a/app/views/admin/enterprise_relationships/index.html.haml b/app/views/admin/enterprise_relationships/index.html.haml new file mode 100644 index 0000000000..e0e289efcf --- /dev/null +++ b/app/views/admin/enterprise_relationships/index.html.haml @@ -0,0 +1,15 @@ +- content_for :page_title do + Enterprise Relationships + += render 'admin/shared/enterprises_sub_menu' + +%div{"ng-app" => "ofn.admin", "ng-controller" => "AdminEnterpriseRelationshipsCtrl"} + = render 'data' + + %input.search{"ng-model" => "query", "placeholder" => "Search"} + + %table#enterprise-relationships + %tbody + = render 'form' + %tr{"ng-repeat" => "enterprise_relationship in EnterpriseRelationships.enterprise_relationships | filter:query"} + = render 'enterprise_relationship' diff --git a/app/views/admin/enterprises/index.html.erb b/app/views/admin/enterprises/index.html.erb index d2917bcc45..1795b17950 100644 --- a/app/views/admin/enterprises/index.html.erb +++ b/app/views/admin/enterprises/index.html.erb @@ -8,6 +8,8 @@ <% end %> +<%= render 'admin/shared/enterprises_sub_menu' %> + <%= form_for @enterprise_set, :url => main_app.bulk_update_admin_enterprises_path do |f| %> diff --git a/app/views/admin/json/_enterprise_relationship.rabl b/app/views/admin/json/_enterprise_relationship.rabl new file mode 100644 index 0000000000..9be152ec5c --- /dev/null +++ b/app/views/admin/json/_enterprise_relationship.rabl @@ -0,0 +1,11 @@ +object @enterprise_relationship + +attributes :id, :parent_id, :child_id + +node :parent_name do |enterprise_relationship| + enterprise_relationship.parent.name +end + +node :child_name do |enterprise_relationship| + enterprise_relationship.child.name +end diff --git a/app/views/admin/json/_enterprise_relationships.rabl b/app/views/admin/json/_enterprise_relationships.rabl new file mode 100644 index 0000000000..aad55b9770 --- /dev/null +++ b/app/views/admin/json/_enterprise_relationships.rabl @@ -0,0 +1,2 @@ +collection @enterprise_relationships +extends "admin/json/enterprise_relationship" diff --git a/app/views/admin/json/_enterprises.rabl b/app/views/admin/json/_enterprises.rabl new file mode 100644 index 0000000000..29e1dc7bf6 --- /dev/null +++ b/app/views/admin/json/_enterprises.rabl @@ -0,0 +1,3 @@ +collection @enterprises + +attributes :id, :name diff --git a/app/views/admin/shared/_enterprises_sub_menu.html.haml b/app/views/admin/shared/_enterprises_sub_menu.html.haml new file mode 100644 index 0000000000..4a793689b7 --- /dev/null +++ b/app/views/admin/shared/_enterprises_sub_menu.html.haml @@ -0,0 +1,4 @@ += content_for :sub_menu do + %ul#sub_nav.inline-menu{"data-hook" => "admin_order_sub_tabs"} + = tab :enterprises, url: main_app.admin_enterprises_path + = tab :relationships, url: main_app.admin_enterprise_relationships_path, match_path: '/enterprise_relationships' diff --git a/app/views/json/_injection.html.haml b/app/views/json/_injection.html.haml new file mode 100644 index 0000000000..95b921406b --- /dev/null +++ b/app/views/json/_injection.html.haml @@ -0,0 +1,2 @@ +:javascript + angular.module('Darkswarm').value("#{name.to_s}", #{render "json/#{partial.to_s}"}) diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index 5c2dcaee66..edeffafeed 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -15,16 +15,16 @@ = csrf_meta_tags %body.off-canvas{"ng-app" => "Darkswarm"} + = inject_json "currentHub", "current_hub" + = inject_json "user", "current_user" + .off-canvas-wrap{offcanvas: true} .inner-wrap - = render partial: "shared/current_hub" - = render partial: "shared/current_user" = render partial: "shared/menu/menu" + = display_flash_messages %ofn-flash - -#= render "shared/sidebar" - %section{ role: "main" } = yield diff --git a/app/views/modals/_producer.html.haml b/app/views/modals/_producer.html.haml index 691e9378d3..056f9e488f 100644 --- a/app/views/modals/_producer.html.haml +++ b/app/views/modals/_producer.html.haml @@ -1,10 +1,9 @@ %ofn-modal{title: "{{ producer.name }}"} - #producer_modal{bindonce: true} + #producer_modal .row .small-12.columns - %img{"bo-src" => "producer.promo_image"} + %img{"ng-src" => "producer.promo_image"} %h3 {{ producer.name }} - .row .small-6.columns %p diff --git a/app/views/shop/products/_modal.html.haml b/app/views/modals/_product.html.haml similarity index 73% rename from app/views/shop/products/_modal.html.haml rename to app/views/modals/_product.html.haml index 29a023704f..acca8f919b 100644 --- a/app/views/shop/products/_modal.html.haml +++ b/app/views/modals/_product.html.haml @@ -1,2 +1,4 @@ %ofn-modal{title: "{{product.name}}"} + + {{ product | json }} {{ product.description }} diff --git a/app/views/shared/_current_hub.haml b/app/views/shared/_current_hub.haml deleted file mode 100644 index 5a0ff7c564..0000000000 --- a/app/views/shared/_current_hub.haml +++ /dev/null @@ -1,2 +0,0 @@ -:javascript - angular.module('Darkswarm').value('currentHub', #{render "json/current_hub"}) diff --git a/app/views/shared/_current_user.haml b/app/views/shared/_current_user.haml deleted file mode 100644 index 9745a71313..0000000000 --- a/app/views/shared/_current_user.haml +++ /dev/null @@ -1,2 +0,0 @@ -:javascript - angular.module('Darkswarm').value('user', #{render "json/current_user"}) diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml index 5e777a5dbb..e41c6ef440 100644 --- a/app/views/shop/products/_summary.html.haml +++ b/app/views/shop/products/_summary.html.haml @@ -6,11 +6,10 @@ %img{"bo-src" => "product.primary_taxon.icon", "ng-click" => "ordering.order = 'primary_taxon.name'", name: "{{product.primary_taxon.name}}"} - {{ product.name}} - -#= render partial: "shop/products/modal" + = render partial: "modals/product" .small-5.columns.summary-header - {{ product.supplier.name }} + = render partial: "modals/producer" .small-2.columns.summary-price.text-right.price %span{"ng-if" => "hasVariants"} diff --git a/config/routes.rb b/config/routes.rb index 310d1d9e4d..973cb288cc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -41,6 +41,8 @@ Openfoodnetwork::Application.routes.draw do post :bulk_update, :on => :collection, :as => :bulk_update end + resources :enterprise_relationships + resources :enterprise_fees do post :bulk_update, :on => :collection, :as => :bulk_update end diff --git a/spec/controllers/spree/orders_controller_spec.rb b/spec/controllers/spree/orders_controller_spec.rb index 53c7be68f0..e6c9b91894 100644 --- a/spec/controllers/spree/orders_controller_spec.rb +++ b/spec/controllers/spree/orders_controller_spec.rb @@ -15,6 +15,7 @@ describe Spree::OrdersController do controller.stub(:current_order_cycle).and_return(order_cycle) controller.stub(:current_order).and_return order order.stub_chain(:line_items, :empty?).and_return true + session[:access_token] = order.token spree_get :edit response.should redirect_to shop_path end diff --git a/spec/factories.rb b/spec/factories.rb index 13c0bd0e8e..6da7824d47 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -96,6 +96,9 @@ FactoryGirl.define do is_distributor true end + factory :enterprise_relationship do + end + factory :enterprise_group, :class => EnterpriseGroup do name 'Enterprise group' description 'this is a group' @@ -187,6 +190,10 @@ FactoryGirl.modify do distributors { [Enterprise.is_distributor.first || FactoryGirl.create(:distributor_enterprise)] } end + factory :option_type do + # Prevent inconsistent ordering in specs when all option types have the same (0) position + sequence(:position) + end end diff --git a/spec/features/admin/enterprise_relationships_spec.rb b/spec/features/admin/enterprise_relationships_spec.rb new file mode 100644 index 0000000000..ea95f86ba4 --- /dev/null +++ b/spec/features/admin/enterprise_relationships_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +feature %q{ + As an Administrator + I want to manage relationships between enterprises +}, js: true do + include AuthenticationWorkflow + include WebHelper + + before { login_to_admin_section } + + + scenario "listing relationships" do + # Given some enterprises with relationships + e1, e2, e3, e4 = create(:enterprise), create(:enterprise), create(:enterprise), create(:enterprise) + create(:enterprise_relationship, parent: e1, child: e2) + create(:enterprise_relationship, parent: e3, child: e4) + + # When I go to the relationships page + click_link 'Enterprises' + click_link 'Relationships' + + # Then I should see the relationships + within('table#enterprise-relationships') do + page.should have_table_row [e1.name, 'permits', e2.name, ''] + page.should have_table_row [e3.name, 'permits', e4.name, ''] + end + end + + + scenario "creating a relationship" do + e1 = create(:enterprise, name: 'One') + e2 = create(:enterprise, name: 'Two') + + visit admin_enterprise_relationships_path + select 'One', from: 'enterprise_relationship_parent_name' + select 'Two', from: 'enterprise_relationship_child_name' + click_button 'Create' + + page.should have_table_row [e1.name, 'permits', e2.name, ''] + EnterpriseRelationship.where(parent_id: e1, child_id: e2).should be_present + end + + + scenario "attempting to create a relationship with invalid data" do + e1 = create(:enterprise, name: 'One') + e2 = create(:enterprise, name: 'Two') + create(:enterprise_relationship, parent: e1, child: e2) + + expect do + # When I attempt to create a duplicate relationship + visit admin_enterprise_relationships_path + select 'One', from: 'enterprise_relationship_parent_name' + select 'Two', from: 'enterprise_relationship_child_name' + click_button 'Create' + + # Then I should see an error message + page.should have_content "That relationship is already established." + end.to change(EnterpriseRelationship, :count).by(0) + end + + + scenario "deleting a relationship" do + e1 = create(:enterprise, name: 'One') + e2 = create(:enterprise, name: 'Two') + er = create(:enterprise_relationship, parent: e1, child: e2) + + visit admin_enterprise_relationships_path + page.should have_table_row [e1.name, 'permits', e2.name, ''] + + first("a.delete-enterprise-relationship").click + + page.should_not have_table_row [e1.name, 'permits', e2.name, ''] + EnterpriseRelationship.where(id: er.id).should be_empty + end +end diff --git a/spec/features/consumer/authentication_spec.rb b/spec/features/consumer/authentication_spec.rb index 77b60290d1..76e4a20877 100644 --- a/spec/features/consumer/authentication_spec.rb +++ b/spec/features/consumer/authentication_spec.rb @@ -5,7 +5,27 @@ feature "Authentication", js: true do describe "login" do let(:user) { create(:user, password: "password", password_confirmation: "password") } - describe "newskool" do + describe "With redirects" do + scenario "logging in with a redirect set" do + visit groups_path(anchor: "login?after_login=#{producers_path}") + fill_in "Email", with: user.email + fill_in "Password", with: user.password + click_login_button + page.should have_content "Select a producer from the list below" + current_path.should == producers_path + end + + scenario "logging into admin redirects home, then back to admin" do + visit spree.admin_path + fill_in "Email", with: user.email + fill_in "Password", with: user.password + click_login_button + page.should have_content "Dashboard" + current_path.should == spree.admin_path + end + end + + describe "Loggin in from the home page" do before do visit root_path end diff --git a/spec/javascripts/unit/darkswarm/controllers/hub_node_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/hub_node_controller_spec.js.coffee index a2d14f5811..cb77cb1703 100644 --- a/spec/javascripts/unit/darkswarm/controllers/hub_node_controller_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/controllers/hub_node_controller_spec.js.coffee @@ -19,14 +19,3 @@ describe "HubNodeCtrl", -> expect(scope.current()).toEqual false scope.hub = {id: 99} expect(scope.current()).toEqual true - - it "knows whether selecting this hub will empty the cart", -> - CurrentHub.id = undefined - expect(scope.emptiesCart()).toEqual false - - CurrentHub.id = 99 - scope.hub.id = 99 - expect(scope.emptiesCart()).toEqual false - - scope.hub.id = 1 - expect(scope.emptiesCart()).toEqual true diff --git a/spec/javascripts/unit/darkswarm/controllers/products/product_node_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/products/product_node_controller_spec.js.coffee new file mode 100644 index 0000000000..4b9e404b9e --- /dev/null +++ b/spec/javascripts/unit/darkswarm/controllers/products/product_node_controller_spec.js.coffee @@ -0,0 +1,24 @@ +describe "ProductNodeCtrl", -> + ctrl = null + scope = null + product = + id: 99 + price: 10.00 + variants: [] + + beforeEach -> + module('Darkswarm') + inject ($controller) -> + scope = + product: product + ctrl = $controller 'ProductNodeCtrl', {$scope: scope} + + describe "determining the price to display for a product", -> + it "displays the product price when the product does not have variants", -> + expect(scope.price()).toEqual 10.00 + + it "displays the minimum variant price when the product has variants", -> + scope.product = + price: 11 + variants: [{price: 22}, {price: 33}] + expect(scope.price()).toEqual 22 diff --git a/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee index 269c8385b8..685d495039 100644 --- a/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee @@ -1,47 +1,21 @@ -describe 'All controllers', -> - describe 'ProductsCtrl', -> - ctrl = null - scope = null - event = null - Product = null +describe 'ProductsCtrl', -> + ctrl = null + scope = null + event = null + Product = null - beforeEach -> - module('Darkswarm') - Product = - all: -> - update: -> - data: "testy mctest" - OrderCycle = - order_cycle: {} - - inject ($controller) -> - scope = {} - ctrl = $controller 'ProductsCtrl', {$scope: scope, Product: Product, OrderCycle: OrderCycle} - - it 'fetches products from Product', -> - expect(scope.data).toEqual 'testy mctest' - - describe "determining the price to display for a product", -> - it "displays the product price when the product does not have variants", -> - product = {variants: [], price: 12.34} - expect(scope.productPrice(product)).toEqual 12.34 - - it "displays the minimum variant price when the product has variants", -> - product = - price: 11 - variants: [{price: 22}, {price: 33}] - expect(scope.productPrice(product)).toEqual 22 - - describe 'OrderCycleCtrl', -> - ctrl = null - scope = null - event = null - product_ctrl = null - OrderCycle = null - - beforeEach -> - module 'Darkswarm' + beforeEach -> + module('Darkswarm') + Product = + all: -> + update: -> + data: "testy mctest" + OrderCycle = + order_cycle: {} + + inject ($controller) -> scope = {} - inject ($controller) -> - scope = {} - ctrl = $controller 'OrderCycleCtrl', {$scope: scope} + ctrl = $controller 'ProductsCtrl', {$scope: scope, Product: Product, OrderCycle: OrderCycle} + + it 'fetches products from Product', -> + expect(scope.data).toEqual 'testy mctest' diff --git a/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee index 0462e92952..fedcf23629 100644 --- a/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee @@ -26,8 +26,10 @@ describe 'Order service', -> } angular.module('Darkswarm').value('order', orderData) module 'Darkswarm' + inject ($injector, _$httpBackend_)-> $httpBackend = _$httpBackend_ + $httpBackend.expectGET("/shop/products").respond 200, [] Order = $injector.get("Order") Navigation = $injector.get("Navigation") flash = $injector.get("flash") diff --git a/spec/javascripts/unit/darkswarm/product_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/product_spec.js.coffee similarity index 86% rename from spec/javascripts/unit/darkswarm/product_spec.js.coffee rename to spec/javascripts/unit/darkswarm/services/product_spec.js.coffee index 7108d819af..260074a981 100644 --- a/spec/javascripts/unit/darkswarm/product_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/product_spec.js.coffee @@ -10,5 +10,5 @@ describe 'Product service', -> it "Fetches products from the backend on init", -> $httpBackend.expectGET("/shop/products").respond([{test : "cats"}]) - products = Product.all() $httpBackend.flush() + expect(Product.data.products[0].test).toEqual "cats" diff --git a/spec/models/enterprise_relationship_spec.rb b/spec/models/enterprise_relationship_spec.rb new file mode 100644 index 0000000000..7cca07472e --- /dev/null +++ b/spec/models/enterprise_relationship_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe EnterpriseRelationship do + describe "scopes" do + it "sorts by parent, child enterprise name" do + e1 = create(:enterprise, name: 'A') + e2 = create(:enterprise, name: 'B') + e3 = create(:enterprise, name: 'C') + er1 = create(:enterprise_relationship, parent: e1, child: e3) + er2 = create(:enterprise_relationship, parent: e2, child: e1) + er3 = create(:enterprise_relationship, parent: e1, child: e2) + + EnterpriseRelationship.by_name.should == [er3, er1, er2] + end + end +end diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index 06c4c0850e..f375b8890a 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -31,10 +31,10 @@ describe Enterprise do let(:e) { create(:distributor_enterprise) } let(:p) { create(:supplier_enterprise) } let(:c) { create(:distributor_enterprise) } - before do - EnterpriseRelationship.create! parent_id: p.id, child_id: e.id - EnterpriseRelationship.create! parent_id: e.id, child_id: c.id - end + + let!(:er1) { create(:enterprise_relationship, parent_id: p.id, child_id: e.id) } + let!(:er2) { create(:enterprise_relationship, parent_id: e.id, child_id: c.id) } + it "finds relatives" do e.relatives.sort.should == [p, c].sort end diff --git a/spec/support/matchers/table_matchers.rb b/spec/support/matchers/table_matchers.rb new file mode 100644 index 0000000000..146002b751 --- /dev/null +++ b/spec/support/matchers/table_matchers.rb @@ -0,0 +1,43 @@ +RSpec::Matchers.define :have_table_row do |row| + + match_for_should do |node| + @row = row + + false_on_timeout_error do + wait_until { rows_under(node).include? row } + end + end + + match_for_should_not do |node| + @row = row + + false_on_timeout_error do + # Without this sleep, we trigger capybara's wait when looking up the table, for the full + # period of default_wait_time. + sleep 0.1 + wait_until { !rows_under(node).include? row } + end + end + + failure_message_for_should do |text| + "expected to find table row #{@row}" + end + + failure_message_for_should_not do |text| + "expected not to find table row #{@row}" + end + + + def rows_under(node) + node.all('tr').map { |tr| tr.all('th, td').map(&:text) } + end + + def false_on_timeout_error + yield + rescue TimeoutError + false + else + true + end + +end diff --git a/spec/views/admin/json/enterprise_relationships_rabl_spec.rb b/spec/views/admin/json/enterprise_relationships_rabl_spec.rb new file mode 100644 index 0000000000..9b72a0d45b --- /dev/null +++ b/spec/views/admin/json/enterprise_relationships_rabl_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe "admin/json/_enterprise_relationships.json.rabl" do + let(:parent) { create(:enterprise) } + let(:child) { create(:enterprise) } + let(:enterprise_relationship) { create(:enterprise_relationship, parent: parent, child: child) } + let(:render) { Rabl.render([enterprise_relationship], 'admin/json/enterprise_relationships', view_path: 'app/views', scope: RablHelper::FakeContext.instance) } + + it "renders a list of enterprise relationships" do + render.should have_json_type(Array).at_path '' + render.should have_json_type(Object).at_path '0' + end + + it "renders enterprise ids" do + render.should be_json_eql(parent.id).at_path '0/parent_id' + render.should be_json_eql(child.id).at_path '0/child_id' + end + + it "renders enterprise names" do + render.should be_json_eql(parent.name.to_json).at_path '0/parent_name' + render.should be_json_eql(child.name.to_json).at_path '0/child_name' + end +end