mirror of
https://github.com/ash-project/ash_hq.git
synced 2024-09-19 12:53:49 +12:00
improvement: initial discord bot support, indexing messages:wq
This commit is contained in:
parent
406d13ddb2
commit
fc6573bfdd
36 changed files with 1851 additions and 51 deletions
|
@ -12,7 +12,8 @@ config :ash_hq,
|
|||
|
||||
config :ash, allow_flow: true
|
||||
|
||||
config :ash_hq, ash_apis: [AshHq.Blog, AshHq.Docs, AshHq.Accounts, AshHq.MailingList]
|
||||
config :ash_hq,
|
||||
ash_apis: [AshHq.Blog, AshHq.Docs, AshHq.Accounts, AshHq.MailingList, AshHq.Discord]
|
||||
|
||||
config :ash_hq, AshHq.Repo,
|
||||
timeout: :timer.minutes(10),
|
||||
|
|
|
@ -26,6 +26,9 @@ if config_env() != :dev do
|
|||
config :logger, level: String.to_existing_atom(System.get_env("LOG_LEVEL") || "info")
|
||||
end
|
||||
|
||||
config :nostrum,
|
||||
token: System.get_env("DISCORD_BOT_TOKEN")
|
||||
|
||||
if config_env() == :prod do
|
||||
database_url =
|
||||
System.get_env("DATABASE_URL") ||
|
||||
|
|
2
fly.toml
2
fly.toml
|
@ -7,7 +7,7 @@ kill_timeout = 5
|
|||
processes = []
|
||||
|
||||
[deploy]
|
||||
release_command = "_build/prod/rel/ash_hq/bin/ash_hq eval 'AshHq.Release.migrate'"
|
||||
# release_command = "_build/prod/rel/ash_hq/bin/ash_hq eval 'AshHq.Release.migrate'"
|
||||
|
||||
[env]
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ defmodule AshHq.Application do
|
|||
{Phoenix.PubSub, name: AshHq.PubSub},
|
||||
# Start the Endpoint (http/https)
|
||||
AshHqWeb.Endpoint,
|
||||
{AshHq.Docs.Library.Agent, nil}
|
||||
{AshHq.Docs.Library.Agent, nil},
|
||||
AshHq.Discord.Supervisor
|
||||
|
||||
# Start a worker by calling: AshHq.Worker.start_link(arg)
|
||||
# {AshHq.Worker, arg}
|
||||
|
|
7
lib/ash_hq/discord/discord.ex
Normal file
7
lib/ash_hq/discord/discord.ex
Normal file
|
@ -0,0 +1,7 @@
|
|||
defmodule AshHq.Discord do
|
||||
use Ash.Api
|
||||
|
||||
resources do
|
||||
registry AshHq.Discord.Registry
|
||||
end
|
||||
end
|
20
lib/ash_hq/discord/listener.ex
Normal file
20
lib/ash_hq/discord/listener.ex
Normal file
|
@ -0,0 +1,20 @@
|
|||
defmodule AshHq.Discord.Listener do
|
||||
use Nostrum.Consumer
|
||||
|
||||
# alias Nostrum.Api
|
||||
|
||||
def start_link do
|
||||
Consumer.start_link(__MODULE__)
|
||||
end
|
||||
|
||||
# Lets set up slash commands later
|
||||
# def handle_event({:MESSAGE_CREATE, msg, _ws_state}) do
|
||||
# IO.inspect(msg)
|
||||
# end
|
||||
|
||||
# Default event handler, if you don't include this, your consumer WILL crash if
|
||||
# you don't have a method definition for each event type.
|
||||
def handle_event(_event) do
|
||||
:noop
|
||||
end
|
||||
end
|
166
lib/ash_hq/discord/poller.ex
Normal file
166
lib/ash_hq/discord/poller.ex
Normal file
|
@ -0,0 +1,166 @@
|
|||
defmodule AshHq.Discord.Poller do
|
||||
use GenServer
|
||||
|
||||
@poll_interval :timer.hours(2)
|
||||
@server_id 711_271_361_523_351_632
|
||||
@archived_thread_lookback 20
|
||||
|
||||
@channels [
|
||||
1_066_222_835_758_014_606,
|
||||
1_066_223_107_922_210_867,
|
||||
1_019_647_368_196_534_283
|
||||
]
|
||||
|
||||
def server_id, do: @server_id
|
||||
|
||||
defmacrop unwrap(value) do
|
||||
quote do
|
||||
case unquote(value) do
|
||||
{:ok, value} ->
|
||||
value
|
||||
|
||||
{:error, error} ->
|
||||
raise Exception.format(:error, error, [])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def start_link(state) do
|
||||
GenServer.start_link(__MODULE__, state, name: __MODULE__)
|
||||
end
|
||||
|
||||
def init(_) do
|
||||
Process.send_after(self(), :poll, @poll_interval)
|
||||
{:ok, nil}
|
||||
end
|
||||
|
||||
def handle_info(:poll, state) do
|
||||
poll()
|
||||
Process.send_after(self(), :poll, @poll_interval)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def poll() do
|
||||
for {channel, index} <- Enum.with_index(@channels) do
|
||||
channel
|
||||
|> Nostrum.Api.get_channel!()
|
||||
|> tap(fn channel ->
|
||||
channel
|
||||
|> Map.from_struct()
|
||||
|> Map.put(:order, index)
|
||||
|> AshHq.Discord.Channel.upsert!()
|
||||
end)
|
||||
|> Map.get(:available_tags)
|
||||
|> Enum.each(fn available_tag ->
|
||||
AshHq.Discord.Tag.upsert!(channel, available_tag.id, available_tag.name)
|
||||
end)
|
||||
end
|
||||
|
||||
active =
|
||||
@server_id
|
||||
|> Nostrum.Api.list_guild_threads()
|
||||
|> unwrap()
|
||||
|> Map.get(:threads)
|
||||
|> Stream.filter(fn thread ->
|
||||
thread.parent_id in @channels
|
||||
end)
|
||||
|> Stream.map(fn thread ->
|
||||
%{
|
||||
thread: thread,
|
||||
messages: get_all_channel_messages(thread.id)
|
||||
}
|
||||
end)
|
||||
|
||||
archived =
|
||||
@channels
|
||||
|> Stream.flat_map(fn channel ->
|
||||
channel
|
||||
|> Nostrum.Api.list_public_archived_threads(limit: @archived_thread_lookback)
|
||||
|> unwrap()
|
||||
|> Map.get(:threads)
|
||||
|> Enum.map(fn thread ->
|
||||
messages =
|
||||
thread.id
|
||||
|> get_all_channel_messages()
|
||||
|
||||
%{
|
||||
thread: thread,
|
||||
messages: messages
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|
||||
active
|
||||
|> Stream.concat(archived)
|
||||
|> Enum.reject(fn
|
||||
%{messages: []} ->
|
||||
true
|
||||
|
||||
_ ->
|
||||
false
|
||||
end)
|
||||
|> Enum.map(fn %{thread: thread, messages: messages} ->
|
||||
thread
|
||||
|> Map.put(:author, Enum.at(messages, 0).author)
|
||||
|> Map.from_struct()
|
||||
|> Map.put(:channel_id, thread.parent_id)
|
||||
|> Map.put(:tags, thread.applied_tags)
|
||||
|> Map.put(:create_timestamp, thread.thread_metadata.create_timestamp)
|
||||
|> Map.put(:messages, Enum.map(messages, &Map.from_struct/1))
|
||||
|> AshHq.Discord.Thread.upsert!()
|
||||
end)
|
||||
end
|
||||
|
||||
defp get_all_channel_messages(thread) do
|
||||
Stream.resource(
|
||||
fn ->
|
||||
:all
|
||||
end,
|
||||
fn
|
||||
nil ->
|
||||
{:halt, nil}
|
||||
|
||||
before ->
|
||||
locator =
|
||||
case before do
|
||||
:all ->
|
||||
nil
|
||||
|
||||
before ->
|
||||
{:before, before}
|
||||
end
|
||||
|
||||
messages =
|
||||
if locator do
|
||||
Nostrum.Api.get_channel_messages!(thread, 100, locator)
|
||||
else
|
||||
Nostrum.Api.get_channel_messages!(thread, 100)
|
||||
end
|
||||
|
||||
if Enum.count(messages) == 100 do
|
||||
{messages, List.last(messages).id}
|
||||
else
|
||||
{messages, nil}
|
||||
end
|
||||
end,
|
||||
& &1
|
||||
)
|
||||
|> Stream.map(fn message ->
|
||||
message
|
||||
|> Map.put(:author, message.author.username)
|
||||
|> Map.update!(:reactions, fn reactions ->
|
||||
reactions
|
||||
|> Kernel.||([])
|
||||
# just don't know what this looks like, so removing them
|
||||
|> Enum.reject(&(is_nil(&1.emoji) || &1.emoji == "" || &1.emoji.animated))
|
||||
|> Enum.map(fn %{count: count, emoji: emoji} ->
|
||||
%{emoji: emoji.name, count: count}
|
||||
end)
|
||||
end)
|
||||
|> Map.update!(:attachments, fn attachments ->
|
||||
Enum.map(attachments, &Map.from_struct/1)
|
||||
end)
|
||||
end)
|
||||
|> Enum.to_list()
|
||||
end
|
||||
end
|
14
lib/ash_hq/discord/registry.ex
Normal file
14
lib/ash_hq/discord/registry.ex
Normal file
|
@ -0,0 +1,14 @@
|
|||
defmodule AshHq.Discord.Registry do
|
||||
use Ash.Registry,
|
||||
extensions: [Ash.Registry.ResourceValidations]
|
||||
|
||||
entries do
|
||||
entry AshHq.Discord.Attachment
|
||||
entry AshHq.Discord.Channel
|
||||
entry AshHq.Discord.Message
|
||||
entry AshHq.Discord.Reaction
|
||||
entry AshHq.Discord.Tag
|
||||
entry AshHq.Discord.Thread
|
||||
entry AshHq.Discord.ThreadTag
|
||||
end
|
||||
end
|
30
lib/ash_hq/discord/resources/attachment.ex
Normal file
30
lib/ash_hq/discord/resources/attachment.ex
Normal file
|
@ -0,0 +1,30 @@
|
|||
defmodule AshHq.Discord.Attachment do
|
||||
use Ash.Resource,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
postgres do
|
||||
table "discord_attachments"
|
||||
repo AshHq.Repo
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
end
|
||||
|
||||
attributes do
|
||||
integer_primary_key :id, generated?: false, writable?: true
|
||||
attribute :filename, :string
|
||||
attribute :size, :integer
|
||||
attribute :url, :string
|
||||
attribute :proxy_url, :string
|
||||
attribute :height, :integer
|
||||
attribute :width, :integer
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :message, AshHq.Discord.Message do
|
||||
allow_nil? false
|
||||
attribute_type :integer
|
||||
end
|
||||
end
|
||||
end
|
39
lib/ash_hq/discord/resources/channel.ex
Normal file
39
lib/ash_hq/discord/resources/channel.ex
Normal file
|
@ -0,0 +1,39 @@
|
|||
defmodule AshHq.Discord.Channel do
|
||||
use Ash.Resource,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
postgres do
|
||||
table "discord_channels"
|
||||
repo AshHq.Repo
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
create :upsert do
|
||||
upsert? true
|
||||
end
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Discord
|
||||
define :read
|
||||
define :upsert
|
||||
end
|
||||
|
||||
attributes do
|
||||
integer_primary_key :id, writable?: true, generated?: false
|
||||
|
||||
attribute :name, :string do
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :order, :integer do
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
has_many :threads, AshHq.Discord.Thread
|
||||
end
|
||||
end
|
67
lib/ash_hq/discord/resources/message.ex
Normal file
67
lib/ash_hq/discord/resources/message.ex
Normal file
|
@ -0,0 +1,67 @@
|
|||
defmodule AshHq.Discord.Message do
|
||||
use Ash.Resource,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshHq.Docs.Extensions.RenderMarkdown]
|
||||
|
||||
postgres do
|
||||
table "discord_messages"
|
||||
repo AshHq.Repo
|
||||
end
|
||||
|
||||
render_markdown do
|
||||
render_attributes content: :content_html
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:read, :destroy]
|
||||
|
||||
create :create do
|
||||
primary? true
|
||||
argument :attachments, {:array, :map}
|
||||
argument :reactions, {:array, :map}
|
||||
change manage_relationship(:attachments, type: :direct_control)
|
||||
|
||||
change manage_relationship(:reactions,
|
||||
type: :direct_control,
|
||||
use_identities: [:unique_message_emoji]
|
||||
)
|
||||
end
|
||||
|
||||
update :update do
|
||||
primary? true
|
||||
argument :attachments, {:array, :map}
|
||||
argument :reactions, {:array, :map}
|
||||
change manage_relationship(:attachments, type: :direct_control)
|
||||
|
||||
change manage_relationship(:reactions,
|
||||
type: :direct_control,
|
||||
use_identities: [:unique_message_emoji]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
attributes do
|
||||
integer_primary_key :id, generated?: false, writable?: true
|
||||
|
||||
attribute :author, :string do
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :content, :string
|
||||
attribute :content_html, :string
|
||||
|
||||
attribute :timestamp, :utc_datetime do
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :thread, AshHq.Discord.Thread do
|
||||
attribute_type :integer
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
has_many :attachments, AshHq.Discord.Attachment
|
||||
has_many :reactions, AshHq.Discord.Reaction
|
||||
end
|
||||
end
|
36
lib/ash_hq/discord/resources/reaction.ex
Normal file
36
lib/ash_hq/discord/resources/reaction.ex
Normal file
|
@ -0,0 +1,36 @@
|
|||
defmodule AshHq.Discord.Reaction do
|
||||
use Ash.Resource,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
postgres do
|
||||
table "discord_reactions"
|
||||
repo AshHq.Repo
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
end
|
||||
|
||||
attributes do
|
||||
uuid_primary_key :id
|
||||
|
||||
attribute :count, :integer do
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :emoji, :string do
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
identities do
|
||||
identity :unique_message_emoji, [:emoji, :message_id]
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :message, AshHq.Discord.Message do
|
||||
attribute_type :integer
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
end
|
45
lib/ash_hq/discord/resources/tag.ex
Normal file
45
lib/ash_hq/discord/resources/tag.ex
Normal file
|
@ -0,0 +1,45 @@
|
|||
defmodule AshHq.Discord.Tag do
|
||||
@moduledoc "A tag that can be applied to a post. Currently uses CSV data layer and therefore is static"
|
||||
use Ash.Resource,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
postgres do
|
||||
table "discord_tags"
|
||||
repo AshHq.Repo
|
||||
end
|
||||
|
||||
attributes do
|
||||
integer_primary_key :id, generated?: false, writable?: true
|
||||
|
||||
attribute :name, :ci_string do
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
create :upsert do
|
||||
upsert? true
|
||||
upsert_identity :unique_name_per_channel
|
||||
end
|
||||
end
|
||||
|
||||
identities do
|
||||
identity :unique_name_per_channel, [:name, :channel_id]
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Discord
|
||||
define :upsert, args: [:channel_id, :id, :name]
|
||||
define :read
|
||||
define :destroy
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :channel, AshHq.Discord.Channel do
|
||||
attribute_type :integer
|
||||
attribute_writable? true
|
||||
end
|
||||
end
|
||||
end
|
105
lib/ash_hq/discord/resources/thread.ex
Normal file
105
lib/ash_hq/discord/resources/thread.ex
Normal file
|
@ -0,0 +1,105 @@
|
|||
defmodule AshHq.Discord.Thread do
|
||||
use Ash.Resource,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
postgres do
|
||||
table "discord_threads"
|
||||
repo AshHq.Repo
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
read :feed do
|
||||
pagination do
|
||||
countable true
|
||||
offset? true
|
||||
default_limit 25
|
||||
end
|
||||
|
||||
argument :channel, :integer do
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
argument :tag_name, :string
|
||||
|
||||
prepare build(sort: [create_timestamp: :desc])
|
||||
|
||||
filter expr(
|
||||
channel_id == ^arg(:channel) and
|
||||
(is_nil(^arg(:tag_name)) or tags.name == ^arg(:tag_name))
|
||||
)
|
||||
end
|
||||
|
||||
create :upsert do
|
||||
upsert? true
|
||||
argument :messages, {:array, :map}
|
||||
argument :tags, {:array, :integer}
|
||||
|
||||
change manage_relationship(:messages, type: :direct_control)
|
||||
|
||||
change fn changeset, _ ->
|
||||
Ash.Changeset.after_action(changeset, fn changeset, thread ->
|
||||
tags = Ash.Changeset.get_argument(changeset, :tags) || []
|
||||
|
||||
# Not optimized in `manage_relationship`
|
||||
# bulk actions should make this unnecessary
|
||||
to_delete =
|
||||
from thread_tag in AshHq.Discord.ThreadTag,
|
||||
where: thread_tag.thread_id == ^thread.id,
|
||||
where: thread_tag.tag_id not in ^tags
|
||||
|
||||
AshHq.Repo.delete_all(to_delete)
|
||||
|
||||
Enum.map(tags, fn tag ->
|
||||
AshHq.Discord.ThreadTag.tag!(thread.id, tag) |> IO.inspect()
|
||||
end)
|
||||
|
||||
{:ok, thread}
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Discord
|
||||
define :upsert
|
||||
define :by_id, action: :read, get_by: [:id]
|
||||
define :feed, args: [:channel]
|
||||
end
|
||||
|
||||
attributes do
|
||||
integer_primary_key :id, generated?: false, writable?: true
|
||||
attribute :type, :integer
|
||||
|
||||
attribute :name, :string do
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :author, :string do
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :create_timestamp, :utc_datetime do
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
has_many :messages, AshHq.Discord.Message
|
||||
|
||||
belongs_to :channel, AshHq.Discord.Channel do
|
||||
attribute_type :integer
|
||||
allow_nil? false
|
||||
attribute_writable? true
|
||||
end
|
||||
|
||||
many_to_many :tags, AshHq.Discord.Tag do
|
||||
through AshHq.Discord.ThreadTag
|
||||
source_attribute_on_join_resource :thread_id
|
||||
destination_attribute_on_join_resource :tag_id
|
||||
end
|
||||
end
|
||||
end
|
38
lib/ash_hq/discord/resources/thread_tag.ex
Normal file
38
lib/ash_hq/discord/resources/thread_tag.ex
Normal file
|
@ -0,0 +1,38 @@
|
|||
defmodule AshHq.Discord.ThreadTag do
|
||||
use Ash.Resource,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
postgres do
|
||||
table "discord_thread_tags"
|
||||
repo AshHq.Repo
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:read, :destroy]
|
||||
|
||||
create :tag do
|
||||
upsert? true
|
||||
end
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Discord
|
||||
define :tag, args: [:thread_id, :tag_id]
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :thread, AshHq.Discord.Thread do
|
||||
primary_key? true
|
||||
allow_nil? false
|
||||
attribute_writable? true
|
||||
attribute_type :integer
|
||||
end
|
||||
|
||||
belongs_to :tag, AshHq.Discord.Tag do
|
||||
primary_key? true
|
||||
allow_nil? false
|
||||
attribute_writable? true
|
||||
attribute_type :integer
|
||||
end
|
||||
end
|
||||
end
|
14
lib/ash_hq/discord/supervisor.ex
Normal file
14
lib/ash_hq/discord/supervisor.ex
Normal file
|
@ -0,0 +1,14 @@
|
|||
defmodule AshHq.Discord.Supervisor do
|
||||
use Supervisor
|
||||
|
||||
def start_link(args) do
|
||||
Supervisor.start_link(__MODULE__, args, name: __MODULE__)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_init_arg) do
|
||||
children = [AshHq.Discord.Listener]
|
||||
|
||||
Supervisor.init(children, strategy: :one_for_one)
|
||||
end
|
||||
end
|
|
@ -75,6 +75,10 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown do
|
|||
end
|
||||
end
|
||||
|
||||
def as_html(nil, _, _, _, _) do
|
||||
{:ok, nil, []}
|
||||
end
|
||||
|
||||
def as_html(text, libraries, current_library, current_module, add_ids?) do
|
||||
text
|
||||
|> Earmark.as_html(opts(add_ids?))
|
||||
|
|
|
@ -53,6 +53,13 @@ defmodule AshHqWeb.Components.AppView.TopBar do
|
|||
>
|
||||
Blog
|
||||
</a>
|
||||
<a
|
||||
href="/forum/showcase"
|
||||
title="Forum"
|
||||
class="text-lg font-bold px-2 md:px-4 dark:hover:text-primary-light-500 hover:text-primary-light-700"
|
||||
>
|
||||
Forum
|
||||
</a>
|
||||
<a
|
||||
href="/media"
|
||||
title="Media"
|
||||
|
|
|
@ -5,12 +5,13 @@ defmodule AshHqWeb.Components.Blog.Tag do
|
|||
alias Surface.Components.LivePatch
|
||||
|
||||
prop tag, :string, required: true
|
||||
prop prefix, :string
|
||||
|
||||
def render(assigns) do
|
||||
~F"""
|
||||
<LivePatch
|
||||
to={"/blog?tag=#{@tag}"}
|
||||
class="dark:bg-gray-700 bg-gray-300 rounded-lg px-2 text-lg max-w-min"
|
||||
to={"#{@prefix}?tag=#{@tag}"}
|
||||
class="dark:bg-gray-700 bg-gray-300 rounded-lg px-2 text-lg max-w-min whitespace-nowrap"
|
||||
>
|
||||
{@tag}
|
||||
</LivePatch>
|
||||
|
|
37
lib/ash_hq_web/components/forum/attachment.ex
Normal file
37
lib/ash_hq_web/components/forum/attachment.ex
Normal file
|
@ -0,0 +1,37 @@
|
|||
defmodule AshHqWeb.Components.Forum.Attachment do
|
||||
use Surface.Component
|
||||
|
||||
prop attachment, :any, required: true
|
||||
|
||||
def render(assigns) do
|
||||
~F"""
|
||||
<div>
|
||||
{#case video_type(@attachment.filename)}
|
||||
{#match {:video, mime}}
|
||||
<video controls width={@attachment.width} height={@attachment.height}>
|
||||
<source src={@attachment.url} type={mime}>
|
||||
</video>
|
||||
{#match :image}
|
||||
image
|
||||
{#match _}
|
||||
other
|
||||
{/case}
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp video_type(path) do
|
||||
mime = MIME.from_path(path)
|
||||
|
||||
case mime do
|
||||
"image/" <> _ ->
|
||||
{:image, mime}
|
||||
|
||||
"video/" <> _ ->
|
||||
{:video, mime}
|
||||
|
||||
_ ->
|
||||
{:other, mime}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -29,7 +29,7 @@ defmodule AshHqWeb.Pages.Blog do
|
|||
<h1 class="mt-6 text-3xl font-semibold mb-4">{@post.title}</h1>
|
||||
<div class="flex flex-row space-x-2 mb-4">
|
||||
{#for tag <- @post.tag_names}
|
||||
<Tag tag={tag} />
|
||||
<Tag prefix="/blog" tag={tag} />
|
||||
{/for}
|
||||
</div>
|
||||
<div class="flex flex-row items-center align-middle justify-between">
|
||||
|
@ -70,7 +70,7 @@ defmodule AshHqWeb.Pages.Blog do
|
|||
</div>
|
||||
<div class="flex space-x-2">
|
||||
{#for tag <- post.tag_names}
|
||||
<Tag tag={tag} />
|
||||
<Tag prefix="/blog" tag={tag} />
|
||||
{/for}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -96,7 +96,7 @@ defmodule AshHqWeb.Pages.Blog do
|
|||
<h3 class="text-lg font-bold mb-1">All Tags:</h3>
|
||||
<div class="flex gap-2 flex-wrap w-full">
|
||||
{#for tag <- @tags}
|
||||
<Tag tag={to_string(tag.name)} />
|
||||
<Tag prefix="/blog" tag={to_string(tag.name)} />
|
||||
{/for}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,29 +12,29 @@ defmodule AshHqWeb.Pages.Docs do
|
|||
require Logger
|
||||
require Ash.Query
|
||||
|
||||
prop(change_versions, :event, required: true)
|
||||
prop(selected_versions, :map, required: true)
|
||||
prop(libraries, :list, default: [])
|
||||
prop(uri, :string)
|
||||
prop(remove_version, :event)
|
||||
prop(add_version, :event)
|
||||
prop(change_version, :event)
|
||||
prop(params, :map, required: true)
|
||||
prop change_versions, :event, required: true
|
||||
prop selected_versions, :map, required: true
|
||||
prop libraries, :list, default: []
|
||||
prop uri, :string
|
||||
prop remove_version, :event
|
||||
prop add_version, :event
|
||||
prop change_version, :event
|
||||
prop params, :map, required: true
|
||||
|
||||
data(library, :any)
|
||||
data(extension, :any)
|
||||
data(docs, :any)
|
||||
data(library_version, :any)
|
||||
data(guide, :any)
|
||||
data(doc_path, :list, default: [])
|
||||
data(dsls, :list, default: [])
|
||||
data(dsl, :any)
|
||||
data(options, :list, default: [])
|
||||
data(module, :any)
|
||||
data(mix_task, :any)
|
||||
data(positional_options, :list)
|
||||
data(description, :string)
|
||||
data(title, :string)
|
||||
data library, :any
|
||||
data extension, :any
|
||||
data docs, :any
|
||||
data library_version, :any
|
||||
data guide, :any
|
||||
data doc_path, :list, default: []
|
||||
data dsls, :list, default: []
|
||||
data dsl, :any
|
||||
data options, :list, default: []
|
||||
data module, :any
|
||||
data mix_task, :any
|
||||
data positional_options, :list
|
||||
data description, :string
|
||||
data title, :string
|
||||
|
||||
@spec render(any) :: Phoenix.LiveView.Rendered.t()
|
||||
def render(assigns) do
|
||||
|
|
344
lib/ash_hq_web/pages/forum.ex
Normal file
344
lib/ash_hq_web/pages/forum.ex
Normal file
|
@ -0,0 +1,344 @@
|
|||
defmodule AshHqWeb.Pages.Forum do
|
||||
@moduledoc "Forum page"
|
||||
use Surface.LiveComponent
|
||||
|
||||
require Ash.Query
|
||||
|
||||
alias AshHqWeb.Components.Blog.Tag
|
||||
alias AshHqWeb.Components.Forum.Attachment
|
||||
alias Surface.Components.LivePatch
|
||||
|
||||
import AshHqWeb.Tails
|
||||
|
||||
prop params, :map, default: %{}
|
||||
|
||||
data thread, :any, default: nil
|
||||
data threads, :any, default: []
|
||||
data tag, :string, default: nil
|
||||
data tags, :any, default: []
|
||||
data channels, :any, default: []
|
||||
data channel, :any, default: []
|
||||
|
||||
def render(assigns) do
|
||||
~F"""
|
||||
<div class="container md:mx-auto">
|
||||
<div class="flex flex-col md:flex-row md:pt-32 md:mx-32 min-h-screen">
|
||||
<div class="w-full">
|
||||
{#if @thread}
|
||||
<div class="flex flex-row space-x-4 mb-6">
|
||||
<LivePatch
|
||||
class={classes([
|
||||
"px-4 py-2 rounded-xl text-center border-2 bg-primary-light-300 dark:bg-primary-dark-200 border-primary-light-300 dark:text-black dark:border-primary-dark-200"
|
||||
])}
|
||||
to={"/forum/#{@channel.name}"}
|
||||
>
|
||||
<div class="flex flex-row">
|
||||
<Heroicons.Outline.ArrowLeftIcon class="h-6 w-6 mr-2" />
|
||||
Back to {String.capitalize(@channel.name)}
|
||||
</div>
|
||||
</LivePatch>
|
||||
<a
|
||||
_target="blank"
|
||||
href={"discord://discordapp.com/channels/#{AshHq.Discord.Poller.server_id()}/#{@thread.id}"}
|
||||
class="bg-primary-light-300 dark:bg-primary-dark-300 dark:text-black align-middle px-4 py-2 rounded-lg mt-2 md:mt-0"
|
||||
>
|
||||
<div class="flex flex-row items-center">
|
||||
<span class="whitespace-nowrap">Discord App</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
_target="blank"
|
||||
href={"https://discord.com/channels/#{AshHq.Discord.Poller.server_id()}/#{@thread.id}"}
|
||||
class="bg-primary-light-300 dark:bg-primary-dark-300 dark:text-black align-middle px-4 py-2 rounded-lg mt-2 md:mt-0"
|
||||
>
|
||||
<div class="flex flex-row items-center">
|
||||
<span class="whitespace-nowrap">Discord Web</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<head>
|
||||
<meta property="og:title" content={@thread.name}>
|
||||
<meta
|
||||
property="og:description"
|
||||
content={"See the forum discussion in the #{String.capitalize(@channel.name)} channel"}
|
||||
/>
|
||||
</head>
|
||||
<div class="border shadow-sm rounded-lg px-8 pb-6 dark:border-gray-600 mb-4" ">
|
||||
<h2 class="mt-6 text-3xl font-semibold mb-4">{@thread.name}</h2>
|
||||
<div class="border-b pb-2">
|
||||
<div>
|
||||
{@thread.author}
|
||||
</div>
|
||||
<div>
|
||||
{@thread.create_timestamp |> DateTime.to_date()}
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-2">
|
||||
{#for tag <- @thread.tags}
|
||||
<Tag prefix={"/forum/#{@channel.name}"} tag={tag.name} />
|
||||
{/for}
|
||||
</div>
|
||||
</div>
|
||||
<div class="divide-y divide-solid space-y-6 mt-4">
|
||||
{#for message <- @thread.messages}
|
||||
<div class="prose dark:prose-invert break-words">
|
||||
<p>
|
||||
{message.author}:
|
||||
</p>{raw(message.content_html)}
|
||||
{#for attachment <- message.attachments}
|
||||
<Attachment attachment={attachment} />
|
||||
{/for}
|
||||
</div>
|
||||
{/for}
|
||||
</div>
|
||||
</div>
|
||||
{#else}
|
||||
<h2 class="text-xl font-bold mt-2">
|
||||
Channels
|
||||
</h2>
|
||||
<div class="flex flex-row space-x-4 mb-6">
|
||||
{#for channel <- @channels}
|
||||
<LivePatch
|
||||
class={classes([
|
||||
"px-4 py-2 rounded-xl text-center border-2 border-black dark:border-white",
|
||||
"bg-primary-light-600 dark:bg-primary-dark-500 border-primary-light-600 dark:text-black dark:border-primary-dark-500":
|
||||
@channel && @channel.id == channel.id
|
||||
])}
|
||||
to={"/forum/#{channel.name}"}
|
||||
>
|
||||
{String.capitalize(channel.name)}
|
||||
</LivePatch>
|
||||
{/for}
|
||||
</div>
|
||||
<div class="flex flex-row space-x-6 w-full justify-start ml-2 md:ml-0">
|
||||
{#if @threads.offset != 0}
|
||||
<LivePatch to={"/forum/#{@channel.name}?offset=#{min(@threads.offset - @threads.limit, 0)}"}>
|
||||
<div class="px-4 py-2 rounded-xl text-center border-2 bg-primary-light-500 dark:bg-primary-dark-400 border-primary-light-500 dark:text-black dark:border-primary-dark-400">
|
||||
Previous Page
|
||||
</div>
|
||||
</LivePatch>
|
||||
{/if}
|
||||
|
||||
{#if @threads.more?}
|
||||
<LivePatch to={"/forum/#{@channel.name}?offset=#{@threads.offset + @threads.limit}"}>
|
||||
<div class="px-4 py-2 rounded-xl text-center border-2 bg-primary-light-500 dark:bg-primary-dark-400 border-primary-light-500 dark:text-black dark:border-primary-dark-400">
|
||||
Next Page
|
||||
</div>
|
||||
</LivePatch>
|
||||
{/if}
|
||||
</div>
|
||||
<head>
|
||||
<meta property="og:title" content="Ash Framework Blog">
|
||||
<meta
|
||||
property="og:description"
|
||||
content="A declarative foundation for ambitious Elixir applications. Model your domain, derive the rest."
|
||||
/>
|
||||
</head>
|
||||
{#if @tag}
|
||||
<h2 class="text-2xl font-semibold mb-1 mt-2">Showing {page_info(@threads)} with tag: {@tag}</h2>
|
||||
{#else}
|
||||
<h2 class="text-2xl font-semibold mb-1 mt-2">Showing {page_info(@threads)}</h2>
|
||||
{/if}
|
||||
<div>
|
||||
{#for thread <- @threads.results}
|
||||
<div class="border shadow-sm rounded-lg px-8 pb-6 dark:border-gray-600 mb-4" ">
|
||||
<h2 class="mt-6 text-3xl font-semibold mb-4">{thread.name}</h2>
|
||||
<div class="border-b pb-2">
|
||||
<div>
|
||||
{thread.author}
|
||||
</div>
|
||||
<div>
|
||||
{thread.create_timestamp |> DateTime.to_date()}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col md:flex-row items-center mt-2 py-2 space-x-2">
|
||||
<LivePatch
|
||||
to={"/forum/#{@channel.name}/#{thread.id}"}
|
||||
class="bg-primary-light-600 dark:bg-primary-dark-500 dark:text-black align-middle px-4 py-2 rounded-lg"
|
||||
>
|
||||
<div class="flex flex-row items-center">
|
||||
<span>Read</span><Heroicons.Solid.ArrowRightIcon class="h-4 w-4" />
|
||||
</div>
|
||||
</LivePatch>
|
||||
<a
|
||||
_target="blank"
|
||||
href={"discord://discordapp.com/channels/#{AshHq.Discord.Poller.server_id()}/#{thread.id}"}
|
||||
class="bg-primary-light-300 dark:bg-primary-dark-300 dark:text-black align-middle px-4 py-2 rounded-lg mt-2 md:mt-0"
|
||||
>
|
||||
<div class="flex flex-row items-center">
|
||||
<span class="whitespace-nowrap">Discord App</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
_target="blank"
|
||||
href={"https://discord.com/channels/#{AshHq.Discord.Poller.server_id()}/#{thread.id}"}
|
||||
class="bg-primary-light-300 dark:bg-primary-dark-300 dark:text-black align-middle px-4 py-2 rounded-lg mt-2 md:mt-0"
|
||||
>
|
||||
<div class="flex flex-row items-center">
|
||||
<span class="whitespace-nowrap">Discord Web</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
{#for tag <- thread.tags}
|
||||
<Tag prefix={"/forum/#{@channel.name}"} tag={tag.name} />
|
||||
{/for}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/for}
|
||||
</div>
|
||||
<div class="flex flex-row space-x-6 w-full justify-start ml-2 md:ml-0">
|
||||
{#if @threads.offset != 0}
|
||||
<LivePatch to={"/forum/#{@channel.name}?offset=#{@threads.offset - @threads.limit}"}>
|
||||
<div class="px-4 py-2 rounded-xl text-center border-2 bg-primary-light-500 dark:bg-primary-dark-400 border-primary-light-500 dark:text-black dark:border-primary-dark-400">
|
||||
Previous Page
|
||||
</div>
|
||||
</LivePatch>
|
||||
{/if}
|
||||
|
||||
{#if @threads.more?}
|
||||
<LivePatch to={"/forum/#{@channel.name}?offset=#{@threads.offset + @threads.limit}"}>
|
||||
<div class="px-4 py-2 rounded-xl text-center border-2 bg-primary-light-500 dark:bg-primary-dark-400 border-primary-light-500 dark:text-black dark:border-primary-dark-400">
|
||||
Next Page
|
||||
</div>
|
||||
</LivePatch>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if !@thread}
|
||||
<div class={classes(["flex flex-col px-4 md:pr-0 md:pl-4 md:w-3/12 space-y-6", "mt-9": !@thread])}>
|
||||
<div class="border rounded-lg p-4 flex flex-col w-full dark:border-gray-600">
|
||||
<h3 class="text-lg font-bold mb-1">All Tags:</h3>
|
||||
<div class="flex gap-2 flex-wrap w-full">
|
||||
{#for tag <- @tags}
|
||||
<Tag prefix={"/forum/#{@channel.name}"} tag={tag} />
|
||||
{/for}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def update(assigns, socket) do
|
||||
{
|
||||
:ok,
|
||||
socket
|
||||
|> assign(assigns)
|
||||
|> assign_channels()
|
||||
|> assign_channel()
|
||||
|> assign_tags()
|
||||
|> assign_tag()
|
||||
|> assign_thread()
|
||||
|> assign_threads()
|
||||
}
|
||||
end
|
||||
|
||||
defp assign_tags(socket) do
|
||||
tags =
|
||||
AshHq.Discord.Tag
|
||||
# TODO: use distinct
|
||||
# |> Ash.Query.distinct(:name)
|
||||
|> Ash.Query.filter(channel_id == ^socket.assigns.channel.id)
|
||||
|> Ash.Query.select(:name)
|
||||
|> Ash.Query.sort(:name)
|
||||
|> AshHq.Discord.read!()
|
||||
|> Enum.map(&to_string(&1.name))
|
||||
|> Enum.uniq_by(&String.downcase/1)
|
||||
|
||||
assign(socket, :tags, tags)
|
||||
end
|
||||
|
||||
defp assign_tag(socket) do
|
||||
tag =
|
||||
if socket.assigns.params["tag"] do
|
||||
Enum.find(
|
||||
socket.assigns.tags,
|
||||
&Ash.Type.CiString.equal?(&1, socket.assigns.params["tag"])
|
||||
)
|
||||
end
|
||||
|
||||
assign(socket, :tag, tag)
|
||||
end
|
||||
|
||||
defp assign_thread(socket) do
|
||||
if socket.assigns.params["id"] do
|
||||
messages_query =
|
||||
AshHq.Discord.Message
|
||||
|> Ash.Query.sort(timestamp: :asc)
|
||||
|> Ash.Query.deselect(:content)
|
||||
|> Ash.Query.load(:attachments)
|
||||
|
||||
assign(
|
||||
socket,
|
||||
:thread,
|
||||
AshHq.Discord.Thread.by_id!(socket.assigns.params["id"],
|
||||
load: [:tags, messages: messages_query]
|
||||
)
|
||||
)
|
||||
else
|
||||
assign(socket, :thread, nil)
|
||||
end
|
||||
end
|
||||
|
||||
defp assign_threads(socket) do
|
||||
assign(
|
||||
socket,
|
||||
:threads,
|
||||
AshHq.Discord.Thread.feed!(
|
||||
socket.assigns.channel.id,
|
||||
%{tag_name: socket.assigns.tag},
|
||||
page: [offset: String.to_integer(socket.assigns.params["offset"] || "0"), count: true],
|
||||
load: :tags
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
defp assign_channels(socket) do
|
||||
assign(socket, :channels, AshHq.Discord.Channel.read!() |> Enum.sort_by(& &1.order))
|
||||
end
|
||||
|
||||
defp assign_channel(socket) do
|
||||
channel =
|
||||
Enum.find(
|
||||
socket.assigns.channels,
|
||||
&(&1.name == socket.assigns.params["channel"])
|
||||
)
|
||||
|
||||
if is_nil(channel) do
|
||||
raise Ash.Error.Query.NotFound.exception(
|
||||
primary_key: %{name: socket.assigns.params["channel"]}
|
||||
)
|
||||
end
|
||||
|
||||
assign(
|
||||
socket,
|
||||
:channel,
|
||||
channel
|
||||
)
|
||||
end
|
||||
|
||||
defp page_info(%{results: []}) do
|
||||
"no threads "
|
||||
end
|
||||
|
||||
defp page_info(%{more?: false, offset: 0, count: count}) do
|
||||
"all #{count} threads "
|
||||
end
|
||||
|
||||
defp page_info(%{more?: false, results: results, count: count}) do
|
||||
"the last #{Enum.count(results)} of #{count} threads "
|
||||
end
|
||||
|
||||
defp page_info(%{offset: 0, limit: limit, count: count}) do
|
||||
"the first #{limit} of #{count} threads "
|
||||
end
|
||||
|
||||
defp page_info(%{offset: offset, limit: limit, count: count}) do
|
||||
"threads #{offset + 1} to #{offset + limit} of #{count}"
|
||||
end
|
||||
end
|
|
@ -51,6 +51,8 @@ defmodule AshHqWeb.Router do
|
|||
live("/media", AppViewLive, :media)
|
||||
live("/blog", AppViewLive, :blog)
|
||||
live("/blog/:slug", AppViewLive, :blog)
|
||||
live("/forum/:channel", AppViewLive, :forum)
|
||||
live("/forum/:channel/:id", AppViewLive, :forum)
|
||||
live("/docs/", AppViewLive, :docs_dsl)
|
||||
live("/docs/guides/:library/:version/*guide", AppViewLive, :docs_dsl)
|
||||
live("/docs/dsl/:library", AppViewLive, :docs_dsl)
|
||||
|
|
|
@ -5,29 +5,29 @@ defmodule AshHqWeb.AppViewLive do
|
|||
|
||||
alias AshHqWeb.Components.AppView.TopBar
|
||||
alias AshHqWeb.Components.{CatalogueModal, Search}
|
||||
alias AshHqWeb.Pages.{Blog, Docs, Home, Media, UserSettings}
|
||||
alias AshHqWeb.Pages.{Blog, Docs, Forum, Home, Media, UserSettings}
|
||||
alias Phoenix.LiveView.JS
|
||||
alias Surface.Components.Context
|
||||
require Ash.Query
|
||||
|
||||
import AshHqWeb.Tails
|
||||
|
||||
data(configured_theme, :string, default: :system)
|
||||
data(selected_versions, :map, default: %{})
|
||||
data(libraries, :list, default: [])
|
||||
data(selected_types, :map, default: %{})
|
||||
data(current_user, :map)
|
||||
data configured_theme, :string, default: :system
|
||||
data selected_versions, :map, default: %{}
|
||||
data libraries, :list, default: []
|
||||
data selected_types, :map, default: %{}
|
||||
data current_user, :map
|
||||
|
||||
data(library, :any, default: nil)
|
||||
data(extension, :any, default: nil)
|
||||
data(docs, :any, default: nil)
|
||||
data(library_version, :any, default: nil)
|
||||
data(guide, :any, default: nil)
|
||||
data(doc_path, :list, default: [])
|
||||
data(dsls, :list, default: [])
|
||||
data(dsl, :any, default: nil)
|
||||
data(options, :list, default: [])
|
||||
data(module, :any, default: nil)
|
||||
data library, :any, default: nil
|
||||
data extension, :any, default: nil
|
||||
data docs, :any, default: nil
|
||||
data library_version, :any, default: nil
|
||||
data guide, :any, default: nil
|
||||
data doc_path, :list, default: []
|
||||
data dsls, :list, default: []
|
||||
data dsl, :any, default: nil
|
||||
data options, :list, default: []
|
||||
data module, :any, default: nil
|
||||
|
||||
def render(%{platform: :ios} = assigns) do
|
||||
~F"""
|
||||
|
@ -47,7 +47,7 @@ defmodule AshHqWeb.AppViewLive do
|
|||
>
|
||||
<head>
|
||||
<meta property="og:type" content="text/html">
|
||||
<meta property="og:image" content="https://ash-hq.org/images/ash-logo.png">
|
||||
<meta property="og:image" content="https://ash-hq.org/images/ash-logo-side-big.svg">
|
||||
<meta property="og:url" content={to_string(@uri)}>
|
||||
<meta property="og:site_name" content="Ash HQ">
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
|
@ -56,7 +56,7 @@ defmodule AshHqWeb.AppViewLive do
|
|||
<!-- Need to adjust this for future blog writers -->
|
||||
<meta property="twitter:creator" content="@ZachSDaniel1">
|
||||
|
||||
{#if @live_action not in [:docs_dsl, :blog]}
|
||||
{#if @live_action not in [:docs_dsl, :blog, :forum]}
|
||||
<meta property="og:title" content="Ash Framework">
|
||||
<meta
|
||||
property="og:description"
|
||||
|
@ -120,6 +120,8 @@ defmodule AshHqWeb.AppViewLive do
|
|||
<UserSettings id="user_settings" current_user={@current_user} />
|
||||
{#match :media}
|
||||
<Media id="media" />
|
||||
{#match :forum}
|
||||
<Forum id="forum" params={@params} />
|
||||
{/case}
|
||||
|
||||
{#if @live_action != :docs_dsl}
|
||||
|
|
8
mix.exs
8
mix.exs
|
@ -47,19 +47,23 @@ defmodule AshHq.MixProject do
|
|||
{:ash_json_api, github: "ash-project/ash_json_api"},
|
||||
{:ash_authentication, github: "team-alembic/ash_authentication", override: true},
|
||||
{:ash_authentication_phoenix, github: "team-alembic/ash_authentication_phoenix"},
|
||||
{:absinthe_plug, "~> 1.5"},
|
||||
{:ash_blog, github: "ash-project/ash_blog"},
|
||||
{:ash_csv, github: "ash-project/ash_csv"},
|
||||
# Discord
|
||||
{:nostrum, github: "zachdaniel/nostrum"},
|
||||
{:cowlib, "~> 2.11", hex: :remedy_cowlib, override: true},
|
||||
# UI
|
||||
{:tails, "~> 0.1"},
|
||||
{:sunflower_ui, github: "zachdaniel/sunflower_ui"},
|
||||
{:earmark, "~> 1.5.0-pre1", override: true},
|
||||
# Other
|
||||
{:absinthe_plug, "~> 1.5"},
|
||||
{:nimble_options, "~> 0.5.1", override: true},
|
||||
{:spark, "~> 0.3", override: true},
|
||||
{:surface, "~> 0.9.1"},
|
||||
{:surface_heroicons, "~> 0.6.0"},
|
||||
{:ua_inspector, "~> 3.0"},
|
||||
# Syntax Highlighting
|
||||
{:elixir_sense, github: "elixir-lsp/elixir_sense", only: [:dev, :test]},
|
||||
{:makeup, "~> 1.1"},
|
||||
{:makeup_elixir, "~> 0.16.0"},
|
||||
{:makeup_graphql, "~> 0.1.2"},
|
||||
|
|
12
mix.lock
12
mix.lock
|
@ -16,6 +16,7 @@
|
|||
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
|
||||
"castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"},
|
||||
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
|
||||
"chacha20": {:hex, :chacha20, "1.0.4", "0359d8f9a32269271044c1b471d5cf69660c362a7c61a98f73a05ef0b5d9eb9e", [:mix], [], "hexpm", "2027f5d321ae9903f1f0da7f51b0635ad6b8819bc7fe397837930a2011bc2349"},
|
||||
"cloak": {:hex, :cloak, "1.1.2", "7e0006c2b0b98d976d4f559080fabefd81f0e0a50a3c4b621f85ceeb563e80bb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "940d5ac4fcd51b252930fd112e319ea5ae6ab540b722f3ca60a85666759b9585"},
|
||||
"comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"},
|
||||
"comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"},
|
||||
|
@ -23,9 +24,10 @@
|
|||
"conv_case": {:hex, :conv_case, "0.2.3", "c1455c27d3c1ffcdd5f17f1e91f40b8a0bc0a337805a6e8302f441af17118ed8", [:mix], [], "hexpm", "88f29a3d97d1742f9865f7e394ed3da011abb7c5e8cc104e676fdef6270d4b4a"},
|
||||
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
|
||||
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
|
||||
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
|
||||
"cowlib": {:hex, :remedy_cowlib, "2.11.1", "7abb4d0779a7d1c655f7642dc0bd0af754951e95005dfa01b500c68fe35a5961", [:rebar3], [], "hexpm", "0b613dc308e080cb6134285f1b1b55c3873e101652e70c70010fc6651c91b130"},
|
||||
"credo": {:hex, :credo, "1.6.6", "f51f8d45db1af3b2e2f7bee3e6d3c871737bda4a91bff00c5eec276517d1a19c", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "625520ce0984ee0f9f1f198165cd46fa73c1e59a17ebc520038b8fce056a5bdc"},
|
||||
"csv": {:hex, :csv, "2.5.0", "c47b5a5221bf2e56d6e8eb79e77884046d7fd516280dc7d9b674251e0ae46246", [:mix], [{:parallel_stream, "~> 1.0.4 or ~> 1.1.0", [hex: :parallel_stream, repo: "hexpm", optional: false]}], "hexpm", "e821f541487045c7591a1963eeb42afff0dfa99bdcdbeb3410795a2f59c77d34"},
|
||||
"curve25519": {:hex, :curve25519, "1.0.5", "f801179424e4012049fcfcfcda74ac04f65d0ffceeb80e7ef1d3352deb09f5bb", [:mix], [], "hexpm", "0fba3ad55bf1154d4d5fc3ae5fb91b912b77b13f0def6ccb3a5d58168ff4192d"},
|
||||
"dataloader": {:hex, :dataloader, "1.0.10", "a42f07641b1a0572e0b21a2a5ae1be11da486a6790f3d0d14512d96ff3e3bbe9", [:mix], [{:ecto, ">= 3.4.3 and < 4.0.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "54cd70cec09addf4b2ace14cc186a283a149fd4d3ec5475b155951bf33cd963f"},
|
||||
"db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"},
|
||||
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
|
||||
|
@ -35,9 +37,11 @@
|
|||
"ecto": {:hex, :ecto, "3.9.4", "3ee68e25dbe0c36f980f1ba5dd41ee0d3eb0873bccae8aeaf1a2647242bffa35", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de5f988c142a3aa4ec18b85a4ec34a2390b65b24f02385c1144252ff6ff8ee75"},
|
||||
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"},
|
||||
"ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
|
||||
"ed25519": {:hex, :ed25519, "1.4.1", "479fb83c3e31987c9cad780e6aeb8f2015fb5a482618cdf2a825c9aff809afc4", [:mix], [], "hexpm", "0dacb84f3faa3d8148e81019ca35f9d8dcee13232c32c9db5c2fb8ff48c80ec7"},
|
||||
"eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.7.3", "c37fdae1b52d2cc51069713a58c2314877c1ad40800a57efb213f77b078a460d", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "24ada3e3996adbed1fa024ca14995ef2ba3d0d17b678b0f3f2b1f66e6ce2b274"},
|
||||
"elixir_sense": {:git, "https://github.com/elixir-lsp/elixir_sense.git", "ed875265f54994911774ac05c3a1b9adb65b80e7", []},
|
||||
"equivalex": {:hex, :equivalex, "1.0.3", "170d9a82ae066e0020dfe1cf7811381669565922eb3359f6c91d7e9a1124ff74", [:mix], [], "hexpm", "46fa311adb855117d36e461b9c0ad2598f72110ad17ad73d7533c78020e045fc"},
|
||||
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
|
||||
"esbuild": {:hex, :esbuild, "0.5.0", "d5bb08ff049d7880ee3609ed5c4b864bd2f46445ea40b16b4acead724fb4c4a3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "f183a0b332d963c4cfaf585477695ea59eef9a6f2204fdd0efa00e099694ffe5"},
|
||||
"ets": {:hex, :ets, "0.8.1", "8ff9bcda5682b98493f8878fc9dbd990e48d566cba8cce59f7c2a78130da29ea", [:mix], [], "hexpm", "6be41b50adb5bc5c43626f25ea2d0af1f4a242fb3fad8d53f0c67c20b78915cc"},
|
||||
|
@ -47,9 +51,11 @@
|
|||
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
|
||||
"finch": {:hex, :finch, "0.10.2", "9ad27d68270d879f73f26604bb2e573d40f29bf0e907064a9a337f90a16a0312", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dd8b11b282072cec2ef30852283949c248bd5d2820c88d8acc89402b81db7550"},
|
||||
"floki": {:hex, :floki, "0.33.1", "f20f1eb471e726342b45ccb68edb9486729e7df94da403936ea94a794f072781", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "461035fd125f13fdf30f243c85a0b1e50afbec876cbf1ceefe6fddd2e6d712c6"},
|
||||
"gen_stage": {:hex, :gen_stage, "1.1.2", "b1656cd4ba431ed02c5656fe10cb5423820847113a07218da68eae5d6a260c23", [:mix], [], "hexpm", "9e39af23140f704e2b07a3e29d8f05fd21c2aaf4088ff43cb82be4b9e3148d02"},
|
||||
"gettext": {:hex, :gettext, "0.20.0", "75ad71de05f2ef56991dbae224d35c68b098dd0e26918def5bb45591d5c8d429", [:mix], [], "hexpm", "1c03b177435e93a47441d7f681a7040bd2a816ece9e2666d1c9001035121eb3d"},
|
||||
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
|
||||
"git_ops": {:hex, :git_ops, "2.5.1", "94ab6e3bc69fe765a62cbdb09969016613a154dec8fc4f6ebae682f030451da9", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "1219edc8810dcea40472ec5b7ed04786a9e1b0e4e49d8642b0e1cdfb8a6ad261"},
|
||||
"gun": {:hex, :remedy_gun, "2.0.1", "0f0caed812ed9e4da4f144df2d5bf73b0a99481d395ecde990a3791decf321c6", [:rebar3], [{:cowlib, "~> 2.11.1", [hex: :remedy_cowlib, repo: "hexpm", optional: false]}], "hexpm", "b6685a85fbd12b757f86809be1b3d88fcef365b77605cd5aa34db003294c446e"},
|
||||
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
|
||||
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
|
||||
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
|
||||
|
@ -58,6 +64,7 @@
|
|||
"joken": {:hex, :joken, "2.5.0", "09be497d804b8115eb6f07615cef2e60c2a1008fb89dc0aef0d4c4b4609b99aa", [:mix], [{:jose, "~> 1.11.2", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "22b25c89617c5ed8ca7b31026340a25ea0f9ca7160f9706b79be9ed81fdf74e7"},
|
||||
"jose": {:hex, :jose, "1.11.5", "3bc2d75ffa5e2c941ca93e5696b54978323191988eb8d225c2e663ddfefd515e", [:mix, :rebar3], [], "hexpm", "dcd3b215bafe02ea7c5b23dafd3eb8062a5cd8f2d904fd9caa323d37034ab384"},
|
||||
"json_xema": {:hex, :json_xema, "0.4.2", "85de190f597a98ce9da436b8a59c97ef561a6ab6017255df8b494babefd6fb10", [:mix], [{:conv_case, "~> 0.2", [hex: :conv_case, repo: "hexpm", optional: false]}, {:xema, "~> 0.11", [hex: :xema, repo: "hexpm", optional: false]}], "hexpm", "5516213758667d21669e0d63ea287238d277519527bac6c02140a5e34c1fda80"},
|
||||
"kcl": {:hex, :kcl, "1.4.2", "8b73a55a14899dc172fcb05a13a754ac171c8165c14f65043382d567922f44ab", [:mix], [{:curve25519, ">= 1.0.4", [hex: :curve25519, repo: "hexpm", optional: false]}, {:ed25519, "~> 1.3", [hex: :ed25519, repo: "hexpm", optional: false]}, {:poly1305, "~> 1.0", [hex: :poly1305, repo: "hexpm", optional: false]}, {:salsa20, "~> 1.0", [hex: :salsa20, repo: "hexpm", optional: false]}], "hexpm", "9f083dd3844d902df6834b258564a82b21a15eb9f6acdc98e8df0c10feeabf05"},
|
||||
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
|
||||
"makeup_eex": {:hex, :makeup_eex, "0.1.1", "89352d5da318d97ae27bbcc87201f274504d2b71ede58ca366af6a5fbed9508d", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.16", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_html, "~> 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d111a0994eaaab09ef1a4b3b313ef806513bb4652152c26c0d7ca2be8402a964"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},
|
||||
|
@ -73,6 +80,7 @@
|
|||
"nimble_options": {:hex, :nimble_options, "0.5.2", "42703307b924880f8c08d97719da7472673391905f528259915782bb346e0a1b", [:mix], [], "hexpm", "4da7f904b915fd71db549bcdc25f8d56f378ef7ae07dc1d372cbe72ba950dce0"},
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
|
||||
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
|
||||
"nostrum": {:git, "https://github.com/zachdaniel/nostrum.git", "240a1bdb0b63b7e0a9ae065dc4a9841f17c4c778", []},
|
||||
"parallel_stream": {:hex, :parallel_stream, "1.1.0", "f52f73eb344bc22de335992377413138405796e0d0ad99d995d9977ac29f1ca9", [:mix], [], "hexpm", "684fd19191aedfaf387bbabbeb8ff3c752f0220c8112eb907d797f4592d6e871"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
|
||||
"phoenix": {:hex, :phoenix, "1.7.0-rc.1", "28d6591441347ba68da9750771cec6fe18ce040c91095a46d5d332804d5037d5", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "96d98dcf161b2784fd08a52fd480729a9eeae33773440b4e7a89d1e7e804af52"},
|
||||
|
@ -89,9 +97,11 @@
|
|||
"plug_content_security_policy": {:hex, :plug_content_security_policy, "0.2.1", "0a19c76307ad000b3757739c14b34b83ecccf7d0a3472e64e14797a20b62939b", [:mix], [{:plug, "~> 1.3", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ceea10050671c0387c64526e2cb337ee08e12705c737eaed80439266df5b2e29"},
|
||||
"plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
|
||||
"poly1305": {:hex, :poly1305, "1.0.4", "7cdc8961a0a6e00a764835918cdb8ade868044026df8ef5d718708ea6cc06611", [:mix], [{:chacha20, "~> 1.0", [hex: :chacha20, repo: "hexpm", optional: false]}, {:equivalex, "~> 1.0", [hex: :equivalex, repo: "hexpm", optional: false]}], "hexpm", "e14e684661a5195e149b3139db4a1693579d4659d65bba115a307529c47dbc3b"},
|
||||
"postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
|
||||
"premailex": {:hex, :premailex, "0.3.16", "25c0c9c969f0025bbfdb06834f8f0fbd46e5ec50f5c252e6492165802ffbd2a6", [:mix], [{:certifi, ">= 0.0.0", [hex: :certifi, repo: "hexpm", optional: true]}, {:floki, "~> 0.19", [hex: :floki, repo: "hexpm", optional: false]}, {:meeseeks, "~> 0.11", [hex: :meeseeks, repo: "hexpm", optional: true]}, {:ssl_verify_fun, ">= 0.0.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: true]}], "hexpm", "c6b042f89ca63025dfbe3ef54fdbbe9d5f043b7c33d8e58f43a41d13a9475111"},
|
||||
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
|
||||
"salsa20": {:hex, :salsa20, "1.0.4", "404cbea1fa8e68a41bcc834c0a2571ac175580fec01cc38cc70c0fb9ffc87e9b", [:mix], [], "hexpm", "745ddcd8cfa563ddb0fd61e7ce48d5146279a2cf7834e1da8441b369fdc58ac6"},
|
||||
"slugify": {:hex, :slugify, "1.3.1", "0d3b8b7e5c1eeaa960e44dce94382bee34a39b3ea239293e457a9c5b47cc6fd3", [:mix], [], "hexpm", "cb090bbeb056b312da3125e681d98933a360a70d327820e4b7f91645c4d8be76"},
|
||||
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},
|
||||
"sourceror": {:hex, :sourceror, "0.11.2", "549ce48be666421ac60cfb7f59c8752e0d393baa0b14d06271d3f6a8c1b027ab", [:mix], [], "hexpm", "9ab659118896a36be6eec68ff7b0674cba372fc8e210b1e9dc8cf2b55bb70dfb"},
|
||||
|
|
218
priv/repo/migrations/20230122063404_migrate_resources43.exs
Normal file
218
priv/repo/migrations/20230122063404_migrate_resources43.exs
Normal file
|
@ -0,0 +1,218 @@
|
|||
defmodule AshHq.Repo.Migrations.MigrateResources43 do
|
||||
@moduledoc """
|
||||
Updates resources based on their most recent snapshots.
|
||||
|
||||
This file was autogenerated with `mix ash_postgres.generate_migrations`
|
||||
"""
|
||||
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
create table(:discord_threads, primary_key: false) do
|
||||
add :id, :bigint, null: false, primary_key: true
|
||||
add :type, :bigint
|
||||
add :name, :text, null: false
|
||||
add :author, :text, null: false
|
||||
add :create_timestamp, :utc_datetime, null: false
|
||||
add :channel_id, :bigint, null: false
|
||||
end
|
||||
|
||||
create table(:discord_thread_tags, primary_key: false) do
|
||||
add :thread_id,
|
||||
references(:discord_threads,
|
||||
column: :id,
|
||||
name: "discord_thread_tags_thread_id_fkey",
|
||||
type: :bigint,
|
||||
prefix: "public"
|
||||
),
|
||||
primary_key: true,
|
||||
null: false
|
||||
|
||||
add :tag_id, :bigint, null: false, primary_key: true
|
||||
end
|
||||
|
||||
create table(:discord_tags, primary_key: false) do
|
||||
add :id, :bigint, null: false, primary_key: true
|
||||
end
|
||||
|
||||
alter table(:discord_thread_tags) do
|
||||
modify :tag_id,
|
||||
references(:discord_tags,
|
||||
column: :id,
|
||||
prefix: "public",
|
||||
name: "discord_thread_tags_tag_id_fkey",
|
||||
type: :bigint
|
||||
)
|
||||
end
|
||||
|
||||
alter table(:discord_tags) do
|
||||
add :name, :citext, null: false
|
||||
add :channel_id, :bigint
|
||||
end
|
||||
|
||||
create table(:discord_reactions, primary_key: false) do
|
||||
add :id, :uuid, null: false, default: fragment("uuid_generate_v4()"), primary_key: true
|
||||
add :count, :bigint, null: false
|
||||
add :emoji, :text, null: false
|
||||
add :message_id, :bigint, null: false
|
||||
end
|
||||
|
||||
create table(:discord_messages, primary_key: false) do
|
||||
add :id, :bigint, null: false, primary_key: true
|
||||
end
|
||||
|
||||
alter table(:discord_reactions) do
|
||||
modify :message_id,
|
||||
references(:discord_messages,
|
||||
column: :id,
|
||||
prefix: "public",
|
||||
name: "discord_reactions_message_id_fkey",
|
||||
type: :bigint
|
||||
)
|
||||
end
|
||||
|
||||
create unique_index(:discord_reactions, [:emoji, :message_id],
|
||||
name: "discord_reactions_unique_message_emoji_index"
|
||||
)
|
||||
|
||||
alter table(:discord_messages) do
|
||||
add :author, :text, null: false
|
||||
add :content, :text
|
||||
add :content_html, :text
|
||||
add :timestamp, :utc_datetime, null: false
|
||||
|
||||
add :thread_id,
|
||||
references(:discord_threads,
|
||||
column: :id,
|
||||
name: "discord_messages_thread_id_fkey",
|
||||
type: :bigint,
|
||||
prefix: "public"
|
||||
),
|
||||
null: false
|
||||
end
|
||||
|
||||
create table(:discord_channels, primary_key: false) do
|
||||
add :id, :bigint, null: false, primary_key: true
|
||||
end
|
||||
|
||||
alter table(:discord_threads) do
|
||||
modify :channel_id,
|
||||
references(:discord_channels,
|
||||
column: :id,
|
||||
prefix: "public",
|
||||
name: "discord_threads_channel_id_fkey",
|
||||
type: :bigint
|
||||
)
|
||||
end
|
||||
|
||||
alter table(:discord_tags) do
|
||||
modify :channel_id,
|
||||
references(:discord_channels,
|
||||
column: :id,
|
||||
prefix: "public",
|
||||
name: "discord_tags_channel_id_fkey",
|
||||
type: :bigint
|
||||
)
|
||||
end
|
||||
|
||||
create unique_index(:discord_tags, [:name, :channel_id],
|
||||
name: "discord_tags_unique_name_per_channel_index"
|
||||
)
|
||||
|
||||
alter table(:discord_channels) do
|
||||
add :name, :text, null: false
|
||||
add :order, :bigint, null: false
|
||||
end
|
||||
|
||||
create table(:discord_attachments, primary_key: false) do
|
||||
add :id, :bigint, null: false, primary_key: true
|
||||
add :filename, :text
|
||||
add :size, :bigint
|
||||
add :url, :text
|
||||
add :proxy_url, :text
|
||||
add :height, :bigint
|
||||
add :width, :bigint
|
||||
|
||||
add :message_id,
|
||||
references(:discord_messages,
|
||||
column: :id,
|
||||
name: "discord_attachments_message_id_fkey",
|
||||
type: :bigint,
|
||||
prefix: "public"
|
||||
),
|
||||
null: false
|
||||
end
|
||||
end
|
||||
|
||||
def down do
|
||||
drop constraint(:discord_attachments, "discord_attachments_message_id_fkey")
|
||||
|
||||
drop table(:discord_attachments)
|
||||
|
||||
alter table(:discord_channels) do
|
||||
remove :order
|
||||
remove :name
|
||||
end
|
||||
|
||||
drop_if_exists unique_index(:discord_tags, [:name, :channel_id],
|
||||
name: "discord_tags_unique_name_per_channel_index"
|
||||
)
|
||||
|
||||
drop constraint(:discord_tags, "discord_tags_channel_id_fkey")
|
||||
|
||||
alter table(:discord_tags) do
|
||||
modify :channel_id, :bigint
|
||||
end
|
||||
|
||||
drop constraint(:discord_threads, "discord_threads_channel_id_fkey")
|
||||
|
||||
alter table(:discord_threads) do
|
||||
modify :channel_id, :bigint
|
||||
end
|
||||
|
||||
drop table(:discord_channels)
|
||||
|
||||
drop constraint(:discord_messages, "discord_messages_thread_id_fkey")
|
||||
|
||||
alter table(:discord_messages) do
|
||||
remove :thread_id
|
||||
remove :timestamp
|
||||
remove :content_html
|
||||
remove :content
|
||||
remove :author
|
||||
end
|
||||
|
||||
drop_if_exists unique_index(:discord_reactions, [:emoji, :message_id],
|
||||
name: "discord_reactions_unique_message_emoji_index"
|
||||
)
|
||||
|
||||
drop constraint(:discord_reactions, "discord_reactions_message_id_fkey")
|
||||
|
||||
alter table(:discord_reactions) do
|
||||
modify :message_id, :bigint
|
||||
end
|
||||
|
||||
drop table(:discord_messages)
|
||||
|
||||
drop table(:discord_reactions)
|
||||
|
||||
alter table(:discord_tags) do
|
||||
remove :channel_id
|
||||
remove :name
|
||||
end
|
||||
|
||||
drop constraint(:discord_thread_tags, "discord_thread_tags_tag_id_fkey")
|
||||
|
||||
alter table(:discord_thread_tags) do
|
||||
modify :tag_id, :bigint
|
||||
end
|
||||
|
||||
drop table(:discord_tags)
|
||||
|
||||
drop constraint(:discord_thread_tags, "discord_thread_tags_thread_id_fkey")
|
||||
|
||||
drop table(:discord_thread_tags)
|
||||
|
||||
drop table(:discord_threads)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,113 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "filename",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "size",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "url",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "proxy_url",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "height",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "width",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": {
|
||||
"destination_attribute": "id",
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null,
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"name": "discord_attachments_message_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"schema": "public",
|
||||
"table": "discord_messages"
|
||||
},
|
||||
"size": null,
|
||||
"source": "message_id",
|
||||
"type": "bigint"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "881EA45557EDAE9BEDA6B1499907FC4360ADFC433081EF5A517BAD2737142699",
|
||||
"identities": [],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.AshHq.Repo",
|
||||
"schema": null,
|
||||
"table": "discord_attachments"
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "name",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "order",
|
||||
"type": "bigint"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "016FA4BD290C4F8B78EB8E76812E8C212E54D239C0F29723DD9F0C375610E11B",
|
||||
"identities": [],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.AshHq.Repo",
|
||||
"schema": null,
|
||||
"table": "discord_channels"
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "author",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "content",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "content_html",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "timestamp",
|
||||
"type": "utc_datetime"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": {
|
||||
"destination_attribute": "id",
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null,
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"name": "discord_messages_thread_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"schema": "public",
|
||||
"table": "discord_threads"
|
||||
},
|
||||
"size": null,
|
||||
"source": "thread_id",
|
||||
"type": "bigint"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "B6769A4474069F35583B825B15DB3E90E89E9B5BE7746F3CDC01F6F63F91DFBE",
|
||||
"identities": [],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.AshHq.Repo",
|
||||
"schema": null,
|
||||
"table": "discord_messages"
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "fragment(\"uuid_generate_v4()\")",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "id",
|
||||
"type": "uuid"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "count",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "emoji",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": {
|
||||
"destination_attribute": "id",
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null,
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"name": "discord_reactions_message_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"schema": "public",
|
||||
"table": "discord_messages"
|
||||
},
|
||||
"size": null,
|
||||
"source": "message_id",
|
||||
"type": "bigint"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "D5988E48113667274892255D4AC922235CB8B69E1F8F7510587324190CB773F9",
|
||||
"identities": [
|
||||
{
|
||||
"base_filter": null,
|
||||
"index_name": "discord_reactions_unique_message_emoji_index",
|
||||
"keys": [
|
||||
"emoji",
|
||||
"message_id"
|
||||
],
|
||||
"name": "unique_message_emoji"
|
||||
}
|
||||
],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.AshHq.Repo",
|
||||
"schema": null,
|
||||
"table": "discord_reactions"
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "name",
|
||||
"type": "citext"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": {
|
||||
"destination_attribute": "id",
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null,
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"name": "discord_tags_channel_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"schema": "public",
|
||||
"table": "discord_channels"
|
||||
},
|
||||
"size": null,
|
||||
"source": "channel_id",
|
||||
"type": "bigint"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "4BC43E070E42BD9B6DF346361EA7C569CEC386861E071BE60010802B3B7B1A4C",
|
||||
"identities": [
|
||||
{
|
||||
"base_filter": null,
|
||||
"index_name": "discord_tags_unique_name_per_channel_index",
|
||||
"keys": [
|
||||
"name",
|
||||
"channel_id"
|
||||
],
|
||||
"name": "unique_name_per_channel"
|
||||
}
|
||||
],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.AshHq.Repo",
|
||||
"schema": null,
|
||||
"table": "discord_tags"
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": {
|
||||
"destination_attribute": "id",
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null,
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"name": "discord_thread_tags_thread_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"schema": "public",
|
||||
"table": "discord_threads"
|
||||
},
|
||||
"size": null,
|
||||
"source": "thread_id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": {
|
||||
"destination_attribute": "id",
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null,
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"name": "discord_thread_tags_tag_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"schema": "public",
|
||||
"table": "discord_tags"
|
||||
},
|
||||
"size": null,
|
||||
"source": "tag_id",
|
||||
"type": "bigint"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "C15DF3DE538A5AEEB42B4EB683E5C1AD6582D4A778652030E9FB80F39989D8A7",
|
||||
"identities": [],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.AshHq.Repo",
|
||||
"schema": null,
|
||||
"table": "discord_thread_tags"
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "type",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "name",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "author",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "create_timestamp",
|
||||
"type": "utc_datetime"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": {
|
||||
"destination_attribute": "id",
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null,
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"name": "discord_threads_channel_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"schema": "public",
|
||||
"table": "discord_channels"
|
||||
},
|
||||
"size": null,
|
||||
"source": "channel_id",
|
||||
"type": "bigint"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "44F703FEF49D5A94C72022E82B830E1580E218320783CFCF26BB5B9E6297CEF3",
|
||||
"identities": [],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.AshHq.Repo",
|
||||
"schema": null,
|
||||
"table": "discord_threads"
|
||||
}
|
14
priv/static/images/ash-logo-side-big.svg
Normal file
14
priv/static/images/ash-logo-side-big.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 11 KiB |
Loading…
Reference in a new issue