diff --git a/Dockerfile b/Dockerfile index b01252e89..fed3244cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,6 @@ FROM base AS assets RUN apt-get update -qq && apt-get install -y \ build-essential \ nodejs \ - imagemagick \ libvips \ poppler-utils \ tzdata \ @@ -53,7 +52,6 @@ RUN SECRET_KEY_BASE=1 \ FROM base AS server RUN apt-get update -qq && apt-get install --no-install-recommends -y \ - imagemagick \ libvips \ poppler-utils \ tzdata \ diff --git a/Dockerfile.dev b/Dockerfile.dev index 4c7963f03..dd2c56a6e 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -6,7 +6,6 @@ RUN apt-get update -qq && apt-get install -y \ git \ curl \ default-libmysqlclient-dev \ - imagemagick \ libvips \ tzdata \ libxml2-dev \ diff --git a/app/controllers/community_news_controller.rb b/app/controllers/community_news_controller.rb index a07116777..5a087c6fd 100644 --- a/app/controllers/community_news_controller.rb +++ b/app/controllers/community_news_controller.rb @@ -93,7 +93,7 @@ def set_community_news # Strong parameters def community_news_params params.require(:community_news).permit( - :title, :rhino_body, :published, :featured, + :title, :rhino_body, :published, :featured, :public, :public_featured, :reference_url, :youtube_url, :project_id, :author_id, :created_by_id, :updated_by_id diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index d4c1c9d68..16eccb191 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -7,8 +7,8 @@ def index if turbo_frame_request? case turbo_frame_request_id when "dashboard_workshops" - ids = Rails.cache.fetch("featured_and_visitor_featured_workshop_ids", expires_in: 1.year) do - Workshop.featured_or_visitor_featured.pluck(:id) + ids = Rails.cache.fetch("featured_and_public_featured_workshop_ids", expires_in: 1.year) do + Workshop.featured_or_public_featured.pluck(:id) end base_scope = Workshop.includes(:bookmarks, :windows_type, :primary_asset) diff --git a/app/controllers/event_registrations_controller.rb b/app/controllers/event_registrations_controller.rb index 80f542c43..e3c5a5dfe 100644 --- a/app/controllers/event_registrations_controller.rb +++ b/app/controllers/event_registrations_controller.rb @@ -74,7 +74,7 @@ def destroy # Optional hooks for setting variables for forms or index def set_form_variables - @events = Event.publicly_visible.order(:start_date) + @events = Event.where(inactive: false).order(:start_date) @registrants = User.active.order(:last_name, :first_name) end diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index fd4a35933..2a2f4df7e 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -1,25 +1,28 @@ class EventsController < ApplicationController include AhoyViewTracking, AssetUpdatable + skip_before_action :authenticate_user!, only: %i[ index show] before_action :set_event, only: %i[ show edit update destroy ] - before_action :authorize_admin!, only: %i[ edit update destroy ] def index - unpaginated = current_user.super_user? ? Event.all : Event.published - unpaginated = unpaginated.search_by_params(params) - @events = unpaginated.order(start_date: :desc) + authorize! + base_scope = authorized_scope(Event.all) + @events = base_scope.search_by_params(params).order(start_date: :desc) end def show + authorize! @event @event = @event.decorate track_view(@event) end - def new # all logged in users can create events + def new + authorize! @event = Event.new.decorate set_form_variables end def edit + authorize! @event set_form_variables unless @event.created_by == current_user || current_user.super_user? redirect_to events_path, alert: "You are not authorized to edit this event." @@ -27,6 +30,7 @@ def edit end def create + authorize! @event = Event.new(event_params).decorate @event.created_by ||= current_user @@ -46,6 +50,7 @@ def create end def update + authorize! @event respond_to do |format| if @event.update(event_params) format.html { redirect_to events_path, notice: "Event was successfully updated." } @@ -59,6 +64,7 @@ def update end def destroy + authorize! @event @event.destroy respond_to do |format| @@ -87,12 +93,9 @@ def event_params :featured, :start_date, :end_date, :registration_close_date, - :publicly_visible + :inactive, + :public, + :public_featured ) end - - def authorize_admin! - redirect_to events_path, - alert: "You are not authorized to perform this action." unless current_user.super_user? - end end diff --git a/app/controllers/resources_controller.rb b/app/controllers/resources_controller.rb index 071cbb1d6..f82cccda4 100644 --- a/app/controllers/resources_controller.rb +++ b/app/controllers/resources_controller.rb @@ -147,7 +147,7 @@ def resource_id_param def resource_params params.require(:resource).permit( - :rhino_text, :kind, :male, :female, :title, :featured, :inactive, :url, + :rhino_text, :kind, :male, :female, :title, :featured, :inactive, :public, :public_featured, :url, :agency, :author, :filemaker_code, :windows_type_id, :position, categorizable_items_attributes: [ :id, :category_id, :_destroy ], category_ids: [], sectorable_items_attributes: [ :id, :sector_id, :is_leader, :_destroy ], sector_ids: [] diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb index 0f37da84f..c442bdc89 100644 --- a/app/controllers/stories_controller.rb +++ b/app/controllers/stories_controller.rb @@ -110,7 +110,7 @@ def set_story # Strong parameters def story_params params.require(:story).permit( - :title, :rhino_body, :featured, :published, :youtube_url, :website_url, + :title, :rhino_body, :featured, :published, :public, :public_featued, :youtube_url, :website_url, :windows_type_id, :project_id, :workshop_id, :external_workshop_title, :created_by_id, :updated_by_id, :story_idea_id, :spotlighted_facilitator_id ) diff --git a/app/controllers/workshops_controller.rb b/app/controllers/workshops_controller.rb index 7a3476b2b..429093615 100644 --- a/app/controllers/workshops_controller.rb +++ b/app/controllers/workshops_controller.rb @@ -239,6 +239,8 @@ def workshop_params :title, :featured, :inactive, :full_name, :user_id, :windows_type_id, :workshop_idea_id, :month, :year, + :public, + :public_featured, :time_intro, :time_closing, :time_creation, :time_demonstration, :time_warm_up, :time_opening, :time_opening_circle, diff --git a/app/models/community_news.rb b/app/models/community_news.rb index ec70cf65d..a9772e8a4 100644 --- a/app/models/community_news.rb +++ b/app/models/community_news.rb @@ -43,7 +43,7 @@ class CommunityNews < ApplicationRecord end scope :featured, -> { where(featured: true) } - scope :visitor_featured, -> { where(visitor_featured: true) } + scope :public_featured, -> { where(public_featured: true) } scope :category_names, ->(names) { tag_names(:categories, names) } scope :sector_names, ->(names) { tag_names(:sectors, names) } scope :community_news_name, ->(community_news_name) { diff --git a/app/models/event.rb b/app/models/event.rb index 84681c227..796245af1 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -20,7 +20,7 @@ class Event < ApplicationRecord # Validations validates_presence_of :title, :start_date, :end_date - validates_inclusion_of :publicly_visible, in: [ true, false ] + validates_inclusion_of :inactive, in: [ true, false ] validates_numericality_of :cost_cents, greater_than_or_equal_to: 0, allow_nil: true # Nested attributes @@ -33,13 +33,24 @@ class Event < ApplicationRecord attributes :title, :description end - scope :featured, -> { where(featured: true) } - scope :visitor_featured, -> { where(visitor_featured: true) } - scope :published, ->(published = nil) { publicly_visible(published) } - scope :publicly_visible, ->(publicly_visible = nil) { publicly_visible ? where(publicly_visible: publicly_visible): where(publicly_visible: true) } + + # Action Policy + scope :featured, -> { + where(featured: true) + .where("registration_close_date IS NULL OR registration_close_date >= ?", Time.current) + } + scope :public_featured, -> { + where(public: true, public_featured: true) + .where("registration_close_date IS NULL OR registration_close_date >= ?", Time.current) + } + + + scope :published, ->(published = nil) { published.to_s.present? ? + where(inactive: !published) : where(inactive: false) } scope :category_names, ->(names) { tag_names(:categories, names) } scope :sector_names, ->(names) { tag_names(:sectors, names) } + def self.search_by_params(params) stories = self.all stories = stories.search(params[:query]) if params[:query].present? @@ -49,12 +60,8 @@ def self.search_by_params(params) stories end - def inactive? - !publicly_visible - end - def registerable? - publicly_visible && + !inactive && (registration_close_date.nil? || registration_close_date >= Time.current) end diff --git a/app/models/resource.rb b/app/models/resource.rb index 7cb0b6a30..65cc819b0 100644 --- a/app/models/resource.rb +++ b/app/models/resource.rb @@ -77,7 +77,7 @@ class Resource < ApplicationRecord scope :category_names, ->(names) { tag_names(:categories, names) } scope :sector_names, ->(names) { tag_names(:sectors, names) } scope :featured, ->(featured = nil) { featured.present? ? where(featured: featured) : where(featured: true) } - scope :visitor_featured, -> { where(visitor_featured: true) } + scope :public_featured, -> { where(public_featured: true) } scope :kinds, ->(kinds) { kinds = Array(kinds).flatten.map(&:to_s) where(kind: kinds) diff --git a/app/models/story.rb b/app/models/story.rb index b7fde0746..6320c1a9b 100644 --- a/app/models/story.rb +++ b/app/models/story.rb @@ -50,7 +50,7 @@ class Story < ApplicationRecord # Scopes scope :featured, -> { where(featured: true) } - scope :visitor_featured, -> { where(visitor_featured: true) } + scope :public_featured, -> { where(public_featured: true) } scope :category_names, ->(names) { tag_names(:categories, names) } scope :sector_names, ->(names) { tag_names(:sectors, names) } scope :story_name, ->(story_name) { diff --git a/app/models/workshop.rb b/app/models/workshop.rb index 0bcc7534b..f1b0416e5 100644 --- a/app/models/workshop.rb +++ b/app/models/workshop.rb @@ -119,7 +119,7 @@ class Workshop < ApplicationRecord scope :sector_names, ->(names) { tag_names(:sectors, names) } scope :created_by_id, ->(created_by_id) { where(user_id: created_by_id) } scope :featured, -> { where(featured: true) } - scope :visitor_featured, -> { where(visitor_featured: true) } + scope :public_featured, -> { where(public_featured: true) } scope :legacy, -> { where(legacy: true) } scope :published, ->(published = nil) { published.to_s.present? ? where(inactive: !published) : where(inactive: false) } @@ -141,8 +141,8 @@ class Workshop < ApplicationRecord .select("workshops.*, COUNT(bookmarks.id) AS bookmarks_count") .group("workshops.id") } - scope :featured_or_visitor_featured, -> { - where("(featured = ? OR visitor_featured = ?) AND inactive = ?", true, true, false) + scope :featured_or_public_featured, -> { + where("(featured = ? OR public_featured = ?) AND inactive = ?", true, true, false) } # Search Cop @@ -282,13 +282,13 @@ def attachable_content_type end def invalidate_featured_cache_if_changed - if featured_or_visitor_featured_changed? - Rails.cache.delete("featured_and_visitor_featured_workshop_ids") + if featured_or_public_featured_changed? + Rails.cache.delete("featured_and_public_featured_workshop_ids") end end - def featured_or_visitor_featured_changed? - featured_changed? || visitor_featured_changed? || inactive_changed? + def featured_or_public_featured_changed? + featured_changed? || public_featured_changed? || inactive_changed? end def attach_assets_from_idea! diff --git a/app/policies/dashboard_policy.rb b/app/policies/dashboard_policy.rb index 009322416..da78cb6cc 100644 --- a/app/policies/dashboard_policy.rb +++ b/app/policies/dashboard_policy.rb @@ -9,7 +9,7 @@ def index? if authenticated? relation.featured else - relation.visitor_featured + relation.public_featured end end end diff --git a/app/policies/event_policy.rb b/app/policies/event_policy.rb new file mode 100644 index 000000000..e47272f8d --- /dev/null +++ b/app/policies/event_policy.rb @@ -0,0 +1,27 @@ +class EventPolicy < ApplicationPolicy + # See https://actionpolicy.evilmartians.io/#/writing_policies + # + # override or add new rules here that are not defined in ApplicationPolicy + + skip_pre_check :verify_authenticated! + + def show? + admin? || + record.public? || + (!record.inactive? && authenticated?) + end + + relation_scope do |relation| + if admin? + relation + elsif authenticated? + relation.left_outer_joins(:registrants) + .where(inactive: false) + .where("registration_close_date IS NULL OR registration_close_date >= ? OR users.id = ?", Time.current, user.id) + .distinct + else + relation.where(inactive: false) + .where("registration_close_date IS NULL OR registration_close_date >= ?", Time.current) + end + end +end diff --git a/app/views/bookmarks/_editable_bookmark_button.html.erb b/app/views/bookmarks/_editable_bookmark_button.html.erb index 5bdb604d6..18408f7e8 100644 --- a/app/views/bookmarks/_editable_bookmark_button.html.erb +++ b/app/views/bookmarks/_editable_bookmark_button.html.erb @@ -1,8 +1,8 @@ -<% resource = Draper.undecorate(resource) %> - -<%= tag.span id: dom_id(resource, :bookmark_button), data: {controller: "optimistic-bookmark"} do %> - <% if resource.bookmarks.any? { |b| b.user_id == current_user.id } %> - <%= button_to bookmark_path(current_user.bookmark_for(resource)), +<% if allowed_to?(:update?, Bookmark) %> + <% resource = Draper.undecorate(resource) %> + <%= tag.span id: dom_id(resource, :bookmark_button), data: {controller: "optimistic-bookmark"} do %> + <% if resource.bookmarks.any? { |b| b.user_id == current_user.id } %> + <%= button_to bookmark_path(current_user.bookmark_for(resource)), method: :delete, class: "inline-flex items-center gap-2 px-4 py-2 border border-gray-500 text-primary rounded-lg @@ -12,18 +12,19 @@ turbo_confirm: "Remove bookmark?", action: "click->optimistic-bookmark#toggle" } do %> - - Bookmarked - <% end %> - <% else %> - <%= button_to bookmarks_path(bookmark: { bookmarkable_id: resource.id, bookmarkable_type: resource.class.name }), + + Bookmarked + <% end %> + <% else %> + <%= button_to bookmarks_path(bookmark: { bookmarkable_id: resource.id, bookmarkable_type: resource.class.name }), class: "inline-flex items-center gap-2 px-4 py-2 border border-gray-500 text-primary rounded-lg hover:bg-primary hover:text-white transition-colors duration-200 font-medium shadow-sm leading-none", data: { action: "click->optimistic-bookmark#toggle" } do %> - - Bookmark + + Bookmark + <% end %> <% end %> <% end %> <% end %> diff --git a/app/views/community_news/_form.html.erb b/app/views/community_news/_form.html.erb index d9423f48d..ed1ba1048 100644 --- a/app/views/community_news/_form.html.erb +++ b/app/views/community_news/_form.html.erb @@ -10,10 +10,17 @@
Registration Close Date
+<%= @event.registration_close_date&.strftime("%B %-d, %Y %l:%M %P") || "—" %>
- <%= @event.detail.presence || "—" %> -
+<%= @event.detail.presence || "—" %>
- (This will override any attachments uploaded in the form below once you click submit.) -
-+ (This will override any attachments uploaded in the form below once you click submit.) +
+