[deploy] Allow org admins to delete their organizations (#9357)
* Add destroy organization backend * Add view for deleting org * Add new line to end of file * Refactor and move destroyable? to model * Use a nice card to distinguish the message * Prevent organizations from being deleted if they have credits * Fix codeclimate issues * Remove let_it_be_changeable for flakiness
This commit is contained in:
parent
c9ff792497
commit
a589529269
9 changed files with 173 additions and 11 deletions
|
|
@ -49,6 +49,25 @@ class OrganizationsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
organization = Organization.find_by(id: params[:id])
|
||||
authorize organization
|
||||
if organization.destroy
|
||||
current_user.touch(:organization_info_updated_at)
|
||||
CacheBuster.bust_user(current_user)
|
||||
flash[:settings_notice] = "Your organization: \"#{organization.name}\" was successfully deleted."
|
||||
redirect_to user_settings_path(:organization)
|
||||
else
|
||||
flash[:settings_notice] = "#{organization.errors.full_messages.to_sentence}.
|
||||
Please email #{SiteConfig.email_addresses['default']} for assistance."
|
||||
redirect_to user_settings_path(:organization, id: organization.id)
|
||||
end
|
||||
rescue Pundit::NotAuthorizedError
|
||||
flash[:error] = "Your organization was not deleted; you must be an admin, the only member in the organization,
|
||||
and have no articles connected to the organization."
|
||||
redirect_to user_settings_path(:organization, id: organization.id)
|
||||
end
|
||||
|
||||
def generate_new_secret
|
||||
set_organization
|
||||
@organization.secret = @organization.generated_random_secret
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class Organization < ApplicationRecord
|
|||
has_many :articles
|
||||
has_many :listings
|
||||
has_many :collections
|
||||
has_many :credits
|
||||
has_many :credits, dependent: :restrict_with_error
|
||||
has_many :display_ads
|
||||
has_many :notifications
|
||||
has_many :organization_memberships, dependent: :delete_all
|
||||
|
|
@ -58,6 +58,7 @@ class Organization < ApplicationRecord
|
|||
before_validation :evaluate_markdown
|
||||
|
||||
after_commit :sync_related_elasticsearch_docs, on: %i[update destroy]
|
||||
after_commit :bust_cache, on: :destroy
|
||||
|
||||
mount_uploader :profile_image, ProfileImageUploader
|
||||
mount_uploader :nav_image, ProfileImageUploader
|
||||
|
|
@ -104,6 +105,10 @@ class Organization < ApplicationRecord
|
|||
false
|
||||
end
|
||||
|
||||
def destroyable?
|
||||
organization_memberships.count == 1 && articles.count.zero?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def evaluate_markdown
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ class OrganizationPolicy < ApplicationPolicy
|
|||
user.org_admin?(record)
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.org_admin?(record) && record.destroyable?
|
||||
end
|
||||
|
||||
def leave_org?
|
||||
part_of_org?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -198,3 +198,45 @@
|
|||
<div><button class="crayons-btn" type="submit">Save</button></div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-card grid gap-6 p-6 mb-6">
|
||||
<header>
|
||||
<h2 class="color-accent-danger">Danger Zone</h2>
|
||||
</header>
|
||||
<div class="crayons-field">
|
||||
<div class="grid gap-2">
|
||||
<header>
|
||||
<h3>Delete Organization</h3>
|
||||
</header>
|
||||
<p>
|
||||
You can delete your organization if you:
|
||||
<ul>
|
||||
<li>are the only member in the organization</li>
|
||||
<li>are an admin of the organization</li>
|
||||
<li>the organization has no posts</li>
|
||||
<li>and the organization has no credits</li>
|
||||
</ul>
|
||||
</p>
|
||||
<% if @org_organization_memberships.size === 1 && @organization.articles_count.zero? %>
|
||||
<% onsubmit = "return confirm('Are you absolutely sure you want to delete your organization: #{@organization.name}?');" %>
|
||||
<%= form_tag organization_path(@organization.id), method: :delete, onsubmit: onsubmit do %>
|
||||
<button class="crayons-btn crayons-btn--danger crayons-btn--icon-left" type="submit">
|
||||
Delete "<%= @organization.name %>"
|
||||
</button>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="crayons-card crayons-card--secondary">
|
||||
<div class="crayons-card__body">
|
||||
Your organization currently does not meet the above requirements.
|
||||
Please remove all other members and organization posts first.
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<p>
|
||||
Questions? Email us at
|
||||
<a href="<%= SiteConfig.email_addresses[:default] %>"><%= SiteConfig.email_addresses[:default] %></a>
|
||||
for help.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ Rails.application.routes.draw do
|
|||
resources :reactions, only: %i[index create]
|
||||
resources :response_templates, only: %i[index create edit update destroy]
|
||||
resources :feedback_messages, only: %i[index create]
|
||||
resources :organizations, only: %i[update create]
|
||||
resources :organizations, only: %i[update create destroy]
|
||||
resources :followed_articles, only: [:index]
|
||||
resources :follows, only: %i[show create update] do
|
||||
collection do
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe UserDecorator, type: :decorator do
|
||||
let_it_be_changeable(:saved_user) { create(:user) }
|
||||
let(:saved_user) { create(:user) }
|
||||
let(:user) { build(:user) }
|
||||
|
||||
context "with serialization" do
|
||||
|
|
|
|||
|
|
@ -165,4 +165,55 @@ RSpec.describe "UserOrganization", type: :request do
|
|||
.to raise_error Pundit::NotAuthorizedError
|
||||
end
|
||||
end
|
||||
|
||||
context "when deleting an organization" do
|
||||
let(:org_admin) { create(:user, :org_admin) }
|
||||
let(:org_member) { create(:user, :org_member) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it "deletes the organization" do
|
||||
org_id = org_admin.organizations.first.id
|
||||
sign_in org_admin
|
||||
delete "/organizations/#{org_id}"
|
||||
expect { Organization.find(org_id) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it "does not delete the organization if the user is only an org member" do
|
||||
org_id = org_member.organizations.first.id
|
||||
sign_in org_member
|
||||
delete "/organizations/#{org_id}"
|
||||
expect(Organization.find(org_id).persisted?).to eq true
|
||||
end
|
||||
|
||||
it "does not delete the organization if the user is not a part of the org" do
|
||||
org = create(:organization)
|
||||
sign_in user
|
||||
delete "/organizations/#{org.id}"
|
||||
expect(org.persisted?).to eq true
|
||||
end
|
||||
|
||||
it "does not delete the organization if the organization has an article associated to it" do
|
||||
org_id = org_admin.organizations.first.id
|
||||
create(:article, user: org_admin, organization_id: org_id)
|
||||
sign_in org_admin
|
||||
delete "/organizations/#{org_id}"
|
||||
expect(Organization.find(org_id).persisted?).to eq true
|
||||
end
|
||||
|
||||
it "does not delete the organization if the organization has more than one member" do
|
||||
org_id = org_admin.organizations.first.id
|
||||
create(:organization_membership, user: user, organization_id: org_id, type_of_user: "member")
|
||||
sign_in org_admin
|
||||
delete "/organizations/#{org_id}"
|
||||
expect(Organization.find(org_id).persisted?).to eq true
|
||||
end
|
||||
|
||||
it "does not delete the organization if the organization has credits" do
|
||||
org = org_admin.organizations.first
|
||||
sign_in org_admin
|
||||
Credit.add_to(org, 1)
|
||||
delete "/organizations/#{org.id}"
|
||||
expect(org.persisted?).to eq true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -48,14 +48,6 @@ RSpec.describe "UserSettings", type: :request do
|
|||
expect(response.body).to include error_message
|
||||
end
|
||||
|
||||
it "renders the proper organization page" do
|
||||
first_org, second_org = create_list(:organization, 2)
|
||||
create(:organization_membership, user: user, organization: first_org)
|
||||
create(:organization_membership, user: user, organization: second_org, type_of_user: "admin")
|
||||
get user_settings_path(tab: "organization", org_id: second_org.id) # /settings/organization/:org_id
|
||||
expect(response.body).to include "Grow the team"
|
||||
end
|
||||
|
||||
it "renders the proper response template" do
|
||||
response_template = create(:response_template, user: user)
|
||||
get user_settings_path(tab: "response-templates", id: response_template.id)
|
||||
|
|
|
|||
49
spec/views/users/settings_spec.rb
Normal file
49
spec/views/users/settings_spec.rb
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "users/edit", type: :view do
|
||||
let(:user) { create(:user) }
|
||||
let(:org) { create(:organization) }
|
||||
|
||||
describe "/settings/organization" do
|
||||
before do
|
||||
sign_in user
|
||||
assign(:user, user)
|
||||
assign(:tab_list, user.settings_tab_list)
|
||||
assign(:tab, "organization")
|
||||
end
|
||||
|
||||
context "when the user is an org admin" do
|
||||
before do
|
||||
org_membership = create(:organization_membership, user: user, organization: org, type_of_user: "admin")
|
||||
assign(:organizations, user.organizations)
|
||||
assign(:organization, org)
|
||||
assign(:organization_membership, org_membership)
|
||||
assign(:org_organization_memberships, org.organization_memberships)
|
||||
end
|
||||
|
||||
it "shows the org admin page" do
|
||||
render
|
||||
expect(rendered).to have_text("Grow the team")
|
||||
end
|
||||
|
||||
it "shows the destroy button if the org has one admin and no content" do
|
||||
render
|
||||
expect(rendered).to have_css(".crayons-btn--danger")
|
||||
end
|
||||
|
||||
it "shows the proper message if the org has more than one member" do
|
||||
second_user = create(:user)
|
||||
create(:organization_membership, user: second_user, organization: org)
|
||||
assign(:org_organization_memberships, org.organization_memberships)
|
||||
render
|
||||
expect(rendered).to have_text("Your organization currently does not meet the above requirements.")
|
||||
end
|
||||
|
||||
it "shows the proper message if the org has an article" do
|
||||
allow(org).to receive(:articles_count).and_return(1)
|
||||
render
|
||||
expect(rendered).to have_text("Your organization currently does not meet the above requirements.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue