diff --git a/PERMISSIONS.md b/PERMISSIONS.md index f5d9fee8..0072bd2f 100644 --- a/PERMISSIONS.md +++ b/PERMISSIONS.md @@ -20,4 +20,4 @@ When the user has the read permission it is able to get all groups (as always). ### Activity/Article/Photo #### Unauthenticated and without permission -When not logged in or when without permission it is possible to get activities, articles and photos which have the publicly visible property to true. +When not logged in or when without permission it is possible to get activities, articles and photos which have the visibility property to public. diff --git a/app/controllers/v1/photos_controller.rb b/app/controllers/v1/photos_controller.rb index 76df8ee2..aaba56c8 100644 --- a/app/controllers/v1/photos_controller.rb +++ b/app/controllers/v1/photos_controller.rb @@ -1,8 +1,2 @@ class V1::PhotosController < V1::ApplicationController - before_action :doorkeeper_authorize!, except: %i[index show get_related_resources] - before_action do - doorkeeper_authorize! unless %w[index show].include?(action_name) || - (action_name == 'get_related_resources' && - params[:source] == 'v1/photo_albums') - end end diff --git a/app/models/photo.rb b/app/models/photo.rb index b39582cc..ad13120e 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -21,12 +21,16 @@ class Photo < ApplicationRecord joins(:comments).distinct } - scope :with_tags, lambda { - joins(:tags).distinct + scope :alumni_visible, lambda { |start_date, end_date| + joins(:photo_album) + .where(photo_albums: { visibility: 'alumni' }) + .or(photo_albums: { visibility: 'public' }) + .or(where.not(photo_albums: { date: nil }).where(photo_albums: { date: start_date..end_date })) + .or(where(photo_albums: { date: nil }).where(photo_albums: { created_at: start_date..end_date })) } - scope :publicly_visible, lambda { - joins(:photo_album).where(photo_albums: { publicly_visible: true }) + scope :with_tags, lambda { + joins(:tags).distinct } before_save :extract_exif diff --git a/app/models/photo_album.rb b/app/models/photo_album.rb index 549edf48..5c38b9c3 100644 --- a/app/models/photo_album.rb +++ b/app/models/photo_album.rb @@ -7,10 +7,18 @@ class PhotoAlbum < ApplicationRecord belongs_to :group, optional: true validates :title, presence: true - validates :publicly_visible, inclusion: [true, false] - - scope :publicly_visible, -> { where(publicly_visible: true) } + validates :visibility, inclusion: { in: %w[public alumni members] } + scope :publicly_visible, lambda { + joins(:photo_album).where(photo_albums: { visibility: 'public' }) + } + scope :alumni_visible, lambda { |start_date, end_date| + joins(:photo_album) + .where(photo_albums: { visibility: 'alumni' }) + .or(photo_albums: { visibility: 'public' }) + .or(where.not(date: nil).where(date: start_date..end_date)) + .or(where(date: nil).where(created_at: start_date..end_date)) + } scope :without_photo_tags, lambda { where.not(id: Photo.joins(:tags).select(:photo_album_id).distinct) } diff --git a/app/models/photo_comment.rb b/app/models/photo_comment.rb index 642d613f..2eb3e6e8 100644 --- a/app/models/photo_comment.rb +++ b/app/models/photo_comment.rb @@ -6,8 +6,11 @@ class PhotoComment < ApplicationRecord validates :content, presence: true, length: { minimum: 1, maximum: 500 } - scope :publicly_visible, lambda { + scope :alumni_visible, lambda { |start_date, end_date| joins(photo: :photo_album) - .where(photo_albums: { publicly_visible: true }) + .where(photo_albums: { visibility: 'alumni' }) + .or(photo_albums: { visibility: 'public' }) + .or(where.not(photo_albums: { date: nil }).where(photo_albums: { date: start_date..end_date })) + .or(where(photo_albums: { date: nil }).where(photo_albums: { created_at: start_date..end_date })) } end diff --git a/app/policies/photo_album_policy.rb b/app/policies/photo_album_policy.rb index f54a4e16..7ecaaf1b 100644 --- a/app/policies/photo_album_policy.rb +++ b/app/policies/photo_album_policy.rb @@ -1,8 +1,14 @@ class PhotoAlbumPolicy < ApplicationPolicy class Scope < ApplicationPolicy::Scope - def resolve + def resolve # rubocop:disable Metrics/AbcSize if user_can_read? - scope + membership = user.memberships.joins(:group).where(groups: { name: 'Leden' }).first + return scope.publicly_visible if membership.nil? + + scope.alumni_visible( + membership.start_date&.advance(months: -18), + membership.end_date&.advance(months: 6) + ) else scope.publicly_visible end diff --git a/app/policies/photo_comment_policy.rb b/app/policies/photo_comment_policy.rb index b3322463..fbcc4c89 100644 --- a/app/policies/photo_comment_policy.rb +++ b/app/policies/photo_comment_policy.rb @@ -2,9 +2,13 @@ class PhotoCommentPolicy < ApplicationPolicy class Scope < ApplicationPolicy::Scope def resolve if user_can_read? - scope - else - scope.publicly_visible + membership = user.memberships.joins(:group).where(groups: { name: 'Leden' }).first + return if membership.nil? + + scope.alumni_visible( + membership.start_date&.advance(months: -18), + membership.end_date&.advance(months: 6) + ) end end end diff --git a/app/policies/photo_policy.rb b/app/policies/photo_policy.rb index 751a55ed..5d10b751 100644 --- a/app/policies/photo_policy.rb +++ b/app/policies/photo_policy.rb @@ -2,9 +2,13 @@ class PhotoPolicy < ApplicationPolicy class Scope < ApplicationPolicy::Scope def resolve if user_can_read? - scope - else - scope.publicly_visible + membership = user.memberships.joins(:group).where(groups: { name: 'Leden' }).first + return if membership.nil? + + scope.alumni_visible( + membership.start_date&.advance(months: -18), + membership.end_date&.advance(months: 6) + ) end end end diff --git a/app/resources/v1/photo_album_resource.rb b/app/resources/v1/photo_album_resource.rb index a79e8910..c616b221 100644 --- a/app/resources/v1/photo_album_resource.rb +++ b/app/resources/v1/photo_album_resource.rb @@ -1,5 +1,5 @@ class V1::PhotoAlbumResource < V1::ApplicationResource - attributes :title, :date, :publicly_visible + attributes :title, :date, :visibility filter :without_photo_tags, apply: ->(records, _value, _options) { records.without_photo_tags } @@ -8,7 +8,7 @@ class V1::PhotoAlbumResource < V1::ApplicationResource has_one :group, always_include_linkage_data: true def self.creatable_fields(_context) - %i[title date publicly_visible group] + %i[title date visibility group] end def self.searchable_fields diff --git a/db/migrate/20250314221852_alumni_visibility.rb b/db/migrate/20250314221852_alumni_visibility.rb new file mode 100644 index 00000000..7f92024d --- /dev/null +++ b/db/migrate/20250314221852_alumni_visibility.rb @@ -0,0 +1,21 @@ +class AlumniVisibility < ActiveRecord::Migration[7.0] + def up + add_column :photo_albums, :visibility, :string, default: 'members' + + PhotoAlbum.find_each do |record| + record.update!(visibility: record.publicly_visible ? 'public' : 'members') + end + + remove_column :photo_albums, :publicly_visible + end + + def down + add_column :photo_albums, :publicly_visible, :boolean, default: false, null: false + + PhotoAlbum.find_each do |record| + record.update!(publicly_visible: record.visibility == 'public') + end + + remove_column :photo_albums, :visibility + end +end diff --git a/db/schema.rb b/db/schema.rb index 20015070..e6d40e6c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2025_03_10_235232) do +ActiveRecord::Schema[7.1].define(version: 2025_03_14_221852) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -411,9 +411,9 @@ t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false t.datetime "deleted_at", precision: nil - t.boolean "publicly_visible", default: false, null: false t.bigint "author_id" t.bigint "group_id" + t.string "visibility", default: "members" t.index ["author_id"], name: "index_photo_albums_on_author_id" t.index ["deleted_at"], name: "index_photo_albums_on_deleted_at" t.index ["group_id"], name: "index_photo_albums_on_group_id" diff --git a/spec/models/photo_spec.rb b/spec/models/photo_spec.rb index e931031b..5ae5f305 100644 --- a/spec/models/photo_spec.rb +++ b/spec/models/photo_spec.rb @@ -62,12 +62,13 @@ end describe '#publicly_visible' do - let(:public_album) { create(:photo_album, publicly_visible: true) } - let(:private_album) { create(:photo_album, publicly_visible: false) } + let(:public_album) { create(:photo_album, visibility: 'public') } + let(:alumni_album) { create(:photo_album, visibility: 'alumni') } + let(:private_album) { create(:photo_album, visibility: 'members') } before do create(:photo, photo_album: public_album) - create(:photo, photo_album: public_album) + create(:photo, photo_album: alumni_album) create(:photo, photo_album: private_album) end @@ -75,6 +76,21 @@ it { expect(described_class.count - described_class.publicly_visible.count).to be 1 } end + describe '#alumni_visible' do + let(:public_album) { create(:photo_album, visibility: 'public') } + let(:alumni_album) { create(:photo_album, visibility: 'alumni') } + let(:private_album) { create(:photo_album, visibility: 'members') } + + before do + create(:photo, photo_album: public_album) + create(:photo, photo_album: alumni_album) + create(:photo, photo_album: private_album) + end + + it { expect(described_class.alumni_visible.count).to be 2 } + it { expect(described_class.count - described_class.alumni_visible.count).to be 1 } + end + describe '#extract_exif' do subject(:photo) { create(:photo) } diff --git a/spec/support/contexts/requests/when_alumni.rb b/spec/support/contexts/requests/when_alumni.rb new file mode 100644 index 00000000..fc10e779 --- /dev/null +++ b/spec/support/contexts/requests/when_alumni.rb @@ -0,0 +1,10 @@ +shared_context 'when alumni' do + let(:user) { create(:user) } + let(:group) { create(:group, name: 'Leden') } + let(:membership) { create(:membership, user: user, group: group, start_date: 4.years.ago, end_date: 2.years.ago) } + let(:access_token) { Doorkeeper::AccessToken.create!(resource_owner_id: user.id) } + + before do + header('Authorization', "Bearer #{access_token.plaintext_token}") + end +end diff --git a/spec/support/contexts/requests/when_member.rb b/spec/support/contexts/requests/when_member.rb new file mode 100644 index 00000000..09cde513 --- /dev/null +++ b/spec/support/contexts/requests/when_member.rb @@ -0,0 +1,10 @@ +shared_context 'when member' do + let(:user) { create(:user) } + let(:group) { create(:group, name: 'Leden') } + let(:membership) { create(:membership, user: user, group: group, start_date: 2.years.ago, end_date: nil) } + let(:access_token) { Doorkeeper::AccessToken.create!(resource_owner_id: user.id) } + + before do + header('Authorization', "Bearer #{access_token.plaintext_token}") + end +end