e9_vendors 0.0.1

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 (67) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/README.markdown +6 -0
  4. data/Rakefile +1 -0
  5. data/app/controllers/e9_vendors/settings_controller.rb +11 -0
  6. data/app/controllers/e9_vendors/vendor_categories_controller.rb +36 -0
  7. data/app/controllers/e9_vendors/vendor_members_controller.rb +61 -0
  8. data/app/controllers/e9_vendors/vendor_proxies_controller.rb +38 -0
  9. data/app/controllers/e9_vendors/vendors_controller.rb +22 -0
  10. data/app/decorators/vendor_category_decorator.rb +10 -0
  11. data/app/decorators/vendor_member_decorator.rb +55 -0
  12. data/app/decorators/vendor_proxy_decorator.rb +74 -0
  13. data/app/decorators/vendors_decorator.rb +27 -0
  14. data/app/models/vendor.rb +23 -0
  15. data/app/models/vendor_category.rb +17 -0
  16. data/app/models/vendor_member.rb +21 -0
  17. data/app/models/vendor_proxy.rb +39 -0
  18. data/app/observers/vendor_member_observer.rb +17 -0
  19. data/app/observers/vendor_observer.rb +18 -0
  20. data/app/uploaders/logo_uploader.rb +14 -0
  21. data/app/views/e9_vendors/settings/_form.html.haml +18 -0
  22. data/app/views/e9_vendors/settings/show.html.haml +2 -0
  23. data/app/views/e9_vendors/vendor_categories/_form.html.haml +7 -0
  24. data/app/views/e9_vendors/vendor_categories/_table.html.haml +21 -0
  25. data/app/views/e9_vendors/vendor_categories/destroy.js.erb +3 -0
  26. data/app/views/e9_vendors/vendor_categories/edit.html.haml +2 -0
  27. data/app/views/e9_vendors/vendor_categories/index.html.haml +4 -0
  28. data/app/views/e9_vendors/vendor_categories/index.js.erb +1 -0
  29. data/app/views/e9_vendors/vendor_categories/new.html.haml +2 -0
  30. data/app/views/e9_vendors/vendor_members/_form.html.haml +49 -0
  31. data/app/views/e9_vendors/vendor_members/_table.html.haml +21 -0
  32. data/app/views/e9_vendors/vendor_members/_vendors.html.haml +24 -0
  33. data/app/views/e9_vendors/vendor_members/destroy.js.erb +3 -0
  34. data/app/views/e9_vendors/vendor_members/edit.html.haml +2 -0
  35. data/app/views/e9_vendors/vendor_members/index.html.haml +4 -0
  36. data/app/views/e9_vendors/vendor_members/index.js.erb +1 -0
  37. data/app/views/e9_vendors/vendor_members/new.html.haml +2 -0
  38. data/app/views/e9_vendors/vendor_members/widget_code.html.haml +3 -0
  39. data/app/views/e9_vendors/vendor_proxies/_form.html.haml +28 -0
  40. data/app/views/e9_vendors/vendor_proxies/_table.html.haml +16 -0
  41. data/app/views/e9_vendors/vendor_proxies/_table_row.html.haml +11 -0
  42. data/app/views/e9_vendors/vendor_proxies/destroy.js.erb +3 -0
  43. data/app/views/e9_vendors/vendor_proxies/edit.html.haml +2 -0
  44. data/app/views/e9_vendors/vendor_proxies/index.html.haml +1 -0
  45. data/app/views/e9_vendors/vendor_proxies/index.js.erb +1 -0
  46. data/app/views/e9_vendors/vendor_proxies/new.html.haml +2 -0
  47. data/app/views/e9_vendors/vendor_proxies/update.js.erb +7 -0
  48. data/app/views/e9_vendors/vendors/_form.html.haml +91 -0
  49. data/app/views/e9_vendors/vendors/_table.html.haml +20 -0
  50. data/app/views/e9_vendors/vendors/destroy.js.erb +3 -0
  51. data/app/views/e9_vendors/vendors/edit.html.haml +2 -0
  52. data/app/views/e9_vendors/vendors/index.html.haml +4 -0
  53. data/app/views/e9_vendors/vendors/index.js.erb +1 -0
  54. data/app/views/e9_vendors/vendors/new.html.haml +2 -0
  55. data/config/locales/vendorboon.en.yml +61 -0
  56. data/config/routes.rb +38 -0
  57. data/e9_vendors.gemspec +20 -0
  58. data/lib/e9_vendors.rb +24 -0
  59. data/lib/e9_vendors/controller.rb +18 -0
  60. data/lib/e9_vendors/model.rb +13 -0
  61. data/lib/e9_vendors/version.rb +3 -0
  62. data/lib/generators/e9_vendors/install_generator.rb +31 -0
  63. data/lib/generators/e9_vendors/templates/javascript.js +16 -0
  64. data/lib/generators/e9_vendors/templates/migration.rb +84 -0
  65. data/lib/generators/e9_vendors/templates/stylesheets/vb-widget-ie.scss +21 -0
  66. data/lib/generators/e9_vendors/templates/stylesheets/vb-widget.scss +151 -0
  67. metadata +129 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in e9_directory.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,6 @@
