Skip to content
Draft
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 PERMISSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
6 changes: 0 additions & 6 deletions app/controllers/v1/photos_controller.rb
Original file line number Diff line number Diff line change
@@ -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
12 changes: 8 additions & 4 deletions app/models/photo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 11 additions & 3 deletions app/models/photo_album.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
7 changes: 5 additions & 2 deletions app/models/photo_comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 8 additions & 2 deletions app/policies/photo_album_policy.rb
Original file line number Diff line number Diff line change
@@ -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
Expand Down
10 changes: 7 additions & 3 deletions app/policies/photo_comment_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions app/policies/photo_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions app/resources/v1/photo_album_resource.rb
Original file line number Diff line number Diff line change
@@ -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 }

Expand All @@ -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
Expand Down
21 changes: 21 additions & 0 deletions db/migrate/20250314221852_alumni_visibility.rb
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions 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: 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"

Expand Down Expand Up @@ -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"
Expand Down
22 changes: 19 additions & 3 deletions spec/models/photo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,35 @@
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

it { expect(described_class.publicly_visible.count).to be 2 }
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) }

Expand Down
10 changes: 10 additions & 0 deletions spec/support/contexts/requests/when_alumni.rb
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions spec/support/contexts/requests/when_member.rb
Original file line number Diff line number Diff line change
@@ -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
Loading