Packages

phoenix_kit

1.7.21
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules connections follow.ex
Raw

lib/modules/connections/follow.ex

defmodule PhoenixKit.Modules.Connections.Follow do
@moduledoc """
Schema for one-way follow relationships.
Represents a unidirectional relationship where one user follows another.
No consent is required from the followed user.
## Fields
- `follower_id` - User who is doing the following
- `followed_id` - User being followed
- `inserted_at` - When the follow was created
## Examples
# User A follows User B
%Follow{
id: "018e3c4a-9f6b-7890-abcd-ef1234567890",
follower_id: 1,
followed_id: 2,
inserted_at: ~N[2025-01-15 10:30:00]
}
## Business Rules
- Cannot follow yourself
- Cannot follow if blocked (either direction)
- Duplicate follows are prevented by unique constraint
"""
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, UUIDv7, autogenerate: true}
@type t :: %__MODULE__{
id: UUIDv7.t() | nil,
follower_id: integer(),
followed_id: integer(),
follower: PhoenixKit.Users.Auth.User.t() | Ecto.Association.NotLoaded.t(),
followed: PhoenixKit.Users.Auth.User.t() | Ecto.Association.NotLoaded.t(),
inserted_at: NaiveDateTime.t() | nil
}
schema "phoenix_kit_user_follows" do
belongs_to :follower, PhoenixKit.Users.Auth.User, type: :integer
belongs_to :followed, PhoenixKit.Users.Auth.User, type: :integer
field :inserted_at, :naive_datetime
end
@doc """
Changeset for creating a follow relationship.
## Required Fields
- `follower_id` - The user who is following
- `followed_id` - The user being followed
## Validation Rules
- Both user IDs are required
- Cannot follow yourself (follower_id != followed_id)
- Unique constraint on (follower_id, followed_id) pair
"""
def changeset(follow, attrs) do
follow
|> cast(attrs, [:follower_id, :followed_id])
|> validate_required([:follower_id, :followed_id])
|> validate_not_self_follow()
|> put_inserted_at()
|> foreign_key_constraint(:follower_id)
|> foreign_key_constraint(:followed_id)
|> unique_constraint([:follower_id, :followed_id],
name: :phoenix_kit_user_follows_unique_idx,
message: "already following this user"
)
end
defp validate_not_self_follow(changeset) do
follower_id = get_field(changeset, :follower_id)
followed_id = get_field(changeset, :followed_id)
if follower_id && followed_id && follower_id == followed_id do
add_error(changeset, :followed_id, "cannot follow yourself")
else
changeset
end
end
defp put_inserted_at(changeset) do
if get_field(changeset, :inserted_at) do
changeset
else
put_change(
changeset,
:inserted_at,
NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
)
end
end
end