8000 Code cleanup by mwoods79 · Pull Request #101 · huddlz-hq/huddlz · GitHub
[go: up one dir, main page]

Skip to content
Merged
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
4 changes: 4 additions & 0 deletions lib/huddlz/communities.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule Huddlz.Communities do

resources do
resource Huddlz.Communities.Huddl do
define :get_huddl, action: :read, get_by: [:id]
define :get_upcoming, action: :upcoming

define :search_huddlz,
Expand All @@ -18,6 +19,9 @@ defmodule Huddlz.Communities do
define :get_by_status, action: :by_status, args: [:status]
define :get_group_huddlz, action: :by_group, args: [:group_id]
define :get_past_group_huddlz, action: :past_by_group, args: [:group_id]
define :rsvp_huddl, action: :rsvp, args: [:user_id]
define :cancel_rsvp_huddl, action: :cancel_rsvp, args: [:user_id]
define :destroy_huddl, action: :destroy
end

resource Huddlz.Communities.Group do
Expand Down
4 changes: 4 additions & 0 deletions lib/huddlz/communities/group.ex
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ defmodule Huddlz.Communities.Group do
primary_key? false
end

has_many :group_members, Huddlz.Communities.GroupMember do
destination_attribute :group_id
end

many_to_many :members, Huddlz.Accounts.User do
through Huddlz.Communities.GroupMember
source_attribute_on_join_resource :group_id
Expand Down
164 changes: 22 additions & 142 deletions lib/huddlz/communities/huddl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ defmodule Huddlz.Communities.Huddl do
authorizers: [Ash.Policy.Authorizer],
primary_read_warning?: false

require Ash.Query

postgres do
table "huddlz"
repo Huddlz.Repo
Expand All @@ -37,7 +35,6 @@ defmodule Huddlz.Communities.Huddl do
:physical_location,
:virtual_link,
:is_private,
:rsvp_count,
:thumbnail_url,
:creator_id,
:group_id,
Expand Down Expand Up @@ -75,7 +72,6 @@ defmodule Huddlz.Communities.Huddl do
:physical_location,
:virtual_link,
:is_private,
:rsvp_count,
:thumbnail_url,
:huddl_template_id
]
Expand Down Expand Up @@ -190,78 +186,22 @@ defmodule Huddlz.Communities.Huddl do
description "RSVP to this huddl"
require_atomic? false

# Accept the user_id as an argument
argument :user_id, :uuid do
allow_nil? false
end

# Custom change to handle RSVP
change fn changeset, _context ->
user_id = Ash.Changeset.get_argument(changeset, :user_id)
huddl_id = changeset.data.id

# Check if already RSVPed
existing =
Huddlz.Communities.HuddlAttendee
|> Ash.Query.for_read(:check_rsvp, %{huddl_id: huddl_id, user_id: user_id})
|> Ash.read_one(authorize?: false)

case existing do
{:ok, nil} ->
# Create RSVP
Huddlz.Communities.HuddlAttendee
|> Ash.Changeset.for_create(:rsvp, %{huddl_id: huddl_id, user_id: user_id})
|> Ash.create!(authorize?: false)

# Increment count
Ash.Changeset.atomic_update(changeset, :rsvp_count, expr(rsvp_count + 1))

{:ok, _} ->
# Already RSVPed, no change needed
changeset

{:error, error} ->
Ash.Changeset.add_error(changeset, error)
end
end
change Huddlz.Communities.Huddl.Changes.Rsvp
end

update :cancel_rsvp do
description "Cancel RSVP to this huddl"
require_atomic? false

# Accept the user_id as an argument
argument :user_id, :uuid do
allow_nil? false
end

# Custom change to handle cancellation
change fn changeset, _context ->
user_id = Ash.Changeset.get_argument(changeset, :user_id)
huddl_id = changeset.data.id

# Find the existing RSVP
existing =
Huddlz.Communities.HuddlAttendee
|> Ash.Query.for_read(:check_rsvp, %{huddl_id: huddl_id, user_id: user_id})
|> Ash.read_one(authorize?: false)

case existing do
{:ok, nil} ->
# No RSVP to cancel, return unchanged
changeset

{:ok, attendee} ->
# Delete the attendee record
Ash.destroy!(attendee, authorize?: false)

# Decrement count
Ash.Changeset.atomic_update(changeset, :rsvp_count, expr(rsvp_count - 1))

{:error, error} ->
Ash.Changeset.add_error(changeset, error)
end
end
change Huddlz.Communities.Huddl.Changes.CancelRsvp
end
end

Expand All @@ -278,95 +218,38 @@ defmodule Huddlz.Communities.Huddl do
authorize_if Huddlz.Communities.Huddl.Checks.GroupOwnerOrOrganizer
end

# Read policies
policy action(:read) do
description "Users can read huddls they have access to"
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
end

policy action(:upcoming) do
description "Users can view upcoming huddls they have access to"
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
end

policy action(:past) do
description "Users can view past huddls they have access to"
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
end

policy action(:search) do
description "Users can search huddls they have access to"
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
end

