From b64327fbb3d83108a72ee4ccab1042e43c120b31 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Fri, 29 Sep 2017 15:16:02 +0100 Subject: [PATCH] Invite enterprise manager functionality --- .../enterprise_controller.js.coffee | 17 +++++++++-- .../admin/modals/invite_manager.html.haml | 19 +++++++++++++ .../admin/openfoodnetwork.css.scss | 4 +++ .../admin/enterprises_controller.rb | 28 +++++++++++++++++++ app/jobs/manager_invitation_job.rb | 7 +++++ app/mailers/enterprise_mailer.rb | 12 ++++++++ app/models/enterprise.rb | 4 +++ .../admin/enterprises/form/_users.html.haml | 13 +++++++++ .../manager_invitation.html.haml | 16 +++++++++++ config/locales/en.yml | 22 +++++++++++++-- config/routes.rb | 2 ++ 11 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 app/assets/javascripts/templates/admin/modals/invite_manager.html.haml create mode 100644 app/jobs/manager_invitation_job.rb create mode 100644 app/views/enterprise_mailer/manager_invitation.html.haml 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 98183a7c26..9fa74e78d3 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, $window, NavigationCheck, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> + .controller "enterpriseCtrl", ($scope, $http, $window, NavigationCheck, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> $scope.Enterprise = enterprise $scope.PaymentMethods = EnterprisePaymentMethods.paymentMethods $scope.ShippingMethods = EnterpriseShippingMethods.shippingMethods @@ -26,7 +26,7 @@ angular.module("admin.enterprises") # from a directive "nav-check" in the page - if we pass it here it will be called in the test suite, # and on all new uses of this contoller, and we might not want that. enterpriseNavCallback = -> - if $scope.enterprise_form.$dirty + if $scope.enterprise_form != undefined && $scope.enterprise_form.$dirty t('admin.unsaved_confirm_leave') # Register the NavigationCheck callback @@ -51,3 +51,16 @@ angular.module("admin.enterprises") $scope.Enterprise.users.push manager else alert ("#{manager.email}" + " " + t("is_already_manager")) + + $scope.inviteUser = -> + $scope.invite_errors = $scope.invite_success = null + email = $scope.newUser + + $http.post('/admin/enterprises/invite_manager', {email: email, enterprise: $scope.Enterprise.id}).success (data)-> + $scope.addManager({id: data.user, email: email}) + $scope.invite_success = t('user_invited', email: email) + .error (data) -> + $scope.invite_errors = data.errors + + $scope.resetModal = -> + $scope.newUser = $scope.invite_errors = $scope.invite_success = null diff --git a/app/assets/javascripts/templates/admin/modals/invite_manager.html.haml b/app/assets/javascripts/templates/admin/modals/invite_manager.html.haml new file mode 100644 index 0000000000..618299cfb3 --- /dev/null +++ b/app/assets/javascripts/templates/admin/modals/invite_manager.html.haml @@ -0,0 +1,19 @@ +#invite-manager-modal{ng: {app: 'admin.enterprises', controller: 'enterpriseCtrl'}} + + .margin-bottom-30.text-center + .text-big + = t('js.admin.modals.invite_title') + + %p.alert-box.ok{ng: {show: 'invite_success'}} + {{invite_success}} + + %p.alert-box.error{ng: {show: 'invite_errors'}} + {{invite_errors}} + + %input#invite_email.fullwidth.margin-bottom-20{ng: {model: 'newUser'}} + + .margin-bottom-20.text-center + %button.text-center.margin-top-10{ng: {show: '!invite_success', click: 'inviteUser()'}} + = t('js.admin.modals.invite') + %button.text-center.margin-top-10{ng: {show: 'invite_success', click: 'resetModal(); close()'}} + = t('js.admin.modals.close') diff --git a/app/assets/stylesheets/admin/openfoodnetwork.css.scss b/app/assets/stylesheets/admin/openfoodnetwork.css.scss index 9a970c87d4..d10ca748d0 100644 --- a/app/assets/stylesheets/admin/openfoodnetwork.css.scss +++ b/app/assets/stylesheets/admin/openfoodnetwork.css.scss @@ -1,3 +1,7 @@ +input[type="submit"], input[type="button"], button, .button { + cursor: pointer; +} + .text-center { text-align: center; } diff --git a/app/controllers/admin/enterprises_controller.rb b/app/controllers/admin/enterprises_controller.rb index 11dd547042..fe6e8b8c44 100644 --- a/app/controllers/admin/enterprises_controller.rb +++ b/app/controllers/admin/enterprises_controller.rb @@ -114,8 +114,36 @@ module Admin end end + def invite_manager + existing_user = Spree::User.where("email = :email OR unconfirmed_email = :email", email: params[:email]).first + + if existing_user + render json: { errors: t('admin.enterprises.invite_manager.user_already_exists') }, status: :unprocessable_entity + return + end + + new_user = create_new_manager(params[:email], params[:enterprise]) + + if new_user + render json: { user: new_user.id }, status: :ok + else + render json: { errors: t('admin.enterprises.invite_manager.error') }, status: 500 + end + end + protected + def create_new_manager(email, enterprise_id) + enterprise = Enterprise.find(enterprise_id) + password = Devise.friendly_token.first(8) + new_user = Spree::User.create(email: email, unconfirmed_email: email, password: password, password_confirmation: password) + + enterprise.send_manager_invitation(new_user) + enterprise.users << new_user + + new_user + end + def build_resource_with_address enterprise = build_resource_without_address enterprise.address ||= Spree::Address.new diff --git a/app/jobs/manager_invitation_job.rb b/app/jobs/manager_invitation_job.rb new file mode 100644 index 0000000000..5a1e894f0e --- /dev/null +++ b/app/jobs/manager_invitation_job.rb @@ -0,0 +1,7 @@ +ManagerInvitationJob = Struct.new(:enterprise_id, :user_id) do + def perform + enterprise = Enterprise.find enterprise_id + user = Spree::User.find user_id + EnterpriseMailer.manager_invitation(enterprise, user).deliver + end +end diff --git a/app/mailers/enterprise_mailer.rb b/app/mailers/enterprise_mailer.rb index 350a247d73..a57e39535e 100644 --- a/app/mailers/enterprise_mailer.rb +++ b/app/mailers/enterprise_mailer.rb @@ -12,6 +12,18 @@ class EnterpriseMailer < Spree::BaseMailer :subject => subject) end + def manager_invitation(enterprise, user) + @enterprise = enterprise + @instance = Spree::Config[:site_name] + @instance_email = Spree::Config[:preferred_mails_from] + + subject = t('enterprise_mailer.invite_manager.subject', enterprise: @enterprise.name) + + mail(to: user.email, + from: from_address, + subject: subject) + end + private def find_enterprise(enterprise) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 8b0f3fe385..3333f8441a 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -348,6 +348,10 @@ class Enterprise < ActiveRecord::Base abn.present? end + def send_manager_invitation(user) + Delayed::Job.enqueue ManagerInvitationJob.new(self.id, user.id) + end + protected def devise_mailer diff --git a/app/views/admin/enterprises/form/_users.html.haml b/app/views/admin/enterprises/form/_users.html.haml index 45318ec114..6934f58931 100644 --- a/app/views/admin/enterprises/form/_users.html.haml +++ b/app/views/admin/enterprises/form/_users.html.haml @@ -60,3 +60,16 @@ - @enterprise.users.each do |manager| = manager.email %br + +- if full_permissions + %form + .row + .three.columns.alpha + %label + = t('.invite_manager') + %div{'ofn-with-tip' => t('.invite_manager_tip')} + %a= t('admin.whats_this') + .eight.columns.omega + .row + %a.button.help-modal{template: 'admin/modals/invite_manager.html'} + = t('.add_unregistered_user') diff --git a/app/views/enterprise_mailer/manager_invitation.html.haml b/app/views/enterprise_mailer/manager_invitation.html.haml new file mode 100644 index 0000000000..e7256b47c9 --- /dev/null +++ b/app/views/enterprise_mailer/manager_invitation.html.haml @@ -0,0 +1,16 @@ +%h3 + = t('invite_email.greeting') +%p.lead + = t('invite_email.invited_to_manage', enterprise: @enterprise.name, instance: @instance) + +%p + = t('invite_email.confirm_your_email') +%p + = t('invite_email.mistakenly_sent', owner_email: @enterprise.owner.email, instance: @instance, instance_email: @instance_email) + +%p + = t :email_help + += render 'shared/mailers/signoff' + += render 'shared/mailers/social_and_contact' diff --git a/config/locales/en.yml b/config/locales/en.yml index bedb5c6295..d020513384 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -114,6 +114,8 @@ en: subject: "Please confirm the email address for %{enterprise}" welcome: subject: "%{enterprise} is now on %{sitename}" + invite_manager: + subject: "%{enterprise} has invited you to be a manager" producer_mailer: order_cycle: subject: "Order cycle report for %{producer}" @@ -655,6 +657,9 @@ en: notifications_note: 'Note: A new email address may need to be confirmed prior to use' managers: Managers managers_tip: The other users with permission to manage this enterprise. + invite_manager: "Invite Manager" + invite_manager_tip: "Invite an unregistered user to sign up and become a manager of this enterprise." + add_unregistered_user: "Add an unregistered user" email_confirmed: "Email confirmed" email_not_confirmed: "Email not confirmed" actions: @@ -714,6 +719,9 @@ en: welcome_text: You have successfully created a next_step: Next step choose_starting_point: 'Choose your starting point:' + invite_manager: + user_already_exists: "User already exists" + error: "Something went wrong" order_cycles: edit: advanced_settings: Advanced Settings @@ -1309,6 +1317,13 @@ See the %{link} to find out more about %{sitename}'s features and to start using If you are a producer or food enterprise, we are excited to have you as a part of the network." email_signup_help_html: "We welcome all your questions and feedback; you can use the Send Feedback button on the site or email us at %{email}" + invite_email: + greeting: "Hello!" + invited_to_manage: "You have been invited to manage %{enterprise} on %{instance}." + confirm_your_email: "You will receive an email shortly to confirm your registration." + set_a_password: "You will then be prompted to set a password before you are able to administer the enterprise." + mistakenly_sent: "Not sure why you have received this email? Please contact %{owner_email} for more information, or you can contact %{instance} at %{instance_email}." + producer_mail_greeting: "Dear" producer_mail_text_before: "We now have all the consumer orders for the next food drop." producer_mail_order_text: "Here is a summary of the orders for your products:" @@ -2123,10 +2138,10 @@ See the %{link} to find out more about %{sitename}'s features and to start using unsaved_changes_confirmation: "Unsaved changes will be lost. Continue anyway?" one_product_unsaved: "Changes to one product remain unsaved." products_unsaved: "Changes to %{n} products remain unsaved." - add_manager: "Add a manager" is_already_manager: "is already a manager!" no_change_to_save: " No change to save" - add_manager: "Add a manager" + user_invited: "%{email} has been invited to manage this enterprise" + add_manager: "Add an existing user" users: "Users" about: "About" images: "Images" @@ -2209,6 +2224,9 @@ See the %{link} to find out more about %{sitename}'s features and to start using enterprise_limit_reached: "You have reached the standard limit of enterprises per account. Write to %{contact_email} if you need to increase it." modals: got_it: Got it + close: "Close" + invite: "Invite" + invite_title: "Invite an unregistered user" tag_rule_help: title: Tag Rules overview: Overview diff --git a/config/routes.rb b/config/routes.rb index 85276ad0b4..c46516a9a6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -85,6 +85,8 @@ Openfoodnetwork::Application.routes.draw do get "/enterprises/:permalink", to: redirect("/") # Legacy enterprise URL namespace :admin do + post '/enterprises/invite_manager', to: 'enterprises#invite_manager' + resources :order_cycles do post :bulk_update, on: :collection, as: :bulk_update