Skip to content

Commit

Permalink
Organisation index per service
Browse files Browse the repository at this point in the history
We want an organisation index for each service.
This index page will be shown to the user after he sigin in as a
persona only if the user has multiple organisations.

An organisation can be a school or a provider, the Membership
polymorphic table handles this.

The Placements service will show both schools and providers, the claims
only schools.
  • Loading branch information
CatalinVoineag committed Dec 21, 2023
1 parent ac4268f commit 4e9d6b9
Show file tree
Hide file tree
Showing 24 changed files with 325 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ group :test do
gem "rails-controller-testing"
gem "selenium-webdriver"
gem "shoulda-matchers"
# launch browser when inspecting capybara specs
gem "launchy"
end

group :test, :development do
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ GEM
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
language_server-protocol (3.17.0.3)
launchy (2.5.2)
addressable (~> 2.8)
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
Expand Down Expand Up @@ -525,6 +527,7 @@ DEPENDENCIES
govuk-components (~> 5.0.0)
govuk_design_system_formbuilder (~> 5.0.0)
jsbundling-rails
launchy
mail-notify
omniauth
omniauth-rails_csrf_protection
Expand Down
5 changes: 5 additions & 0 deletions app/controllers/claims/organisations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Claims::OrganisationsController < ApplicationController
def index
@schools = current_user.schools
end
end
6 changes: 6 additions & 0 deletions app/controllers/placements/organisations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Placements::OrganisationsController < ApplicationController
def index
@schools = current_user.schools
@providers = current_user.providers
end
end
10 changes: 10 additions & 0 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,14 @@ def signout
DfESignInUser.end_session!(session)
redirect_to root_path
end

private

def after_sign_in_path
if current_user.memberships.count > 1
public_send("#{current_service}_organisations_path")
else
root_path
end
end
end
24 changes: 24 additions & 0 deletions app/models/membership.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# == Schema Information
#
# Table name: memberships
#
# id :uuid not null, primary key
# organisation_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# organisation_id :uuid not null
# user_id :uuid not null
#
# Indexes
#
# index_memberships_on_organisation (organisation_type,organisation_id)
# index_memberships_on_user_id (user_id)
#
# Foreign Keys
#
# fk_rails_... (user_id => users.id)
#
class Membership < ApplicationRecord
belongs_to :user
belongs_to :organisation, polymorphic: true
end
2 changes: 2 additions & 0 deletions app/models/provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# index_providers_on_provider_code (provider_code) UNIQUE
#
class Provider < ApplicationRecord
has_many :memberships, as: :organisation

validates :provider_code, presence: true
validates :provider_code, uniqueness: { case_sensitive: false }
end
2 changes: 2 additions & 0 deletions app/models/school.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#
class School < ApplicationRecord
belongs_to :gias_school, foreign_key: :urn, primary_key: :urn
has_many :memberships, as: :organisation

validates :urn, presence: true
validates :urn, uniqueness: { case_sensitive: false }

Expand Down
4 changes: 4 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
# index_users_on_service_and_email (service,email) UNIQUE
#
class User < ApplicationRecord
has_many :memberships
has_many :schools, through: :memberships, source: :organisation, source_type: "School"
has_many :providers, through: :memberships, source: :organisation, source_type: "Provider"

enum :service,
{ no_service: "no_service", claims: "claims", placements: "placements" },
validate: true
Expand Down
15 changes: 15 additions & 0 deletions app/views/claims/organisations/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-xl"><%= t("organisations") %></h1>

<% if @schools.any? %>
<ul class="govuk-list">
<% @schools.each do |school| %>
<li>
<%= govuk_link_to school.name, request.env["PATH_INFO"], class: "govuk-link--no-visited-state" %>
</li>
<% end %>
</ul>
<% end %>
</div>
</div>
27 changes: 27 additions & 0 deletions app/views/placements/organisations/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-xl"><%= t("organisations") %></h1>

<% if @schools.any? %>
<h2 class="govuk-heading-l"><%= t("schools") %></h2>
<ul class="govuk-list">
<% @schools.each do |school| %>
<li>
<%= govuk_link_to school.name, request.env["PATH_INFO"], class: "govuk-link--no-visited-state" %>
</li>
<% end %>
</ul>
<% end %>

<% if @providers.any? %>
<h2 class="govuk-heading-l"><%= t("providers") %></h2>
<ul class="govuk-list">
<% @providers.each do |provider| %>
<li>
<%= govuk_link_to provider.provider_code, request.env["PATH_INFO"], class: "govuk-link--no-visited-state" %>
</li>
<% end %>
</ul>
<% end %>
</div>
</div>
6 changes: 6 additions & 0 deletions config/initializers/school.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SCHOOLS = [
{ claims: true },
{ placements: true },
{ claims: true, placements: true },
{ claims: true, placements: true }
].freeze
2 changes: 2 additions & 0 deletions config/routes/claims.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
scope module: :claims, as: :claims, constraints: { host: ENV["CLAIMS_HOST"] } do
root to: "pages#index"

resources :organisations, only: [:index]
end
2 changes: 2 additions & 0 deletions config/routes/placements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
root to: redirect("/support/organisations")
resources :organisations, only: :index
end

resources :organisations, only: [:index]
end
10 changes: 10 additions & 0 deletions db/migrate/20231220143008_create_memberships.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateMemberships < ActiveRecord::Migration[7.1]
def change
create_table :memberships, id: :uuid do |t|
t.references :user, null: false, foreign_key: true, type: :uuid
t.references :organisation, polymorphic: true, null: false, type: :uuid

