Merge tag 'v1.8.9' into transifex

This commit is contained in:
Maikel Linke
2017-04-06 10:36:14 +10:00
23 changed files with 139 additions and 27 deletions

View File

@@ -1 +1 @@
angular.module("admin.products", ["admin.utils"])
angular.module("admin.products", ["textAngular", "admin.utils"])

View File

@@ -0,0 +1,5 @@
angular.module("admin.utils").directive "textangularStrip", () ->
restrict: 'CA'
link: (scope, element, attrs) ->
scope.stripFormatting = ($html) ->
return String($html).replace(/<[^>]+>/gm, '')

View File

@@ -3,9 +3,9 @@
%p.modal-header {{'contact' | t}}
%p{"ng-if" => "::enterprise.phone", "ng-bind" => "::enterprise.phone"}
%p.word-wrap{"ng-if" => "::enterprise.email_address"}
%p{"ng-if" => "::enterprise.email_address"}
%a{"ng-href" => "{{::enterprise.email_address | stripUrl}}", target: "_blank", mailto: true}
%span.email{"ng-bind" => "::enterprise.email_address | stripUrl"}
%p.word-wrap{"ng-if" => "enterprise.website"}
%p{"ng-if" => "enterprise.website"}
%a{"ng-href" => "http://{{::enterprise.website | stripUrl}}", target: "_blank", "ng-bind" => "::enterprise.website | stripUrl"}

View File

@@ -14,9 +14,9 @@
.filter-shopfront.property-selectors.inline-block
%filter-selector{ 'selector-set' => "productPropertySelectors", objects: "[product] | propertiesWithValuesOf" }
%div{"ng-if" => "product.description"}
%div{"ng-if" => "product.description_html"}
%hr
%p.text-small{"ng-bind" => "::product.description"}
%p.text-small{"ng-bind-html" => "::product.description_html"}
%hr
.columns.small-12.large-6

View File

