Merge branch 'refactoring_services' into laura_and_will

This commit is contained in:
Will Marshall
2014-06-19 12:10:28 +10:00
38 changed files with 332 additions and 136 deletions

View File

@@ -1,11 +1,11 @@
Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle) ->
$scope.data = Product.data
$scope.Product = Product
$scope.limit = 3
$scope.ordering = {order: "name"}
$scope.order_cycle = OrderCycle.order_cycle
$scope.incrementLimit = ->
if $scope.limit < $scope.data.products.length
if $scope.limit < $scope.Product.products.length
$scope.limit = $scope.limit + 1
$scope.searchKeypress = (e)->

View File

@@ -0,0 +1,18 @@
Darkswarm.factory 'Enterprises', (enterprises)->
new class Enterprises
enterprises_by_id: {} # id/object pairs for lookup
constructor: ->
@enterprises = enterprises
for enterprise in enterprises
@enterprises_by_id[enterprise.id] = enterprise
@dereference()
dereference: ->
for enterprise in @enterprises
if enterprise.hubs
for hub, i in enterprise.hubs
enterprise.hubs[i] = @enterprises_by_id[hub.id]
if enterprise.producers
for producer, i in enterprise.producers
enterprise.producers[i] = @enterprises_by_id[producer.id]

View File

@@ -1,4 +1,8 @@
Darkswarm.factory 'Hubs', ($location, hubs, $filter, CurrentHub) ->
Darkswarm.factory 'Hubs', ($filter, Enterprises) ->
new class Hubs
constructor: ->
@hubs = $filter('orderBy')(hubs, ['-active', '+orders_close_at'])
@hubs = @order Enterprises.enterprises.filter (hub)->
hub.is_distributor
order: (hubs)->
$filter('orderBy')(hubs, ['-active', '+orders_close_at'])

View File

@@ -1,12 +1,17 @@
Darkswarm.factory "OfnMap", (enterprisesForMap, MapModal)->
Darkswarm.factory "OfnMap", (Enterprises, MapModal)->
new class OfnMap
constructor: ->
@enterprises = (@extend(enterprise) for enterprise in enterprisesForMap)
@enterprises = (@extend(enterprise) for enterprise in Enterprises.enterprises)
# Adding methods to each enterprise
extend: (enterprise)->
new class MapMarker
constructor: ->
@[k] = v for k, v of enterprise
# We're whitelisting attributes because GMaps tries to crawl
# our data, and our data is recursive, so it breaks
latitude: enterprise.latitude
longitude: enterprise.longitude
icon: enterprise.icon
id: enterprise.id
reveal: =>
MapModal.open @
MapModal.open enterprise

View File

@@ -2,9 +2,10 @@ Darkswarm.factory "MapModal", ($modal, $rootScope)->
new class MapModal
open: (enterprise)->
scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise
if enterprise['is_primary_producer?']
scope.producer = enterprise
$modal.open(templateUrl: "map_modal_producer.html", scope: scope)
else
if enterprise.is_distributor
scope.hub = enterprise
$modal.open(templateUrl: "map_modal_hub.html", scope: scope)
else
scope.producer = enterprise
$modal.open(templateUrl: "map_modal_producer.html", scope: scope)

View File

@@ -1,12 +1,6 @@
Darkswarm.factory 'Producers', (producers) ->
Darkswarm.factory 'Producers', (Enterprises) ->
new class Producers
constructor: ->
@producers = producers
# TODO: start adding functionality to producers like so
#@producers = (@extend(producer) for producer in producers)
@producers = Enterprises.enterprises.filter (enterprise)->
enterprise.is_primary_producer
#extend: (producer)->
#new class Producer
#constructor: ->
#@[k] = v for k, v of Producer

View File

@@ -5,11 +5,11 @@ Darkswarm.factory 'Product', ($resource) ->
# TODO: don't need to scope this into object
# Already on object as far as controller scope is concerned
data:
products: null
loading: true
products: null
loading: true
update: =>
@data.products = $resource("/shop/products").query =>
@data.loading = false
@data
@loading = true
@products = $resource("/shop/products").query =>
@loading = false
@

View File

