mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge branch 'master' into ent_types_frontend
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -42,6 +42,7 @@ gem 'gmaps4rails'
|
||||
gem 'spinjs-rails'
|
||||
gem 'rack-ssl', :require => 'rack/ssl'
|
||||
gem 'custom_error_message', :github => 'jeremydurham/custom-err-msg'
|
||||
gem 'angularjs-file-upload-rails', '~> 1.1.0'
|
||||
|
||||
gem 'foreigner'
|
||||
gem 'immigrant'
|
||||
|
||||
@@ -153,6 +153,7 @@ GEM
|
||||
railties (>= 3.1)
|
||||
sprockets
|
||||
tilt
|
||||
angularjs-file-upload-rails (1.1.0)
|
||||
angularjs-rails (1.2.13)
|
||||
ansi (1.4.2)
|
||||
arel (3.0.3)
|
||||
@@ -505,6 +506,7 @@ DEPENDENCIES
|
||||
active_model_serializers
|
||||
andand
|
||||
angular-rails-templates
|
||||
angularjs-file-upload-rails (~> 1.1.0)
|
||||
angularjs-rails
|
||||
awesome_print
|
||||
aws-sdk
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#= require ../shared/bindonce.min.js
|
||||
#= require ../shared/ng-infinite-scroll.min.js
|
||||
#= require ../shared/angular-local-storage.js
|
||||
#= require angularjs-file-upload
|
||||
|
||||
|
||||
#= require angular-rails-templates
|
||||
#= require_tree ../templates
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
angular.module('Darkswarm').controller "EnterpriseImageCtrl", ($scope, EnterpriseImageService) ->
|
||||
$scope.imageStep = 'logo'
|
||||
|
||||
$scope.imageSteps = ['logo', 'promo']
|
||||
|
||||
$scope.imageUploader = EnterpriseImageService.imageUploader
|
||||
|
||||
$scope.imageSelect = (image_step) ->
|
||||
EnterpriseImageService.imageSrc = null
|
||||
$scope.imageStep = image_step
|
||||
|
||||
$scope.imageSrc = ->
|
||||
EnterpriseImageService.imageSrc
|
||||
@@ -12,4 +12,4 @@ Darkswarm.controller "RegistrationFormCtrl", ($scope, RegistrationService, Enter
|
||||
EnterpriseRegistrationService.update(nextStep) if $scope.valid(form)
|
||||
|
||||
$scope.selectIfValid = (nextStep, form) ->
|
||||
RegistrationService.select(nextStep) if $scope.valid(form)
|
||||
RegistrationService.select(nextStep) if $scope.valid(form)
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
window.Darkswarm = angular.module("Darkswarm", ["ngResource",
|
||||
'mm.foundation',
|
||||
'angularLocalStorage',
|
||||
'pasvaz.bindonce',
|
||||
'infinite-scroll',
|
||||
'angular-flash.service',
|
||||
window.Darkswarm = angular.module("Darkswarm", ["ngResource",
|
||||
'mm.foundation',
|
||||
'angularLocalStorage',
|
||||
'pasvaz.bindonce',
|
||||
'infinite-scroll',
|
||||
'angular-flash.service',
|
||||
'templates',
|
||||
'ngSanitize',
|
||||
'ngAnimate',
|
||||
'google-maps',
|
||||
'duScroll',
|
||||
'angularFileUpload',
|
||||
]).config ($httpProvider, $tooltipProvider, $locationProvider, $anchorScrollProvider) ->
|
||||
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers.put['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers['common']['X-Requested-With'] = 'XMLHttpRequest'
|
||||
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers.put['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers['common']['X-Requested-With'] = 'XMLHttpRequest'
|
||||
$httpProvider.defaults.headers.common.Accept = "application/json, text/javascript, */*"
|
||||
|
||||
# This allows us to trigger these two events on tooltips
|
||||
@@ -20,4 +21,3 @@ window.Darkswarm = angular.module("Darkswarm", ["ngResource",
|
||||
|
||||
# We manually handle our scrolling
|
||||
$anchorScrollProvider.disableAutoScrolling()
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Darkswarm.factory "EnterpriseImageService", (FileUploader, spreeApiKey) ->
|
||||
new class EnterpriseImageService
|
||||
imageSrc: null
|
||||
|
||||
imageUploader: new FileUploader
|
||||
headers:
|
||||
'X-Spree-Token': spreeApiKey
|
||||
autoUpload: true
|
||||
|
||||
configure: (enterprise) =>
|
||||
@imageUploader.url = "/api/enterprises/#{enterprise.id}/update_image"
|
||||
@imageUploader.onSuccessItem = (image, response) => @imageSrc = response
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService, CurrentUser, spreeApiKey, Loading, availableCountries, enterpriseAttributes) ->
|
||||
Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService, EnterpriseImageService, CurrentUser, spreeApiKey, Loading, availableCountries, enterpriseAttributes) ->
|
||||
new class EnterpriseRegistrationService
|
||||
enterprise:
|
||||
user_ids: [CurrentUser.id]
|
||||
@@ -22,6 +22,7 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
|
||||
).success((data) =>
|
||||
Loading.clear()
|
||||
@enterprise.id = data
|
||||
EnterpriseImageService.configure(@enterprise)
|
||||
RegistrationService.select('about')
|
||||
).error((data) =>
|
||||
Loading.clear()
|
||||
@@ -54,4 +55,4 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
|
||||
enterprise[key] = value
|
||||
enterprise.address_attributes = @enterprise.address if @enterprise.address?
|
||||
enterprise.address_attributes.country_id = @enterprise.country.id if @enterprise.country?
|
||||
enterprise
|
||||
enterprise
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.factory "RegistrationService", (Navigation, $modal, Loading)->
|
||||
angular.module('Darkswarm').factory "RegistrationService", (Navigation, $modal, Loading)->
|
||||
|
||||
new class RegistrationService
|
||||
constructor: ->
|
||||
@@ -20,4 +20,4 @@ Darkswarm.factory "RegistrationService", (Navigation, $modal, Loading)->
|
||||
|
||||
close: ->
|
||||
Loading.message = "Taking you back to the home page"
|
||||
Navigation.go "/"
|
||||
Navigation.go "/"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ enterprise.name }}
|
||||
|
||||
%ng-include{ src: "'registration/steps.html'" }
|
||||
%form{ name: 'about', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('social',about)" } }
|
||||
%form{ name: 'about', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('images',about)" } }
|
||||
.row
|
||||
.small-12.columns
|
||||
.alert-box.alert{"data-alert" => ""}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
.container#registration-images
|
||||
.container#registration-images{ 'nv-file-drop' => true, uploader: "imageUploader", options:"{ alias: imageStep }", ng: { controller: "EnterpriseImageCtrl" } }
|
||||
.header
|
||||
%h2 Thanks!
|
||||
%h5 Let's upload some pretty pictures so your profile looks great! :)
|
||||
%ng-include{ src: "'registration/steps.html'" }
|
||||
.row.content
|
||||
%form{ name: 'images', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "select('social')" } }
|
||||
.row{ ng: { repeat: 'image_step in imageSteps', show: "imageStep == image_step" } }
|
||||
%ng-include{ src: "'registration/images/'+ image_step + '.html'" }
|
||||
|
||||
.row.buttons
|
||||
.small-12.columns
|
||||
%input.button.primary.left{ type: "button", value: "Back", ng: { click: "select('about')" } }
|
||||
|
||||
%input.button.primary.right{ type: "button", value: "Continue", ng: { click: "select('social')" } }
|
||||
|
||||
|
||||
.row.buttons.pad-top{ ng: { if: "imageStep == 'logo'" } }
|
||||
.small-12.columns
|
||||
%input.button.primary{ type: "button", value: "Back", ng: { click: "select('about')" } }
|
||||
|
||||
%input.button.primary{ type: "button", value: "Continue", ng: { click: "imageSelect('promo')" } }
|
||||
|
||||
.row.buttons.pad-top{ ng: { if: "imageStep == 'promo'" } }
|
||||
.small-12.columns
|
||||
%input.button.primary{ type: "button", value: "Back", ng: { click: "imageSelect('logo')" } }
|
||||
|
||||
%input.button.primary{ type: "submit", value: "Continue" }
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
.small-12.medium-12.large-6.columns
|
||||
.row
|
||||
.small-12.columns.center
|
||||
.row
|
||||
.small-12.columns.center
|
||||
%h4
|
||||
Step 1. Select Logo Image
|
||||
.row
|
||||
.small-12.columns.center
|
||||
%span.small
|
||||
Tip: Square images will work best, preferably at least 300×300px
|
||||
.row.pad-top
|
||||
.small-12.columns
|
||||
.image-select.small-12.columns
|
||||
%label.small-12.columns.button{ for: 'image-select' } Choose a logo image
|
||||
%input#image-select{ type: 'file', hidden: true, 'nv-file-select' => true, uploader: "imageUploader", options: '{ alias: imageStep }' }
|
||||
.row.show-for-large-up
|
||||
.large-12.columns
|
||||
%span#or.large-12.columns
|
||||
OR
|
||||
.row.show-for-large-up
|
||||
.large-12.columns
|
||||
#image-over{ 'nv-file-over' => true, uploader: "imageUploader" }
|
||||
Drag and drop your logo here
|
||||
.small-12.medium-12.large-6.columns
|
||||
.row
|
||||
.small-12.columns.center
|
||||
.row
|
||||
.small-12.columns.center
|
||||
%h4
|
||||
Step 2. Review Your Logo
|
||||
.row
|
||||
.small-12.columns.center
|
||||
%span.small
|
||||
Tip: for best results, your logo should fill the available space
|
||||
.row.pad-top
|
||||
.small-12.columns.center
|
||||
#image-placeholder.logo
|
||||
%img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
|
||||
.message{ ng: { hide: "imageSrc()" } }
|
||||
Your logo will appear here for review once uploaded
|
||||
@@ -0,0 +1,39 @@
|
||||
.small-12.medium-12.large-12.columns
|
||||
.row
|
||||
.small-12.columns.center
|
||||
%h4
|
||||
Step 3. Select Promo Image
|
||||
.row
|
||||
.small-12.medium-12.large-5.columns.center
|
||||
.row
|
||||
.small-12.columns.center
|
||||
%span.small
|
||||
Tip: Shown as a banner, preferred size is 1200×260px
|
||||
.row.pad-top
|
||||
.small-12.columns
|
||||
.image-select.small-12.columns
|
||||
%label.small-12.columns.button{ for: 'image-select' } Choose a promo image
|
||||
%input#image-select{ type: 'file', hidden: true, 'nv-file-select' => true, uploader: "imageUploader", options: '{ alias: imageStep }' }
|
||||
.large-2.columns
|
||||
%span#or.horizontal.large-12.columns
|
||||
OR
|
||||
.large-5.columns
|
||||
#image-over{ 'nv-file-over' => true, uploader: "imageUploader" }
|
||||
Drag and drop your promo here
|
||||
.small-12.medium-12.large-12.columns.pad-top
|
||||
.row
|
||||
.small-12.columns.center
|
||||
%h4
|
||||
Step 4. Review Your Promo Banner
|
||||
.row
|
||||
.small-12.columns.center
|
||||
.row
|
||||
.small-12.columns.center
|
||||
%span.small
|
||||
Tip: for best results, your promo image should fill the available space
|
||||
.row.pad-top
|
||||
.small-12.columns.center
|
||||
#image-placeholder.promo
|
||||
%img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
|
||||
.message{ ng: { hide: "imageSrc()" } }
|
||||
Your logo will appear here for review once uploaded
|
||||
@@ -6,35 +6,34 @@
|
||||
.small-12.medium-3.large-2.columns.text-right.hide-for-small-only
|
||||
%img{:src => "/assets/potatoes.png"}
|
||||
.small-12.medium-9.large-10.columns
|
||||
%p
|
||||
Your profile gives you an online presence on the
|
||||
%strong Open Food Network,
|
||||
%p
|
||||
Your profile gives you an online presence on the
|
||||
%strong Open Food Network,
|
||||
allowing you to easily connect with potential customers or partners. You can always choose to update your info later, as well as choose to upgrade your Profile to and Online Store, where you can sell products, track orders and receive payments. Creating a profile takes about 5-10 minutes.
|
||||
.row{ 'data-equalizer' => true }
|
||||
.small-12.medium-6.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
|
||||
%h5 You'll need the following:
|
||||
%ul.check-list
|
||||
%li
|
||||
%li
|
||||
Your enterprise address and contact details
|
||||
%li
|
||||
%li
|
||||
Your logo image
|
||||
%li
|
||||
%li
|
||||
A pretty picture for your profile header
|
||||
%li
|
||||
%li
|
||||
Some 'About Us' text
|
||||
|
||||
.small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true}
|
||||
.highlight-box
|
||||
%h5 Your profile entitles you to:
|
||||
%ul.small-block-grid-1
|
||||
%li
|
||||
%li
|
||||
%i.ofn-i_020-search
|
||||
A searchable listing
|
||||
%li
|
||||
%li
|
||||
%i.ofn-i_040-hub
|
||||
A pin on the OFN map
|
||||
.row
|
||||
.small-12.columns
|
||||
%hr
|
||||
%input.button.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
|
||||
|
||||
@@ -30,6 +30,6 @@
|
||||
|
||||
.row.buttons
|
||||
.small-12.columns
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('about')" } }
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('images')" } }
|
||||
|
||||
%input.button.primary{ type: "submit", value: "Continue" }
|
||||
%input.button.primary{ type: "submit", value: "Continue" }
|
||||
|
||||
@@ -80,6 +80,53 @@
|
||||
color: #333
|
||||
@include box-shadow(inset 0 0 1px 0 #fff)
|
||||
|
||||
|
||||
.image-select
|
||||
label
|
||||
font-size: 18px
|
||||
padding: 21px 0px
|
||||
#logo-select
|
||||
display: none
|
||||
|
||||
#image-over
|
||||
font-size: 18px
|
||||
padding: 41px 0px
|
||||
border: 3px dashed #494949
|
||||
text-align: center
|
||||
font-weight: bold
|
||||
color: #494949
|
||||
&.nv-file-over
|
||||
background-color: #78cd91
|
||||
|
||||
#or
|
||||
text-align: center
|
||||
font-weight: bold
|
||||
font-size: 18px
|
||||
padding: 21px 0px
|
||||
&.horizontal
|
||||
padding: 41px 0px
|
||||
|
||||
#image-placeholder
|
||||
font-size: 18px
|
||||
font-weight: bold
|
||||
color: #373737
|
||||
background-color: #e1e1e1
|
||||
text-align: center
|
||||
border: 3px dashed #494949
|
||||
margin-left: auto
|
||||
margin-right: auto
|
||||
&.logo
|
||||
.message
|
||||
padding-top: 6em
|
||||
width: 306px
|
||||
height: 306px
|
||||
&.promo
|
||||
.message
|
||||
padding-top: 4em
|
||||
width: 726px
|
||||
height: 166px
|
||||
|
||||
|
||||
#registration-details
|
||||
#enterprise-types
|
||||
a.panel
|
||||
@@ -112,4 +159,3 @@
|
||||
p
|
||||
clear: both
|
||||
font-size: 0.875rem
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ module Admin
|
||||
before_filter :check_bulk_type, only: :bulk_update
|
||||
before_filter :override_owner, only: :create
|
||||
before_filter :check_owner, only: :update
|
||||
before_filter :check_bulk_owner, only: :bulk_update
|
||||
|
||||
helper 'spree/products'
|
||||
include OrderCyclesHelper
|
||||
@@ -79,11 +80,19 @@ module Admin
|
||||
end
|
||||
|
||||
def check_owner
|
||||
unless spree_current_user == @enterprise.owner || spree_current_user.admin?
|
||||
unless ( spree_current_user == @enterprise.owner ) || spree_current_user.admin?
|
||||
params[:enterprise].delete :owner_id
|
||||
end
|
||||
end
|
||||
|
||||
def check_bulk_owner
|
||||
unless spree_current_user.admin?
|
||||
params[:enterprise_set][:collection_attributes].each do |i, enterprise_params|
|
||||
enterprise_params.delete :owner_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Overriding method on Spree's resource controller
|
||||
def location_after_save
|
||||
if params[:enterprise].key? :producer_properties_attributes
|
||||
|
||||
@@ -27,9 +27,9 @@ module Api
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, Enterprise
|
||||
|
||||
@enterprise = Enterprise.find(params[:id])
|
||||
authorize! :update, @enterprise
|
||||
|
||||
if @enterprise.update_attributes(params[:enterprise])
|
||||
render text: @enterprise.id, :status => 200
|
||||
else
|
||||
@@ -37,6 +37,19 @@ module Api
|
||||
end
|
||||
end
|
||||
|
||||
def update_image
|
||||
@enterprise = Enterprise.find(params[:id])
|
||||
authorize! :update, @enterprise
|
||||
|
||||
if params[:logo] && @enterprise.update_attributes( { logo: params[:logo] } )
|
||||
render text: @enterprise.logo.url(:medium), :status => 200
|
||||
elsif params[:promo] && @enterprise.update_attributes( { promo_image: params[:promo] } )
|
||||
render text: @enterprise.promo_image.url(:medium), :status => 200
|
||||
else
|
||||
invalid_resource!(@enterprise)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def override_owner
|
||||
|
||||
@@ -2,7 +2,7 @@ require 'open_food_network/spree_api_key_loader'
|
||||
|
||||
class RegistrationController < BaseController
|
||||
include OpenFoodNetwork::SpreeApiKeyLoader
|
||||
before_filter :load_spree_api_key, only: :index
|
||||
before_filter :load_spree_api_key, only: [:index, :store]
|
||||
before_filter :check_user, except: :authenticate
|
||||
layout 'registration'
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ Spree::Api::ProductsController.class_eval do
|
||||
def bulk_products
|
||||
@products = OpenFoodNetwork::Permissions.new(current_api_user).managed_products.
|
||||
merge(product_scope).
|
||||
order('created_at DESC').
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page]).per(params[:per_page])
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class Enterprise < ActiveRecord::Base
|
||||
path: 'public/images/enterprises/logos/:id/:style/:basename.:extension'
|
||||
|
||||
has_attached_file :promo_image,
|
||||
styles: { large: "1200x260#", thumb: "100x100>" },
|
||||
styles: { large: "1200x260#", medium: "720x156#", thumb: "100x100>" },
|
||||
url: '/images/enterprises/promo_images/:id/:style/:basename.:extension',
|
||||
path: 'public/images/enterprises/promo_images/:id/:style/:basename.:extension'
|
||||
|
||||
|
||||
@@ -2,12 +2,17 @@ class AbilityDecorator
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(user)
|
||||
add_base_abilities user if is_new_user? user
|
||||
add_enterprise_management_abilities user if can_manage_enterprises? user
|
||||
add_product_management_abilities user if can_manage_products? user
|
||||
add_relationship_management_abilities user if can_manage_relationships? user
|
||||
end
|
||||
|
||||
|
||||
def is_new_user?(user)
|
||||
user.enterprises.blank?
|
||||
end
|
||||
|
||||
def can_manage_enterprises?(user)
|
||||
user.enterprises.present?
|
||||
end
|
||||
@@ -22,6 +27,9 @@ class AbilityDecorator
|
||||
can_manage_enterprises? user
|
||||
end
|
||||
|
||||
def add_base_abilities(user)
|
||||
can [:create], Enterprise
|
||||
end
|
||||
|
||||
def add_enterprise_management_abilities(user)
|
||||
# Spree performs authorize! on (:create, nil) when creating a new order from admin, and also (:search, nil)
|
||||
@@ -71,7 +79,7 @@ class AbilityDecorator
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Shipment
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Adjustment
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::ReturnAuthorization
|
||||
|
||||
|
||||
can [:create], OrderCycle
|
||||
can [:admin, :index, :read, :edit, :update, :bulk_update, :clone], OrderCycle do |order_cycle|
|
||||
user.enterprises.include? order_cycle.coordinator
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
%col{style: "width: 5%;"}/
|
||||
- if spree_current_user.admin?
|
||||
%col{style: "width: 12%;"}/
|
||||
%col{style: "width: 18%;"}/
|
||||
- if spree_current_user.admin?
|
||||
%col{style: "width: 18%;"}/
|
||||
%col{style: "width: 25%;"}/
|
||||
%thead
|
||||
%tr{"data-hook" => "enterprises_header"}
|
||||
@@ -25,7 +26,8 @@
|
||||
%th Visible?
|
||||
- if spree_current_user.admin?
|
||||
%th Type
|
||||
%th Owner
|
||||
- if spree_current_user.admin?
|
||||
%th Owner
|
||||
%th
|
||||
%tbody
|
||||
= f.fields_for :collection do |enterprise_form|
|
||||
@@ -41,7 +43,8 @@
|
||||
%td= enterprise_form.check_box :visible
|
||||
- if spree_current_user.admin?
|
||||
%td= enterprise_form.select :type, Enterprise::TYPES, {}, class: 'select2 fullwidth'
|
||||
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
|
||||
- if spree_current_user.admin?
|
||||
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
|
||||
%td{"data-hook" => "admin_users_index_row_actions"}
|
||||
= render 'actions', enterprise: enterprise
|
||||
- if @enterprises.empty?
|
||||
|
||||
@@ -31,6 +31,6 @@
|
||||
|
||||
%section{ role: "main" }
|
||||
= yield
|
||||
|
||||
|
||||
#footer
|
||||
%loading
|
||||
|
||||
@@ -23,6 +23,11 @@ Spree.config do |config|
|
||||
#config.override_actionmailer_config = false
|
||||
end
|
||||
|
||||
# TODO Work out why this is necessary
|
||||
# Seems like classes within OFN module become 'uninitialized' when server reloads
|
||||
# unless the empty module is explicity 'registered' here. Something to do with autoloading?
|
||||
module OpenFoodNetwork
|
||||
end
|
||||
|
||||
# Add calculators category for enterprise fees
|
||||
module Spree
|
||||
@@ -38,7 +43,7 @@ module Spree
|
||||
end
|
||||
|
||||
# Forcing spree to always allow SSL connections
|
||||
# Since we are using config.force_ssl = true
|
||||
# Since we are using config.force_ssl = true
|
||||
# Without this we get a redirect loop: see https://groups.google.com/forum/#!topic/spree-user/NwpqGxJ4klk
|
||||
SslRequirement.module_eval do
|
||||
protected
|
||||
|
||||
@@ -67,6 +67,7 @@ Openfoodnetwork::Application.routes.draw do
|
||||
|
||||
namespace :api do
|
||||
resources :enterprises do
|
||||
post :update_image, on: :member
|
||||
get :managed, on: :collection
|
||||
get :accessible, on: :collection
|
||||
end
|
||||
|
||||
@@ -9,4 +9,4 @@ module OpenFoodNetwork
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,6 +2,7 @@ require 'spec_helper'
|
||||
|
||||
module Admin
|
||||
describe EnterprisesController do
|
||||
include AuthenticationWorkflow
|
||||
let(:distributor_owner) do
|
||||
user = create(:user)
|
||||
user.spree_roles = []
|
||||
@@ -110,36 +111,52 @@ module Admin
|
||||
end
|
||||
|
||||
describe "bulk updating enterprises" do
|
||||
let(:profile_enterprise1) { create(:enterprise, type: 'profile') }
|
||||
let(:profile_enterprise2) { create(:enterprise, type: 'profile') }
|
||||
let!(:original_owner) do
|
||||
user = create_enterprise_user
|
||||
user.enterprise_limit = 2
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let!(:new_owner) do
|
||||
user = create_enterprise_user
|
||||
user.enterprise_limit = 2
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let!(:profile_enterprise1) { create(:enterprise, type: 'profile', owner: original_owner ) }
|
||||
let!(:profile_enterprise2) { create(:enterprise, type: 'profile', owner: original_owner ) }
|
||||
|
||||
context "as manager" do
|
||||
it "does not allow 'type' to be changed" do
|
||||
profile_enterprise1.enterprise_roles.build(user: user).save
|
||||
profile_enterprise2.enterprise_roles.build(user: user).save
|
||||
controller.stub spree_current_user: user
|
||||
bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, type: 'full' }, '1' => { id: profile_enterprise2.id, type: 'full' } } } }
|
||||
it "does not allow 'type' or 'owner' to be changed" do
|
||||
profile_enterprise1.enterprise_roles.build(user: new_owner).save
|
||||
profile_enterprise2.enterprise_roles.build(user: new_owner).save
|
||||
controller.stub spree_current_user: new_owner
|
||||
bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, type: 'full', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, type: 'full', owner_id: new_owner.id } } } }
|
||||
|
||||
spree_put :bulk_update, bulk_enterprise_params
|
||||
profile_enterprise1.reload
|
||||
profile_enterprise2.reload
|
||||
expect(profile_enterprise1.type).to eq 'profile'
|
||||
expect(profile_enterprise2.type).to eq 'profile'
|
||||
expect(profile_enterprise1.owner).to eq original_owner
|
||||
expect(profile_enterprise2.owner).to eq original_owner
|
||||
end
|
||||
end
|
||||
|
||||
context "as super admin" do
|
||||
it "allows 'type' to be changed" do
|
||||
profile_enterprise1.enterprise_roles.build(user: user).save
|
||||
profile_enterprise2.enterprise_roles.build(user: user).save
|
||||
it "allows 'type' and 'owner' to be changed" do
|
||||
profile_enterprise1.enterprise_roles.build(user: new_owner).save
|
||||
profile_enterprise2.enterprise_roles.build(user: new_owner).save
|
||||
controller.stub spree_current_user: admin_user
|
||||
bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, type: 'full' }, '1' => { id: profile_enterprise2.id, type: 'full' } } } }
|
||||
bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, type: 'full', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, type: 'full', owner_id: new_owner.id } } } }
|
||||
|
||||
spree_put :bulk_update, bulk_enterprise_params
|
||||
profile_enterprise1.reload
|
||||
profile_enterprise2.reload
|
||||
expect(profile_enterprise1.type).to eq 'full'
|
||||
expect(profile_enterprise2.type).to eq 'full'
|
||||
expect(profile_enterprise1.owner).to eq new_owner
|
||||
expect(profile_enterprise2.owner).to eq new_owner
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
54
spec/controllers/api/enterprises_controller_spec.rb
Normal file
54
spec/controllers/api/enterprises_controller_spec.rb
Normal file
@@ -0,0 +1,54 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Api
|
||||
describe EnterprisesController do
|
||||
include AuthenticationWorkflow
|
||||
render_views
|
||||
|
||||
let(:enterprise) { create(:distributor_enterprise) }
|
||||
|
||||
before do
|
||||
stub_authentication!
|
||||
Enterprise.stub(:find).and_return(enterprise)
|
||||
end
|
||||
|
||||
describe "as an enterprise manager" do
|
||||
let(:enterprise_manager) { create_enterprise_user }
|
||||
|
||||
before do
|
||||
enterprise_manager.enterprise_roles.build(enterprise: enterprise).save
|
||||
Spree.user_class.stub :find_by_spree_api_key => enterprise_manager
|
||||
end
|
||||
|
||||
describe "submitting a valid image" do
|
||||
before do
|
||||
enterprise.stub(:update_attributes).and_return(true)
|
||||
end
|
||||
|
||||
it "I can update enterprise image" do
|
||||
spree_post :update_image, logo: 'a logo'
|
||||
response.should be_success
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "as an non-managing user" do
|
||||
let(:non_managing_user) { create_enterprise_user }
|
||||
|
||||
before do
|
||||
Spree.user_class.stub :find_by_spree_api_key => non_managing_user
|
||||
end
|
||||
|
||||
describe "submitting a valid image" do
|
||||
before do
|
||||
enterprise.stub(:update_attributes).and_return(true)
|
||||
end
|
||||
|
||||
it "I can't update enterprise image" do
|
||||
spree_post :update_image, logo: 'a logo'
|
||||
assert_unauthorized!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,4 +12,28 @@ describe RegistrationController do
|
||||
response.should redirect_to registration_auth_path(anchor: "signup?after_login=/register/store")
|
||||
end
|
||||
end
|
||||
|
||||
describe "loading data when user is logged in" do
|
||||
let!(:user) { double(:user) }
|
||||
|
||||
before do
|
||||
controller.stub spree_current_user: user
|
||||
user.stub spree_api_key: '12345'
|
||||
user.stub last_incomplete_spree_order: nil
|
||||
end
|
||||
|
||||
describe "index" do
|
||||
it "loads the spree api key" do
|
||||
get :index
|
||||
expect(assigns(:spree_api_key)).to eq '12345'
|
||||
end
|
||||
end
|
||||
|
||||
describe "store" do
|
||||
it "loads the spree api key" do
|
||||
get :store
|
||||
expect(assigns(:spree_api_key)).to eq '12345'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,21 +10,29 @@ FactoryGirl.define do
|
||||
|
||||
after(:create) do |oc|
|
||||
# Suppliers
|
||||
supplier1 = create(:supplier_enterprise)
|
||||
supplier2 = create(:supplier_enterprise)
|
||||
|
||||
# Incoming Exchanges
|
||||
ex1 = create(:exchange, :order_cycle => oc, :incoming => true,
|
||||
:sender => create(:supplier_enterprise), :receiver => oc.coordinator)
|
||||
:sender => supplier1, :receiver => oc.coordinator)
|
||||
ex2 = create(:exchange, :order_cycle => oc, :incoming => true,
|
||||
:sender => create(:supplier_enterprise), :receiver => oc.coordinator)
|
||||
:sender => supplier2, :receiver => oc.coordinator)
|
||||
ExchangeFee.create!(exchange: ex1,
|
||||
enterprise_fee: create(:enterprise_fee, enterprise: ex1.sender))
|
||||
ExchangeFee.create!(exchange: ex2,
|
||||
enterprise_fee: create(:enterprise_fee, enterprise: ex2.sender))
|
||||
|
||||
# Distributors
|
||||
#Distributors
|
||||
distributor1 = create(:distributor_enterprise)
|
||||
distributor2 = create(:distributor_enterprise)
|
||||
|
||||
# Outgoing Exchanges
|
||||
ex3 = create(:exchange, :order_cycle => oc, :incoming => false,
|
||||
:sender => oc.coordinator, :receiver => create(:distributor_enterprise),
|
||||
:sender => oc.coordinator, :receiver => distributor1,
|
||||
:pickup_time => 'time 0', :pickup_instructions => 'instructions 0')
|
||||
ex4 = create(:exchange, :order_cycle => oc, :incoming => false,
|
||||
:sender => oc.coordinator, :receiver => create(:distributor_enterprise),
|
||||
:sender => oc.coordinator, :receiver => distributor2,
|
||||
:pickup_time => 'time 1', :pickup_instructions => 'instructions 1')
|
||||
ExchangeFee.create!(exchange: ex3,
|
||||
enterprise_fee: create(:enterprise_fee, enterprise: ex3.receiver))
|
||||
|
||||
@@ -10,7 +10,7 @@ feature %q{
|
||||
after { Warden.test_reset! }
|
||||
stub_authorization!
|
||||
|
||||
pending "listing orders" do
|
||||
context "listing orders" do
|
||||
before :each do
|
||||
admin_user = quick_login_as_admin
|
||||
end
|
||||
@@ -92,7 +92,7 @@ feature %q{
|
||||
end
|
||||
end
|
||||
|
||||
pending "altering line item properties" do
|
||||
context "altering line item properties" do
|
||||
before :each do
|
||||
admin_user = quick_login_as_admin
|
||||
end
|
||||
@@ -140,7 +140,7 @@ feature %q{
|
||||
end
|
||||
end
|
||||
|
||||
pending "using page controls" do
|
||||
context "using page controls" do
|
||||
before :each do
|
||||
admin_user = quick_login_as_admin
|
||||
end
|
||||
@@ -562,7 +562,7 @@ feature %q{
|
||||
end
|
||||
end
|
||||
|
||||
pending "as an enterprise manager" do
|
||||
context "as an enterprise manager" do
|
||||
let(:s1) { create(:supplier_enterprise, name: 'First Supplier') }
|
||||
let(:d1) { create(:distributor_enterprise, name: 'First Distributor') }
|
||||
let(:d2) { create(:distributor_enterprise, name: 'Another Distributor') }
|
||||
|
||||
@@ -110,10 +110,10 @@ feature %q{
|
||||
let(:coordinator2) { create(:distributor_enterprise) }
|
||||
let!(:order_cycle1) { create(:order_cycle, coordinator: coordinator1) }
|
||||
let!(:order_cycle2) { create(:simple_order_cycle, coordinator: coordinator2) }
|
||||
let(:supplier1) { order_cycle1.suppliers.first }
|
||||
let(:supplier2) { order_cycle1.suppliers.last }
|
||||
let(:distributor1) { order_cycle1.distributors.first }
|
||||
let(:distributor2) { order_cycle1.distributors.last }
|
||||
let!(:supplier1) { order_cycle1.suppliers.first }
|
||||
let!(:supplier2) { order_cycle1.suppliers.last }
|
||||
let!(:distributor1) { order_cycle1.distributors.first }
|
||||
let!(:distributor2) { order_cycle1.distributors.reject{ |d| d == distributor1 }.last } # ensure d1 != d2
|
||||
let(:product) { order_cycle1.products.first }
|
||||
|
||||
before(:each) do
|
||||
@@ -132,19 +132,6 @@ feature %q{
|
||||
expect(page).to have_content 'ADD PRODUCT'
|
||||
targetted_select2_search product.name, from: '#add_variant_id', dropdown_css: '.select2-drop'
|
||||
|
||||
puts "c1: " + coordinator1.id.to_s + " "+ coordinator1.name
|
||||
puts "c2: " + coordinator2.id.to_s + " "+ coordinator2.name
|
||||
puts "s1: " + supplier1.id.to_s + " "+ supplier1.name
|
||||
puts "s2: " + supplier2.id.to_s + " "+ supplier2.name
|
||||
puts "d1: " + distributor1.id.to_s + " "+ distributor1.name
|
||||
puts "d2: " + distributor2.id.to_s + " "+ distributor2.name
|
||||
order_cycle1.distributors.each do |distributor|
|
||||
puts "oc1d: " + distributor.id.to_s + " "+ distributor.name
|
||||
end
|
||||
Enterprise.is_distributor.managed_by(@enterprise_user).each do |distributor|
|
||||
puts "eud: " + distributor.id.to_s + " "+ distributor.name
|
||||
end
|
||||
|
||||
click_link 'Add'
|
||||
page.has_selector? "table.index tbody[data-hook='admin_order_form_line_items'] tr" # Wait for JS
|
||||
expect(page).to have_selector 'td', text: product.name
|
||||
|
||||
@@ -60,15 +60,22 @@ feature "Registration", js: true do
|
||||
fill_in 'enterprise_acn', with: '54321'
|
||||
click_button 'Continue'
|
||||
|
||||
# Enterprise should be updated
|
||||
expect(page).to have_content 'Last step!'
|
||||
# Enterprise should be update
|
||||
expect(page).to have_content "Let's upload some pretty pictures so your profile looks great!"
|
||||
e.reload
|
||||
expect(e.description).to eq "Short description"
|
||||
expect(e.long_description).to eq "Long description"
|
||||
expect(e.abn).to eq '12345'
|
||||
expect(e.acn).to eq '54321'
|
||||
|
||||
# Images
|
||||
# Move from logo page
|
||||
click_button 'Continue'
|
||||
# Move from promo page
|
||||
click_button 'Continue'
|
||||
|
||||
# Filling in social
|
||||
expect(page).to have_content 'Last step!'
|
||||
fill_in 'enterprise_website', with: 'www.shop.com'
|
||||
fill_in 'enterprise_facebook', with: 'FaCeBoOk'
|
||||
fill_in 'enterprise_linkedin', with: 'LiNkEdIn'
|
||||
|
||||
@@ -7,7 +7,7 @@ describe "enterpriseCtrl", ->
|
||||
|
||||
beforeEach ->
|
||||
module('admin.enterprises')
|
||||
Enterprise =
|
||||
Enterprise =
|
||||
enterprise:
|
||||
payment_method_ids: [ 1, 3 ]
|
||||
shipping_method_ids: [ 2, 4 ]
|
||||
@@ -15,7 +15,7 @@ describe "enterpriseCtrl", ->
|
||||
paymentMethods: [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 } ]
|
||||
ShippingMethods =
|
||||
shippingMethods: [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 } ]
|
||||
|
||||
|
||||
inject ($controller) ->
|
||||
scope = {}
|
||||
ctrl = $controller 'enterpriseCtrl', {$scope: scope, Enterprise: Enterprise, PaymentMethods: PaymentMethods, ShippingMethods: ShippingMethods}
|
||||
@@ -82,4 +82,4 @@ describe "enterpriseCtrl", ->
|
||||
describe "counting selected shipping methods", ->
|
||||
it "counts only shipping methods with selected: true", ->
|
||||
scope.ShippingMethods = [ { selected: true }, { selected: true }, { selected: false }, { selected: true } ]
|
||||
expect(scope.selectedShippingMethodsCount()).toBe 3
|
||||
expect(scope.selectedShippingMethodsCount()).toBe 3
|
||||
|
||||
@@ -13,6 +13,13 @@ module Spree
|
||||
let(:enterprise_single) { create(:enterprise, type: 'single') }
|
||||
let(:enterprise_profile) { create(:enterprise, type: 'profile') }
|
||||
|
||||
describe "creating enterprises" do
|
||||
it "can create enterprises straight off the bat" do
|
||||
subject.is_new_user?(user).should be_true
|
||||
expect(user).to have_ability :create, for: Enterprise
|
||||
end
|
||||
end
|
||||
|
||||
describe "managing enterprises" do
|
||||
it "can manage enterprises when the user has at least one enterprise assigned" do
|
||||
user.enterprise_roles.create! enterprise: enterprise_full
|
||||
|
||||
@@ -3,20 +3,15 @@ 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
|
||||
node.has_selector? "tr", text: row.join(" ").strip # Check for appearance
|
||||
rows_under(node).include? row # Robust check of columns
|
||||
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
|
||||
node.has_no_selector? "tr", text: row.join(" ").strip # Check for appearance
|
||||
!rows_under(node).include? row # Robust check of columns
|
||||
end
|
||||
|
||||
failure_message_for_should do |text|
|
||||
@@ -27,17 +22,7 @@ RSpec::Matchers.define :have_table_row do |row|
|
||||
"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
|
||||
|
||||
Reference in New Issue
Block a user