t.timestamps
end
end
end
13 changes: 12 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.1].define(version: 2023_12_16_102842) do
ActiveRecord::Schema[7.1].define(version: 2023_12_20_143008) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

Expand Down Expand Up @@ -41,6 +41,16 @@
t.index ["urn"], name: "index_gias_schools_on_urn", unique: true
end

create_table "memberships", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.uuid "user_id", null: false
t.string "organisation_type", null: false
t.uuid "organisation_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["organisation_type", "organisation_id"], name: "index_memberships_on_organisation"
t.index ["user_id"], name: "index_memberships_on_user_id"
end

create_table "providers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "provider_code", null: false
t.datetime "created_at", null: false
Expand Down Expand Up @@ -70,4 +80,5 @@
t.index ["service", "email"], name: "index_users_on_service_and_email", unique: true
end

add_foreign_key "memberships", "users"
end
24 changes: 24 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,27 @@
end

Rails.logger.debug "Personas successfully created!"

Rake::Task['gias_update'].invoke unless GiasSchool.any?
gias_scools = GiasSchool.last(SCHOOLS.count)

SCHOOLS.each.with_index do |school_attributes, index|
school = School.find_or_initialize_by(**school_attributes)
school.urn = gias_scools[index].urn

school.save!
end

User.where(first_name: ["Anne", "Patricia"]).each do |user|
school = School.public_send(user.service).first
user.memberships.find_or_create_by!(organisation: school)
end

User.where(first_name: ["Mary", "Colin"]).each do |user|
schools = School.where("#{user.service}": true)

schools.each do |school|
user.memberships.find_or_create_by!(organisation: school)
end
end

26 changes: 26 additions & 0 deletions spec/factories/memberships.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# == Schema Information
#
# Table name: memberships
#
# id :uuid not null, primary key
# organisation_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# organisation_id :uuid not null
# user_id :uuid not null
#
# Indexes
#
# index_memberships_on_organisation (organisation_type,organisation_id)
# index_memberships_on_user_id (user_id)
#
# Foreign Keys
#
# fk_rails_... (user_id => users.id)
#
FactoryBot.define do
factory :membership do
association :user
association :organisation, factory: :school
end
end
32 changes: 32 additions & 0 deletions spec/models/membership_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# == Schema Information
#
# Table name: memberships
#
# id :uuid not null, primary key
# organisation_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# organisation_id :uuid not null
# user_id :uuid not null
#
# Indexes
#
# index_memberships_on_organisation (organisation_type,organisation_id)
# index_memberships_on_user_id (user_id)
#
# Foreign Keys
#
# fk_rails_... (user_id => users.id)
#
require 'rails_helper'

RSpec.describe Membership, type: :model do
subject { create(:membership) }

context "associations" do
it do
should belong_to(:user)
should belong_to(:organisation)
end
end
end
6 changes: 6 additions & 0 deletions spec/models/provider_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
require "rails_helper"

RSpec.describe Provider, type: :model do
context "associations" do
it do
should have_many(:memberships)
end
end

context "validations" do
subject { create(:provider) }

Expand Down
7 changes: 7 additions & 0 deletions spec/models/school_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
should belong_to(:gias_school).with_foreign_key(:urn).with_primary_key(
:urn
)
should have_many(:memberships)
end
end

Expand All @@ -33,6 +34,12 @@
it { is_expected.to validate_uniqueness_of(:urn).case_insensitive }
end

context "delegations" do
it do
should delegate_method(:name).to(:gias_school)
end
end

context "scopes" do
describe "services" do
let!(:placements_on) { create(:school, placements: true) }
Expand Down
8 changes: 8 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
RSpec.describe User, type: :model do
subject { create(:user) }

context "associations" do
it do
should have_many(:memberships)
should have_many(:schools).through(:memberships).source(:organisation)
should have_many(:providers).through(:memberships).source(:organisation)
end
end

describe "validations" do
it { is_expected.to validate_presence_of(:email) }
it do
Expand Down
44 changes: 44 additions & 0 deletions spec/system/claims/view_organisations_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require "rails_helper"

feature "View organisations as a multi org user" do
around do |example|
Capybara.app_host = "https://#{ENV["CLAIMS_HOST"]}"
example.run
Capybara.app_host = nil
end

scenario "I sign in as persona Marry" do
persona = given_there_is_an_existing_claims_persona_for("Mary")
and_persona_has_multiple_organisations(persona)
when_i_visit_the_claims_personas_page
when_i_click_sign_in_as(persona)
i_can_see_a_list_marys_organisations(persona)
end
end

private

def given_there_is_an_existing_claims_persona_for(persona_name)
create(:persona, persona_name.downcase.to_sym, service: "claims")
end

def and_persona_has_multiple_organisations(persona)
school1 = create(:school)
school2 = create(:school)
create(:membership, user: persona, organisation: school1)
create(:membership, user: persona, organisation: school2)
end

def when_i_visit_the_claims_personas_page
visit personas_path
end

def when_i_click_sign_in_as(persona)
click_on "Sign In as #{persona.first_name}"
end

def i_can_see_a_list_marys_organisations(persona)
expect(page).to have_content("Organisations")
expect(page).to have_content(persona.schools.first.name)
expect(page).to have_content(persona.schools.last.name)
end
Loading

0 comments on commit 4e9d6b9

Please sign in to comment.