Packages
phoenix_kit
1.7.49
1.7.209
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
Current section
Files
lib/modules/publishing/schemas/publishing_group.ex
defmodule PhoenixKit.Modules.Publishing.PublishingGroup do
@moduledoc """
Schema for publishing groups (blog, faq, legal, etc.).
Each group contains posts and defines the content mode (timestamp or slug).
Extensible settings are stored in the `data` JSONB column.
## Data JSONB Keys
- `type` - Group type: "blogging", "faq", "legal", or custom string
- `item_singular` - Display name for single item (e.g., "Post", "Article")
- `item_plural` - Display name for multiple items (e.g., "Posts", "Articles")
- `description` - Group description
- `icon` - Heroicon name for admin UI
- `settings` - Group-specific settings map
- `comments_enabled` - Whether comments are enabled for this group
- `likes_enabled` - Whether likes are enabled for this group
- `views_enabled` - Whether view tracking is enabled for this group
"""
use Ecto.Schema
import Ecto.Changeset
@primary_key {:uuid, UUIDv7, autogenerate: true}
@foreign_key_type UUIDv7
@type t :: %__MODULE__{
uuid: UUIDv7.t() | nil,
name: String.t(),
slug: String.t(),
mode: String.t(),
position: integer(),
data: map(),
inserted_at: DateTime.t() | nil,
updated_at: DateTime.t() | nil
}
schema "phoenix_kit_publishing_groups" do
field :name, :string
field :slug, :string
field :mode, :string, default: "timestamp"
field :position, :integer, default: 0
field :data, :map, default: %{}
has_many :posts, PhoenixKit.Modules.Publishing.PublishingPost, foreign_key: :group_uuid
timestamps(type: :utc_datetime)
end
@doc """
Changeset for creating or updating a publishing group.
"""
def changeset(group, attrs) do
group
|> cast(attrs, [:name, :slug, :mode, :position, :data])
|> validate_required([:name, :slug, :mode])
|> validate_inclusion(:mode, ["timestamp", "slug"])
|> validate_length(:name, max: 255)
|> validate_length(:slug, max: 255)
|> unique_constraint(:slug, name: :idx_publishing_groups_slug)
|> maybe_generate_slug()
end
# Data JSONB accessors
@doc "Returns the group type from data (blogging/faq/legal/custom)."
def get_type(%__MODULE__{data: data}), do: Map.get(data, "type", "blogging")
@doc "Returns the singular item name (e.g., 'Post')."
def get_item_singular(%__MODULE__{data: data}), do: Map.get(data, "item_singular", "Post")
@doc "Returns the plural item name (e.g., 'Posts')."
def get_item_plural(%__MODULE__{data: data}), do: Map.get(data, "item_plural", "Posts")
@doc "Returns the group description."
def get_description(%__MODULE__{data: data}), do: Map.get(data, "description")
@doc "Returns the group icon name."
def get_icon(%__MODULE__{data: data}), do: Map.get(data, "icon")
@doc "Returns whether comments are enabled for this group."
def comments_enabled?(%__MODULE__{data: data}), do: Map.get(data, "comments_enabled", false)
@doc "Returns whether likes are enabled for this group."
def likes_enabled?(%__MODULE__{data: data}), do: Map.get(data, "likes_enabled", false)
@doc "Returns whether view tracking is enabled for this group."
def views_enabled?(%__MODULE__{data: data}), do: Map.get(data, "views_enabled", false)
defp maybe_generate_slug(changeset) do
case get_change(changeset, :slug) do
nil ->
name = get_field(changeset, :name)
if name do
slug =
name
|> String.downcase()
|> String.replace(~r/[^\w\s-]/, "")
|> String.replace(~r/\s+/, "-")
|> String.trim("-")
put_change(changeset, :slug, slug)
else
changeset
end
_slug ->
changeset
end
end
end