@@ -11,4 +11,8 @@ class BaseController < ApplicationController
include Spree::ProductsHelper
before_filter :check_order_cycle_expiry
def load_active_distributors
@active_distributors ||= Enterprise.distributors_with_active_order_cycles
end
end

View File

@@ -1,10 +1,11 @@
class HomeController < BaseController
layout 'darkswarm'
before_filter :load_active_distributors
def index
@active_distributors ||= Enterprise.distributors_with_active_order_cycles
end
def about_us
end
end

View File

@@ -1,7 +1,7 @@
class MapController < BaseController
layout 'darkswarm'
before_filter :load_active_distributors
def index
@active_distributors ||= Enterprise.distributors_with_active_order_cycles
@enterprises = Enterprise.visible
end
end

View File

@@ -1,7 +1,7 @@
class ProducersController < BaseController
layout 'darkswarm'
before_filter :load_active_distributors
def index
@producers = Enterprise.is_primary_producer.visible
end
end

View File

@@ -1,7 +1,10 @@
module SharedHelper
def inject_enterprises
inject_json "enterprises" , "enterprises"
end
def inject_json(name, partial, opts = {})
render "json/injection", {name: name, partial: partial}.merge(opts)
render partial: "json/injection", locals: {name: name, partial: partial}.merge(opts)
end
def distributor_link_class(distributor)

View File

@@ -1,6 +1,5 @@
#hubs.hubs{"ng-controller" => "HubsCtrl"}
:javascript
angular.module('Darkswarm').value('hubs', #{render "json/hubs"})
= inject_enterprises
.row
.small-12.columns.text-center

View File

@@ -1,18 +1,7 @@
# DON'T USE DIRECTLY - for inheritance
attributes :name, :id, :description
node :email do |enterprise|
enterprise.email.to_s.reverse
end
child :address do
extends "json/partials/address"
end
node :path do |enterprise|
shop_enterprise_path(enterprise)
end
node :hash do |enterprise|
enterprise.to_param
end
# TODO: This should be moved into the controller
# RABL is tricky to pass variables into: so we do this as a workaround for now
# I noticed some vague comments on Rabl github about this, but haven't looked into
collection Enterprise.visible
extends 'json/partials/enterprise'
extends 'json/partials/producer'
extends 'json/partials/hub'

View File

@@ -1,26 +1,4 @@
collection Enterprise.visible.is_distributor
extends 'json/enterprises'
collection Enterprise.is_distributor.visible
extends 'json/partials/enterprise'
extends 'json/partials/hub'
child distributed_taxons: :taxons do
extends "json/taxon"
end
child suppliers: :producers do
extends "json/producer"
end
node :pickup do |hub|
not hub.shipping_methods.where(:require_ship_address => false).empty?
end
node :delivery do |hub|
not hub.shipping_methods.where(:require_ship_address => true).empty?
end
node :active do |hub|
@active_distributors.include?(hub)
end
node :orders_close_at do |hub|
OrderCycle.first_closing_for(hub).andand.orders_close_at
end

View File

@@ -1,2 +1,2 @@
:javascript
angular.module('Darkswarm').value("#{name.to_s}", #{render "json/#{partial.to_s}"})
angular.module('Darkswarm').value("#{name.to_s}", #{render partial: "json/#{partial.to_s}"})

View File

@@ -1,21 +1,3 @@
collection @producers
extends 'json/enterprises'
child supplied_taxons: :taxons do
extends 'json/taxon'
end
child distributors: :distributors do
attributes :name, :id
node :path do |distributor|
shop_enterprise_path(distributor)
end
end
node :path do |producer|
producer_path(producer)
end
node :hash do |producer|
producer.to_param
end
collection Enterprise.is_primary_producer.visible
extends 'json/partials/enterprise'
extends 'json/partials/producer'

View File

@@ -1,6 +1,16 @@
collection @enterprises
extends 'json/enterprises'
attributes :latitude, :longitude, :long_description, :website, :instagram, :linkedin, :twitter, :facebook, :is_primary_producer?, :is_distributor?
attributes :name, :id, :description, :latitude, :longitude, :long_description, :website, :instagram, :linkedin, :twitter, :facebook, :is_primary_producer, :is_distributor
node :email do |enterprise|
enterprise.email.to_s.reverse
end
child :address do
extends "json/partials/address"
end
node :hash do |enterprise|
enterprise.to_param
end
node :logo do |enterprise|
enterprise.logo(:medium) if enterprise.logo.exists?
@@ -10,18 +20,6 @@ node :promo_image do |enterprise|
enterprise.promo_image(:large) if enterprise.promo_image.exists?
end
node :active do |enterprise|
@active_distributors.include?(enterprise)
end
child distributors: :hubs do
extends 'json/enterprises'
node :active do |hub|
@active_distributors.include?(hub)
end
end
node :icon do |e|
if e.is_primary_producer? and e.is_distributor?
image_path "map-icon-both.svg"

View File

@@ -0,0 +1,21 @@
child distributed_taxons: :taxons do
extends "json/taxon"
end
child suppliers: :producers do
attributes :id
end
node :path do |enterprise|
shop_enterprise_path(enterprise)
end
node :pickup do |hub|
hub.shipping_methods.where(:require_ship_address => false).present?
end
node :delivery do |hub|
hub.shipping_methods.where(:require_ship_address => true).present?
end
node :active do |hub|
@active_distributors.include?(hub)
end
node :orders_close_at do |hub|
OrderCycle.first_closing_for(hub).andand.orders_close_at
end

View File

@@ -0,0 +1,9 @@
child supplied_taxons: :taxons do
extends 'json/taxon'
end
child distributors: :hubs do
attributes :id
end
node :path do |producer|
producer_path(producer)
end

View File

@@ -1,4 +1,4 @@
= inject_json "enterprisesForMap" , "enterprises_for_map", collection: @enterprises
= inject_enterprises
.map-container{"fill-vertical" => true}
%map{"ng-controller" => "MapCtrl"}

View File

@@ -1,8 +1,5 @@
.producers{"ng-controller" => "ProducersCtrl"}
:javascript
angular.module('Darkswarm').value('producers', #{render partial: "json/producers", object: @producers})
-#%pre
-#{{ Producers.producers | json }}
= inject_enterprises
.row
.small-12.columns.text-center.pad-top

View File

@@ -14,7 +14,7 @@
%div{bindonce: true}
%product{"ng-controller" => "ProductNodeCtrl",
"ng-repeat" => "product in data.products | filter:query | orderBy:ordering.order | limitTo: limit track by product.id"}
"ng-repeat" => "product in Product.products | filter:query | orderBy:ordering.order | limitTo: limit track by product.id"}
%div
= render partial: "shop/products/summary"
%div{"bo-if" => "hasVariants"}
@@ -22,12 +22,10 @@
.variants.row{"bo-if" => "!hasVariants"}
= render partial: "shop/products/master"
%product{"ng-show" => "data.loading"}
%product{"ng-show" => "Product.loading"}
.row.summary
.small-12.columns.text-center
Loading products
.row
.small-12.columns
%input.button.primary.right.add_to_cart{type: :submit, value: "Add to Cart"}

View File

@@ -18,4 +18,9 @@ describe BaseController do
response.should redirect_to root_url
flash[:info].should == "The order cycle you've selected has just closed. Please try again!"
end
it "loads active_distributors" do
Enterprise.should_receive(:distributors_with_active_order_cycles)
controller.load_active_distributors
end
end

View File

@@ -1,8 +1,8 @@
require 'spec_helper'
describe MapController do
it "loads all visible enterprises" do
Enterprise.should_receive(:visible)
it "loads active distributors" do
Enterprise.should_receive(:distributors_with_active_order_cycles)
get :index
end
end

View File

@@ -1,9 +1,15 @@
require 'spec_helper'
describe ProducersController do
it "gets all active producers" do
Enterprise.stub_chain(:is_primary_producer, :visible)
Enterprise.should_receive(:is_primary_producer)
let!(:distributor) { create(:distributor_enterprise) }
before do
Enterprise.stub(:distributors_with_active_order_cycles).and_return [distributor]
Enterprise.stub(:visible).and_return [distributor]
end
it "sets active distributors" do
get :index
assigns[:active_distributors].should == [distributor]
end
end

View File

@@ -77,7 +77,6 @@ feature "As a consumer I want to shop with a distributor", js: true do
page.should have_content "Next order closing in 2 days"
Spree::Order.last.order_cycle.should == oc1
page.should have_content product.name
save_screenshot "/Users/willmarshall/Desktop/shop.png"
page.should have_content product.master.display_name
page.should have_content product.master.display_as
end

View File

@@ -5,7 +5,10 @@
//= require angular-mocks
//= require angular-cookies
//= require angular-backstretch.js
//= require lodash.underscore.js
//= require angular-flash.min.js
//= require moment
angular.module('templates', [])
angular.module('google-maps', []);
angular.module('duScroll', []);

View File

@@ -0,0 +1,68 @@
@google =
maps:
event:
addDomListener: ->
addDomListenerOnce: ->
addListener: ->
addListenerOnce: ->
bind: ->
clearInstanceListeners: ->
clearListeners: ->
forward: ->
removeListener: ->
trigger: ->
vf: ->
class google.maps.LatLng
constructor: (lat, lng) ->
@latitude = parseFloat(lat)
@longitude = parseFloat(lng)
lat: -> @latitude
lng: -> @longitude
class google.maps.LatLngBounds
constructor: (@ne, @sw) ->
getSouthWest: -> @sw
getNorthEast: -> @ne
class google.maps.OverlayView
class google.maps.Marker
getAnimation: ->
getClickable: ->
getCursor: ->
getDraggable: ->
getFlat: ->
getIcon: ->
getPosition: ->
getShadow: ->
getShape: ->
getTitle: ->
getVisible: ->
getZIndex: ->
setAnimation: ->
setClickable: ->
setCursor: ->
setDraggable: ->
setFlat: ->
setIcon: ->
setPosition: ->
setShadow: ->
setShape: ->
setTitle: ->
setVisible: ->
setZIndex: ->
setMap: ->
getMap: ->
class google.maps.MarkerImage
class google.maps.Map
class google.maps.Point
class google.maps.Size
class google.maps.InfoWindow

View File

@@ -1,9 +1,14 @@
describe "AccordionCtrl", ->
ctrl = null
scope = null
CurrentHubMock =
id: 1
beforeEach ->
module "Darkswarm"
module ($provide)->
$provide.value "CurrentHub", CurrentHubMock
null
localStorage.clear()
describe "loading incomplete form", ->

View File

@@ -9,7 +9,7 @@ describe 'ProductsCtrl', ->
Product =
all: ->
update: ->
data: "testy mctest"
products: "testy mctest"
OrderCycle =
order_cycle: {}
@@ -18,4 +18,4 @@ describe 'ProductsCtrl', ->
ctrl = $controller 'ProductsCtrl', {$scope: scope, Product: Product, OrderCycle: OrderCycle}
it 'fetches products from Product', ->
expect(scope.data).toEqual 'testy mctest'
expect(scope.Product.products).toEqual 'testy mctest'

View File

@@ -0,0 +1,27 @@
describe "Enterprises service", ->
Enterprises = null
enterprises = [
{id: 1, type: "hub", producers: [{id: 2}]},
{id: 2, type: "producer", hubs: [{id: 1}]},
{id: 3, type: "producer", hubs: [{id: 1}]}
]
beforeEach ->
module 'Darkswarm'
angular.module('Darkswarm').value('enterprises', enterprises)
inject ($injector)->
Enterprises = $injector.get("Enterprises")
it "stores enterprises as id/object pairs", ->
expect(Enterprises.enterprises_by_id["1"]).toBe enterprises[0]
expect(Enterprises.enterprises_by_id["2"]).toBe enterprises[1]
it "stores enterprises as an array", ->
expect(Enterprises.enterprises).toBe enterprises
it "puts the same objects in enterprises and enterprises_by_id", ->
expect(Enterprises.enterprises[0]).toBe Enterprises.enterprises_by_id["1"]
it "dereferences references to other enterprises", ->
expect(Enterprises.enterprises_by_id["1"].producers[0]).toBe enterprises[1]
expect(Enterprises.enterprises_by_id["3"].hubs[0]).toBe enterprises[0]

View File

@@ -0,0 +1,39 @@
describe "Hubs service", ->
Hubs = null
Enterprises = null
hubs = [
{
id: 2
active: false
orders_close_at: new Date()
is_distributor: true
}
{
id: 3
active: false
orders_close_at: new Date()
is_distributor: true
}
{
id: 1
active: true
orders_close_at: new Date()
is_distributor: true
}
]
beforeEach ->
module 'Darkswarm'
angular.module('Darkswarm').value('enterprises', hubs)
inject ($injector)->
Enterprises = $injector.get("Enterprises")
Hubs = $injector.get("Hubs")
it "filters Enterprise.hubs into a new array", ->
expect(Hubs.hubs[0]).toBe Enterprises.enterprises[2]
# Because the $filter is a new sorted array
# We check to see the objects in both arrays are still the same
Enterprises.enterprises[2].active = false
expect(Hubs.hubs[0].active).toBe false

View File

@@ -0,0 +1,19 @@
describe "Hubs service", ->
OfnMap = null
enterprises = [
{
id: 2
active: false
orders_close_at: new Date()
type: "hub"
}
]
beforeEach ->
module 'Darkswarm'
angular.module('Darkswarm').value('enterprises', enterprises)
inject ($injector)->
OfnMap = $injector.get("OfnMap")
it "builds MapMarkers from enterprises", ->
expect(OfnMap.enterprises[0].id).toBe enterprises[0].id

View File

@@ -6,6 +6,10 @@ describe 'Order service', ->
flash = null
storage = null
scope = null
CurrentHubMock =
id: 1
FlashLoaderMock =
loadFlash: (arg)->
beforeEach ->
orderData =
@@ -36,6 +40,10 @@ describe 'Order service', ->
angular.module('Darkswarm').value('order', orderData)
module 'Darkswarm'
module ($provide)->
$provide.value "CurrentHub", CurrentHubMock
$provide.value "RailsFlashLoader", FlashLoaderMock
null
inject ($injector, _$httpBackend_, _storage_, $rootScope)->
$httpBackend = _$httpBackend_
@@ -58,13 +66,13 @@ describe 'Order service', ->
spyOn(storage, "bind")
Order.fieldsToBind = ["testy"]
Order.bindFieldsToLocalStorage({})
prefix = "order_#{Order.order.id}#{Order.order.user_id}"
prefix = "order_#{Order.order.id}#{Order.order.user_id}#{CurrentHubMock.id}"
expect(storage.bind).toHaveBeenCalledWith({}, "Order.order.testy", {storeName: "#{prefix}_testy"})
expect(storage.bind).toHaveBeenCalledWith({}, "Order.ship_address_same_as_billing", {storeName: "#{prefix}_sameasbilling", defaultValue: true})
it "binds order to local storage", ->
Order.bindFieldsToLocalStorage(scope)
prefix = "order_#{Order.order.id}#{Order.order.user_id}"
prefix = "order_#{Order.order.id}#{Order.order.user_id}#{CurrentHubMock.id}"
expect(localStorage.getItem("#{prefix}_email")).toMatch "test@test.com"
it "does not store secrets in local storage", ->
@@ -100,10 +108,11 @@ describe 'Order service', ->
$httpBackend.flush()
it "sends flash messages to the flash service", ->
spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location
$httpBackend.expectPUT("/checkout").respond 400, {flash: {error: "frogs"}}
Order.submit()
$httpBackend.flush()
expect(flash.error).toEqual "frogs"
expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith {error: "frogs"}
it "puts errors into the scope", ->
$httpBackend.expectPUT("/checkout").respond 400, {errors: {error: "frogs"}}

View File

@@ -0,0 +1,15 @@
describe "Producers service", ->
Producers = null
Enterprises = null
enterprises = [
{is_primary_producer: true}
]
beforeEach ->
module 'Darkswarm'
angular.module('Darkswarm').value('enterprises', enterprises)
inject ($injector)->
Producers = $injector.get("Producers")
it "delegates producers array to Enterprises", ->
expect(Producers.producers[0]).toBe enterprises[0]

View File

@@ -11,4 +11,4 @@ describe 'Product service', ->
it "Fetches products from the backend on init", ->
$httpBackend.expectGET("/shop/products").respond([{test : "cats"}])
$httpBackend.flush()
expect(Product.data.products[0].test).toEqual "cats"
expect(Product.products[0].test).toEqual "cats"