diff --git a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee index bb1ae6b31a..4acd61e84b 100644 --- a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee +++ b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee @@ -1,5 +1,5 @@ angular.module("admin.enterprises") - .controller "enterpriseCtrl", ($scope, $http, $window, NavigationCheck, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> + .controller "enterpriseCtrl", ($scope, $http, $window, NavigationCheck, enterprise, Enterprises, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> $scope.Enterprise = enterprise $scope.PaymentMethods = EnterprisePaymentMethods.paymentMethods $scope.ShippingMethods = EnterpriseShippingMethods.shippingMethods @@ -67,3 +67,27 @@ angular.module("admin.enterprises") $scope.resetModal = -> $scope.newUser = $scope.invite_errors = $scope.invite_success = null + + $scope.removeLogo = -> + return unless confirm(t("admin.enterprises.remove_logo.immediate_removal_warning")) + + Enterprises.removeLogo($scope.Enterprise).then (data) -> + $scope.Enterprise = angular.copy(data) + $scope.$emit("enterprise:updated", $scope.Enterprise) + + StatusMessage.display("success", t("admin.enterprises.remove_logo.removed_successfully")) + , (response) -> + if response.data.error? + StatusMessage.display("failure", response.data.error) + + $scope.removePromoImage = -> + return unless confirm(t("admin.enterprises.remove_promo_image.immediate_removal_warning")) + + Enterprises.removePromoImage($scope.Enterprise).then (data) -> + $scope.Enterprise = angular.copy(data) + $scope.$emit("enterprise:updated", $scope.Enterprise) + + StatusMessage.display("success", t("admin.enterprises.remove_promo_image.removed_successfully")) + , (response) -> + if response.data.error? + StatusMessage.display("failure", response.data.error) diff --git a/app/assets/javascripts/admin/resources/resources/enterprise_resource.js.coffee b/app/assets/javascripts/admin/resources/resources/enterprise_resource.js.coffee index 7cdd5b7bce..ec89bbda36 100644 --- a/app/assets/javascripts/admin/resources/resources/enterprise_resource.js.coffee +++ b/app/assets/javascripts/admin/resources/resources/enterprise_resource.js.coffee @@ -8,4 +8,10 @@ angular.module("admin.resources").factory 'EnterpriseResource', ($resource) -> isArray: true 'update': method: 'PUT' + 'removeLogo': + url: '/api/enterprises/:id/logo.json' + method: 'DELETE' + 'removePromoImage': + url: '/api/enterprises/:id/promo_image.json' + method: 'DELETE' }) diff --git a/app/assets/javascripts/admin/resources/services/enterprises.js.coffee b/app/assets/javascripts/admin/resources/services/enterprises.js.coffee index 0b7fa6e870..435cc88500 100644 --- a/app/assets/javascripts/admin/resources/services/enterprises.js.coffee +++ b/app/assets/javascripts/admin/resources/services/enterprises.js.coffee @@ -38,3 +38,17 @@ angular.module("admin.resources").factory 'Enterprises', ($q, EnterpriseResource resetAttribute: (enterprise, attribute) -> enterprise[attribute] = @pristineByID[enterprise.id][attribute] + + performActionOnEnterpriseResource = (resourceAction) -> + (enterprise) -> + deferred = $q.defer() + resourceAction({id: enterprise.permalink}, ((data) => + @pristineByID[enterprise.id] = angular.copy(data) + deferred.resolve(data) + ), ((response) -> + deferred.reject(response) + )) + deferred.promise + + removeLogo: performActionOnEnterpriseResource(EnterpriseResource.removeLogo) + removePromoImage: performActionOnEnterpriseResource(EnterpriseResource.removePromoImage) diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index f25c47417d..a7f96d01cf 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -9,5 +9,9 @@ module Api include ActionController::UrlFor include Rails.application.routes.url_helpers use_renderers :json + + def respond_with_conflict(json_hash) + render json: json_hash, status: :conflict + end end end diff --git a/app/controllers/api/enterprise_attachment_controller.rb b/app/controllers/api/enterprise_attachment_controller.rb new file mode 100644 index 0000000000..083d6946be --- /dev/null +++ b/app/controllers/api/enterprise_attachment_controller.rb @@ -0,0 +1,37 @@ +module Api + class EnterpriseAttachmentController < BaseController + class MissingImplementationError < StandardError; end + class UnknownEnterpriseAuthorizationActionError < StandardError; end + + before_filter :load_enterprise + + respond_to :json + + def destroy + return respond_with_conflict(error: destroy_attachment_does_not_exist_error_message) unless @enterprise.public_send("#{attachment_name}?") + + @enterprise.update_attributes!(attachment_name => nil) + render json: @enterprise, serializer: Admin::EnterpriseSerializer, spree_current_user: spree_current_user + end + + protected + + def attachment_name + raise MissingImplementationError, "Method attachment_name should be defined" + end + + def enterprise_authorize_action + raise MissingImplementationError, "Method enterprise_authorize_action should be defined" + end + + def load_enterprise + @enterprise = Enterprise.find_by_permalink(params[:enterprise_id].to_s) + raise UnknownEnterpriseAuthorizationActionError if enterprise_authorize_action.blank? + authorize!(enterprise_authorize_action, @enterprise) + end + + def destroy_attachment_does_not_exist_error_message + I18n.t("api.enterprise_#{attachment_name}.destroy_attachment_does_not_exist") + end + end +end diff --git a/app/controllers/api/logos_controller.rb b/app/controllers/api/logos_controller.rb new file mode 100644 index 0000000000..f3e7934724 --- /dev/null +++ b/app/controllers/api/logos_controller.rb @@ -0,0 +1,16 @@ +module Api + class LogosController < EnterpriseAttachmentController + private + + def attachment_name + :logo + end + + def enterprise_authorize_action + case action_name.to_sym + when :destroy + :remove_logo + end + end + end +end diff --git a/app/controllers/api/promo_images_controller.rb b/app/controllers/api/promo_images_controller.rb new file mode 100644 index 0000000000..0e79ebdb93 --- /dev/null +++ b/app/controllers/api/promo_images_controller.rb @@ -0,0 +1,16 @@ +module Api + class PromoImagesController < EnterpriseAttachmentController + private + + def attachment_name + :promo_image + end + + def enterprise_authorize_action + case action_name.to_sym + when :destroy + :remove_promo_image + end + end + end +end diff --git a/app/controllers/spree/admin/base_controller_decorator.rb b/app/controllers/spree/admin/base_controller_decorator.rb index fb0e54baa8..60887f2ce5 100644 --- a/app/controllers/spree/admin/base_controller_decorator.rb +++ b/app/controllers/spree/admin/base_controller_decorator.rb @@ -28,7 +28,11 @@ Spree::Admin::BaseController.class_eval do record = self.class.to_s.sub("Controller", "").underscore.split('/').last.singularize.to_sym end authorize! :admin, record - authorize! action, record + authorize! resource_authorize_action, record + end + + def resource_authorize_action + action end # This is in Spree::Core::ControllerHelpers::Auth diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index 53198251b9..9d0941a220 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -99,7 +99,7 @@ class AbilityDecorator end can [:admin, :index, :create], Enterprise - can [:read, :edit, :update, :bulk_update, :resend_confirmation], Enterprise do |enterprise| + can [:read, :edit, :update, :remove_logo, :remove_promo_image, :bulk_update, :resend_confirmation], Enterprise do |enterprise| OpenFoodNetwork::Permissions.new(user).editable_enterprises.include? enterprise end can [:welcome, :register], Enterprise do |enterprise| diff --git a/app/serializers/api/admin/enterprise_serializer.rb b/app/serializers/api/admin/enterprise_serializer.rb index e29954992f..348bb75461 100644 --- a/app/serializers/api/admin/enterprise_serializer.rb +++ b/app/serializers/api/admin/enterprise_serializer.rb @@ -5,11 +5,20 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer attributes :preferred_product_selection_from_inventory_only attributes :owner, :contact, :users, :tag_groups, :default_tag_group attributes :require_login, :allow_guest_orders, :allow_order_changes + attributes :logo, :promo_image has_one :owner, serializer: Api::Admin::UserSerializer has_many :users, serializer: Api::Admin::UserSerializer has_one :address, serializer: Api::AddressSerializer + def logo + attachment_urls(object.logo, [:thumb, :small, :medium]) + end + + def promo_image + attachment_urls(object.promo_image, [:thumb, :medium, :large]) + end + def tag_groups object.tag_rules.prioritised.reject(&:is_default).each_with_object([]) do |tag_rule, tag_groups| tag_group = find_match(tag_groups, tag_rule.preferred_customer_tags.split(",").map{ |t| { text: t } }) @@ -33,4 +42,24 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer end return { tags: tags, rules: [] } end + + private + + # Returns a hash of URLs for specified versions of an attachment. + # + # Example: + # + # attachment_urls(object.logo, [:thumb, :small, :medium]) + # # { + # # thumb: LOGO_THUMB_URL, + # # small: LOGO_SMALL_URL, + # # medium: LOGO_MEDIUM_URL + # # } + def attachment_urls(attachment, versions) + return unless attachment.exists? + + versions.each_with_object({}) do |version, urls| + urls[version] = attachment.url(version) + end + end end diff --git a/app/views/admin/enterprises/form/_images.html.haml b/app/views/admin/enterprises/form/_images.html.haml index 97d31dabcc..0f48fce322 100644 --- a/app/views/admin/enterprises/form/_images.html.haml +++ b/app/views/admin/enterprises/form/_images.html.haml @@ -1,12 +1,15 @@ -.row +.row.page-admin-enterprises-form__logo-field-group.image-field-group .alpha.three.columns = f.label :logo %br 100 x 100 pixels .omega.eight.columns - = image_tag @object.logo(:medium) if @object.logo.present? + %img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.logo.medium }}', if: 'Enterprise.logo' } } = f.file_field :logo -.row + %a.button.red{ href: '', ng: {click: 'removeLogo()', if: 'Enterprise.logo'} } + = t('admin.enterprises.remove_logo.remove') + +.row.page-admin-enterprises-form__promo-image-field-group.image-field-group .alpha.three.columns = f.label :promo_image, 'ofn-with-tip' => t('.promo_image_placeholder') %br/ @@ -17,5 +20,7 @@ = t('.promo_image_note3') .omega.eight.columns - = image_tag @object.promo_image(:large) if @object.promo_image.present? + %img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.promo_image.large }}', if: 'Enterprise.promo_image' } } = f.file_field :promo_image + %a.button.red{ href: '', ng: {click: 'removePromoImage()', if: 'Enterprise.promo_image'} } + = t('admin.enterprises.remove_promo_image.remove') diff --git a/config/locales/en.yml b/config/locales/en.yml index 723d4c8cf1..b03855fcb4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -853,6 +853,14 @@ en: new: title: New Enterprise back_link: Back to enterprises list + remove_logo: + remove: "Remove Image" + removed_successfully: "Logo removed successfully" + immediate_removal_warning: "The logo will be removed immediately after you confirm." + remove_promo_image: + remove: "Remove Image" + removed_successfully: "Promo image removed successfully" + immediate_removal_warning: "The promo image will be removed immediately after you confirm." welcome: welcome_title: Welcome to the Open Food Network! welcome_text: You have successfully created a @@ -1101,6 +1109,14 @@ en: stripe_connect_settings: resource: Stripe Connect configuration +# API +# + api: + enterprise_logo: + destroy_attachment_does_not_exist: "Logo does not exist" + enterprise_promo_image: + destroy_attachment_does_not_exist: "Promo image does not exist" + # Frontend views # # These keys are referenced relatively like `t('.message')` in diff --git a/config/routes.rb b/config/routes.rb index 574140bd5b..4f6125c8ac 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -95,7 +95,11 @@ Openfoodnetwork::Application.routes.draw do post :update_image, on: :member get :managed, on: :collection get :accessible, on: :collection + + resource :logo, only: [:destroy] + resource :promo_image, only: [:destroy] end + resources :order_cycles do get :managed, on: :collection get :accessible, on: :collection diff --git a/spec/controllers/api/logos_controller_spec.rb b/spec/controllers/api/logos_controller_spec.rb new file mode 100644 index 0000000000..213ac8bc6e --- /dev/null +++ b/spec/controllers/api/logos_controller_spec.rb @@ -0,0 +1,90 @@ +require "spec_helper" + +module Api + describe LogosController, type: :controller do + include AuthenticationWorkflow + + let(:admin_user) { create(:admin_user) } + let(:enterprise_owner) { create(:user) } + let(:enterprise) { create(:enterprise, owner: enterprise_owner ) } + let(:enterprise_manager) { create(:user, enterprise_limit: 10, enterprises: [enterprise]) } + let(:other_enterprise_owner) { create(:user) } + let(:other_enterprise) { create(:enterprise, owner: other_enterprise_owner ) } + let(:other_enterprise_manager) { create(:user, enterprise_limit: 10, enterprises: [other_enterprise]) } + + describe "removing logo" do + image_path = File.open(Rails.root.join("app", "assets", "images", "logo-black.png")) + let(:image) { Rack::Test::UploadedFile.new(image_path, "image/png") } + + let(:enterprise) { create(:enterprise, owner: enterprise_owner, logo: image) } + + before do + allow(controller).to receive(:spree_current_user) { current_user } + end + + context "as manager" do + let(:current_user) { enterprise_manager } + + it "removes logo" do + spree_delete :destroy, enterprise_id: enterprise + + expect(response).to be_success + expect(json_response["id"]).to eq enterprise.id + enterprise.reload + expect(enterprise.logo?).to be false + end + + context "when logo does not exist" do + let(:enterprise) { create(:enterprise, owner: enterprise_owner, logo: nil) } + + it "responds with error" do + spree_delete :destroy, enterprise_id: enterprise + + expect(response.status).to eq(409) + expect(json_response["error"]).to eq I18n.t("api.enterprise_logo.destroy_attachment_does_not_exist") + end + end + end + + context "as owner" do + let(:current_user) { enterprise_owner } + + it "allows removal of logo" do + spree_delete :destroy, enterprise_id: enterprise + expect(response).to be_success + end + end + + context "as super admin" do + let(:current_user) { admin_user } + + it "allows removal of logo" do + spree_delete :destroy, enterprise_id: enterprise + expect(response).to be_success + end + end + + context "as manager of other enterprise" do + let(:current_user) { other_enterprise_manager } + + it "does not allow removal of logo" do + spree_delete :destroy, enterprise_id: enterprise + expect(response.status).to eq(401) + enterprise.reload + expect(enterprise.logo?).to be true + end + end + + context "as owner of other enterprise" do + let(:current_user) { other_enterprise_owner } + + it "does not allow removal of logo" do + spree_delete :destroy, enterprise_id: enterprise + expect(response.status).to eq(401) + enterprise.reload + expect(enterprise.logo?).to be true + end + end + end + end +end diff --git a/spec/controllers/api/promo_images_controller_spec.rb b/spec/controllers/api/promo_images_controller_spec.rb new file mode 100644 index 0000000000..cce6d08f5f --- /dev/null +++ b/spec/controllers/api/promo_images_controller_spec.rb @@ -0,0 +1,90 @@ +require "spec_helper" + +module Api + describe PromoImagesController, type: :controller do + include AuthenticationWorkflow + + let(:admin_user) { create(:admin_user) } + let(:enterprise_owner) { create(:user) } + let(:enterprise) { create(:enterprise, owner: enterprise_owner ) } + let(:enterprise_manager) { create(:user, enterprise_limit: 10, enterprises: [enterprise]) } + let(:other_enterprise_owner) { create(:user) } + let(:other_enterprise) { create(:enterprise, owner: other_enterprise_owner ) } + let(:other_enterprise_manager) { create(:user, enterprise_limit: 10, enterprises: [other_enterprise]) } + + describe "removing promo image" do + image_path = File.open(Rails.root.join("app", "assets", "images", "logo-black.png")) + let(:image) { Rack::Test::UploadedFile.new(image_path, "image/png") } + + let(:enterprise) { create(:enterprise, owner: enterprise_owner, promo_image: image) } + + before do + allow(controller).to receive(:spree_current_user) { current_user } + end + + context "as manager" do + let(:current_user) { enterprise_manager } + + it "removes promo image" do + spree_delete :destroy, enterprise_id: enterprise + + expect(response).to be_success + expect(json_response["id"]).to eq enterprise.id + enterprise.reload + expect(enterprise.promo_image?).to be false + end + + context "when promo image does not exist" do + let(:enterprise) { create(:enterprise, owner: enterprise_owner, promo_image: nil) } + + it "responds with error" do + spree_delete :destroy, enterprise_id: enterprise + + expect(response.status).to eq(409) + expect(json_response["error"]).to eq I18n.t("api.enterprise_promo_image.destroy_attachment_does_not_exist") + end + end + end + + context "as owner" do + let(:current_user) { enterprise_owner } + + it "allows removal of promo image" do + spree_delete :destroy, enterprise_id: enterprise + expect(response).to be_success + end + end + + context "as super admin" do + let(:current_user) { admin_user } + + it "allows removal of promo image" do + spree_delete :destroy, enterprise_id: enterprise + expect(response).to be_success + end + end + + context "as manager of other enterprise" do + let(:current_user) { other_enterprise_manager } + + it "does not allow removal of promo image" do + spree_delete :destroy, enterprise_id: enterprise + expect(response.status).to eq(401) + enterprise.reload + expect(enterprise.promo_image?).to be true + end + end + + context "as owner of other enterprise" do + let(:current_user) { other_enterprise_owner } + + it "does not allow removal of promo image" do + spree_delete :destroy, enterprise_id: enterprise + expect(response.status).to eq(401) + enterprise.reload + expect(enterprise.promo_image?).to be true + end + end + end + end +end diff --git a/spec/features/admin/enterprises/images_spec.rb b/spec/features/admin/enterprises/images_spec.rb new file mode 100644 index 0000000000..92c4bbafaf --- /dev/null +++ b/spec/features/admin/enterprises/images_spec.rb @@ -0,0 +1,104 @@ +require "spec_helper" + +feature "Managing enterprise images" do + include AuthenticationWorkflow + include WebHelper + + context "as an Enterprise user", js: true do + let(:enterprise_user) { create_enterprise_user(enterprise_limit: 1) } + let(:distributor) { create(:distributor_enterprise, name: "First Distributor") } + + before do + enterprise_user.enterprise_roles.build(enterprise: distributor).save! + + quick_login_as enterprise_user + visit edit_admin_enterprise_path(distributor) + end + + describe "images for an enterprise", js: true do + def go_to_images + within(".side_menu") do + click_link "Images" + end + end + + before do + go_to_images + end + + scenario "editing logo" do + # Adding image + attach_file "enterprise[logo]", Rails.root.join("app", "assets", "images", "logo-white.png") + click_button "Update" + + expect(page).to have_content("Enterprise \"#{distributor.name}\" has been successfully updated!") + + go_to_images + within ".page-admin-enterprises-form__logo-field-group" do + expect(page).to have_selector(".image-field-group__preview-image") + expect(html).to include("logo-white.png") + end + + # Replacing image + attach_file "enterprise[logo]", Rails.root.join("app", "assets", "images", "logo-black.png") + click_button "Update" + + expect(page).to have_content("Enterprise \"#{distributor.name}\" has been successfully updated!") + + go_to_images + within ".page-admin-enterprises-form__logo-field-group" do + expect(page).to have_selector(".image-field-group__preview-image") + expect(html).to include("logo-black.png") + end + + # Removing image + within ".page-admin-enterprises-form__logo-field-group" do + click_on "Remove Image" + end + + expect(page).to have_content("Logo removed successfully") + + within ".page-admin-enterprises-form__logo-field-group" do + expect(page).to have_no_selector(".image-field-group__preview-image") + end + end + + scenario "editing promo image" do + # Adding image + attach_file "enterprise[promo_image]", Rails.root.join("app", "assets", "images", "logo-white.png") + click_button "Update" + + expect(page).to have_content("Enterprise \"#{distributor.name}\" has been successfully updated!") + + go_to_images + within ".page-admin-enterprises-form__promo-image-field-group" do + expect(page).to have_selector(".image-field-group__preview-image") + expect(html).to include("logo-white.jpg") + end + + # Replacing image + attach_file "enterprise[promo_image]", Rails.root.join("app", "assets", "images", "logo-black.png") + click_button "Update" + + expect(page).to have_content("Enterprise \"#{distributor.name}\" has been successfully updated!") + + go_to_images + within ".page-admin-enterprises-form__promo-image-field-group" do + expect(page).to have_selector(".image-field-group__preview-image") + expect(html).to include("logo-black.jpg") + end + + # Removing image + within ".page-admin-enterprises-form__promo-image-field-group" do + click_on "Remove Image" + end + + expect(page).to have_content("Promo image removed successfully") + + within ".page-admin-enterprises-form__promo-image-field-group" do + expect(page).to have_no_selector(".image-field-group__preview-image") + end + end + end + end +end diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index 5a78b80954..f594536127 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -417,18 +417,6 @@ feature %q{ end end - scenario "editing images for an enterprise" do - visit admin_enterprises_path - within("tbody#e_#{distributor1.id}") { click_link 'Settings' } - - within(".side_menu") do - click_link "Images" - end - - page.should have_content "LOGO" - page.should have_content "PROMO" - end - scenario "managing producer properties" do create(:property, name: "Certified Organic") visit admin_enterprises_path diff --git a/spec/javascripts/unit/admin/enterprises/controllers/enterprise_controller_spec.js.coffee b/spec/javascripts/unit/admin/enterprises/controllers/enterprise_controller_spec.js.coffee index 17ef445846..475de27e29 100644 --- a/spec/javascripts/unit/admin/enterprises/controllers/enterprise_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/enterprises/controllers/enterprise_controller_spec.js.coffee @@ -4,6 +4,8 @@ describe "enterpriseCtrl", -> enterprise = null PaymentMethods = null ShippingMethods = null + Enterprises = null + StatusMessage = null beforeEach -> module('admin.enterprises') @@ -18,9 +20,11 @@ describe "enterpriseCtrl", -> shippingMethods: "shipping methods" receivesNotifications = 99 - inject ($rootScope, $controller) -> + inject ($rootScope, $controller, _Enterprises_, _StatusMessage_) -> scope = $rootScope - ctrl = $controller 'enterpriseCtrl', {$scope: scope, enterprise: enterprise, EnterprisePaymentMethods: PaymentMethods, EnterpriseShippingMethods: ShippingMethods, receivesNotifications: receivesNotifications} + Enterprises = _Enterprises_ + StatusMessage = _StatusMessage_ + ctrl = $controller "enterpriseCtrl", {$scope: scope, enterprise: enterprise, EnterprisePaymentMethods: PaymentMethods, EnterpriseShippingMethods: ShippingMethods, Enterprises: Enterprises, StatusMessage: StatusMessage, receivesNotifications: receivesNotifications} describe "initialisation", -> it "stores enterprise", -> @@ -32,6 +36,72 @@ describe "enterpriseCtrl", -> it "stores shipping methods", -> expect(scope.ShippingMethods).toBe ShippingMethods.shippingMethods + describe "removing logo", -> + deferred = null + + beforeEach inject ($q) -> + spyOn(scope, "$emit") + deferred = $q.defer() + spyOn(window, "confirm").and.returnValue(true) + spyOn(Enterprises, "removeLogo").and.returnValue(deferred.promise) + spyOn(StatusMessage, "display").and.callThrough() + scope.removeLogo() + + describe "when successful", -> + beforeEach inject ($rootScope) -> + deferred.resolve() + $rootScope.$digest() + + it "emits an 'enterprise:updated' event", -> + expect(scope.$emit).toHaveBeenCalledWith("enterprise:updated", scope.Enterprise) + + it "notifies user of success", -> + expect(StatusMessage.display).toHaveBeenCalledWith("success", "Logo removed successfully") + + describe "when unsuccessful", -> + beforeEach inject ($rootScope) -> + deferred.reject({ data: { error: "Logo does not exist" } }) + $rootScope.$digest() + + it "does not emit an 'enterprise:updated' event", -> + expect(scope.$emit).not.toHaveBeenCalled() + + it "notifies user of failure", -> + expect(StatusMessage.display).toHaveBeenCalledWith("failure", "Logo does not exist") + + describe "removing promo image", -> + deferred = null + + beforeEach inject ($q) -> + spyOn(scope, "$emit") + deferred = $q.defer() + spyOn(window, "confirm").and.returnValue(true) + spyOn(Enterprises, "removePromoImage").and.returnValue(deferred.promise) + spyOn(StatusMessage, "display").and.callThrough() + scope.removePromoImage() + + describe "when successful", -> + beforeEach inject ($rootScope) -> + deferred.resolve() + $rootScope.$digest() + + it "emits an 'enterprise:updated' event", -> + expect(scope.$emit).toHaveBeenCalledWith("enterprise:updated", scope.Enterprise) + + it "notifies user of success", -> + expect(StatusMessage.display).toHaveBeenCalledWith("success", "Promo image removed successfully") + + describe "when unsuccessful", -> + beforeEach inject ($rootScope) -> + deferred.reject({ data: { error: "Promo image does not exist" } }) + $rootScope.$digest() + + it "does not emit an 'enterprise:updated' event", -> + expect(scope.$emit).not.toHaveBeenCalled() + + it "notifies user of failure", -> + expect(StatusMessage.display).toHaveBeenCalledWith("failure", "Promo image does not exist") + describe "adding managers", -> u1 = u2 = u3 = null beforeEach -> diff --git a/spec/javascripts/unit/admin/enterprises/services/enterprises_spec.js.coffee b/spec/javascripts/unit/admin/enterprises/services/enterprises_spec.js.coffee index 8c088b1715..47c669e105 100644 --- a/spec/javascripts/unit/admin/enterprises/services/enterprises_spec.js.coffee +++ b/spec/javascripts/unit/admin/enterprises/services/enterprises_spec.js.coffee @@ -118,3 +118,73 @@ describe "Enterprises service", -> it "resets the specified value according to the pristine record", -> Enterprises.resetAttribute(enterprise, "name") expect(enterprise.name).toEqual "enterprise1" + + describe "#removeLogo", -> + enterprise = null + + describe "success", -> + resolved = false + + beforeEach -> + enterprise = new EnterpriseResource({ id: 15, permalink: "enterprise1", name: "Enterprise 1", logo: {} }) + $httpBackend.expectDELETE("/api/enterprises/enterprise1/logo.json").respond 200, { id: 15, name: "Enterprise 1"} + Enterprises.removeLogo(enterprise).then( -> resolved = true) + $httpBackend.flush() + + it "updates the pristine copy of the enterprise", -> + expect(Enterprises.pristineByID[15]).not.toBeUndefined() + expect(Enterprises.pristineByID[15]["id"]).toEqual(15) + expect(Enterprises.pristineByID[15]["logo"]).toBeUndefined() + + it "resolves the promise", -> + expect(resolved).toBe(true) + + describe "failure", -> + rejected = false + + beforeEach -> + enterprise = new EnterpriseResource( { id: 15, permalink: "enterprise1", name: "Enterprise 1" } ) + $httpBackend.expectDELETE("/api/enterprises/enterprise1/logo.json").respond 409, { error: "obj" } + Enterprises.removeLogo(enterprise).catch( -> rejected = true) + $httpBackend.flush() + + it "does not update the pristine copy of the enterprise", -> + expect(Enterprises.pristineByID[15]).toBeUndefined() + + it "rejects the promise", -> + expect(rejected).toBe(true) + + describe "#removePromoImage", -> + enterprise = null + + describe "success", -> + resolved = false + + beforeEach -> + enterprise = new EnterpriseResource({ id: 15, permalink: "enterprise1", name: "Enterprise 1", promo_image: {} }) + $httpBackend.expectDELETE("/api/enterprises/enterprise1/promo_image.json").respond 200, { id: 15, name: "Enterprise 1"} + Enterprises.removePromoImage(enterprise).then( -> resolved = true) + $httpBackend.flush() + + it "updates the pristine copy of the enterprise", -> + expect(Enterprises.pristineByID[15]).not.toBeUndefined() + expect(Enterprises.pristineByID[15]["id"]).toEqual(15) + expect(Enterprises.pristineByID[15]["promo_image"]).toBeUndefined() + + it "resolves the promise", -> + expect(resolved).toBe(true) + + describe "failure", -> + rejected = false + + beforeEach -> + enterprise = new EnterpriseResource( { id: 15, permalink: "enterprise1", name: "Enterprise 1" } ) + $httpBackend.expectDELETE("/api/enterprises/enterprise1/promo_image.json").respond 409, { error: "obj" } + Enterprises.removePromoImage(enterprise).catch( -> rejected = true) + $httpBackend.flush() + + it "does not update the pristine copy of the enterprise", -> + expect(Enterprises.pristineByID[15]).toBeUndefined() + + it "rejects the promise", -> + expect(rejected).toBe(true); diff --git a/spec/models/spree/ability_spec.rb b/spec/models/spree/ability_spec.rb index 7882665618..dcd290e195 100644 --- a/spec/models/spree/ability_spec.rb +++ b/spec/models/spree/ability_spec.rb @@ -297,11 +297,11 @@ module Spree let!(:er_pd) { create(:enterprise_relationship, parent: d_related, child: d1, permissions_list: [:edit_profile]) } it "should be able to edit enterprises it manages" do - should have_ability([:read, :edit, :update, :bulk_update, :resend_confirmation], for: d1) + should have_ability([:read, :edit, :update, :remove_logo, :remove_promo_image, :bulk_update, :resend_confirmation], for: d1) end it "should be able to edit enterprises it has permission to" do - should have_ability([:read, :edit, :update, :bulk_update, :resend_confirmation], for: d_related) + should have_ability([:read, :edit, :update, :remove_logo, :remove_promo_image, :bulk_update, :resend_confirmation], for: d_related) end it "should be able to manage shipping methods, payment methods and enterprise fees for enterprises it manages" do diff --git a/spec/serializers/admin/enterprise_serializer_spec.rb b/spec/serializers/admin/enterprise_serializer_spec.rb index 0898b7d4a0..5bf40559d0 100644 --- a/spec/serializers/admin/enterprise_serializer_spec.rb +++ b/spec/serializers/admin/enterprise_serializer_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require "spec_helper" describe Api::Admin::EnterpriseSerializer do let(:enterprise) { create(:distributor_enterprise) } @@ -6,4 +6,56 @@ describe Api::Admin::EnterpriseSerializer do serializer = Api::Admin::EnterpriseSerializer.new enterprise serializer.to_json.should match enterprise.name end + + context "for logo" do + let(:enterprise) { create(:distributor_enterprise, logo: image) } + + context "when there is a logo" do + let(:image) do + image_path = File.open(Rails.root.join("app", "assets", "images", "logo-black.png")) + Rack::Test::UploadedFile.new(image_path, "image/png") + end + + it "includes URLs of image versions" do + serializer = Api::Admin::EnterpriseSerializer.new(enterprise) + expect(serializer.as_json[:logo]).to_not be_blank + expect(serializer.as_json[:logo][:medium]).to match(/logo-black.png/) + end + end + + context "when there is no logo" do + let(:image) { nil } + + it "includes URLs of image versions" do + serializer = Api::Admin::EnterpriseSerializer.new(enterprise) + expect(serializer.as_json[:logo]).to be_blank + end + end + end + + context "for promo image" do + let(:enterprise) { create(:distributor_enterprise, promo_image: image) } + + context "when there is a promo image" do + let(:image) do + image_path = File.open(Rails.root.join("app", "assets", "images", "logo-black.png")) + Rack::Test::UploadedFile.new(image_path, "image/png") + end + + it "includes URLs of image versions" do + serializer = Api::Admin::EnterpriseSerializer.new(enterprise) + expect(serializer.as_json[:promo_image]).to_not be_blank + expect(serializer.as_json[:promo_image][:medium]).to match(/logo-black.jpg/) + end + end + + context "when there is no promo image" do + let(:image) { nil } + + it "includes URLs of image versions" do + serializer = Api::Admin::EnterpriseSerializer.new(enterprise) + expect(serializer.as_json[:promo_image]).to be_nil + end + end + end end