@@ -200,6 +200,13 @@ table#listing_enterprise_groups {
// textAngular wysiwyg
text-angular {
.ta-toolbar {
border: 1px solid #cdd9e4;
padding: 0.4em;
margin-bottom: -1px;
background-color: #f1f1f1;
border-radius: 0.25em 0.25em 0 0;
}
.ta-scroll-window > .ta-bind {
max-height: 400px;
min-height: 100px;
@@ -210,12 +217,18 @@ text-angular {
}
.ta-scroll-window.form-control {
min-height: 100px;
box-shadow: none !important;
}
.btn-group {
display: inline;
margin-right: 8px;
button {
padding: 5px 10px;
margin-right: 0.25em;
}
button.active:not(:hover) {
box-shadow: 0 0 0.7em rgba(0,0,0,0.3) inset;
background-color: #4583bf;
}
}
}

View File

@@ -175,7 +175,7 @@ class AbilityDecorator
def add_order_management_abilities(user)
# Enterprise User can only access orders that they are a distributor for
can [:index, :create], Spree::Order
can [:read, :update, :fire, :resend, :invoice, :print], Spree::Order do |order|
can [:read, :update, :fire, :resend, :invoice, :print, :print_ticket], Spree::Order do |order|
# We allow editing orders with a nil distributor as this state occurs
# during the order creation process from the admin backend
order.distributor.nil? || user.enterprises.include?(order.distributor) || order.order_cycle.andand.coordinated_by?(user)

View File

@@ -6,7 +6,6 @@ Spree::AppConfiguration.class_eval do
# Terms of Service Preferences
preference :enterprises_require_tos, :boolean, default: false
preference :enterprise_tos_link, :string, default: "/Terms-of-service.pdf"
# Tax Preferences
preference :products_require_tax_category, :boolean, default: false

View File

@@ -2,10 +2,6 @@
%fieldset.enterprise_toc.no-border-bottom
%legend{:align => "center"}= t(:enterprise_terms_of_service)
- [:enterprise_tos_link, :enterprises_require_tos].each do |pref|
- type = Spree::Config.preference_type(pref)
.field
= label_tag(pref, t(pref) + ': ') + tag(:br) if type != :boolean
= preference_field_tag(pref, Spree::Config[pref], :type => type)
= label_tag(pref, t(pref)) + tag(:br) if type == :boolean
.field
= preference_field_tag(:enterprises_require_tos, Spree::Config[:enterprises_require_tos], :type => Spree::Config.preference_type(:enterprises_require_tos))
= label_tag(:enterprises_require_tos, t(:enterprises_require_tos)) + tag(:br)

View File

@@ -9,8 +9,8 @@
%table.index
%thead
%tr{"data-hook" => "producer_properties_header"}
%th= t(:inherited_property)
%th= t(:value)
%th= t('admin.products.properties.inherited_property')
%th= t('admin.description')
%th.actions
%tbody#producer_properties{"data-hook" => ""}
- @product.supplier.producer_properties.each do |producer_property|

View File

@@ -0,0 +1,5 @@
/ replace "tr[data-hook='product_properties_header']"
%tr{"data-hook" => "product_properties_header"}
%th= t('admin.products.properties.property_name')
%th= t('admin.description')
%th.actions

View File

@@ -0,0 +1,3 @@
/ replace "[data-hook=admin_product_form_left] code[erb-loud]:contains('f.text_area :description')"
%text-angular{'id' => 'product_description', 'name' => 'product[description]', 'class' => 'text-angular', 'textangular-strip' => true, 'ta-paste' => "stripFormatting($html)", 'ta-toolbar' => "[['bold','italics','clear']]"}
= sanitize(@product.description)

View File

@@ -0,0 +1,2 @@
add_to_attributes 'fieldset.no-border-top'
attributes 'ng-app' => 'admin.products'

View File

@@ -72,7 +72,7 @@
= f.field_container :description do
= f.label :product_description, t(:product_description)
%br/
= f.text_area :description, class: 'fullwidth', rows: 3
%text-angular{'id' => 'product_description', 'name' => 'product[description]', 'class' => 'text-angular', 'textangular-strip' => true, 'ta-paste' => "stripFormatting($html)", 'ta-toolbar' => "[['bold','italics','clear']]"}
= f.error_message_on :description
.four.columns.omega{ style: "text-align: center" }
%fieldset.no-border-bottom{ id: "image" }

View File

@@ -37,7 +37,7 @@ class Api::CachedProductSerializer < ActiveModel::Serializer
include ActionView::Helpers::SanitizeHelper
attributes :id, :name, :permalink
attributes :on_demand, :group_buy, :notes, :description
attributes :on_demand, :group_buy, :notes, :description, :description_html
attributes :properties_with_values
has_many :variants, serializer: Api::VariantSerializer
@@ -49,10 +49,17 @@ class Api::CachedProductSerializer < ActiveModel::Serializer
has_many :images, serializer: Api::ImageSerializer
has_one :supplier, serializer: Api::IdSerializer
#return an unformatted descripton
def description
strip_tags object.description
end
#return a sanitized html description
def description_html
d = sanitize(object.description, options = {tags: "p, b, strong, em, i"})
d.to_s.html_safe
end
def properties_with_values
object.properties_including_inherited
end

View File

@@ -4,8 +4,8 @@
%table.index.sortable{"data-hook" => "", "data-sortable-link" => main_app.update_positions_admin_enterprise_producer_properties_url(@enterprise)}
%thead
%tr{"data-hook" => "producer_properties_header"}
%th{colspan: "2"}= t('.property')
%th= t('.value')
%th{colspan: "2"}= t('admin.products.properties.property_name')
%th= t('admin.description')
%th.actions
%tbody#producer_properties{"data-hook" => ""}
= f.fields_for :producer_properties do |pp_form|

View File

@@ -6,7 +6,7 @@
= inject_enterprise_attributes
- steps = %w{about contact details finished images introduction}
- steps += %w{limit_reached logo promo social steps type}
- steps += %w{logo promo social steps type}
- steps.each do |step|
= render partial: "registration/steps/#{step}"
= render "modal"

View File

@@ -1,2 +1,4 @@
= render partial: "registration/steps/limit_reached"
/ Directive which loads the modal
%div{ "ofn-registration-limit-modal" => true }

View File

@@ -37,7 +37,7 @@
.small-12.columns{'ng-hide' => '!tos_required' }
%p.tos-message
#{t(:enterprise_tos_message)}
%a{href: "#{Spree::Config.enterprise_tos_link}", target: "_blank" } #{t(:enterprise_tos_link_text)}
%a{href: ContentConfig.footer_tos_url, target: "_blank" } #{t(:enterprise_tos_link_text)}
%p.tos-checkbox
%input{ type: 'checkbox', name: 'accept_terms', id: 'accept_terms', ng: { model: "tos_accepted" } }
%label{for: "accept_terms"} #{t(:enterprise_tos_agree)}

View File

@@ -105,6 +105,7 @@ module Openfoodnetwork
config.assets.precompile += ['mail/all.css']
config.assets.precompile += ['search/all.css', 'search/*.js']
config.assets.precompile += ['shared/*']
config.assets.precompile += ['qz/*']
config.active_support.escape_html_entities_in_json = true
end

View File

@@ -109,6 +109,7 @@ en:
columns: Columns
actions: Actions
viewing: "Viewing: %{current_view_name}"
description: Description
whats_this: What's this?
@@ -223,6 +224,9 @@ en:
inherits_properties?: Inherits Properties?
available_on: Available On
av_on: "Av. On"
properties:
property_name: Property Name
inherited_property: Inherited Property
variants:
to_order_tip: "Items made to order do not have a set stock level, such as loaves of bread made fresh to order."
@@ -503,9 +507,6 @@ en:
advanced_settings: Advanced Settings
update_and_close: Update and Close
producer_properties:
form:
property: Property
value: Value
index:
title: Producer Properties
shared:

View File

@@ -35,7 +35,7 @@ feature %q{
fill_in 'product_on_hand', with: 5
select 'Test Tax Category', from: 'product_tax_category_id'
select 'Test Shipping Category', from: 'product_shipping_category_id'
fill_in 'product_description', with: "A description..."
page.find("input[name='product\[description\]']", visible: false).set('A description...')
click_button 'Create'
@@ -75,7 +75,8 @@ feature %q{
check 'product_on_demand'
select 'Test Tax Category', from: 'product_tax_category_id'
select 'Test Shipping Category', from: 'product_shipping_category_id'
fill_in 'product_description', with: "In demand, and on_demand! The hottest cakes in town."
#fill_in 'product_description', with: "In demand, and on_demand! The hottest cakes in town."
page.first("input[name='product\[description\]']", visible: false).set('In demand, and on_demand! The hottest cakes in town.')
click_button 'Create'

View File

@@ -98,6 +98,23 @@ feature "Registration", js: true do
expect(e.instagram).to eq "@InStAgRaM"
end
context "when the user has no more remaining enterprises" do
before do
user.update_attributes(enterprise_limit: 0)
end
it "displays the limit reached page" do
visit registration_path
expect(page).to have_selector "dd", text: "Login"
switch_to_login_tab
# Enter Login details
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_login_and_ensure_content I18n.t('limit_reached_headline')
end
end
end
describe "Terms of Service agreement" do

View File

@@ -0,0 +1,60 @@
require 'spec_helper'
feature "As a consumer I want to view products", js: true do
include AuthenticationWorkflow
include WebHelper
include ShopWorkflow
include UIComponentHelper
describe "Viewing a product" do
let(:distributor) { create(:distributor_enterprise, with_payment_and_shipping: true) }
let(:supplier) { create(:supplier_enterprise) }
let(:oc1) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), orders_close_at: 2.days.from_now) }
let(:product) { create(:simple_product, supplier: supplier) }
let(:variant) { product.variants.first }
let(:order) { create(:order, distributor: distributor) }
let(:exchange1) { oc1.exchanges.to_enterprises(distributor).outgoing.first }
before do
set_order order
end
describe "viewing HTML product descriptions" do
before do
exchange1.update_attribute :pickup_time, "monday"
add_variant_to_order_cycle(exchange1, variant)
end
it "shows HTML product description" do
product.description = "<p><b>Formatted</b> product description.</p>"
product.save!
visit shop_path
select "monday", :from => "order_cycle_id"
open_product_modal product
modal_should_be_open_for product
within(".reveal-modal") do
html.should include("<p><b>Formatted</b> product description.</p>")
end
end
it "does not show unsecure HTML" do
product.description = "<script>alert('Dangerous!');</script><p>Safe</p>"
product.save!
visit shop_path
select "monday", :from => "order_cycle_id"
open_product_modal product
modal_should_be_open_for product
within(".reveal-modal") do
html.should include("<p>Safe</p>")
html.should_not include("<script>alert('Dangerous!');</script>")
end
end
end
end
end