diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 4ef9c4e3..b8881233 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -29,10 +29,9 @@ def destroy render json: { message: "User deleted successfully!" } end - # Add profile action and pass current_user as params def profile - @user = User.find(params[:id]) - render json: UserProfileSerializer.new(@user).serializable_hash + role = current_user.role + render json: UserProfileSerializer.new(@user, { params: { role: role } }).serializable_hash end private diff --git a/app/models/user.rb b/app/models/user.rb index 13c587fa..7dcd8a2f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -40,19 +40,16 @@ def set_default_role self.role ||= "user" end - def admin? - role == "admin" + # Define methods to access bookings through orders and events + def pending_bookings + Booking.joins(:order).where(orders: { user_id: id }, status: "pending") end - def teacher? - role == "teacher" + def confirmed_bookings + Booking.joins(:order).where(orders: { user_id: id }, status: "confirmed") end - def speaker? - role == "speaker" - end - - def user? - role == "user" + def bookings + Booking.joins(:order).where(orders: { user_id: id }) end end diff --git a/app/serializers/availability_serializer.rb b/app/serializers/availability_serializer.rb new file mode 100644 index 00000000..9bbd25e3 --- /dev/null +++ b/app/serializers/availability_serializer.rb @@ -0,0 +1,4 @@ +class AvailabilitySerializer + include JSONAPI::Serializer + attributes :start_time, :end_time, :speaker, presence: true +end diff --git a/app/serializers/booking_serializer.rb b/app/serializers/booking_serializer.rb new file mode 100644 index 00000000..7d9766e7 --- /dev/null +++ b/app/serializers/booking_serializer.rb @@ -0,0 +1,6 @@ +class BookingSerializer + include JSONAPI::Serializer + attributes :id, :status, :start_time, :end_time, :created_at, :updated_at + + belongs_to :event +end diff --git a/app/serializers/event_serializer.rb b/app/serializers/event_serializer.rb new file mode 100644 index 00000000..daf68de4 --- /dev/null +++ b/app/serializers/event_serializer.rb @@ -0,0 +1,7 @@ +class EventSerializer + include JSONAPI::Serializer + attributes :id, :title, :description, :duration + + belongs_to :speaker, serializer: UserSerializer + has_many :bookings +end diff --git a/app/serializers/user_profile_serializer.rb b/app/serializers/user_profile_serializer.rb index 7f4192e5..c80955ad 100644 --- a/app/serializers/user_profile_serializer.rb +++ b/app/serializers/user_profile_serializer.rb @@ -2,49 +2,37 @@ class UserProfileSerializer include JSONAPI::Serializer attributes :name, :email, :id, :bio, :profile_image_url, :organization_id - attribute :donations do |user| - user.donations ? user.donations.map { |donation| DonationSerializer.new(donation).serializable_hash } : [] + attribute :events, if: Proc.new { |user, params| params[:role] == "speaker" || params[:role] == "teacher" } do |user| + user.events ? user.events.map { |event| EventSerializer.new(event).serializable_hash } : [] end - # attribute :orders do |user| - # user.orders ? user.orders.map { |order| OrderSerializer.new(order).serializable_hash } : [] - # end + attribute :availabilities, if: Proc.new { |user, params| params[:role] == "speaker" || params[:role] == "teacher" } do |user| + user.availabilities ? user.availabilities.map { |availability| AvailabilitySerializer.new(availability).serializable_hash } : [] + end - attribute :orders do |user| - if user.orders - kit_orders = user.orders.select { |order| order.product.is_a?(Kit) } - kit_orders.map { |order| OrderSerializer.new(order).serializable_hash } - else - [] - end + attribute :pending_bookings, if: Proc.new { |user, params| params[:role] == "speaker" } do |user| + user.pending_bookings ? user.pending_bookings.map { |booking| BookingSerializer.new(booking).serializable_hash } : [] end - attribute :bookings do |user| - if user.orders.present? - booking_orders = user.orders.select { |order| order.product.is_a?(Booking) } - booking_orders.map { |order| OrderSerializer.new(order).serializable_hash } - else - [] - end + attribute :confirmed_bookings, if: Proc.new { |user, params| params[:role] == "speaker" } do |user| + user.confirmed_bookings ? user.confirmed_bookings.map { |booking| BookingSerializer.new(booking).serializable_hash } : [] end - attribute :organization do |user| - if user.organization - OrganizationSerializer.new(user.organization).serializable_hash[:data][:attributes] - else - {} - end + attribute :bookings, if: Proc.new { |user, params| params[:role] == "teacher" } do |user| + user.bookings ? user.bookings.map { |booking| BookingSerializer.new(booking).serializable_hash } : [] end - attribute :addresses do |user| - user.addresses.map { |address| AddressSerializer.new(address).serializable_hash[:data][:attributes] } + attribute :donations do |user| + user.donations ? user.donations.map { |donation| DonationSerializer.new(donation).serializable_hash } : [] end - # Added the profile_image_url method here + attribute :orders, if: Proc.new { |user, params| params[:role] == "teacher" } do |user| + user.orders ? user.orders.map { |order| OrderSerializer.new(order).serializable_hash } : [] + end def profile_image_url - if object.profile_image.attached? - Rails.application.routes.url_helpers.rails_blob_url(object.profile_image, only_path: false) + if @resource.profile_image.attached? + Rails.application.routes.url_helpers.rails_blob_url(@resource.profile_image, only_path: false) end end end diff --git a/spec/requests/users_spec.rb b/spec/requests/users_spec.rb index 47d00212..debc8081 100644 --- a/spec/requests/users_spec.rb +++ b/spec/requests/users_spec.rb @@ -3,7 +3,22 @@ RSpec.describe "Users", type: :request do let(:admin_user) { create(:user, :admin_user) } let(:regular_user) { create(:user, :regular_user) } - + # let(:speaker_user) { create(:user, role: 'speaker', events: [ create(:event) ], availabilities: [ create(:availability) ]) } + # let(:teacher) { create(:user, role: 'teacher') } + let(:speaker_user) do + create( + :user, + role: 'speaker', + events: [ create(:event) ], + availabilities: [ create(:availability) ], + ) + end + let(:teacher_user) do + create( + :user, + role: 'teacher', + ) + end describe "GET /index" do context "when user role is admin" do @@ -24,11 +39,11 @@ end end - describe "GET/ show" do + describe "GET /show" do context "when user role is admin" do it "returns http success" do sign_in admin_user - get api_v1_users_path(admin_user), headers: { 'Authorization': "Bearer #{@auth_token}" } + get api_v1_user_path(admin_user), headers: { 'Authorization': "Bearer #{@auth_token}" } expect(response).to have_http_status(:success) end end @@ -37,7 +52,7 @@ it "returns http response success" do # Changed permissions to view speakers sign_in regular_user - get api_v1_users_path(regular_user), headers: { 'Authorization': "Bearer #{@auth_token}" } + get api_v1_user_path(regular_user), headers: { 'Authorization': "Bearer #{@auth_token}" } expect(response).to have_http_status(:success) end end @@ -96,4 +111,47 @@ end end end + +# describe "GET /profile" do +context "when user is a speaker" do + it "returns the full speaker profile with all bookings and events" do + sign_in speaker_user + get profile_api_v1_user_path(speaker_user), headers: { 'Authorization': "Bearer #{@auth_token}" } + expect(response).to have_http_status(:success) + + json_response = JSON.parse(response.body) + expect(json_response['data']['attributes']).to include( + 'bio', 'profile_image_url', 'events', 'availabilities', 'pending_bookings', 'confirmed_bookings' + ) + end +end + +context "when user is a teacher" do + it "returns a teacher profile with limited information" do + sign_in teacher_user + get profile_api_v1_user_path(teacher_user), headers: { 'Authorization': "Bearer #{@auth_token}" } + expect(response).to have_http_status(:success) + + json_response = JSON.parse(response.body) + expect(json_response['data']['attributes']).to include( + 'bio', 'profile_image_url', 'events', 'availabilities', 'bookings' + ) + end +end + +context "when teacher views a speaker profile" do + it "returns the speaker profile with limited information" do + sign_in teacher_user + get profile_api_v1_user_path(speaker_user), headers: { 'Authorization': "Bearer #{@auth_token}" } + expect(response).to have_http_status(:success) + + json_response = JSON.parse(response.body) + expect(json_response['data']['attributes']).to include( + 'bio', 'profile_image_url', 'events', 'availabilities' + ) + expect(json_response['data']['attributes']).not_to include( + 'pending_bookings', 'confirmed_bookings' + ) + end +end end