policy action(:by_group) do
description "Users can view huddls by group if they have access"
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
end

policy action(:past_by_group) do
description "Users can view past huddls by group if they have access"
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
end

policy action(:by_status) do
description "Users can filter huddls by status"
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
# Read policies - visibility filtering is handled by the FilterByVisibility preparation
# on each read action, which adds database-level filters. We authorize all reads here
# and rely on the preparation to restrict results.
policy action_type(:read) do
description "Users can read huddlz they have access to (filtered by preparation)"
authorize_if always()
end

# RSVP policies
policy action(:rsvp) do
description "Users can RSVP to huddls they have access to"
# User must be RSVPing for themselves
description "Users can RSVP to huddlz they have access to"
forbid_unless expr(^arg(:user_id) == ^actor(:id))
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
authorize_if expr(is_private == false and group.is_public == true)
authorize_if expr(exists(group.members, id == ^actor(:id)))
end

# Cancel RSVP policies
policy action(:cancel_rsvp) do
description "Users can cancel their own RSVPs"
# User must be cancelling their own RSVP
forbid_unless expr(^arg(:user_id) == ^actor(:id))
# Public huddls in public groups
authorize_if Huddlz.Communities.Huddl.Checks.PublicHuddl
# Any huddl in a group they're a member of
authorize_if Huddlz.Communities.Huddl.Checks.GroupMember
authorize_if expr(is_private == false and group.is_public == true)
authorize_if expr(exists(group.members, id == ^actor(:id)))
end

# Update policies
policy action(:update) do
description "Only group owners and organizers can update huddls"
authorize_if Huddlz.Communities.Huddl.Checks.GroupOwnerOrOrganizer
end
# Update and delete policies
policy action([:update, :destroy]) do
description "Only group owners and organizers can update or delete huddlz"
authorize_if expr(group.owner_id == ^actor(:id))

# Delete policies
policy action(:destroy) do
description "Only group owners and organizers can delete huddls"
authorize_if Huddlz.Communities.Huddl.Checks.GroupOwnerOrOrganizer
authorize_if expr(
exists(group.group_members, user_id == ^actor(:id) and role == :organizer)
)
end
end

Expand Down Expand Up @@ -433,11 +316,6 @@ defmodule Huddlz.Communities.Huddl do
default false
end

attribute :rsvp_count, :integer do
allow_nil? false
default 0
end

attribute :thumbnail_url, :string do
allow_nil? true
end
Expand Down Expand Up @@ -514,6 +392,8 @@ defmodule Huddlz.Communities.Huddl do
end

aggregates do
count :rsvp_count, :attendees

first :current_image_url, :huddl_images, :thumbnail_path do
description "Returns the thumbnail path of the huddl's current image"
sort inserted_at: :desc
Expand Down
31 changes: 31 additions & 0 deletions lib/huddlz/communities/huddl/changes/cancel_rsvp.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
defmodule Huddlz.Communities.Huddl.Changes.CancelRsvp do
@moduledoc """
Handles RSVP cancellation: destroys the attendee record if one exists.
The rsvp_count is computed as an aggregate, so no manual counter management is needed.
"""
use Ash.Resource.Change

require Ash.Query

def change(changeset, _opts, _context) do
user_id = Ash.Changeset.get_argument(changeset, :user_id)
huddl_id = changeset.data.id

existing =
Huddlz.Communities.HuddlAttendee
|> Ash.Query.for_read(:check_rsvp, %{huddl_id: huddl_id, user_id: user_id})
|> Ash.read_one(authorize?: false)

case existing do
{:ok, nil} ->
changeset

{:ok, attendee} ->
Ash.destroy!(attendee, authorize?: false)
changeset

{:error, error} ->
Ash.Changeset.add_error(changeset, error)
end
end
end
34 changes: 34 additions & 0 deletions lib/huddlz/communities/huddl/changes/rsvp.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule Huddlz.Communities.Huddl.Changes.Rsvp do
@moduledoc """
Handles RSVP logic: creates an attendee record if one doesn't already exist.
The rsvp_count is computed as an aggregate, so no manual counter management is needed.
"""
use Ash.Resource.Change

require Ash.Query

def change(changeset, _opts, _context) do
user_id = Ash.Changeset.get_argument(changeset, :user_id)
huddl_id = changeset.data.id

existing =
Huddlz.Communities.HuddlAttendee
|> Ash.Query.for_read(:check_rsvp, %{huddl_id: huddl_id, user_id: user_id})
|> Ash.read_one(authorize?: false)

case existing do
{:ok, nil} ->
Huddlz.Communities.HuddlAttendee
|> Ash.Changeset.for_create(:rsvp, %{huddl_id: huddl_id, user_id: user_id})
|> Ash.create!(authorize?: false)

changeset

{:ok, _} ->
changeset

{:error, error} ->
Ash.Changeset.add_error(changeset, error)
end
end
end
43 changes: 0 additions & 43 deletions lib/huddlz/communities/huddl/checks/group_member.ex

This file was deleted.

Loading
0