Skip to content

Commit

Permalink
Merge pull request #2218 from geeksforsocialchange/ik-2128-removing-p…
Browse files Browse the repository at this point in the history
…artner-addresses

Removing partner addresses
  • Loading branch information
ivan-kocienski-gfsc authored Jan 31, 2024
2 parents 34ea8f0 + 8406df6 commit 6bfea42
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 12 deletions.
6 changes: 6 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ Style/HashSyntax:
Rails/ActionOrder:
Enabled: false

Metrics/ClassLength:
Exclude:
- "test/**/*.rb"



Rails/RootPathnameMethods:
Enabled: false
GraphQL/MaxComplexitySchema:
Expand Down
15 changes: 14 additions & 1 deletion app/controllers/admin/partners_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Admin
class PartnersController < Admin::ApplicationController
include LoadUtilities
before_action :set_partner, only: %i[show edit update destroy]
before_action :set_partner, only: %i[show edit update destroy clear_address]
before_action :set_tags, only: %i[new create edit]
before_action :set_neighbourhoods, only: %i[new edit]
before_action :set_partner_tags_controller, only: %i[new edit update]
Expand Down Expand Up @@ -108,6 +108,19 @@ def destroy
end
end

def clear_address
authorize @partner

if @partner.can_clear_address?(current_user)
@partner.clear_address!
render json: { message: 'Address cleared' }

else
render json: { message: 'Could not clear address' },
status: :unprocessable_entity
end
end

def setup
@partner = Partner.new
authorize @partner
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ application.register("user-partners", UserPartnersController);

import PartnerTagsController from "./partner_tags_controller.js";
application.register("partner-tags", PartnerTagsController);

import PartnerAddressController from "./partner_address_controller.js";
application.register("partner-address", PartnerAddressController);
64 changes: 64 additions & 0 deletions app/javascript/controllers/partner_address_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
static values = {
partnerId: String,
warnOfDelisting: String, // "true" or "false"
};

static targets = ["addressInfoArea"];

static addressFieldIds = [
"partner_address_attributes_street_address",
"partner_address_attributes_street_address2",
"partner_address_attributes_street_address3",
"partner_address_attributes_city",
"partner_address_attributes_postcode",
];

connect() {}

disconnect() {}

do_clear_address(event) {
event.preventDefault();

let warning_text = "Please confirm you want to clear this partners address";
if (this.warnOfDelistingValue === "true") {
warning_text = `This address links to you to this partner and by clearing this address you will no longer be able to access this partner,\n\n${warning_text}`;
}

if (!confirm(warning_text)) {
return;
}

const csrfToken = document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content");

const url = `/partners/${this.partnerIdValue}/clear_address`;

const payload = {
method: "DELETE",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"X-CSRF-Token": csrfToken,
},
body: "",
};

fetch(url, payload)
.then((response) => response.json())
.then((data) => {
this.constructor.addressFieldIds.forEach((id) => {
let node = document.getElementById(id);
node.value = "";
node.classList.remove("is-valid");
});

this.addressInfoAreaTarget.innerHTML =
"<p>Address has been cleared</p>";
});
}
}
8 changes: 8 additions & 0 deletions app/models/address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ def prepend_room_number(room_number_string)
self
end

def missing_values?
street_address.blank? &&
street_address2.blank? &&
street_address3.blank? &&
city.blank? &&
postcode.blank?
end

def first_address_line
street_address
end
Expand Down
39 changes: 38 additions & 1 deletion app/models/partner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Partner < ApplicationRecord
has_and_belongs_to_many :users
has_many :calendars, dependent: :destroy
has_many :events
belongs_to :address, optional: true
belongs_to :address, optional: true, dependent: :destroy

has_many :partner_tags, dependent: :destroy
has_many :tags, through: :partner_tags
Expand Down Expand Up @@ -247,6 +247,43 @@ def has_service_areas?
service_areas.any?
end

def can_clear_address?(user = nil)
return false if address.blank? || address.missing_values?
return false if service_areas.empty?

return false if user.blank?
return true if user.root?
return true if user.admin_for_partner?(id)

# must admin for this address specifically
user_hood_ids = user.owned_neighbourhood_ids
user_hood_ids.include?(address.neighbourhood_id)
end

def warn_user_clear_address?(user)
return false if user.root?
return false if user.admin_for_partner?(id)

user_hood_ids = user.owned_neighbourhood_ids
return true if user_hood_ids.empty?

sa_hood_ids = service_areas.pluck(:neighbourhood_id)

any_service_areas = Set.new(user_hood_ids).any?(Set.new(sa_hood_ids))

# is the only way this user is tied to this partner through the address?
any_service_areas == false
end

def clear_address!
Partner.transaction do
old_address = address
update! address_id: nil

old_address&.destroy
end
end

def permalink
"https://placecal.org/partners/#{id}"
end
Expand Down
4 changes: 4 additions & 0 deletions app/policies/partner_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def destroy?
return true if user.only_neighbourhood_admin_for_partner?(record.id)
end