1
+ E9 Vendors
2
+ ============
3
+
4
+ Vendor directory plugin for use with the e9 CMS
5
+
6
+ Although it doesn't speficy requirements, this gem is dependent on e9_base and its environment.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,11 @@
1
+ class E9Vendors::SettingsController < Admin::SettingsController
2
+ include E9Vendors::Controller
3
+
4
+ defaults :instance_name => 'settings', :resource_class => Settings
5
+
6
+ skip_before_filter :add_admin_settings_breadcrumb
7
+
8
+ def add_index_breadcrumb
9
+ add_breadcrumb! e9_t(:index_title)
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ class E9Vendors::VendorCategoriesController < Admin::ResourceController
2
+ include E9Vendors::Controller
3
+ include E9Rails::Controllers::Sortable
4
+
5
+ respond_to :html, :js
6
+
7
+ add_resource_breadcrumbs
8
+
9
+ def create
10
+ create! { collection_path }
11
+ end
12
+
13
+ def update
14
+ update! { collection_path }
15
+ end
16
+
17
+ def destroy
18
+ destroy! do |format|
19
+ format.html { redirect_to collection_path }
20
+ format.js
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ ##
27
+ # IR
28
+ #
29
+ def collection
30
+ get_collection_ivar || set_collection_ivar(end_of_association_chain.order(:position).all)
31
+ end
32
+
33
+ def resource
34
+ get_resource_ivar || set_resource_ivar(end_of_association_chain.find(params[:id]))
35
+ end
36
+ end
@@ -0,0 +1,61 @@
1
+ class E9Vendors::VendorMembersController < Admin::ResourceController
2
+ include E9Vendors::Controller
3
+
4
+ respond_to :json, :only => :show
5
+ respond_to :html, :js, :except => :show
6
+
7
+ carrierwave_column_methods :logo, :context => :admin
8
+
9
+ skip_before_filter :authenticate_user!, :filter_access_filter, :only => :show
10
+
11
+ add_resource_breadcrumbs
12
+ before_filter :add_widget_code_breadcrumb, :only => :widget_code
13
+
14
+ def show
15
+ show! do |format|
16
+ format.html { render_404 }
17
+ format.json { render :json => { :type => 'member', :resource => resource }, :callback => params[:jsonp] }
18
+ end
19
+ end
20
+
21
+ def create
22
+ create! { collection_path }
23
+ end
24
+
25
+ def update
26
+ update! { collection_path }
27
+ end
28
+
29
+ def destroy
30
+ destroy! do |format|
31
+ format.html { redirect_to collection_path }
32
+ format.js
33
+ end
34
+ end
35
+
36
+ protected
37
+
38
+ def resource
39
+ get_resource_ivar || set_resource_ivar(decorate end_of_association_chain.send(resource_lookup, params[:id]))
40
+ end
41
+
42
+ def resource_lookup
43
+ params[:action] == 'show' ? :find_by_md5_hash! : :find
44
+ end
45
+
46
+ def collection
47
+ get_collection_ivar || set_collection_ivar(decorate end_of_association_chain.order(:name))
48
+ end
49
+
50
+ def decorate(records)
51
+ VendorMemberDecorator.decorate(records)
52
+ end
53
+
54
+ def add_widget_code_breadcrumb
55
+ add_breadcrumb! e9_t(:widget_code_title)
56
+ end
57
+
58
+ def determine_layout
59
+ request.xhr? ? false : super
60
+ end
61
+ end
@@ -0,0 +1,38 @@
1
+ class E9Vendors::VendorProxiesController < Admin::ResourceController
2
+ include E9Vendors::Controller
3
+
4
+ belongs_to :vendor_member
5
+ defaults :instance_name => :vendor
6
+
7
+ add_resource_breadcrumbs
8
+
9
+ def update
10
+ update! do |format|
11
+ format.html { redirect_to collection_path }
12
+ format.js
13
+ end
14
+ end
15
+
16
+ protected
17
+
18
+ def determine_layout
19
+ request.xhr? ? false : super
20
+ end
21
+
22
+ def add_index_breadcrumb
23
+ add_breadcrumb parent.class.model_name.human.pluralize, polymorphic_path(parent.class)
24
+ add_breadcrumb (@index_title = e9_t(:index_title, :member => parent.name)), collection_path
25
+ end
26
+
27
+ def decorate(records)
28
+ VendorProxyDecorator.decorate(records)
29
+ end
30
+
31
+ def collection
32
+ get_collection_ivar || set_collection_ivar(decorate end_of_association_chain.joins(:vendor).order('vendors.name').all)
33
+ end
34
+
35
+ def resource
36
+ get_resource_ivar || set_resource_ivar(decorate end_of_association_chain.find(params[:id]))
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ class E9Vendors::VendorsController < Admin::ResourceController
2
+ include E9Vendors::Controller
3
+
4
+ respond_to :html, :js
5
+
6
+ carrierwave_column_methods :logo, :context => :admin
7
+
8
+ add_resource_breadcrumbs
9
+
10
+ def create; create! { collection_path } end
11
+ def update; update! { collection_path } end
12
+ def destroy; destroy! { collection_path } end
13
+
14
+ protected
15
+
16
+ ##
17
+ # IR
18
+ #
19
+ def collection
20
+ @vendors ||= end_of_association_chain.order(:name).all
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ class VendorCategoryDecorator < VendorsDecorator
2
+ decorates :vendor_category
3
+
4
+ def as_json(opts = {})
5
+ {
6
+ :id => self.id,
7
+ :name => self.name
8
+ }
9
+ end
10
+ end
@@ -0,0 +1,55 @@
1
+ class VendorMemberDecorator < VendorsDecorator
2
+ decorates :vendor_member
3
+
4
+ def as_json(options = {})
5
+ {
6
+ :name => model.name,
7
+ :address_1 => model.address_1,
8
+ :address_2 => model.address_2,
9
+ :admin_notes => model.admin_notes,
10
+ :categories => VendorCategoryDecorator.decorate(VendorCategory.widget_visible),
11
+ :city => model.city,
12
+ :contact_email => model.contact_email,
13
+ :contact_full_name => model.contact_full_name,
14
+ :contact_phone => model.contact_phone,
15
+ :contact_title => model.contact_title,
16
+ :country => model.country,
17
+ :logo => model.logo_url,
18
+ :nickname => model.nickname,
19
+ :state => model.state,
20
+ :vendors => VendorProxyDecorator.decorate(model.vendor_proxies.widget_visible),
21
+ :website => model.website,
22
+ :widget_form_text => config_render(:vendorboon_widget_form_text),
23
+ :widget_form_title => config_render(:vendorboon_widget_form_title),
24
+ :widget_title => config_render(:vendorboon_widget_title),
25
+ :zipcode => model.zipcode
26
+ }
27
+ end
28
+
29
+ def widget_code
30
+ <<-CODE
31
+ <script type="text/javascript" src="#{script_url}"></script>
32
+ <script type="text/javascript">
33
+ try {
34
+ new VB.Widget({
35
+ code: "#{model.md5_hash}"
36
+ }).render();
37
+ } catch (e) {}
38
+ </script>
39
+ CODE
40
+ end
41
+
42
+ protected
43
+
44
+ def script_url
45
+ dir = Rails.env.development? && 'javascripts' || 'assets'
46
+ Linkable.urlify_path("/#{dir}/widget.js")
47
+ end
48
+
49
+ def liquid_context
50
+ super.merge({
51
+ 'member_name' => self.name,
52
+ 'member_nickname' => self.nickname
53
+ })
54
+ end
55
+ end
@@ -0,0 +1,74 @@
1
+ class VendorProxyDecorator < VendorsDecorator
2
+ decorates :vendor
3
+
4
+ def as_json(options={})
5
+ {
6
+ :id => self.id,
7
+ :address_1 => vendor.address_1,
8
+ :address_2 => vendor.address_2,
9
+ :admin_notes => vendor.admin_notes,
10
+ :city => vendor.city,
11
+ :categories => VendorCategoryDecorator.decorate(vendor.vendor_categories),
12
+ :contact_email => vendor.contact_email,
13
+ :contact_full_name => vendor.contact_full_name,
14
+ :contact_phone => vendor.contact_phone,
15
+ :contact_title => vendor.contact_title,
16
+ :country => vendor.country,
17
+ :discount_code => self.discount_code,
18
+ :discount_percentage => self.discount_percentage,
19
+ :discount_percentage => vendor.discount_percentage,
20
+ :display_on_widget => self.display_on_widget,
21
+ :display_on_widget_contact_form => vendor.display_on_widget_contact_form,
22
+ :landing_page => self.landing_page,
23
+ :logo => vendor.logo_url,
24
+ :long_description => liquid_render(vendor.long_description),
25
+ :member_compensation => vendor.member_compensation,
26
+ :name => vendor.name,
27
+ :nickname => vendor.nickname,
28
+ :sales_email => self.sales_email,
29
+ :sales_email => vendor.sales_email,
30
+ :sales_full_name => self.sales_full_name,
31
+ :sales_phone => self.sales_phone,
32
+ :sales_title => self.sales_title,
33
+ :short_description => liquid_render(vendor.short_description),
34
+ :state => vendor.state,
35
+ :website => vendor.website,
36
+ :zipcode => vendor.zipcode
37
+ }
38
+ end
39
+
40
+ def sales_info_array
41
+ [model.sales_full_name, model.sales_title, model.sales_phone, model.sales_email].reject(&:blank?)
42
+ end
43
+
44
+ def landing_page_url
45
+ model.landing_page =~ /^https?:/ ? model.landing_page : "http://#{model.landing_page}"
46
+ end
47
+
48
+ def label_with_default(column)
49
+ "#{model.class.human_attribute_name(column)}".tap do |retv|
50
+ if (v = model.vendor.send(column)) && v.present?
51
+ retv << ' '
52
+ retv << h.e9_t(:vendor_default, :default_value => v)
53
+ end
54
+ end
55
+ end
56
+
57
+ protected
58
+
59
+ def liquid_context
60
+ super.merge({
61
+ 'vendor_discount_code' => model.discount_code,
62
+ 'vendor_sales_full_name' => model.sales_full_name,
63
+ 'vendor_sales_title' => model.sales_title,
64
+ 'vendor_sales_phone' => model.sales_phone,
65
+ 'vendor_sales_email' => model.sales_email,
66
+ 'vendor_landing_page' => model.landing_page,
67
+ 'vendor_discount_percentage' => model.discount_percentage,
68
+ 'vendor_name' => vendor.name,
69
+ 'vendor_nickname' => vendor.nickname,
70
+ 'member_name' => vendor_member.name,
71
+ 'member_nickname' => vendor_member.nickname
72
+ })
73
+ end
74
+ end
@@ -0,0 +1,27 @@
1
+ class VendorsDecorator < BaseDecorator
2
+ allows :id, :role, :remove_logo!
3
+
4
+ protected
5
+
6
+ class << self
7
+ delegate :lookup_ancestors, :i18n_scope, :to => :model_class
8
+ end
9
+
10
+ # simply send it all over to the model
11
+ def method_missing(*args)
12
+ model.send(*args)
13
+ end
14
+
15
+ def liquid_render(template)
16
+ Liquid::Template.parse(template || '').render(liquid_context)
17
+ end
18
+
19
+ def config_render(key)
20
+ liquid_render(E9::Config[key])
21
+ end
22
+
23
+ def liquid_context
24
+ # from base_controller
25
+ h.liquid_env
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ class Vendor < ActiveRecord::Base
2
+ include E9Vendors::Model
3
+
4
+ has_and_belongs_to_many :vendor_categories
5
+ has_many :vendor_proxies, :dependent => :destroy
6
+ has_many :vendor_members, :through => :vendor_proxies
7
+
8
+ validates :name, :presence => true
9
+ validates :logo, :presence => true
10
+ validates :contact_email, :presence => true, :email => { :allow_blank => true }
11
+ validates :sales_email, :presence => true, :email => { :allow_blank => true }
12
+ validates :short_description, :presence => true
13
+ validates :long_description, :presence => true
14
+ validates :discount_percentage, :presence => true, :numericality => { :allow_blank => true, :greater_than_or_equal_to => 0, :less_than => 100 }
15
+ validates :member_compensation, :presence => true, :numericality => { :allow_blank => true, :greater_than_or_equal_to => 0, :less_than => 100 }
16
+ validates :landing_page, :presence => true
17
+
18
+ mount_uploader :logo, LogoUploader
19
+
20
+ def self.all_proxies
21
+ all.map {|vendor| vendor.vendor_proxies.build }
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ class VendorCategory < ActiveRecord::Base
2
+ include E9Vendors::Model
3
+
4
+ has_and_belongs_to_many :vendors
5
+
6
+ validates :name, :presence => true
7
+
8
+ scope :widget_visible, lambda {
9
+ joins(:vendors => :vendor_proxies) & VendorProxy.widget_visible
10
+ }
11
+
12
+ # On updates, all members are touched, ensuring that widget JSON requests
13
+ # for the associations are pulling the most recent information
14
+ after_save :on => :update do
15
+ VendorMember.touch_all
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ class VendorMember < ActiveRecord::Base
2
+ include E9Vendors::Model
3
+
4
+ def self.add_vendor_proxy(proxy_association)
5
+ all.each {|member| member.vendor_proxies << proxy_association.build }
6
+ end
7
+
8
+ has_many :vendor_proxies, :dependent => :destroy do
9
+ def by_category
10
+ includes(:vendor => :vendor_categories)
11
+ .order('vendor_categories.position')
12
+ .group_by {|vd| vd.vendor.vendor_category.name }
13
+ end
14
+ end
15
+ has_many :vendors, :through => :vendor_proxies
16
+
17
+ mount_uploader :logo, LogoUploader
18
+
19
+ validates :name, :presence => true
20
+ validates :logo, :presence => true
21
+ end
@@ -0,0 +1,39 @@
1
+ class VendorProxy < ActiveRecord::Base
2
+ include E9Vendors::Model
3
+
4
+ belongs_to :vendor, :touch => true
5
+ belongs_to :vendor_member, :touch => true
6
+
7
+ before_validation :populate_default_discount_code, :on => :create
8
+
9
+ validates :discount_code, :presence => true, :on => :update
10
+ validates :discount_percentage, :numericality => { :greater_than_or_equal_to => 0, :less_than => 100 }
11
+ validates :sales_email, :email => { :allow_blank => true }
12
+
13
+ delegate :name, :to => :vendor, :prefix => true
14
+
15
+ scope :widget_visible, lambda { where(:display_on_widget => true) }
16
+
17
+ PROXIED_COLUMNS = %w(
18
+ discount_percentage
19
+ landing_page
20
+ sales_full_name
21
+ sales_title
22
+ sales_phone
23
+ sales_email
24
+ )
25
+
26
+ PROXIED_COLUMNS.each do |column|
27
+ class_eval %Q[def #{column}; vendor_fallback(:#{column}) end]
28
+ end
29
+
30
+ protected
31
+
32
+ def populate_default_discount_code
33
+ self.discount_code = "V-#{self.vendor.id}-#{self.vendor_member.id}"
34
+ end
35
+
36
+ def vendor_fallback(column)
37
+ read_attribute(column).presence || vendor.send(column)
38
+ end
39
+ end