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
10 changes: 7 additions & 3 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ config :ueberauth, Ueberauth, providers: %{}
# Configure Oban (if using job processing)
config :phoenix_kit, Oban,
repo: PhoenixKit.Repo,
queues: [default: 10, emails: 50, file_processing: 20, posts: 10],
queues: [default: 10, emails: 50, file_processing: 20, posts: 10, scheduled_jobs: 1],
plugins: [
# Keep completed/cancelled/discarded jobs for 30 days for dashboard visibility
{Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 30},
# Main pruner: 30 days for most queues
{Oban.Plugins.Pruner,
max_age: 60 * 60 * 24 * 30,
queue: [:default, :emails, :file_processing, :posts, :sitemap, :sqs_polling, :sync]},
# Dedicated pruner: 1 day only for scheduled_jobs (cron runs every minute)
{Oban.Plugins.Pruner, max_age: 60 * 60 * 24, queue: [:scheduled_jobs]},
{Oban.Plugins.Cron,
crontab: [
{"* * * * *", PhoenixKit.ScheduledJobs.Workers.ProcessScheduledJobsWorker},
Expand Down
6 changes: 3 additions & 3 deletions lib/phoenix_kit/install/oauth_config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule PhoenixKit.Install.OAuthConfig do
```

This approach allows:
- **Minimal compile-time configuration** - Only `config :ueberauth, Ueberauth, providers: []`
- **Minimal compile-time configuration** - Only `config :ueberauth, Ueberauth, providers: %{}`
- **Database-driven credentials** - Credentials loaded from Settings table at runtime
- **Dynamic provider management** - Add/remove/modify providers without app restart

Expand Down Expand Up @@ -70,7 +70,7 @@ defmodule PhoenixKit.Install.OAuthConfig do

# Configure Ueberauth (minimal configuration for compilation)
# OAuth providers are configured dynamically at runtime from database
config :ueberauth, Ueberauth, providers: []
config :ueberauth, Ueberauth, providers: %{}
"""

try do
Expand Down Expand Up @@ -184,7 +184,7 @@ defmodule PhoenixKit.Install.OAuthConfig do

Please add the following to config/config.exs:

config :ueberauth, Ueberauth, providers: []
config :ueberauth, Ueberauth, providers: %{}

This minimal configuration is required for compilation.
OAuth providers are configured dynamically at runtime from the database.
Expand Down
12 changes: 10 additions & 2 deletions lib/phoenix_kit/install/oban_config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,16 @@ defmodule PhoenixKit.Install.ObanConfig do
emails: 50, # Email processing
file_processing: 20, # File variant generation (storage system)
posts: 10, # Posts scheduled publishing
scheduled_jobs: 1, # Scheduled jobs cron (1-day retention)
sitemap: 5, # Sitemap generation
sqs_polling: 1, # SQS polling for email events (only one concurrent job)
sync: 5 # Sync data import
],
plugins: [
{Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 30}, # Keep jobs for 30 days
# Main pruner: 30 days for most queues
{Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 30, queue: [:default, :emails, :file_processing, :posts, :sitemap, :sqs_polling, :sync]},
# Dedicated pruner: 1 day only for scheduled_jobs (cron runs every minute)
{Oban.Plugins.Pruner, max_age: 60 * 60 * 24, queue: [:scheduled_jobs]},
{Oban.Plugins.Cron,
crontab: [
{"* * * * *", PhoenixKit.ScheduledJobs.Workers.ProcessScheduledJobsWorker}
Expand Down Expand Up @@ -767,12 +771,16 @@ defmodule PhoenixKit.Install.ObanConfig do
emails: 50,
file_processing: 20,
posts: 10,
scheduled_jobs: 1, # Scheduled jobs cron (1-day retention)
sitemap: 5,
sqs_polling: 1,
sync: 5
],
plugins: [
{Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 30}, # Keep jobs for 30 days
# Main pruner: 30 days for most queues
{Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 30, queue: [:default, :emails, :file_processing, :posts, :sitemap, :sqs_polling, :sync]},
# Dedicated pruner: 1 day only for scheduled_jobs (cron runs every minute)
{Oban.Plugins.Pruner, max_age: 60 * 60 * 24, queue: [:scheduled_jobs]},
{Oban.Plugins.Cron,
crontab: [
{"* * * * *", PhoenixKit.ScheduledJobs.Workers.ProcessScheduledJobsWorker}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ defmodule PhoenixKit.ScheduledJobs.Workers.ProcessScheduledJobsWorker do
- Worker itself always returns :ok to prevent Oban retries
"""

use Oban.Worker, queue: :default, max_attempts: 1
use Oban.Worker, queue: :scheduled_jobs, max_attempts: 1

require Logger

Expand Down
160 changes: 160 additions & 0 deletions lib/phoenix_kit/settings/queries.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
defmodule PhoenixKit.Settings.Queries do
@moduledoc """
Ecto queries for Settings context.

This module encapsulates all database queries for settings management,
providing a centralized location for query logic.
"""

import Ecto.Query

alias PhoenixKit.RepoHelper
alias PhoenixKit.Settings.Setting

# Single record queries

@doc """
Gets a setting record by key.

## Examples

iex> PhoenixKit.Settings.Queries.get_setting_by_key("time_zone")
%Setting{key: "time_zone", value: "0"}

iex> PhoenixKit.Settings.Queries.get_setting_by_key("non_existent")
nil
"""
def get_setting_by_key(key) when is_binary(key) do
repo().get_by(Setting, key: key)
end

# Multiple records queries

@doc """
Lists all settings ordered by key.

## Examples

iex> PhoenixKit.Settings.Queries.list_settings()
[%Setting{key: "date_format", value: "Y-m-d"}, %Setting{key: "time_zone", value: "0"}, ...]
"""
def list_settings do
Setting
|> order_by([s], s.key)
|> repo().all()
end

@doc """
Gets all settings as a list of {key, value} tuples.

## Examples

iex> PhoenixKit.Settings.Queries.list_settings_key_values()
[{"time_zone", "0"}, {"date_format", "Y-m-d"}]
"""
def list_settings_key_values do
Setting
|> select([s], {s.key, s.value})
|> repo().all()
end

@doc """
Lists settings for specific keys as a list of {key, value} tuples.

## Examples

iex> PhoenixKit.Settings.Queries.list_settings_key_values_by_keys(["time_zone", "date_format"])
[{"time_zone", "0"}, {"date_format", "Y-m-d"}]
"""
def list_settings_key_values_by_keys(keys) when is_list(keys) do
Setting
|> where([s], s.key in ^keys)
|> select([s], {s.key, s.value})
|> repo().all()
end

@doc """
Lists setting records for specific keys.

## Examples

iex> PhoenixKit.Settings.Queries.list_settings_by_keys(["time_zone"])
[%Setting{key: "time_zone", value: "0"}]
"""
def list_settings_by_keys(keys) when is_list(keys) do
Setting
|> where([s], s.key in ^keys)
|> repo().all()
end

@doc """
Lists settings by keys with JSON priority as a list of {key, value} tuples.

Returns a list where value_json is used if present, otherwise falls back to
the string value.

## Examples

iex> PhoenixKit.Settings.Queries.list_settings_with_json_priority_by_keys(["theme"])
[{"theme", %{"primary" => "#3b82f6"}}]
"""
def list_settings_with_json_priority_by_keys(keys) when is_list(keys) do
Setting
|> where([s], s.key in ^keys)
|> repo().all()
|> Enum.map(fn setting ->
value = if setting.value_json, do: setting.value_json, else: setting.value
{setting.key, value}
end)
end

# Write operations

@doc """
Inserts a new setting.

## Examples

iex> %Setting{} |> Setting.changeset(%{key: "theme", value: "dark"})
...> |> PhoenixKit.Settings.Queries.insert_setting()
{:ok, %Setting{}}
"""
def insert_setting(changeset) do
repo().insert(changeset)
end

@doc """
Updates an existing setting.

## Examples

iex> setting |> Setting.update_changeset(%{value: "light"})
...> |> PhoenixKit.Settings.Queries.update_setting()
{:ok, %Setting{}}
"""
def update_setting(changeset) do
repo().update(changeset)
end

# Transaction

@doc """
Executes a transaction with multiple operations.

## Examples

iex> Ecto.Multi.new()
...> |> multi_operation()
...> |> PhoenixKit.Settings.Queries.transaction()
{:ok, result}
"""
def transaction(multi) do
repo().transaction(multi)
end

# Private functions

defp repo do
RepoHelper.repo()
end
end
Loading