Repository navigation
Curation Feature: Approval from admin required after material || event registration - #1382
kennethrioja wants to merge 22 commits into
Conversation
…y are not space admins
|
User documentation to add! |
There was a problem hiding this comment.
🟡 Changes recommended
Approval-state migration, authorization, visibility, routing, and pagination defects must be resolved before release.
12 open findings
Event approval parameter authorization is not record-specific · New Approval parameter authorization is not record-specific · New Non-Solr indexes expose unapproved resources · New Migration writes invalid approval status code · New Dashboard lists and modifies disabled approval resource types · New Curation pagination materializes the entire catalog · New Combined feature flag applies approval to disabled resource types · New Approval request condition is unreachable · New Event approval request condition is unreachable · New Approval routes target nonexistent controller actions · New Event approval scopes lack active test coverage · New Curator scope test passes vacuously without private-space role · New
🧠 Review effort: Balanced
| external_resources: %i[url title], material_ids: [], | ||
| llm_interaction_attributes: %i[id scrape_or_process model prompt input output needs_processing _destroy], | ||
| locked_fields: [], instructors: [:name, :orcid], contributors: [:name, :orcid]] | ||
| permitted << :approval_status if User.current_user&.can_approve_resources? |
There was a problem hiding this comment.
Added :approval_status parameter to both #create and #update methods by checking policy(record).approve?. We now pass record to event_params to be able to call policy(record).approve?
| external_resources_attributes: %i[id url title _destroy], | ||
| external_resources: %i[url title], | ||
| event_ids: [], locked_fields: []] | ||
| permitted << :approval_status if User.current_user&.can_approve_resources? |
There was a problem hiding this comment.
Same than previous comment
| # Filters by approval_status for unauthenticated requests (regardless of whether the feature is enabled or disabled) | ||
| if name == 'Material' && TeSS::Config.feature['material_under_admin_approval'] && !(user&.is_admin? || user&.is_curator?) | ||
| any_of do | ||
| with(:approval_status, I18n.t('materials.approval_status.approved')) | ||
| with(:user_id, user.id) if user.present? | ||
| end | ||
| end | ||
|
|
||
| # Filters by approval_status for unauthenticated requests (regardless of whether the feature is enabled or disabled) | ||
| if name == 'Event' && TeSS::Config.feature['event_under_admin_approval'] && !(user&.is_admin? || user&.is_curator?) |
There was a problem hiding this comment.
Added Scope#resolved in both material and event policies (and includes owner/admin/curator/space admin exceptions)
| add_column :materials, :approval_status, :string, default: 'approved' | ||
| add_column :events, :approval_status, :string, default: 'approved' | ||
|
|
||
| reversible do |dir| | ||
| dir.up do | ||
| # Backfill existing records (will be NULL on existing rows when adding a column) | ||
| Material.unscoped.where(approval_status: nil).update_all(approval_status: 'approved') | ||
| Event.unscoped.where(approval_status: nil).update_all(approval_status: 'approved') |
There was a problem hiding this comment.
Accepted the suggestion
| @status = params[:status].presence || 'requested' | ||
| @type = params[:type].presence || 'all' | ||
|
|
||
| target_classes = @type == 'all' ? CURATABLE_TYPES.values : [CURATABLE_TYPES[@type]].compact |
There was a problem hiding this comment.
Tailored target_classes to filter on the enabled_curatable_classes
| <%= resource_approval_badge(@event.approval_status) %> | ||
| </p> | ||
|
|
||
| <% if !@event.not_approved? && !@event.approval_requested? && !@event.approved? && !policy(@event).approve? %> |
There was a problem hiding this comment.
I deleted it, users never ask for request approval, it is automatically done – this is a remnant from my previous design
| <%= resource_approval_badge(@material.approval_status) %> | ||
| </p> | ||
|
|
||
| <% if !@material.not_approved? && !@material.approval_requested? && !@material.approved? && !policy(@material).approve? %> |
There was a problem hiding this comment.
I deleted it, users never ask for request approval, it is automatically done – this is a remnant from my previous design
| get 'curate/materials' => 'curator#materials', as: :curate_materials | ||
| get 'curate/events' => 'curator#events', as: :curate_events |
There was a problem hiding this comment.
Suggestion accepted
| # test '.approved scope returns only approved event' do | ||
| # approved = Event.approved | ||
| # assert_includes approved, @approved_event | ||
| # refute_includes approved, @not_approved_event | ||
| # refute_includes approved, @requested_event |
| context = Struct.new(:user).new(@private_space_owner) | ||
| scope = ApplicationPolicy::Scope.new(context, Material).resolve_curatable | ||
|
|
||
| scope.each do |material| | ||
| assert_equal @space.id, material.space_id | ||
| end |
There was a problem hiding this comment.
Suggestion accepted
… space but cannot see and curate requested private resources Using Copilot, GPT-6 Luna, 6.65 AIC used



Summary of changes
material_under_admin_approvalorevent_under_admin_approvalis set to true, and if a user registers a material or an event, the resource must be approved by either anadministrator, acuratoror aspace admin.Curate {resource}is found next to the Register button OR they can find this page in the user dropdown (see screenshots)/curate/resourcespage, they can see by default the list ofRequestedmaterials. You can filter by Type, User, Provider, Space andbulk_approveorrejectthe filtered list of resources to avoid doing it 1 by 1. A Reset filter button is also present. A list of recent curation activity is found on the right.:requested(seematerial.rb#set_approval_status, same for events):requested:requestedprivate space resources unless they are space adminsapp/policies/application_policy.rb#shown?is the place to manage if a resource can be shown to a user. Then all the other resource-specific policies can be found in the related{resource}_policy.rbfile. I avoided having to put conditions such asis_admin?in thehtml.erbfiles, this is why I tried to have as much conditions with<% if policy(@event).{update|approve}? %>as possible, so that everything is managed in the policies rather that in the views.Motivation and context
Curation is needed in HEP and EVERSE Training
Screenshots
Users view
Admin/Curator/Space admin curation buttons
Curation page
Not covered in this PR, but could be useful
check_exists)Checklist