def clear_address?
edit?
end

def setup?
create?
end
Expand Down
7 changes: 0 additions & 7 deletions app/views/admin/application/_address_fields.html.erb

This file was deleted.

41 changes: 41 additions & 0 deletions app/views/admin/partners/_address_fields.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<%= form.fields_for :address, @partner.address || Address.new do |address_form| %>
<div class='nested-fields'
data-controller="partner-address"
data-partner-address-partner-id-value="<%= partner.id %>"
data-partner-address-warn-of-delisting-value="<%= partner.warn_user_clear_address?(current_user) ? 'true' : 'false' %>">

<%# this view is augmented by the /app/javascript/controllers/parter_address_controller.js %>

<%= address_form.input :street_address,
class: "form-control address_1 address_field",
label: 'Street address' %>

<%= address_form.input :street_address2,
class: "form-control address_2 address_field",
label: 'Street address 2' %>

<%= address_form.input :street_address3,
class: "form-control address_3 address_field",
label: 'Street address 3' %>

<%= address_form.input :city,
class: "form-control city address_field" %>

<%= address_form.input :postcode,
class: "form-control postcode address_field" %>

<% if partner.can_clear_address?(current_user) %>
<div data-partner-address-target="addressInfoArea">
<% if partner.address.neighbourhood.present? %>
<p>Address in neighbourhood <%= link_to_neighbourhood(partner.address.neighbourhood) %>.</p>
<% end %>
<p>
<%= link_to 'Clear Address',
'#',
class: "btn btn-secondary btn-sm",
data: { action: "click->partner-address#do_clear_address" } %>
</p>
</div>
<% end %>
</div>
<% end %>
8 changes: 5 additions & 3 deletions app/views/admin/partners/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
<div id='address'>
<div class="row">
<div class="col-md-6">
<%= f.fields_for :address, @partner.address || Address.new do |a| %>
<%= render 'address_fields', f: a %>
<% end %>

<%= render 'address_fields',
form: f,
partner: @partner %>

<% if @partner&.address&.neighbourhood&.legacy_neighbourhood? %>
<p>
The address for this partner is assigned to an out of date neighbourhood.
Expand Down
3 changes: 3 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
collection do
match :setup, via: %i[get post]
end
member do
delete :clear_address
end
end
resources :tags
resources :sites
Expand Down
14 changes: 14 additions & 0 deletions test/controllers/admin/partners_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,18 @@ class Admin::PartnersControllerTest < ActionDispatch::IntegrationTest
assert_response :redirect
assert_equal 'Partners must have an address or a service area inside your neighbourhood', flash[:danger]
end

test 'root user clear address on partner clears address' do
sign_in @root

delete clear_address_admin_partner_path(@partner)
assert_response :success

@partner.reload
assert_nil @partner.address

# will not work if no address is set
delete clear_address_admin_partner_path(@partner)
assert_response :unprocessable_entity
end
end
69 changes: 69 additions & 0 deletions test/models/partner_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -423,4 +423,73 @@ class PartnerTest < ActiveSupport::TestCase
partner = create(:partner, :accessed_by_user => pa, :tags => [pa.tags.first])
assert_predicate partner, :valid?
end

test 'can_clear_address? for root' do
partner = build(:bare_partner)
# has no address
assert_not partner.can_clear_address?

partner.address = create(:address)
# missing service area
assert_not partner.can_clear_address?

partner.service_areas.build(neighbourhood: create(:neighbourhood))
# is not root
assert_not partner.can_clear_address?

root = create(:root)
assert partner.can_clear_address?(root)
end

test 'can_clear_address? for partner admin' do
partner = build(:bare_partner)
partner.address = create(:address)
partner.service_areas.build(neighbourhood: create(:neighbourhood))
partner.save!

citizen = create(:citizen)
citizen.partners << partner

assert partner.can_clear_address?(citizen)
end

test 'can_clear_address? for neighbourhood admin' do
neighbourhood = create(:neighbourhood)
citizen = create(:citizen)
citizen.neighbourhoods << neighbourhood

# cannot clear address if admin does not "own" address
partner = build(:bare_partner)
partner.address = create(:address)
partner.service_areas.build(neighbourhood: neighbourhood)
partner.save!

assert_not partner.can_clear_address?(citizen)

# now partner is in admins neighbourhood pool, can clear
partner.address.neighbourhood = neighbourhood
assert partner.can_clear_address?(citizen)
end

test 'warn_user_clear_address?' do
partner = build(:bare_partner)
partner.address = create(:address)
partner.save!

# am root
root = create(:root)
assert_not partner.warn_user_clear_address?(root)

# am owner
citizen = create(:citizen)
citizen.partners << partner
assert_not partner.warn_user_clear_address?(citizen)

# not root or owner, so warn
other_neighbourhood = create(:neighbourhood)
other_citizen = create(:citizen)
other_citizen.neighbourhoods << other_neighbourhood

assert partner.warn_user_clear_address?(other_citizen)
end
end

0 comments on commit 6bfea42

Please sign in to comment.