Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/organizations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def section_records(section, page:)
when "community_news"
authorized_scope(@organization.community_news.with_author_credit)
when "workshop_ideas"
authorized_scope(@organization.credited_to_facilitators(WorkshopIdea))
authorized_scope(@organization.affiliated_workshop_ideas)
when "workshop_variation_ideas"
authorized_scope(WorkshopVariationIdea.where(organization_id: @organization.id))
when "story_ideas"
Expand Down
7 changes: 4 additions & 3 deletions app/controllers/workshop_ideas_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ def index
base_scope = authorized_scope(WorkshopIdea.with_author_credit.includes(:workshops))
filtered = base_scope.search(params.slice(:title, :author_name))
filtered = filtered.created_by_person(params[:created_by_person_id]) if params[:created_by_person_id].present?
# Ideas carry no organization; credit them through the org's active facilitators.
# Ideas carry an organization directly or credit through the org's active facilitators.
if params[:organization_id].present?
organization = Organization.find_by(id: params[:organization_id])
filtered = organization ? filtered.merge(organization.credited_to_facilitators(WorkshopIdea)) : filtered.none
filtered = organization ? filtered.merge(organization.affiliated_workshop_ideas) : filtered.none
end
@workshop_ideas_count = filtered.size
@workshop_ideas = filtered.paginate(page: params[:page], per_page: per_page).decorate
Expand Down Expand Up @@ -91,6 +91,7 @@ def set_form_variables
@potential_series_workshops = authorized_scope(Workshop.published).includes(:windows_type).order(:title)
@sectors = Sector.published
@windows_types = WindowsType.all
@organizations = authorized_scope(Organization.all, as: :currently_affiliated).order(:name)
@users = User.has_access.includes(:person).references(:person).order(Arel.sql("LOWER(people.first_name), LOWER(people.last_name), LOWER(users.email), LOWER(people.email_2), LOWER(people.email)"))
@categories_grouped =
Category
Expand All @@ -114,7 +115,7 @@ def set_workshop_idea
def workshop_idea_params
params.require(:workshop_idea).permit(
:title, :staff_notes, :author_credit_preference,
:created_by_id, :updated_by_id, :windows_type_id,
:created_by_id, :updated_by_id, :windows_type_id, :organization_id,
:time_closing, :time_creation, :time_demonstration,
:time_hours, :time_intro, :time_minutes,
:time_opening, :time_opening_circle, :time_warm_up,
Expand Down
5 changes: 3 additions & 2 deletions app/controllers/workshops_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def index
track_index_intent(Workshop, search_service.workshops, params)

@workshops = authorized_scope(search_service.workshops.with_author_credit
.includes(:categories, :windows_type, :bookmarks,
.includes(:categories, :windows_type, :bookmarks, :organization,
created_by: [ :person ], primary_asset: [ :file_attachment ]))
.paginate(page: params[:page], per_page: params[:per_page] || 12)

Expand Down Expand Up @@ -154,6 +154,7 @@ def set_form_variables
potential_series = potential_series.where.not(id: @workshop.id) if @workshop.persisted?
@potential_series_workshops = authorized_scope(potential_series).order(:title)
@windows_types = WindowsType.all
@organizations = authorized_scope(Organization.all, as: :currently_affiliated).order(:name)
@workshop_ideas = authorized_scope(WorkshopIdea.order(created_at: :desc))
.map { |wi|
[ "#{wi.created_at.strftime("%Y-%m-%d")
Expand Down Expand Up @@ -206,7 +207,7 @@ def dedupe_config
def workshop_params
params.require(:workshop).permit(
:title, :featured, :published,
:full_name, :author_id, :windows_type_id, :workshop_idea_id, :author_credit_preference,
:full_name, :author_id, :windows_type_id, :workshop_idea_id, :organization_id, :author_credit_preference,
:month, :year, :filemaker_code,
:publicly_visible,
:publicly_featured,
Expand Down
23 changes: 19 additions & 4 deletions app/models/organization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ def communications_email
has_many :community_news
has_many :resources
has_many :workshop_variations
has_many :workshop_ideas
has_many :workshops
has_many :workshops_as_author, through: :people, source: :workshops_as_author
has_many :workshop_ideas_as_author, through: :people, source: :workshop_ideas_as_author
has_many :grants, as: :funder, dependent: :destroy

has_many :categorizable_items, dependent: :destroy, inverse_of: :categorizable, as: :categorizable
Expand Down Expand Up @@ -265,6 +269,21 @@ def affiliated_workshop_logs
direct.or(legacy).distinct
end

def affiliated_workshops
return Workshop.none unless persisted?

workshops.or(credited_to_facilitators(Workshop)).distinct
end
alias_method :all_workshops, :affiliated_workshops
alias_method :credited_workshops, :affiliated_workshops

def affiliated_workshop_ideas
return WorkshopIdea.none unless persisted?

workshop_ideas.or(credited_to_facilitators(WorkshopIdea)).distinct
end
alias_method :all_workshop_ideas, :affiliated_workshop_ideas

# Display order, and what the attendees index filters on.
FACILITATOR_PROGRAM_STATUSES = FacilitatorProgramStatus::STATUSES

Expand Down Expand Up @@ -372,10 +391,6 @@ def credited_to_facilitators(model)
.or(model.where(author_id: nil, created_by_id: User.where(person_id: person_ids).select(:id)))
end

def credited_workshops
credited_to_facilitators(Workshop)
end

# Sectors and age groups are never entered on an org — they roll up from the
# primary tags of its active facilitators.
# Most-held first, so a capped list shows the most representative; ties break
Expand Down
1 change: 1 addition & 0 deletions app/models/workshop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def self.mentionable_rich_text_fields
belongs_to :updated_by, class_name: "User", optional: true
belongs_to :author, class_name: "Person", optional: true
belongs_to :workshop_idea, optional: true
belongs_to :organization, optional: true

has_many :bookmarks, as: :bookmarkable, dependent: :destroy
has_many :comments, -> { newest_first }, as: :commentable, dependent: :destroy
Expand Down
5 changes: 5 additions & 0 deletions app/models/workshop_idea.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class WorkshopIdea < ApplicationRecord
belongs_to :created_by, class_name: "User"
belongs_to :updated_by, class_name: "User"
belongs_to :windows_type
belongs_to :organization, optional: true

has_many :bookmarks, as: :bookmarkable, dependent: :destroy
has_many :notifications, as: :noticeable, dependent: :nullify
Expand Down Expand Up @@ -35,6 +36,10 @@ class WorkshopIdea < ApplicationRecord

validates :title, presence: true, uniqueness: { case_sensitive: false }, length: { maximum: 255 }

def name
title
end

# Nested attributes
accepts_nested_attributes_for :primary_asset, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :gallery_assets, reject_if: :all_blank, allow_destroy: true
Expand Down
3 changes: 2 additions & 1 deletion app/services/workshop_from_idea_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ def call

def attributes_from_idea
workshop_idea.attributes.slice(
"title", "windows_type_id", "author_credit_preference",
"title", "windows_type_id", "organization_id", "author_credit_preference",
"time_intro", "time_closing", "time_creation",
"time_demonstration", "time_warm_up",
"time_opening", "time_opening_circle"
).merge(
organization_id: workshop_idea.organization_id,
rhino_objective: workshop_idea.rhino_objective,
rhino_materials: workshop_idea.rhino_materials,
rhino_optional_materials: workshop_idea.rhino_optional_materials,
Expand Down
6 changes: 3 additions & 3 deletions app/views/organizations/_associated_records.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
].compact %>
<%# Column flow pairs each record type with its related idea: community news /
resources · stories / story ideas · workshops / workshop ideas · workshop
variations / workshop variation ideas. Workshop ideas carry no organization,
so they're credited through the org's active facilitators. %>
variations / workshop variation ideas. Workshop ideas count both those linked
to the org and those credited to its active facilitators, matching the index. %>
<% contributed = [
CommunityNews.where(org_filter),
Resource.where(org_filter),
Story.where(org_filter),
StoryIdea.where(org_filter),
organization.credited_workshops,
organization.credited_to_facilitators(WorkshopIdea),
organization.affiliated_workshop_ideas,
WorkshopVariation.where(org_filter),
WorkshopVariationIdea.where(org_filter)
] %>
Expand Down
26 changes: 26 additions & 0 deletions app/views/workshop_ideas/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<% promoted_to_workshop = f.object.workshops.any? %>
<% if promoted_to_workshop %>
<%= f.hidden_field :organization_id, value: f.object.organization_id %>
<div class="admin-only m-3 bg-yellow-100 p-3">
This workshops idea has been promoted to a
<% f.object.workshops.each do |workshop| %>
Expand Down Expand Up @@ -62,6 +63,31 @@
</div>
</div>

<!-- Organization -->
<div class="mb-6 grid grid-cols-1 gap-6 md:grid-cols-2">
<div>
<% organizations = @organizations || [] %>
<% if organizations.size == 1 %>
<%= f.hidden_field :organization_id,
value: f.object.organization_id || organizations.first.id %>
<% else %>
<%= f.input :organization_id,
as: :select,
collection: organizations,
label_method: :type_name,
value_method: :id,
label: "Organization",
required: false,
disabled: promoted_to_workshop,
include_blank: "Select organization",
selected: (params[:organization_id].presence || f.object.organization_id),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need include_blank: "Select organization" so they can remove an org/leave it blank

hint: "Please contact AWBW if your organization is not listed.",
input_html: { class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm #{"readonly" if promoted_to_workshop}" },
label_html: { class: "block text-sm font-medium text-gray-700 mb-1" } %>
<% end %>
</div>
</div>

<% if allowed_to?(:manage?, WorkshopIdea) %>
<div class="rounded bg-white pb-6">
<div class="admin-only flex items-center gap-x-2 bg-blue-100 p-3">
Expand Down
2 changes: 2 additions & 0 deletions app/views/workshop_ideas/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<th class="w-1/6 px-4 py-2 text-left text-sm font-semibold text-gray-700">Title</th>
<th class="w-1/6 px-4 py-2 text-left text-sm font-semibold text-gray-700">Timeframe</th>
<th class="w-1/6 px-4 py-2 text-left text-sm font-semibold text-gray-700">Author</th>
<th class="w-1/6 px-4 py-2 text-left text-sm font-semibold text-gray-700">Organization</th>
<th class="w-[60px] px-4 py-2 text-center text-sm font-semibold text-gray-700">Promoted?</th>
<th class="w-[80px] px-4 py-2 text-center text-sm font-semibold text-gray-700">Actions</th>
</tr>
Expand All @@ -46,6 +47,7 @@
<td class="px-4 py-2 text-sm text-gray-800"><%= workshop_idea.title %></td>
<td class="px-4 py-2 text-sm text-gray-800"><%= workshop_idea.time_frame_total %></td>
<td class="px-4 py-2 text-sm text-gray-800"><%= credited_author_link(workshop_idea, class: eyebrow_link_class) %></td>
<td class="px-4 py-2 text-sm text-gray-800"><%= workshop_idea.organization&.name %></td>
<td class="px-4 py-2 text-center text-sm text-gray-800">
<% if workshop_idea.workshops.any? %>
<span class='fa fa-check-circle text-green-500'></span>
Expand Down
11 changes: 11 additions & 0 deletions app/views/workshop_ideas/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@
<span class="font-semibold text-gray-700">Timeframe:</span>
<%= @workshop_idea.timeframe.presence || "—" %>
</div>
<div>
<span class="font-semibold text-gray-700">Organization:</span>
<% if @workshop_idea.organization && allowed_to?(:show?, @workshop_idea.organization) %>
<%= link_to @workshop_idea.organization.name,
organization_path(@workshop_idea.organization),
data: { turbo_frame: "_top" },
class: "inline-block px-3 py-1 rounded-md text-sm font-medium #{DomainTheme.bg_class_for(:organizations, intensity: 100)} #{DomainTheme.text_class_for(:organizations)} #{DomainTheme.bg_class_for(:organizations, intensity: 100, hover: true)}" %>
<% else %>
<%= @workshop_idea.organization&.name || "—" %>
<% end %>
</div>
<div>
<span class="font-semibold text-gray-700">Created by:</span>
<%= person_name(@workshop_idea.created_by) %>
Expand Down
20 changes: 20 additions & 0 deletions app/views/workshops/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,26 @@
hint: "If this workshop was created from a Workshop Idea, select it here.",
input_html: { value: f.object.workshop_idea_id,
class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" } %>
<div>
<% organizations = @organizations || [] %>
<% if organizations.size == 1 %>
<%= f.hidden_field :organization_id,
value: f.object.organization_id || organizations.first.id %>
<% else %>
<%= f.input :organization_id,
as: :select,
collection: organizations,
label_method: :type_name,
value_method: :id,
label: "Organization",
required: false,
include_blank: "Select organization",
selected: (params[:organization_id].presence || f.object.organization_id),
hint: "Please contact AWBW if your organization is not listed.",
input_html: { class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" },
label_html: { class: "block text-sm font-medium text-gray-700 mb-1" } %>
<% end %>
</div>
<div class="mt-4">
<label class="mb-1 block font-medium text-gray-700">Workshop created</label>
<div class="flex gap-x-2">
Expand Down
3 changes: 3 additions & 0 deletions app/views/workshops/_index_row.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
<div class="text-sm leading-tight text-gray-600">
By:
<%= credited_author_link(workshop, class: "hover:underline", data: { turbo: false }) %>
<% if workshop.organization.present? %>
| <%= workshop.organization.name %>
<% end %>
| <%= workshop.date %>
</div>

Expand Down
9 changes: 8 additions & 1 deletion app/views/workshops/_show_header.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@
<span class="text-lg text-red-300">(Unpublished)</span>
<% end %>
</h1>
<div class="mt-3 flex flex-wrap gap-4 text-sm text-gray-200"><span>Author: <%= credited_author_link(workshop, class: "hover:underline") %></span><span>Category: <%= workshop.windows_type&.short_name %></span><span>Added: <%= workshop.date %></span></div>
<div class="mt-3 flex flex-wrap gap-4 text-sm text-gray-200">
<span>Author: <%= credited_author_link(workshop, class: "hover:underline") %></span>
<% if workshop.organization.present? %>
<span>Organization: <%= link_to_if allowed_to?(:show?, workshop.organization), workshop.organization.name, organization_path(workshop.organization), class: "hover:underline" %></span>
<% end %>
<span>Category: <%= workshop.windows_type&.short_name %></span>
<span>Added: <%= workshop.date %></span>
</div>
</div>
<%= render "assets/primary_image_picker", owner: workshop %>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddOrganizationToWorkshopIdeas < ActiveRecord::Migration[8.1]
def change
add_reference :workshop_ideas, :organization, type: :integer, null: true, foreign_key: true
end
end
5 changes: 5 additions & 0 deletions db/migrate/20261018123640_add_organization_to_workshops.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddOrganizationToWorkshops < ActiveRecord::Migration[8.1]
def change
add_reference :workshops, :organization, type: :integer, null: true, foreign_key: true
end
end
6 changes: 6 additions & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2527,8 +2527,10 @@
t.text "warm_up"
t.text "warm_up_spanish"
t.integer "windows_type_id", null: false
t.integer "organization_id"
t.index ["author_id"], name: "index_workshop_ideas_on_author_id"
t.index ["created_by_id"], name: "index_workshop_ideas_on_created_by_id"
t.index ["organization_id"], name: "index_workshop_ideas_on_organization_id"
t.index ["updated_by_id"], name: "index_workshop_ideas_on_updated_by_id"
t.index ["windows_type_id"], name: "index_workshop_ideas_on_windows_type_id"
end
Expand Down Expand Up @@ -2719,11 +2721,13 @@
t.integer "windows_type_id"
t.bigint "workshop_idea_id"
t.integer "year"
t.integer "organization_id"
t.index ["author_id"], name: "index_workshops_on_author_id"
t.index ["created_at"], name: "index_workshops_on_created_at"
t.index ["created_by_id"], name: "index_workshops_on_created_by_id"
t.index ["inactive", "led_count", "title"], name: "index_workshops_on_inactive_and_led_count_and_title"
t.index ["led_count"], name: "index_workshops_on_led_count"
t.index ["organization_id"], name: "index_workshops_on_organization_id"
t.index ["published"], name: "index_workshops_on_published"
t.index ["title", "full_name", "objective", "materials", "introduction", "demonstration", "opening_circle", "warm_up", "creation", "closing", "notes", "tips", "misc1", "misc2"], name: "workshop_fullsearch", type: :fulltext
t.index ["title"], name: "index_workshops_on_title", type: :fulltext
Expand Down Expand Up @@ -2998,6 +3002,7 @@
add_foreign_key "windows_types", "users", column: "updated_by_id"
add_foreign_key "workshop_age_ranges", "age_ranges"
add_foreign_key "workshop_age_ranges", "workshops"
add_foreign_key "workshop_ideas", "organizations"
add_foreign_key "workshop_ideas", "people", column: "author_id"
add_foreign_key "workshop_ideas", "users", column: "created_by_id"
add_foreign_key "workshop_ideas", "users", column: "updated_by_id"
Expand Down Expand Up @@ -3025,6 +3030,7 @@
add_foreign_key "workshop_variations", "windows_types"
add_foreign_key "workshop_variations", "workshop_variation_ideas"
add_foreign_key "workshop_variations", "workshops"
add_foreign_key "workshops", "organizations"
add_foreign_key "workshops", "people", column: "author_id"
add_foreign_key "workshops", "users", column: "created_by_id"
add_foreign_key "workshops", "users", column: "updated_by_id"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: "Workshops and ideas on organization profiles"
area: content
display_status: user_facing
released_on: 2026-10-22
action_path: "/organizations"
summary: >-
Workshops and workshop ideas now link to organizations directly and display on
organization profiles, including content authored by affiliated facilitators.
2 changes: 1 addition & 1 deletion spec/factories/workshop_ideas.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FactoryBot.define do
factory :workshop_idea do
title { "MyString" }
sequence(:title) { |n| "Workshop Idea #{n}" }
description { "MyText" }
staff_notes { "MyText" }
association :windows_type
Expand Down
Loading
Loading