Compare commits

..

14 Commits

Author SHA1 Message Date
Jean-Baptiste Bellet
b17d3e447c Avoid using exception but simply errors attribute contained in object 2023-03-14 15:56:16 +01:00
Jean-Baptiste Bellet
2ae4234015 Sort each array to ensure the order
and then expect the right values.
2023-03-14 09:38:31 +01:00
binarygit
20874dec98 Replace angular for when adding a new unregistered manager to an enterprise
Co-Authored-By: David Cook <david@redcliffs.net>
2023-03-14 09:37:57 +01:00
Jean-Baptiste Bellet
288cd367bc Add I18N to all reflexes 2023-03-13 21:12:00 +01:00
Jean-Baptiste Bellet
68902021ab Delete manager invitation controller 2023-03-13 21:12:00 +01:00
Jean-Baptiste Bellet
7f9c578fca Create a concern for manager invitations
Can be used elsewhere
2023-03-13 21:12:00 +01:00
Jean-Baptiste Bellet
782c9150a2 Move $locationProvider configuration to another file
Actually the `config()` method of `admin_ofn` file did not run on `/admin/enterprises/*` pages for an unknown reason

Now those two files have the same configuration
2023-03-13 21:12:00 +01:00
binarygit
447b040020 Replace what's this tooltips
There are tooltips here that don't have a what's this?
There are many angular directives/methods being used that I haven't
looked into
Every select box is using select2
2023-03-13 21:12:00 +01:00
jibees
6bdb89d090 Merge pull request #10551 from openfoodfoundation/dependabot/bundler/rubocop-1.48.1
Bump rubocop from 1.48.0 to 1.48.1
2023-03-13 16:16:56 +01:00
jibees
a63531c8c2 Merge pull request #10549 from openfoodfoundation/dependabot/bundler/ddtrace-1.10.1
Bump ddtrace from 1.10.0 to 1.10.1
2023-03-13 16:15:06 +01:00
jibees
de2a15e3e1 Merge pull request #10548 from openfoodfoundation/dependabot/npm_and_yarn/floating-ui/dom-1.2.4
Bump @floating-ui/dom from 1.2.3 to 1.2.4
2023-03-13 16:14:00 +01:00
dependabot[bot]
e5f5d42d59 Bump rubocop from 1.48.0 to 1.48.1
Bumps [rubocop](https://github.com/rubocop/rubocop) from 1.48.0 to 1.48.1.
- [Release notes](https://github.com/rubocop/rubocop/releases)
- [Changelog](https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop/rubocop/compare/v1.48.0...v1.48.1)

---
updated-dependencies:
- dependency-name: rubocop
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 10:05:22 +00:00
dependabot[bot]
f23de206d9 Bump ddtrace from 1.10.0 to 1.10.1
Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 1.10.0 to 1.10.1.
- [Release notes](https://github.com/DataDog/dd-trace-rb/releases)
- [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/DataDog/dd-trace-rb/compare/v1.10.0...v1.10.1)

---
updated-dependencies:
- dependency-name: ddtrace
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 10:03:01 +00:00
dependabot[bot]
729bcdf291 Bump @floating-ui/dom from 1.2.3 to 1.2.4
Bumps [@floating-ui/dom](https://github.com/floating-ui/floating-ui/tree/HEAD/packages/dom) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/floating-ui/floating-ui/releases)
- [Commits](https://github.com/floating-ui/floating-ui/commits/@floating-ui/dom@1.2.4/packages/dom)

---
updated-dependencies:
- dependency-name: "@floating-ui/dom"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 09:58:49 +00:00
16 changed files with 166 additions and 195 deletions

View File

@@ -119,7 +119,6 @@ Layout/LineLength:
- 'spec/controllers/admin/bulk_line_items_controller_spec.rb'
- 'spec/controllers/admin/column_preferences_controller_spec.rb'
- 'spec/controllers/admin/enterprises_controller_spec.rb'
- 'spec/controllers/admin/manager_invitations_controller_spec.rb'
- 'spec/controllers/admin/order_cycles_controller_spec.rb'
- 'spec/controllers/admin/schedules_controller_spec.rb'
- 'spec/controllers/admin/stripe_accounts_controller_spec.rb'

View File

@@ -231,7 +231,7 @@ GEM
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
date (3.3.3)
ddtrace (1.10.0)
ddtrace (1.10.1)
debase-ruby_core_source (>= 0.10.16, <= 3.2.0)
libdatadog (~> 2.0.0.1.0)
libddwaf (~> 1.6.2.0.0)
@@ -459,7 +459,7 @@ GEM
parallel (1.22.1)
paranoia (2.6.1)
activerecord (>= 5.1, < 7.1)
parser (3.2.1.0)
parser (3.2.1.1)
ast (~> 2.4.1)
paypal-sdk-core (0.3.4)
multi_json (~> 1.0)
@@ -605,7 +605,7 @@ GEM
rswag-ui (2.8.0)
actionpack (>= 3.1, < 7.1)
railties (>= 3.1, < 7.1)
rubocop (1.48.0)
rubocop (1.48.1)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.2.0.0)

View File

@@ -55,19 +55,6 @@ angular.module("admin.enterprises")
else
alert ("#{manager.email}" + " " + t("is_already_manager"))
$scope.inviteManager = ->
$scope.invite_errors = $scope.invite_success = null
email = $scope.newUser
$http.post("/admin/manager_invitations", {email: email, enterprise_id: $scope.Enterprise.id}).then (response)->
$scope.addManager({id: response.data.user, email: email})
$scope.invite_success = t('user_invited', email: email)
.catch (response) ->
$scope.invite_errors = response.data.errors
$scope.resetModal = ->
$scope.newUser = $scope.invite_errors = $scope.invite_success = null
$scope.removeLogo = ->
$scope.performEnterpriseAction("removeLogo", "immediate_logo_removal_warning", "removed_logo_successfully")

View File

@@ -1,2 +1,3 @@
angular.module("admin.utils", ["templates", "ngSanitize"]).config ($httpProvider) ->
angular.module("admin.utils", ["templates", "ngSanitize"]).config ($httpProvider, $locationProvider) ->
$locationProvider.hashPrefix('')
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"

View File

@@ -1,47 +0,0 @@
# frozen_string_literal: true
module Admin
class ManagerInvitationsController < Spree::Admin::BaseController
authorize_resource class: false
def create
@email = params[:email]
@enterprise = Enterprise.find(params[:enterprise_id])
authorize! :edit, @enterprise
existing_user = Spree::User.find_by(email: @email)
if existing_user
render json: { errors: t('admin.enterprises.invite_manager.user_already_exists') },
status: :unprocessable_entity
return
end
new_user = create_new_manager
if new_user
render json: { user: new_user.id }, status: :ok
else
render json: { errors: t('admin.enterprises.invite_manager.error') },
status: :internal_server_error
end
end
private
def create_new_manager
password = Devise.friendly_token
new_user = Spree::User.create(email: @email, unconfirmed_email: @email, password: password)
new_user.reset_password_token = Devise.friendly_token
# Same time as used in Devise's lib/devise/models/recoverable.rb.
new_user.reset_password_sent_at = Time.now.utc
new_user.save!
@enterprise.users << new_user
EnterpriseMailer.manager_invitation(@enterprise, new_user).deliver_later
new_user
end
end
end

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
module ManagerInvitations
extend ActiveSupport::Concern
def create_new_manager(email, enterprise)
password = Devise.friendly_token
new_user = Spree::User.create(email: email, unconfirmed_email: email, password: password)
new_user.reset_password_token = Devise.friendly_token
# Same time as used in Devise's lib/devise/models/recoverable.rb.
new_user.reset_password_sent_at = Time.now.utc
new_user.save
return new_user unless new_user.valid? # Return early if user is invalid.
enterprise.users << new_user
EnterpriseMailer.manager_invitation(@enterprise, new_user).deliver_later
new_user
end
end

View File

@@ -23,4 +23,8 @@ class ApplicationReflex < StimulusReflex::Reflex
def current_ability
Spree::Ability.new(current_user)
end
def with_locale(&block)
I18n.with_locale(current_user.locale, &block)
end
end

View File

@@ -0,0 +1,43 @@
# frozen_string_literal: true
class InviteManagerReflex < ApplicationReflex
include ManagerInvitations
def invite
email = params[:email]
enterprise = Enterprise.find(params[:enterprise_id])
authorize! :edit, enterprise
existing_user = Spree::User.find_by(email: email)
locals = { error: nil, success: nil, email: email, enterprise: enterprise }
if existing_user
locals[:error] = I18n.t('admin.enterprises.invite_manager.user_already_exists')
return_morph(locals)
return
end
new_user = create_new_manager(email, enterprise)
if new_user.valid?
locals[:success] = true
else
locals[:error] = new_user.errors.full_messages.to_sentence ||
I18n.t('admin.enterprises.invite_manager.error')
end
return_morph(locals)
end
private
def return_morph(locals)
morph "#add_manager_modal",
with_locale {
render(partial: "admin/enterprises/form/add_new_unregistered_manager", locals: locals)
}
end
end

View File

@@ -0,0 +1,22 @@
%div#add_manager_modal
%form{ "data-reflex": "submit->InviteManager#invite", "data-reflex-serialize-form": true }
.margin-bottom-30.text-center
.text-big
= t('js.admin.modals.invite_title')
- if success
%p.alert-box.ok= t('user_invited', email: email)
- if error
%p.alert-box.error= error
= text_field_tag :email, nil, class: 'fullwidth margin-bottom-20'
= hidden_field_tag :enterprise_id, @enterprise&.id || enterprise.id
.modal-actions
- if success
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->help-modal#close" }
- else
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->help-modal#close" }
= submit_tag "#{t('js.admin.modals.invite')}"

View File

@@ -6,8 +6,7 @@
=f.label :owner_id, t('.owner')
- if full_permissions
%span.required *
%div{'ofn-with-tip' => t('.owner_tip')}
%a= t('admin.whats_this')
= render partial: 'admin/shared/tooltip', locals: {tooltip_text: t('.owner_tip')}
.eight.columns.omega
- if full_permissions
= f.hidden_field :owner_id, class: "select2 fullwidth", 'user-select' => 'Enterprise.owner', 'ng-model' => 'Enterprise.owner'
@@ -19,8 +18,7 @@
=f.label :user_ids, t('.notifications')
- if full_permissions
%span.required *
%div{'ofn-with-tip' => t('.contact_tip')}
%a= t('admin.whats_this')
= render partial: 'admin/shared/tooltip', locals: {tooltip_text: t('.contact_tip')}
.eight.columns.omega
- if full_permissions
%select.select2.fullwidth{id: 'receives_notifications_dropdown', name: 'receives_notifications', ng: {model: 'receivesNotifications', init: "receivesNotifications = '#{@enterprise.contact.id}'"}}
@@ -34,8 +32,7 @@
=f.label :user_ids, t('.managers')
- if full_permissions
%span.required *
%div{'ofn-with-tip' => t('.managers_tip')}
%a= t('admin.whats_this')
= render partial: 'admin/shared/tooltip', locals: {tooltip_text: t('.managers_tip')}
.eight.columns.omega
- if full_permissions
%table.managers
@@ -66,8 +63,7 @@
.three.columns.alpha
%label
= t('.invite_manager')
%div{'ofn-with-tip' => t('.invite_manager_tip')}
%a= t('admin.whats_this')
= render partial: 'admin/shared/tooltip', locals: {tooltip_text: t('.invite_manager_tip')}
.eight.columns.omega
.row
%a.button{ "data-controller": "help-modal-link", "data-action": "click->help-modal-link#open", "data-help-modal-link-target-value": "invite-manager-modal" }
@@ -76,22 +72,4 @@
-# add to admin footer to avoid nesting invitation form inside enterprise form
- content_for :admin_footer do
= render HelpModalComponent.new(id: "invite-manager-modal", close_button: false) do
%div{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: 'inviteManager()'}}
= t('js.admin.modals.invite')
%button.text-center.margin-top-10{"data-action": "click->help-modal#close", ng: {show: 'invite_success', click: 'resetModal();'}}
= t('js.admin.modals.close')
= render partial: 'admin/enterprises/form/add_new_unregistered_manager', locals: { error: nil, success: nil }

View File

@@ -42,8 +42,6 @@ Openfoodnetwork::Application.routes.draw do
resources :tag_rules, only: [:destroy]
end
resources :manager_invitations, only: [:create]
resources :enterprise_relationships
resources :enterprise_roles

View File

@@ -20,7 +20,7 @@
},
"dependencies": {
"@babel/preset-env": "^7.18.2",
"@floating-ui/dom": "^1.2.3",
"@floating-ui/dom": "^1.2.4",
"@hotwired/turbo": "^7.3.0",
"@rails/webpacker": "5.4.4",
"babel-loader": "^8.2.3",

View File

@@ -1,89 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
module Admin
describe ManagerInvitationsController, type: :controller do
include OpenFoodNetwork::EmailHelper
let!(:enterprise_owner) { create(:user) }
let!(:other_enterprise_user) { create(:user) }
let!(:existing_user) { create(:user) }
let!(:enterprise) { create(:enterprise, owner: enterprise_owner ) }
let!(:enterprise2) { create(:enterprise, owner: other_enterprise_user ) }
let(:admin) { create(:admin_user) }
describe "#create" do
context "when given email matches an existing user" do
before do
allow(controller).to receive_messages spree_current_user: admin
end
it "returns an error" do
spree_post :create, email: existing_user.email, enterprise_id: enterprise.id
expect(response.status).to eq 422
expect(json_response['errors']).to eq 'User already exists'
end
end
context "signing up a new user" do
let(:mail_mock) { double(:mailer, deliver_later: true) }
before do
allow(EnterpriseMailer).to receive(:manager_invitation).
with(enterprise, kind_of(Spree::User)) { mail_mock }
allow(controller).to receive_messages spree_current_user: admin
end
it 'enqueues an invitation email' do
expect(mail_mock).to receive(:deliver_later)
spree_post :create, email: 'un.registered@email.com', enterprise_id: enterprise.id
end
it "returns the user id" do
spree_post :create, email: 'un.registered@email.com', enterprise_id: enterprise.id
new_user = Spree::User.find_by(email: 'un.registered@email.com')
expect(json_response['user']).to eq new_user.id
end
end
end
describe "with enterprise permissions" do
context "as user with proper enterprise permissions" do
before do
setup_email
allow(controller).to receive_messages spree_current_user: enterprise_owner
end
it "returns success code" do
spree_post :create, email: 'an@email.com', enterprise_id: enterprise.id
new_user = Spree::User.find_by(email: 'an@email.com')
expect(new_user.reset_password_token).to_not be_nil
expect(json_response['user']).to eq new_user.id
expect(response.status).to eq 200
end
end
context "as another enterprise user without permissions for this enterprise" do
before do
allow(controller).to receive_messages spree_current_user: other_enterprise_user
end
it "returns unauthorized response" do
spree_post :create, email: 'another@email.com', enterprise_id: enterprise.id
new_user = Spree::User.find_by(email: 'another@email.com')
expect(new_user).to be_nil
expect(response.status).to eq 302
end
end
end
end
end

View File

@@ -288,8 +288,10 @@ describe OrderCycleForm do
distributor.users.first
)
expect{ form.save }.to change{ order_cycle.distributor_payment_methods.pluck(:id) }
.from([distributor_payment_method, distributor_payment_method2])
expect{ form.save }.to change{
order_cycle.distributor_payment_methods.pluck(:id).sort
}
.from([distributor_payment_method, distributor_payment_method2].sort)
.to([distributor_payment_method])
end
end

View File

@@ -532,5 +532,57 @@ describe '
end
end
end
describe "check users tab" do
before do
login_as_admin_and_visit edit_admin_enterprise_path(distributor1)
within ".side_menu" do
click_link 'Users'
end
end
context "invite user as manager" do
before do
expect(page).to have_selector('a', text: /Add an unregistered user/i)
page.find('a', text: /Add an unregistered user/i).click
end
it "shows an error message if the email is invalid" do
within ".reveal-modal" do
expect(page).to have_content "Invite an unregistered user"
fill_in "email", with: "invalid_email"
expect do
click_button "Invite"
expect(page).to have_content "Email is invalid"
end.to_not enqueue_job ActionMailer::MailDeliveryJob
end
end
it "shows an error message if the email is already linked to an existing user" do
within ".reveal-modal" do
expect(page).to have_content "Invite an unregistered user"
fill_in "email", with: distributor1.owner.email
expect do
click_button "Invite"
expect(page).to have_content "User already exists"
end.to_not enqueue_job ActionMailer::MailDeliveryJob
end
end
it "finally, can invite unregistered users" do
within ".reveal-modal" do
expect(page).to have_content "Invite an unregistered user"
fill_in "email", with: "email@email.com"
expect do
click_button "Invite"
expect(page).to have_content "email@email.com has been invited to manage this enterprise"
end.to enqueue_job(ActionMailer::MailDeliveryJob).exactly(:twice)
end
end
end
end
end
end

View File

@@ -1397,17 +1397,17 @@
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==
"@floating-ui/core@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.2.tgz#66f62cf1b7de2ed23a09c101808536e68caffaec"
integrity sha512-FaO9KVLFnxknZaGWGmNtjD2CVFuc0u4yeGEofoyXO2wgRA7fLtkngT6UB0vtWQWuhH3iMTZZ/Y89CMeyGfn8pA==
"@floating-ui/dom@^1.2.3":
"@floating-ui/core@^1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.3.tgz#8dc6fbf799fbb5c29f705b54bdd51f3ab0ee03a2"
integrity sha512-lK9cZUrHSJLMVAdCvDqs6Ug8gr0wmqksYiaoj/bxj2gweRQkSuhg2/V6Jswz2KiQ0RAULbqw1oQDJIMpQ5GfGA==
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.3.tgz#327a2c11e6570b7d64368ad74a3ac12786c9f751"
integrity sha512-upVRtrNZuYNsw+EoxkiBFRPROnU8UTy/u/dZ9U0W14BlemPYODwhhxYXSR2Y9xOnvr1XtptJRWx7gL8Te1qaog==
"@floating-ui/dom@^1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.4.tgz#e2eb2674f57fc182c425587e48ea43e336f4b8f8"
integrity sha512-4+k+BLhtWj+peCU60gp0+rHeR8+Ohqx6kjJf/lHMnJ8JD5Qj6jytcq1+SZzRwD7rvHKRhR7TDiWWddrNrfwQLg==
dependencies:
"@floating-ui/core" "^1.2.2"
"@floating-ui/core" "^1.2.3"
"@hotwired/stimulus-webpack-helpers@^1.0.0":
version "1.0.1"