mirror of
https://github.com/ash-project/ash_hq.git
synced 2024-09-19 12:53:49 +12:00
improvement: upgrade to 3.0
This commit is contained in:
parent
6a943f22d7
commit
2221ef824d
59 changed files with 381 additions and 548 deletions
|
@ -24,34 +24,43 @@ import { LiveSocket } from "phoenix_live_view";
|
|||
import topbar from "../vendor/topbar";
|
||||
|
||||
function setCookie(name, value) {
|
||||
document.cookie = name + "=" + value + ";path=/;" + "expires=Fri, 31 Dec 9999 23:59:59 GMT;";
|
||||
document.cookie =
|
||||
name + "=" + value + ";path=/;" + "expires=Fri, 31 Dec 9999 23:59:59 GMT;";
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
const cookie = document.cookie.split("; ").find((row) => row.startsWith(name + "="))
|
||||
const cookie = document.cookie
|
||||
.split("; ")
|
||||
.find((row) => row.startsWith(name + "="));
|
||||
if (cookie) {
|
||||
return cookie.split("=")[1]
|
||||
return cookie.split("=")[1];
|
||||
}
|
||||
}
|
||||
|
||||
function cookiesAreAllowed() {
|
||||
return getCookie("cookieconsent_status") === "allow"
|
||||
return getCookie("cookieconsent_status") === "allow";
|
||||
}
|
||||
|
||||
function get_platform() {
|
||||
// 2022 way of detecting. Note : this userAgentData feature is available only in secure contexts (HTTPS)
|
||||
if (typeof navigator.userAgentData !== 'undefined' && navigator.userAgentData != null) {
|
||||
if (
|
||||
typeof navigator.userAgentData !== "undefined" &&
|
||||
navigator.userAgentData != null
|
||||
) {
|
||||
return navigator.userAgentData.platform;
|
||||
}
|
||||
// Deprecated but still works for most of the browser
|
||||
if (typeof navigator.platform !== 'undefined') {
|
||||
if (typeof navigator.userAgent !== 'undefined' && /android/.test(navigator.userAgent.toLowerCase())) {
|
||||
if (typeof navigator.platform !== "undefined") {
|
||||
if (
|
||||
typeof navigator.userAgent !== "undefined" &&
|
||||
/android/.test(navigator.userAgent.toLowerCase())
|
||||
) {
|
||||
// android device's navigator.platform is often set as 'linux', so let's use userAgent for them
|
||||
return 'android';
|
||||
return "android";
|
||||
}
|
||||
return navigator.platform;
|
||||
}
|
||||
return 'unknown';
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
let platform = get_platform();
|
||||
|
@ -110,13 +119,15 @@ let scrolled = false;
|
|||
|
||||
Hooks.RightNav = {
|
||||
mounted() {
|
||||
this.intersectionObserver =
|
||||
new IntersectionObserver((entries) =>
|
||||
this.onScrollChange(entries), { rootMargin: "-10% 0px -89% 0px" }
|
||||
);
|
||||
this.intersectionObserver = new IntersectionObserver(
|
||||
(entries) => this.onScrollChange(entries),
|
||||
{ rootMargin: "-10% 0px -89% 0px" },
|
||||
);
|
||||
|
||||
this.observeElements()
|
||||
window.addEventListener("hashchange", (event) => { this.handleHashChange(); });
|
||||
this.observeElements();
|
||||
window.addEventListener("hashchange", (event) => {
|
||||
this.handleHashChange();
|
||||
});
|
||||
},
|
||||
updated() {
|
||||
this.intersectionObserver.disconnect();
|
||||
|
@ -129,7 +140,9 @@ Hooks.RightNav = {
|
|||
},
|
||||
onScrollChange(entries) {
|
||||
// Wait for scrolling from initial page load to complete
|
||||
if (!scrolled) { return; }
|
||||
if (!scrolled) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
|
@ -139,19 +152,21 @@ Hooks.RightNav = {
|
|||
},
|
||||
handleHashChange() {
|
||||
if (window.location.hash) {
|
||||
this.setAriaCurrent(window.location.hash.substring(1))
|
||||
this.setAriaCurrent(window.location.hash.substring(1));
|
||||
|
||||
// Disable the insersection observer for 1s while the browser
|
||||
// scrolls the selected element to the top.
|
||||
scrolled = false;
|
||||
setTimeout(() => { scrolled = true }, 1000);
|
||||
setTimeout(() => {
|
||||
scrolled = true;
|
||||
}, 1000);
|
||||
}
|
||||
},
|
||||
setAriaCurrent(id) {
|
||||
const el = document.getElementById("right-nav-" + id);
|
||||
if (el) {
|
||||
for (elem of document.querySelectorAll('#right-nav a[aria-current]')) {
|
||||
elem.removeAttribute('aria-current');
|
||||
for (elem of document.querySelectorAll("#right-nav a[aria-current]")) {
|
||||
elem.removeAttribute("aria-current");
|
||||
}
|
||||
el.setAttribute("aria-current", "true");
|
||||
}
|
||||
|
@ -201,9 +216,9 @@ window.addEventListener("phx:page-loading-start", ({ detail }) => {
|
|||
scrolled = false;
|
||||
|
||||
// close mobile sidebar on navigation
|
||||
mobileSideBar = document.getElementById("mobile-sidebar-hide")
|
||||
mobileSideBar = document.getElementById("mobile-sidebar-hide");
|
||||
if (mobileSideBar) {
|
||||
mobileSideBar.click()
|
||||
mobileSideBar.click();
|
||||
}
|
||||
|
||||
if (!topBarScheduled) {
|
||||
|
@ -219,13 +234,17 @@ window.addEventListener("phx:page-loading-stop", ({ detail }) => {
|
|||
if (detail.kind === "initial" && window.location.hash) {
|
||||
scrollEl = document.getElementById(window.location.hash.substring(1));
|
||||
} else if (detail.kind == "patch" && !window.location.hash) {
|
||||
scrollEl = document.querySelector("#docs-window .nav-anchor") || document.querySelector("#docs-window h1");
|
||||
scrollEl =
|
||||
document.querySelector("#docs-window .nav-anchor") ||
|
||||
document.querySelector("#docs-window h1");
|
||||
}
|
||||
if (scrollEl) {
|
||||
Hooks.RightNav.setAriaCurrent(scrollEl.id);
|
||||
// Not using scroll polyfill here - doesn't respect scroll-padding-top CSS
|
||||
scrollEl.scrollIntoView({ block: 'start' })
|
||||
setTimeout(() => { scrolled = true; }, 1000);
|
||||
scrollEl.scrollIntoView({ block: "start" });
|
||||
setTimeout(() => {
|
||||
scrolled = true;
|
||||
}, 1000);
|
||||
} else {
|
||||
scrolled = true;
|
||||
}
|
||||
|
@ -243,13 +262,6 @@ window.addEventListener("phx:js:scroll-to", (e) => {
|
|||
});
|
||||
});
|
||||
|
||||
window.addEventListener("phx:selected-types", (e) => {
|
||||
if (cookiesAreAllowed()) {
|
||||
const cookie = e.detail.types.join(",");
|
||||
setCookies("selected_types", cookie)
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("keydown", (event) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key === "k") {
|
||||
document.getElementById("search-button").click();
|
||||
|
@ -258,9 +270,11 @@ window.addEventListener("keydown", (event) => {
|
|||
});
|
||||
window.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape") {
|
||||
const closeSearchVersions = document.getElementById("close-search-versions");
|
||||
const closeSearchVersions = document.getElementById(
|
||||
"close-search-versions",
|
||||
);
|
||||
if (closeSearchVersions && closeSearchVersions.offsetParent !== null) {
|
||||
closeSearchVersions.click()
|
||||
closeSearchVersions.click();
|
||||
} else {
|
||||
document.getElementById("close-search").click();
|
||||
}
|
||||
|
@ -288,7 +302,7 @@ liveSocket.connect();
|
|||
// >> liveSocket.disableLatencySim()
|
||||
window.liveSocket = liveSocket;
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
window.addEventListener("load", function () {
|
||||
window.cookieconsent.initialise({
|
||||
content: {
|
||||
message:
|
||||
|
|
|
@ -25,7 +25,7 @@ config :ash_appsignal,
|
|||
config :appsignal, :config, revision: "test-4"
|
||||
|
||||
config :ash_hq,
|
||||
ash_apis: [
|
||||
ash_domains: [
|
||||
AshHq.Accounts,
|
||||
AshHq.Blog,
|
||||
AshHq.Docs,
|
||||
|
@ -40,7 +40,6 @@ config :ash_hq, AshHq.Repo,
|
|||
|
||||
config :spark, :formatter,
|
||||
remove_parens?: true,
|
||||
"Ash.Registry": [],
|
||||
"Ash.Resource": [
|
||||
type: Ash.Resource,
|
||||
section_order: [
|
||||
|
|
|
@ -2,13 +2,10 @@ defmodule AshHq.Accounts do
|
|||
@moduledoc """
|
||||
Handles user and user token related operations/state
|
||||
"""
|
||||
use Ash.Api, otp_app: :ash_hq
|
||||
|
||||
authorization do
|
||||
authorize :by_default
|
||||
end
|
||||
use Ash.Domain, otp_app: :ash_hq
|
||||
|
||||
resources do
|
||||
registry AshHq.Accounts.Registry
|
||||
resource AshHq.Accounts.User
|
||||
resource AshHq.Accounts.UserToken
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
defmodule AshHq.Accounts.Registry do
|
||||
@moduledoc false
|
||||
|
||||
use Ash.Registry,
|
||||
extensions: [Ash.Registry.ResourceValidations]
|
||||
|
||||
entries do
|
||||
entry AshHq.Accounts.User
|
||||
entry AshHq.Accounts.UserToken
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
defmodule AshHq.Accounts.User.Changes.RemoveAllTokens do
|
||||
@moduledoc """
|
||||
Removes all tokens for a given user.
|
||||
|
||||
Since Ash does not yet support bulk actions, this goes straight to the data layer.
|
||||
"""
|
||||
use Ash.Resource.Change
|
||||
require Ash.Query
|
||||
|
||||
def change(changeset, _opts, _context) do
|
||||
Ash.Changeset.after_action(
|
||||
changeset,
|
||||
fn _changeset, user ->
|
||||
{:ok, query} =
|
||||
AshHq.Accounts.UserToken
|
||||
|> Ash.Query.filter(user_id == ^user.id)
|
||||
|> Ash.Query.data_layer_query()
|
||||
|
||||
AshHq.Repo.delete_all(query)
|
||||
|
||||
{:ok, user}
|
||||
end,
|
||||
prepend?: true
|
||||
)
|
||||
end
|
||||
end
|
|
@ -6,25 +6,5 @@ defmodule AshHq.Accounts.User.Policies do
|
|||
policy action(:read) do
|
||||
authorize_if(expr(id == ^actor(:id)))
|
||||
end
|
||||
|
||||
policy action(:update_email) do
|
||||
description("A logged in user can update their email")
|
||||
authorize_if(expr(id == ^actor(:id)))
|
||||
end
|
||||
|
||||
policy action(:resend_confirmation_instructions) do
|
||||
description("A logged in user can request an email confirmation")
|
||||
authorize_if(expr(id == ^actor(:id)))
|
||||
end
|
||||
|
||||
policy action(:change_password) do
|
||||
description("A logged in user can reset their password")
|
||||
authorize_if(expr(id == ^actor(:id)))
|
||||
end
|
||||
|
||||
policy action(:update_merch_settings) do
|
||||
description("A logged in user can update their merch settings")
|
||||
authorize_if(expr(id == ^actor(:id)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ defmodule AshHq.Accounts.User do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Accounts,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
fragments: [AshHq.Accounts.User.Policies]
|
||||
|
||||
|
@ -11,130 +12,6 @@ defmodule AshHq.Accounts.User do
|
|||
|
||||
actions do
|
||||
defaults [:read]
|
||||
|
||||
# create :register_with_github do
|
||||
# argument :user_info, :map do
|
||||
# allow_nil? false
|
||||
# end
|
||||
|
||||
# argument :oauth_tokens, :map do
|
||||
# allow_nil? false
|
||||
# end
|
||||
|
||||
# change fn changeset, _ ->
|
||||
# user_info = Ash.Changeset.get_argument(changeset, :user_info)
|
||||
|
||||
# changeset =
|
||||
# if user_info["email_verified"] do
|
||||
# Ash.Changeset.force_change_attribute(
|
||||
# changeset,
|
||||
# :confirmed_at,
|
||||
# Ash.Changeset.get_attribute(changeset, :confirmed_at) || DateTime.utc_now()
|
||||
# )
|
||||
# else
|
||||
# changeset
|
||||
# end
|
||||
|
||||
# changeset
|
||||
# |> Ash.Changeset.change_attribute(:email, Map.get(user_info, "email"))
|
||||
# |> Ash.Changeset.change_attribute(:github_info, user_info)
|
||||
# end
|
||||
|
||||
# change AshAuthentication.GenerateTokenChange
|
||||
# upsert? true
|
||||
# upsert_identity :unique_email
|
||||
# end
|
||||
|
||||
# update :change_password do
|
||||
# accept []
|
||||
|
||||
# argument :current_password, :string do
|
||||
# sensitive? true
|
||||
# allow_nil? false
|
||||
# end
|
||||
|
||||
# argument :password, :string do
|
||||
# sensitive? true
|
||||
# allow_nil? false
|
||||
# end
|
||||
|
||||
# argument :password_confirmation, :string do
|
||||
# sensitive? true
|
||||
# allow_nil? false
|
||||
# end
|
||||
|
||||
# change set_context(%{strategy_name: :password})
|
||||
|
||||
# validate confirm(:password, :password_confirmation)
|
||||
|
||||
# validate {AshAuthentication.Strategy.Password.PasswordValidation,
|
||||
# strategy_name: :password, password_argument: :current_password} do
|
||||
# only_when_valid? true
|
||||
# before_action? true
|
||||
# end
|
||||
|
||||
# change AshAuthentication.Strategy.Password.HashPasswordChange
|
||||
# end
|
||||
|
||||
# update :update_email do
|
||||
# accept [:email]
|
||||
|
||||
# argument :current_password, :string do
|
||||
# sensitive? true
|
||||
# allow_nil? false
|
||||
# end
|
||||
|
||||
# change set_context(%{strategy_name: :password})
|
||||
|
||||
# validate {AshAuthentication.Strategy.Password.PasswordValidation,
|
||||
# password_argument: :current_password} do
|
||||
# only_when_valid? true
|
||||
# before_action? true
|
||||
# end
|
||||
# end
|
||||
|
||||
# update :resend_confirmation_instructions do
|
||||
# accept []
|
||||
|
||||
# change fn changeset, _context ->
|
||||
# Ash.Changeset.before_action(changeset, fn changeset ->
|
||||
# case AshHq.Accounts.UserToken.email_token_for_user(changeset.data.id,
|
||||
# authorize?: false
|
||||
# ) do
|
||||
# {:ok, %{extra_data: %{"email" => changing_to}}} ->
|
||||
# temp_changeset = %{
|
||||
# changeset
|
||||
# | attributes: Map.put(changeset.attributes, :email, changing_to)
|
||||
# }
|
||||
|
||||
# strategy = AshAuthentication.Info.strategy!(changeset.resource, :confirm)
|
||||
|
||||
# {:ok, token} =
|
||||
# AshAuthentication.AddOn.Confirmation.confirmation_token(
|
||||
# strategy,
|
||||
# temp_changeset,
|
||||
# changeset.data
|
||||
# )
|
||||
|
||||
# AshHq.Accounts.User.Senders.SendConfirmationEmail.send(changeset.data, token, [])
|
||||
|
||||
# changeset
|
||||
|
||||
# _ ->
|
||||
# Ash.Changeset.add_error(changeset, "Could not determine what email to use")
|
||||
# end
|
||||
# end)
|
||||
# end
|
||||
# end
|
||||
|
||||
# update :update_merch_settings do
|
||||
# argument :address, :string
|
||||
# argument :name, :string
|
||||
|
||||
# accept [:shirt_size]
|
||||
# change set_attribute(:encrypted_address, arg(:address))
|
||||
# change set_attribute(:encrypted_name, arg(:name))
|
||||
# end
|
||||
end
|
||||
|
||||
attributes do
|
||||
|
@ -146,7 +23,7 @@ defmodule AshHq.Accounts.User do
|
|||
max_length: 160
|
||||
]
|
||||
|
||||
attribute :hashed_password, :string, private?: true, sensitive?: true
|
||||
attribute :hashed_password, :string, sensitive?: true
|
||||
|
||||
attribute :encrypted_name, :string
|
||||
attribute :encrypted_address, :string
|
||||
|
@ -160,7 +37,6 @@ defmodule AshHq.Accounts.User do
|
|||
relationships do
|
||||
has_one :token, AshHq.Accounts.UserToken do
|
||||
destination_attribute :user_id
|
||||
private? true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -169,12 +45,6 @@ defmodule AshHq.Accounts.User do
|
|||
repo AshHq.Repo
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Accounts
|
||||
define :resend_confirmation_instructions
|
||||
define :register_with_password, args: [:email, :password, :password_confirmation]
|
||||
end
|
||||
|
||||
resource do
|
||||
description """
|
||||
Represents the user of a system.
|
||||
|
@ -188,9 +58,6 @@ defmodule AshHq.Accounts.User do
|
|||
end
|
||||
|
||||
changes do
|
||||
change AshHq.Accounts.User.Changes.RemoveAllTokens,
|
||||
where: [action_is(:password_reset_with_password)]
|
||||
|
||||
change {AshHq.Changes.Encrypt, fields: [:encrypted_address, :encrypted_name]}
|
||||
end
|
||||
|
||||
|
|
|
@ -2,27 +2,16 @@ defmodule AshHq.Accounts.UserToken do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Accounts,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
authorizers: [Ash.Policy.Authorizer]
|
||||
|
||||
actions do
|
||||
defaults [:read, :destroy]
|
||||
|
||||
read :email_token_for_user do
|
||||
get? true
|
||||
|
||||
argument :user_id, :uuid do
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
prepare build(sort: [updated_at: :desc], limit: 1)
|
||||
|
||||
filter expr(purpose == "confirm" and not is_nil(extra_data[:email]))
|
||||
end
|
||||
defaults [:read]
|
||||
end
|
||||
|
||||
token do
|
||||
api AshHq.Accounts
|
||||
attributes do
|
||||
uuid_primary_key :id
|
||||
end
|
||||
|
||||
relationships do
|
||||
|
@ -32,8 +21,7 @@ defmodule AshHq.Accounts.UserToken do
|
|||
policies do
|
||||
policy always() do
|
||||
description """
|
||||
There are currently no usages of user tokens resource that should be publicly
|
||||
accessible, they should all be using authorize?: false.
|
||||
There are currently no usages of user tokens resource that should be publicly accessible.
|
||||
"""
|
||||
|
||||
forbid_if always()
|
||||
|
@ -49,30 +37,9 @@ defmodule AshHq.Accounts.UserToken do
|
|||
end
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Accounts
|
||||
define :destroy
|
||||
define :email_token_for_user, args: [:user_id]
|
||||
end
|
||||
|
||||
resource do
|
||||
description """
|
||||
Represents a token allowing a user to log in, reset their password, or confirm their email.
|
||||
"""
|
||||
end
|
||||
|
||||
changes do
|
||||
change fn changeset, _ ->
|
||||
case changeset.context[:ash_authentication][:user] do
|
||||
nil ->
|
||||
changeset
|
||||
|
||||
user ->
|
||||
Ash.Changeset.manage_relationship(changeset, :user, user,
|
||||
type: :append_and_remove
|
||||
)
|
||||
end
|
||||
end,
|
||||
on: [:create]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
defmodule AshHq.ApiHelpers do
|
||||
@moduledoc false
|
||||
defmacro __using__(_) do
|
||||
quote do
|
||||
def stream(query, opts \\ []) do
|
||||
api = __MODULE__
|
||||
query = Ash.Query.to_query(query)
|
||||
|
||||
query =
|
||||
if query.action do
|
||||
query
|
||||
else
|
||||
Ash.Query.for_read(
|
||||
query,
|
||||
Ash.Resource.Info.primary_action!(query.resource, :read).name
|
||||
)
|
||||
end
|
||||
|
||||
Stream.resource(
|
||||
fn -> nil end,
|
||||
fn
|
||||
false ->
|
||||
{:halt, nil}
|
||||
|
||||
after_keyset ->
|
||||
if is_nil(query.action.pagination) || !query.action.pagination.keyset? do
|
||||
raise "Keyset pagination must be enabled"
|
||||
end
|
||||
|
||||
keyset = if after_keyset != nil, do: [after: after_keyset], else: []
|
||||
page_opts = Keyword.merge([limit: 100], keyset)
|
||||
|
||||
opts =
|
||||
[
|
||||
page: page_opts
|
||||
]
|
||||
|> Keyword.merge(opts)
|
||||
|
||||
case api.read!(query, opts) do
|
||||
%{more?: true, results: results} ->
|
||||
{results, List.last(results).__metadata__.keyset}
|
||||
|
||||
%{results: results} ->
|
||||
{results, false}
|
||||
end
|
||||
end,
|
||||
& &1
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,6 +7,7 @@ defmodule AshHq.Application do
|
|||
|
||||
@impl true
|
||||
def start(_type, _args) do
|
||||
:erlang.system_flag(:backtrace_depth, 1000)
|
||||
Appsignal.Phoenix.LiveView.attach()
|
||||
|
||||
# topologies = Application.get_env(:libcluster, :topologies) || []
|
||||
|
@ -48,8 +49,8 @@ defmodule AshHq.Application do
|
|||
end
|
||||
|
||||
defp oban_worker do
|
||||
apis = Application.fetch_env!(:ash_hq, :ash_apis)
|
||||
domains = Application.fetch_env!(:ash_hq, :ash_domains)
|
||||
config = Application.fetch_env!(:ash_hq, Oban)
|
||||
{Oban, AshOban.config(apis, config)}
|
||||
{Oban, AshOban.config(domains, config)}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
defmodule AshHq.Blog do
|
||||
@moduledoc "An api for interacting with the blog"
|
||||
use Ash.Api,
|
||||
extensions: [AshAdmin.Api]
|
||||
@moduledoc "A domain for interacting with the blog"
|
||||
use Ash.Domain,
|
||||
extensions: [AshAdmin.Domain]
|
||||
|
||||
admin do
|
||||
show? true
|
||||
|
@ -9,6 +9,7 @@ defmodule AshHq.Blog do
|
|||
end
|
||||
|
||||
resources do
|
||||
registry AshHq.Blog.Registry
|
||||
resource AshHq.Blog.Post
|
||||
resource AshHq.Blog.Tag
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
defmodule AshHq.Blog.Registry do
|
||||
@moduledoc "The resources used in the blog"
|
||||
use Ash.Registry,
|
||||
extensions: [Ash.Registry.ResourceValidations]
|
||||
|
||||
entries do
|
||||
entry AshHq.Blog.Post
|
||||
entry AshHq.Blog.Tag
|
||||
end
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
defmodule AshHq.Blog.Post do
|
||||
@moduledoc "A blog post. Uses the AshBlog data layer and therefore is static"
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Blog,
|
||||
otp_app: :ash_hq,
|
||||
data_layer: AshBlog.DataLayer,
|
||||
extensions: [AshHq.Docs.Extensions.RenderMarkdown, AshAdmin.Resource]
|
||||
|
@ -22,6 +23,7 @@ defmodule AshHq.Blog.Post do
|
|||
end
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :read, :update]
|
||||
|
||||
read :published do
|
||||
|
@ -52,11 +54,13 @@ defmodule AshHq.Blog.Post do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :tag_line, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
constraints max_length: 250
|
||||
end
|
||||
|
||||
attribute :tag_names, {:array, :ci_string} do
|
||||
public? true
|
||||
constraints items: [
|
||||
match: ~r/^[a-zA-Z]*$/,
|
||||
casing: :lower
|
||||
|
@ -64,10 +68,12 @@ defmodule AshHq.Blog.Post do
|
|||
end
|
||||
|
||||
attribute :author, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :body_html, :string do
|
||||
public? true
|
||||
writable? false
|
||||
end
|
||||
|
||||
|
@ -76,6 +82,7 @@ defmodule AshHq.Blog.Post do
|
|||
|
||||
relationships do
|
||||
has_many :tags, AshHq.Blog.Tag do
|
||||
public? true
|
||||
manual fn posts, %{query: query} ->
|
||||
all_tags = Enum.flat_map(posts, &(&1.tag_names || []))
|
||||
|
||||
|
@ -83,7 +90,7 @@ defmodule AshHq.Blog.Post do
|
|||
query
|
||||
|> Ash.Query.unset([:limit, :offset])
|
||||
|> Ash.Query.filter(name in ^all_tags)
|
||||
|> AshHq.Blog.read!()
|
||||
|> Ash.read!()
|
||||
|
||||
{:ok,
|
||||
Map.new(posts, fn post ->
|
||||
|
@ -94,7 +101,6 @@ defmodule AshHq.Blog.Post do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Blog
|
||||
define :published
|
||||
define :by_slug, args: [:slug]
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule AshHq.Blog.Tag do
|
||||
@moduledoc "A tag that can be applied to a post. Currently uses CSV data layer and therefore is static"
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Blog,
|
||||
data_layer: AshCsv.DataLayer
|
||||
|
||||
csv do
|
||||
|
@ -11,6 +12,7 @@ defmodule AshHq.Blog.Tag do
|
|||
end
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
create :upsert do
|
||||
|
@ -21,6 +23,7 @@ defmodule AshHq.Blog.Tag do
|
|||
|
||||
attributes do
|
||||
attribute :name, :ci_string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
primary_key? true
|
||||
constraints casing: :lower
|
||||
|
@ -28,7 +31,6 @@ defmodule AshHq.Blog.Tag do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Blog
|
||||
define :upsert, args: [:name]
|
||||
define :read
|
||||
define :destroy
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
defmodule AshHq.Calculations.Decrypt do
|
||||
@moduledoc "Decrypts a given value on demand"
|
||||
use Ash.Calculation
|
||||
use Ash.Resource.Calculation
|
||||
|
||||
def calculate(records, opts, _) do
|
||||
{:ok,
|
||||
|
@ -19,10 +19,6 @@ defmodule AshHq.Calculations.Decrypt do
|
|||
end)}
|
||||
end
|
||||
|
||||
def select(_, opts, _) do
|
||||
[opts[:field]]
|
||||
end
|
||||
|
||||
def load(_, opts, _) do
|
||||
[opts[:field]]
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
defmodule AshHq.Discord do
|
||||
@moduledoc "Discord api import & interactions"
|
||||
use Ash.Api
|
||||
use Ash.Domain
|
||||
|
||||
resources do
|
||||
resource AshHq.Discord.Attachment
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
defmodule AshHq.Discord.Attachment do
|
||||
@moduledoc "A discord attachment on a message"
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Discord,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
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
|
||||
attribute :filename, :string, public?: true
|
||||
attribute :size, :integer, public?: true
|
||||
attribute :url, :string, public?: true
|
||||
attribute :proxy_url, :string, public?: true
|
||||
attribute :height, :integer, public?: true
|
||||
attribute :width, :integer, public?: true
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :message, AshHq.Discord.Message do
|
||||
public? true
|
||||
allow_nil? false
|
||||
attribute_type :integer
|
||||
end
|
||||
|
|
|
@ -4,9 +4,11 @@ defmodule AshHq.Discord.Channel do
|
|||
"""
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Discord,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
create :upsert do
|
||||
|
@ -18,16 +20,20 @@ defmodule AshHq.Discord.Channel do
|
|||
integer_primary_key :id, writable?: true, generated?: false
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :order, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
has_many :threads, AshHq.Discord.Thread
|
||||
has_many :threads, AshHq.Discord.Thread do
|
||||
public? true
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
|
@ -36,7 +42,6 @@ defmodule AshHq.Discord.Channel do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Discord
|
||||
define :read
|
||||
define :upsert
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ defmodule AshHq.Discord.Message do
|
|||
Discord messages synchronized by the discord bot
|
||||
"""
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Discord,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [
|
||||
AshHq.Docs.Extensions.RenderMarkdown,
|
||||
|
@ -10,6 +11,8 @@ defmodule AshHq.Discord.Message do
|
|||
]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
|
||||
defaults [:read, :destroy]
|
||||
|
||||
create :create do
|
||||
|
@ -25,6 +28,7 @@ defmodule AshHq.Discord.Message do
|
|||
end
|
||||
|
||||
update :update do
|
||||
require_atomic? false
|
||||
primary? true
|
||||
argument :attachments, {:array, :map}
|
||||
argument :reactions, {:array, :map}
|
||||
|
@ -59,25 +63,37 @@ defmodule AshHq.Discord.Message do
|
|||
integer_primary_key :id, generated?: false, writable?: true
|
||||
|
||||
attribute :author, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :content, :string
|
||||
attribute :content_html, :string
|
||||
attribute :content, :string do
|
||||
public? true
|
||||
end
|
||||
attribute :content_html, :string do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :timestamp, :utc_datetime do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :thread, AshHq.Discord.Thread do
|
||||
public? true
|
||||
attribute_type :integer
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
has_many :attachments, AshHq.Discord.Attachment
|
||||
has_many :reactions, AshHq.Discord.Reaction
|
||||
has_many :attachments, AshHq.Discord.Attachment do
|
||||
public? true
|
||||
end
|
||||
|
||||
has_many :reactions, AshHq.Discord.Reaction do
|
||||
public? true
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
|
|
|
@ -3,9 +3,11 @@ defmodule AshHq.Discord.Reaction do
|
|||
Reactions store emoji reaction counts.
|
||||
"""
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Discord,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
end
|
||||
|
||||
|
@ -13,16 +15,19 @@ defmodule AshHq.Discord.Reaction do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :count, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :emoji, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :message, AshHq.Discord.Message do
|
||||
public? true
|
||||
attribute_type :integer
|
||||
allow_nil? false
|
||||
end
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
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,
|
||||
domain: AshHq.Discord,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
create :upsert do
|
||||
|
@ -16,14 +18,15 @@ defmodule AshHq.Discord.Tag do
|
|||
integer_primary_key :id, generated?: false, writable?: true
|
||||
|
||||
attribute :name, :ci_string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :channel, AshHq.Discord.Channel do
|
||||
public? true
|
||||
attribute_type :integer
|
||||
attribute_writable? true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -33,7 +36,6 @@ defmodule AshHq.Discord.Tag do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Discord
|
||||
define :upsert, args: [:channel_id, :id, :name]
|
||||
define :read
|
||||
define :destroy
|
||||
|
|
|
@ -4,11 +4,13 @@ defmodule AshHq.Discord.Thread do
|
|||
"""
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Discord,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
read :feed do
|
||||
|
@ -64,31 +66,39 @@ defmodule AshHq.Discord.Thread do
|
|||
|
||||
attributes do
|
||||
integer_primary_key :id, generated?: false, writable?: true
|
||||
attribute :type, :integer
|
||||
attribute :type, :integer do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :author, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :create_timestamp, :utc_datetime do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
has_many :messages, AshHq.Discord.Message
|
||||
has_many :messages, AshHq.Discord.Message do
|
||||
public? true
|
||||
end
|
||||
|
||||
belongs_to :channel, AshHq.Discord.Channel do
|
||||
public? true
|
||||
attribute_type :integer
|
||||
allow_nil? false
|
||||
attribute_writable? true
|
||||
end
|
||||
|
||||
many_to_many :tags, AshHq.Discord.Tag do
|
||||
public? true
|
||||
through AshHq.Discord.ThreadTag
|
||||
source_attribute_on_join_resource :thread_id
|
||||
destination_attribute_on_join_resource :tag_id
|
||||
|
@ -101,7 +111,6 @@ defmodule AshHq.Discord.Thread do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Discord
|
||||
define :upsert
|
||||
define :by_id, action: :read, get_by: [:id]
|
||||
define :feed, args: [:channel]
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
defmodule AshHq.Discord.ThreadTag do
|
||||
@moduledoc "Joins a thread to a tag"
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Discord,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:read, :destroy]
|
||||
|
||||
create :tag do
|
||||
|
@ -13,16 +15,16 @@ defmodule AshHq.Discord.ThreadTag do
|
|||
|
||||
relationships do
|
||||
belongs_to :thread, AshHq.Discord.Thread do
|
||||
public? true
|
||||
primary_key? true
|
||||
allow_nil? false
|
||||
attribute_writable? true
|
||||
attribute_type :integer
|
||||
end
|
||||
|
||||
belongs_to :tag, AshHq.Discord.Tag do
|
||||
public? true
|
||||
primary_key? true
|
||||
allow_nil? false
|
||||
attribute_writable? true
|
||||
attribute_type :integer
|
||||
end
|
||||
end
|
||||
|
@ -33,7 +35,6 @@ defmodule AshHq.Discord.ThreadTag do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Discord
|
||||
define :tag, args: [:thread_id, :tag_id]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,14 +2,12 @@ defmodule AshHq.Docs do
|
|||
@moduledoc """
|
||||
Handles documentation data.
|
||||
"""
|
||||
use Ash.Api,
|
||||
use Ash.Domain,
|
||||
extensions: [
|
||||
AshGraphql.Api,
|
||||
AshAdmin.Api
|
||||
AshGraphql.Domain,
|
||||
AshAdmin.Domain
|
||||
]
|
||||
|
||||
use AshHq.ApiHelpers
|
||||
|
||||
admin do
|
||||
show? true
|
||||
default_resource_page :primary_read
|
||||
|
@ -20,6 +18,14 @@ defmodule AshHq.Docs do
|
|||
end
|
||||
|
||||
resources do
|
||||
registry AshHq.Docs.Registry
|
||||
resource AshHq.Docs.Dsl
|
||||
resource AshHq.Docs.Extension
|
||||
resource AshHq.Docs.Function
|
||||
resource AshHq.Docs.Guide
|
||||
resource AshHq.Docs.Library
|
||||
resource AshHq.Docs.LibraryVersion
|
||||
resource AshHq.Docs.MixTask
|
||||
resource AshHq.Docs.Module
|
||||
resource AshHq.Docs.Option
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,7 +30,7 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown.Changes.RenderMarkdown do
|
|||
Ash.Changeset.get_attribute(changeset, :name)
|
||||
|
||||
changeset.resource == AshHq.Docs.Function ->
|
||||
AshHq.Docs.get!(
|
||||
Ash.get!(
|
||||
AshHq.Docs.Module,
|
||||
Ash.Changeset.get_attribute(changeset, :module_id)
|
||||
).name
|
||||
|
@ -49,7 +49,7 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown.Changes.RenderMarkdown do
|
|||
AshHq.Docs.Library
|
||||
|> Ash.Query.select(:name)
|
||||
|> Ash.Query.filter(versions.id == ^library_version_id)
|
||||
|> AshHq.Docs.read_one!()
|
||||
|> Ash.read_one!()
|
||||
|> Map.get(:name)
|
||||
end
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ defmodule AshHq.Docs.Extensions.Search.Transformers.AddSearchStructure do
|
|||
Ash.Resource.Dsl,
|
||||
[:attributes],
|
||||
:attribute,
|
||||
private?: true,
|
||||
name: config.sanitized_name_attribute,
|
||||
type: :string,
|
||||
allow_nil?: false
|
||||
|
|
|
@ -3,8 +3,8 @@ defmodule AshHq.Docs.Extensions.Search.Types do
|
|||
A static list of all search types that currently exist
|
||||
"""
|
||||
|
||||
@search_types [AshHq.Docs.Registry]
|
||||
|> Enum.flat_map(&Ash.Registry.Info.entries/1)
|
||||
@search_types [AshHq.Docs]
|
||||
|> Enum.flat_map(&Ash.Domain.Info.resources/1)
|
||||
|> Enum.filter(&(AshHq.Docs.Extensions.Search in Spark.extensions(&1)))
|
||||
|> Enum.map(&AshHq.Docs.Extensions.Search.type/1)
|
||||
|> Enum.uniq()
|
||||
|
|
|
@ -73,7 +73,7 @@ defmodule AshHq.Docs.Indexer do
|
|||
resource
|
||||
|> Ash.Query.filter(id in ^ids)
|
||||
|> Ash.Query.load(AshHq.Docs.Extensions.Search.load_for_search(resource))
|
||||
|> AshHq.Docs.read!()
|
||||
|> Ash.read!()
|
||||
|> Enum.map(fn item ->
|
||||
Ash.Resource.put_metadata(item, :search_score, scores[item.id])
|
||||
end)
|
||||
|
@ -125,7 +125,7 @@ defmodule AshHq.Docs.Indexer do
|
|||
defp dsls do
|
||||
AshHq.Docs.Dsl
|
||||
|> Ash.Query.load([:library_name, :extension_module])
|
||||
|> AshHq.Docs.stream!()
|
||||
|> Ash.stream!()
|
||||
|> Stream.map(fn dsl ->
|
||||
%{
|
||||
"id" => id("dsl", dsl.id),
|
||||
|
@ -140,7 +140,7 @@ defmodule AshHq.Docs.Indexer do
|
|||
defp guides do
|
||||
AshHq.Docs.Guide
|
||||
|> Ash.Query.load(library_version: :library)
|
||||
|> AshHq.Docs.stream!()
|
||||
|> Ash.stream!()
|
||||
|> Stream.map(fn guide ->
|
||||
%{
|
||||
"id" => id("guide", guide.id),
|
||||
|
@ -154,7 +154,7 @@ defmodule AshHq.Docs.Indexer do
|
|||
defp options do
|
||||
AshHq.Docs.Option
|
||||
|> Ash.Query.load([:library_name, :extension_module])
|
||||
|> AshHq.Docs.stream!()
|
||||
|> Ash.stream!()
|
||||
|> Stream.map(fn option ->
|
||||
%{
|
||||
"id" => id("option", option.id),
|
||||
|
@ -169,7 +169,7 @@ defmodule AshHq.Docs.Indexer do
|
|||
defp modules do
|
||||
AshHq.Docs.Module
|
||||
|> Ash.Query.load([:library_name])
|
||||
|> AshHq.Docs.stream!()
|
||||
|> Ash.stream!()
|
||||
|> Stream.map(fn module ->
|
||||
%{
|
||||
"id" => id("module", module.id),
|
||||
|
@ -184,7 +184,7 @@ defmodule AshHq.Docs.Indexer do
|
|||
defp mix_tasks do
|
||||
AshHq.Docs.MixTask
|
||||
|> Ash.Query.load([:library_name])
|
||||
|> AshHq.Docs.stream!()
|
||||
|> Ash.stream!()
|
||||
|> Stream.map(fn mix_task ->
|
||||
%{
|
||||
"id" => id("mix_task", mix_task.id),
|
||||
|
@ -199,7 +199,7 @@ defmodule AshHq.Docs.Indexer do
|
|||
defp functions do
|
||||
AshHq.Docs.Function
|
||||
|> Ash.Query.load([:library_name, :call_name])
|
||||
|> AshHq.Docs.stream!()
|
||||
|> Ash.stream!()
|
||||
|> Stream.map(fn function ->
|
||||
%{
|
||||
"id" => id("function", function.id),
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
defmodule AshHq.Docs.Registry do
|
||||
@moduledoc false
|
||||
use Ash.Registry,
|
||||
extensions: [Ash.Registry.ResourceValidations]
|
||||
|
||||
entries do
|
||||
entry AshHq.Docs.Dsl
|
||||
entry AshHq.Docs.Extension
|
||||
entry AshHq.Docs.Function
|
||||
entry AshHq.Docs.Guide
|
||||
entry AshHq.Docs.Library
|
||||
entry AshHq.Docs.LibraryVersion
|
||||
entry AshHq.Docs.MixTask
|
||||
entry AshHq.Docs.Module
|
||||
entry AshHq.Docs.Option
|
||||
end
|
||||
end
|
|
@ -2,10 +2,12 @@ defmodule AshHq.Docs.Dsl do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -57,39 +59,61 @@ defmodule AshHq.Docs.Dsl do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :requires_extension, :string
|
||||
attribute :requires_extension, :string do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :doc, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
constraints trim?: false, allow_empty?: true
|
||||
default ""
|
||||
end
|
||||
|
||||
attribute :doc_html, :string do
|
||||
public? true
|
||||
constraints trim?: false, allow_empty?: true
|
||||
writable? false
|
||||
end
|
||||
|
||||
attribute :imports, {:array, :string} do
|
||||
public? true
|
||||
default []
|
||||
end
|
||||
|
||||
attribute :examples, {:array, :string}
|
||||
attribute :args, {:array, :string}
|
||||
attribute :examples, {:array, :string} do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :args, {:array, :string} do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :optional_args, {:array, :string} do
|
||||
public? true
|
||||
default []
|
||||
end
|
||||
|
||||
attribute :arg_defaults, :map
|
||||
attribute :path, {:array, :string}
|
||||
attribute :recursive_as, :string
|
||||
attribute :order, :integer, allow_nil?: false
|
||||
attribute :arg_defaults, :map do
|
||||
public? true
|
||||
end
|
||||
attribute :path, {:array, :string} do
|
||||
public? true
|
||||
end
|
||||
attribute :recursive_as, :string do
|
||||
public? true
|
||||
end
|
||||
attribute :order, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :type, :atom do
|
||||
public? true
|
||||
allow_nil? false
|
||||
constraints one_of: [:entity, :section]
|
||||
end
|
||||
|
@ -99,16 +123,24 @@ defmodule AshHq.Docs.Dsl do
|
|||
|
||||
relationships do
|
||||
belongs_to :library_version, AshHq.Docs.LibraryVersion do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
belongs_to :extension, AshHq.Docs.Extension do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
belongs_to :dsl, __MODULE__
|
||||
has_many :options, AshHq.Docs.Option
|
||||
has_many :dsls, __MODULE__
|
||||
belongs_to :dsl, __MODULE__ do
|
||||
public? true
|
||||
end
|
||||
has_many :options, AshHq.Docs.Option do
|
||||
public? true
|
||||
end
|
||||
has_many :dsls, __MODULE__ do
|
||||
public? true
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
|
@ -124,7 +156,6 @@ defmodule AshHq.Docs.Dsl do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
define :read
|
||||
end
|
||||
|
||||
|
|
|
@ -2,9 +2,11 @@ defmodule AshHq.Docs.Extension do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -33,18 +35,25 @@ defmodule AshHq.Docs.Extension do
|
|||
attributes do
|
||||
uuid_primary_key :id
|
||||
|
||||
attribute :module, :string
|
||||
attribute :module, :string do
|
||||
public? true
|
||||
end
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :library_version, AshHq.Docs.LibraryVersion do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
has_many :dsls, AshHq.Docs.Dsl
|
||||
has_many :options, AshHq.Docs.Option
|
||||
has_many :dsls, AshHq.Docs.Dsl do
|
||||
public? true
|
||||
end
|
||||
has_many :options, AshHq.Docs.Option do
|
||||
public? true
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
|
@ -57,7 +66,6 @@ defmodule AshHq.Docs.Extension do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
|
||||
define :destroy
|
||||
end
|
||||
|
|
|
@ -2,10 +2,12 @@ defmodule AshHq.Docs.Function do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -51,45 +53,58 @@ defmodule AshHq.Docs.Function do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :file, :string
|
||||
attribute :line, :integer
|
||||
attribute :file, :string do
|
||||
public? true
|
||||
end
|
||||
attribute :line, :integer do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :arity, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :type, :atom do
|
||||
public? true
|
||||
constraints one_of: [:function, :macro, :callback, :type]
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :heads, {:array, :string} do
|
||||
public? true
|
||||
default []
|
||||
end
|
||||
|
||||
attribute :heads_html, {:array, :string} do
|
||||
public? true
|
||||
default []
|
||||
end
|
||||
|
||||
attribute :doc, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
constraints trim?: false, allow_empty?: true
|
||||
default ""
|
||||
end
|
||||
|
||||
attribute :doc_html, :string do
|
||||
public? true
|
||||
constraints trim?: false, allow_empty?: true
|
||||
writable? false
|
||||
end
|
||||
|
||||
attribute :order, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :deprecated, :string do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
|
@ -98,10 +113,12 @@ defmodule AshHq.Docs.Function do
|
|||
|
||||
relationships do
|
||||
belongs_to :library_version, AshHq.Docs.LibraryVersion do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
belongs_to :module, AshHq.Docs.Module do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
end
|
||||
|
@ -115,9 +132,6 @@ defmodule AshHq.Docs.Function do
|
|||
end
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
end
|
||||
|
||||
resource do
|
||||
description "A function in a module exposed by an Ash library"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule AshHq.Docs.Guide do
|
||||
@moduledoc false
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [
|
||||
AshHq.Docs.Extensions.Search,
|
||||
|
@ -10,6 +11,7 @@ defmodule AshHq.Docs.Guide do
|
|||
]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -66,39 +68,47 @@ defmodule AshHq.Docs.Guide do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :order, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :text, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
constraints trim?: false, allow_empty?: true
|
||||
default ""
|
||||
end
|
||||
|
||||
attribute :text_html, :string do
|
||||
public? true
|
||||
constraints trim?: false, allow_empty?: true
|
||||
writable? false
|
||||
end
|
||||
|
||||
attribute :category, :string do
|
||||
public? true
|
||||
default "Topics"
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :route, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :sanitized_route, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
writable? false
|
||||
end
|
||||
|
||||
attribute :default, :boolean do
|
||||
public? true
|
||||
default false
|
||||
allow_nil? false
|
||||
end
|
||||
|
@ -121,9 +131,6 @@ defmodule AshHq.Docs.Guide do
|
|||
end
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
end
|
||||
|
||||
resource do
|
||||
description "Represents a markdown guide exposed by a library"
|
||||
|
|
|
@ -75,7 +75,7 @@ defmodule AshHq.Docs.Library.Actions.Import do
|
|||
|
||||
Logger.info("Starting import of #{name}: #{version}")
|
||||
|
||||
if AshHq.Docs.exists?(
|
||||
if Ash.exists?(
|
||||
Ash.Query.for_read(AshHq.Docs.LibraryVersion, :read)
|
||||
|> Ash.Query.filter(library_id == ^library.id and version == ^version)
|
||||
) do
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
defmodule AshHq.Docs.Library do
|
||||
@moduledoc false
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshOban]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -31,6 +33,7 @@ defmodule AshHq.Docs.Library do
|
|||
end
|
||||
|
||||
update :import do
|
||||
require_atomic? false
|
||||
transaction? false
|
||||
|
||||
argument :metadata, :map do
|
||||
|
@ -49,7 +52,7 @@ defmodule AshHq.Docs.Library do
|
|||
end
|
||||
|
||||
oban do
|
||||
api AshHq.Docs
|
||||
domain AshHq.Docs
|
||||
|
||||
triggers do
|
||||
trigger :import do
|
||||
|
@ -69,32 +72,42 @@ defmodule AshHq.Docs.Library do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :display_name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :order, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :description, :string
|
||||
attribute :description, :string do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :repo_org, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
default "ash-project"
|
||||
end
|
||||
|
||||
attribute :module_prefixes, {:array, :string} do
|
||||
public? true
|
||||
allow_nil? false
|
||||
default []
|
||||
end
|
||||
|
||||
attribute :mix_project, :string
|
||||
attribute :mix_project, :string do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :skip_versions, {:array, :string} do
|
||||
public? true
|
||||
default []
|
||||
allow_nil? false
|
||||
end
|
||||
|
@ -103,9 +116,12 @@ defmodule AshHq.Docs.Library do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :versions, AshHq.Docs.LibraryVersion
|
||||
has_many :versions, AshHq.Docs.LibraryVersion do
|
||||
public? true
|
||||
end
|
||||
|
||||
has_one :latest_library_version, AshHq.Docs.LibraryVersion do
|
||||
public? true
|
||||
sort version: :desc
|
||||
from_many? true
|
||||
end
|
||||
|
@ -119,8 +135,6 @@ defmodule AshHq.Docs.Library do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
|
||||
define :read
|
||||
define :by_name, args: [:name], get?: true
|
||||
define :create
|
||||
|
|
|
@ -5,10 +5,10 @@ defmodule AshHq.Docs.Library.Preparations.FilterPendingImport do
|
|||
query
|
||||
|> Ash.Query.ensure_selected([:name])
|
||||
|> Ash.Query.load(:latest_version)
|
||||
|> Ash.Query.after_action(fn query, results ->
|
||||
|> Ash.Query.after_action(fn _query, results ->
|
||||
pending_import =
|
||||
results
|
||||
|> query.api.load!(:latest_version)
|
||||
|> Ash.load!(:latest_version)
|
||||
|> Enum.flat_map(fn result ->
|
||||
hex_info =
|
||||
Finch.build(:get, "https://hex.pm/api/packages/#{result.name}")
|
||||
|
|
|
@ -2,10 +2,12 @@ defmodule AshHq.Docs.LibraryVersion do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -90,10 +92,12 @@ defmodule AshHq.Docs.LibraryVersion do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :version, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :hydrated, :boolean do
|
||||
public? true
|
||||
default false
|
||||
allow_nil? false
|
||||
end
|
||||
|
@ -103,13 +107,22 @@ defmodule AshHq.Docs.LibraryVersion do
|
|||
|
||||
relationships do
|
||||
belongs_to :library, AshHq.Docs.Library do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
has_many :extensions, AshHq.Docs.Extension
|
||||
has_many :guides, AshHq.Docs.Guide
|
||||
has_many :modules, AshHq.Docs.Module
|
||||
has_many :mix_tasks, AshHq.Docs.MixTask
|
||||
has_many :extensions, AshHq.Docs.Extension do
|
||||
public? true
|
||||
end
|
||||
has_many :guides, AshHq.Docs.Guide do
|
||||
public? true
|
||||
end
|
||||
has_many :modules, AshHq.Docs.Module do
|
||||
public? true
|
||||
end
|
||||
has_many :mix_tasks, AshHq.Docs.MixTask do
|
||||
public? true
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
|
@ -118,7 +131,6 @@ defmodule AshHq.Docs.LibraryVersion do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
define :build, args: [:library, :version]
|
||||
define :defined_for, args: [:library, :versions]
|
||||
define :by_version, args: [:library, :version]
|
||||
|
|
|
@ -2,10 +2,12 @@ defmodule AshHq.Docs.MixTask do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -48,30 +50,39 @@ defmodule AshHq.Docs.MixTask do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :category, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
default "Misc"
|
||||
end
|
||||
|
||||
attribute :file, :string
|
||||
attribute :file, :string do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :module_name, :string
|
||||
attribute :module_name, :string do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :doc, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
constraints trim?: false, allow_empty?: true
|
||||
default ""
|
||||
end
|
||||
|
||||
attribute :doc_html, :string do
|
||||
public? true
|
||||
constraints trim?: false, allow_empty?: true
|
||||
writable? false
|
||||
end
|
||||
|
||||
attribute :order, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
|
@ -80,6 +91,7 @@ defmodule AshHq.Docs.MixTask do
|
|||
|
||||
relationships do
|
||||
belongs_to :library_version, AshHq.Docs.LibraryVersion do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
end
|
||||
|
@ -93,9 +105,6 @@ defmodule AshHq.Docs.MixTask do
|
|||
end
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
end
|
||||
|
||||
resource do
|
||||
description "Represents a mix task that has been exposed by a library"
|
||||
|
|
|
@ -2,10 +2,12 @@ defmodule AshHq.Docs.Module do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -51,28 +53,35 @@ defmodule AshHq.Docs.Module do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :category, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
default "Misc"
|
||||
end
|
||||
|
||||
attribute :file, :string
|
||||
attribute :file, :string do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :doc, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
constraints trim?: false, allow_empty?: true
|
||||
default ""
|
||||
end
|
||||
|
||||
attribute :doc_html, :string do
|
||||
public? true
|
||||
constraints trim?: false, allow_empty?: true
|
||||
writable? false
|
||||
end
|
||||
|
||||
attribute :order, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
|
@ -81,10 +90,13 @@ defmodule AshHq.Docs.Module do
|
|||
|
||||
relationships do
|
||||
belongs_to :library_version, AshHq.Docs.LibraryVersion do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
has_many :functions, AshHq.Docs.Function
|
||||
has_many :functions, AshHq.Docs.Function do
|
||||
public? true
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
|
@ -96,9 +108,6 @@ defmodule AshHq.Docs.Module do
|
|||
end
|
||||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
end
|
||||
|
||||
resource do
|
||||
description "Represents a module that has been exposed by a library"
|
||||
|
|
|
@ -2,10 +2,12 @@ defmodule AshHq.Docs.Option do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Docs,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:update, :destroy]
|
||||
|
||||
read :read do
|
||||
|
@ -53,52 +55,70 @@ defmodule AshHq.Docs.Option do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :name, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :type, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
attribute :doc, :string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
constraints trim?: false, allow_empty?: true
|
||||
default ""
|
||||
end
|
||||
|
||||
attribute :doc_html, :string do
|
||||
public? true
|
||||
constraints trim?: false, allow_empty?: true
|
||||
writable? false
|
||||
end
|
||||
|
||||
attribute :required, :boolean do
|
||||
public? true
|
||||
allow_nil? false
|
||||
default false
|
||||
end
|
||||
|
||||
attribute :argument_index, :integer
|
||||
attribute :argument_index, :integer do
|
||||
public? true
|
||||
end
|
||||
|
||||
attribute :links, :map do
|
||||
public? true
|
||||
default %{}
|
||||
end
|
||||
|
||||
attribute :default, :string
|
||||
attribute :path, {:array, :string}
|
||||
attribute :order, :integer, allow_nil?: false
|
||||
attribute :default, :string do
|
||||
public? true
|
||||
end
|
||||
attribute :path, {:array, :string} do
|
||||
public? true
|
||||
end
|
||||
attribute :order, :integer do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :dsl, AshHq.Docs.Dsl do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
belongs_to :library_version, AshHq.Docs.LibraryVersion do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
belongs_to :extension, AshHq.Docs.Extension do
|
||||
public? true
|
||||
allow_nil? true
|
||||
end
|
||||
end
|
||||
|
@ -114,7 +134,6 @@ defmodule AshHq.Docs.Option do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Docs
|
||||
define :read
|
||||
end
|
||||
|
||||
|
|
|
@ -5,9 +5,8 @@ defmodule AshHq.Github.Contributor.Actions.Import do
|
|||
|
||||
def run(_input, _, _) do
|
||||
AshHq.Docs.Library
|
||||
|> AshHq.Docs.read!()
|
||||
|> Ash.stream!()
|
||||
|> Stream.flat_map(fn library ->
|
||||
:timer.sleep(1000)
|
||||
opts = []
|
||||
|
||||
opts =
|
||||
|
@ -33,7 +32,7 @@ defmodule AshHq.Github.Contributor.Actions.Import do
|
|||
Map.put(contributor, "order", index)
|
||||
end)
|
||||
|> Stream.uniq_by(&Map.get(&1, "id"))
|
||||
|> AshHq.Github.bulk_create(AshHq.Github.Contributor, :create,
|
||||
|> Ash.bulk_create(AshHq.Github.Contributor, :create,
|
||||
upsert?: true,
|
||||
upsert_fields: [:order, :login, :avatar_url, :html_url],
|
||||
return_errors?: true,
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
defmodule AshHq.Github.Contributor do
|
||||
@moduledoc "A contributor to any package deployed on Ash HQ."
|
||||
use Ash.Resource,
|
||||
domain: AshHq.Github,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshOban]
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
read :in_order do
|
||||
|
@ -19,7 +21,7 @@ defmodule AshHq.Github.Contributor do
|
|||
end
|
||||
|
||||
oban do
|
||||
api AshHq.Github
|
||||
domain AshHq.Github
|
||||
|
||||
scheduled_actions do
|
||||
schedule :import, "0 */6 * * *" do
|
||||
|
@ -34,10 +36,10 @@ defmodule AshHq.Github.Contributor do
|
|||
writable? true
|
||||
end
|
||||
|
||||
attribute :login, :string, allow_nil?: false
|
||||
attribute :avatar_url, :string, allow_nil?: false
|
||||
attribute :html_url, :string, allow_nil?: false
|
||||
attribute :order, :integer, allow_nil?: false
|
||||
attribute :login, :string, allow_nil?: false, public?: true
|
||||
attribute :avatar_url, :string, allow_nil?: false, public?: true
|
||||
attribute :html_url, :string, allow_nil?: false, public?: true
|
||||
attribute :order, :integer, allow_nil?: false, public?: true
|
||||
end
|
||||
|
||||
postgres do
|
||||
|
@ -46,7 +48,6 @@ defmodule AshHq.Github.Contributor do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.Github
|
||||
|
||||
define :in_order
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
defmodule AshHq.Github do
|
||||
@moduledoc "Api for interacting with data synchronized from github."
|
||||
use Ash.Api
|
||||
@moduledoc "Domain for interacting with data synchronized from github."
|
||||
use Ash.Domain
|
||||
|
||||
resources do
|
||||
resource AshHq.Github.Contributor
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
defmodule AshHq.MailingList.EmailNotifier do
|
||||
@moduledoc "Sends emails from events in the MailingList api"
|
||||
@moduledoc "Sends emails from events in the MailingList domain"
|
||||
use Ash.Notifier
|
||||
|
||||
def notify(%Ash.Notifier.Notification{
|
||||
|
|
|
@ -2,9 +2,9 @@ defmodule AshHq.MailingList do
|
|||
@moduledoc """
|
||||
Handles documentation data.
|
||||
"""
|
||||
use Ash.Api, otp_app: :ash_hq
|
||||
use Ash.Domain, otp_app: :ash_hq
|
||||
|
||||
resources do
|
||||
registry AshHq.MailingList.Registry
|
||||
resource AshHq.MailingList.Email
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
defmodule AshHq.MailingList.Registry do
|
||||
@moduledoc false
|
||||
use Ash.Registry,
|
||||
extensions: [Ash.Registry.ResourceValidations]
|
||||
|
||||
entries do
|
||||
entry AshHq.MailingList.Email
|
||||
end
|
||||
end
|
|
@ -2,10 +2,12 @@ defmodule AshHq.MailingList.Email do
|
|||
@moduledoc false
|
||||
|
||||
use Ash.Resource,
|
||||
domain: AshHq.MailingList,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
notifiers: AshHq.MailingList.EmailNotifier
|
||||
|
||||
actions do
|
||||
default_accept :*
|
||||
defaults [:create, :read]
|
||||
end
|
||||
|
||||
|
@ -13,6 +15,7 @@ defmodule AshHq.MailingList.Email do
|
|||
uuid_primary_key :id
|
||||
|
||||
attribute :email, :ci_string do
|
||||
public? true
|
||||
allow_nil? false
|
||||
end
|
||||
|
||||
|
@ -25,8 +28,6 @@ defmodule AshHq.MailingList.Email do
|
|||
end
|
||||
|
||||
code_interface do
|
||||
define_for AshHq.MailingList
|
||||
|
||||
define :all, action: :read
|
||||
end
|
||||
|
||||
|
|
|
@ -13,12 +13,4 @@ defmodule AshHqWeb.LiveUserAuth do
|
|||
{:cont, assign(socket, :current_user, nil)}
|
||||
end
|
||||
end
|
||||
|
||||
def on_mount(:live_user_required, _params, _session, socket) do
|
||||
if socket.assigns[:current_user] do
|
||||
{:cont, socket}
|
||||
else
|
||||
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/sign-in")}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -224,7 +224,7 @@ defmodule AshHqWeb.Pages.Docs do
|
|||
|> load_for_search()
|
||||
|
||||
new_libraries =
|
||||
AshHq.Docs.load!(socket.assigns.libraries, versions: [guides: guides_query])
|
||||
Ash.load!(socket.assigns.libraries, versions: [guides: guides_query])
|
||||
|
||||
assign(socket, :libraries, new_libraries)
|
||||
end
|
||||
|
@ -331,7 +331,7 @@ defmodule AshHqWeb.Pages.Docs do
|
|||
resource
|
||||
|> Ash.Query.select(field)
|
||||
|> Ash.Query.filter(id == ^record.id)
|
||||
|> AshHq.Docs.read_one!()
|
||||
|> Ash.read_one!()
|
||||
|> Map.get(field)
|
||||
|
||||
Map.put(record, field, value)
|
||||
|
|
|
@ -97,7 +97,7 @@ defmodule AshHqWeb.Pages.Forum do
|
|||
|> Ash.Query.filter(channel_id == ^socket.assigns.channel.id)
|
||||
|> Ash.Query.select(:name)
|
||||
|> Ash.Query.sort(:name)
|
||||
|> AshHq.Discord.read!()
|
||||
|> Ash.read!()
|
||||
|> Enum.map(&to_string(&1.name))
|
||||
|
||||
assign(socket, :tags, tags)
|
||||
|
|
|
@ -489,7 +489,6 @@ defmodule AshHqWeb.Pages.Home do
|
|||
contributors: contributors,
|
||||
email_form:
|
||||
AshPhoenix.Form.for_create(AshHq.MailingList.Email, :create,
|
||||
api: AshHq.MailingList,
|
||||
upsert?: true,
|
||||
upsert_identity: :unique_email
|
||||
)
|
||||
|
@ -638,6 +637,7 @@ defmodule AshHqWeb.Pages.Home do
|
|||
@post_example """
|
||||
defmodule Example.Post do
|
||||
use Ash.Resource,
|
||||
domain: Example,
|
||||
data_layer: AshPostgres.DataLayer
|
||||
|
||||
resource do
|
||||
|
|
|
@ -3,8 +3,7 @@ defmodule AshHqWeb.SessionPlug do
|
|||
@behaviour Plug
|
||||
|
||||
@cookies_to_replicate [
|
||||
"theme",
|
||||
"selected_types"
|
||||
"theme"
|
||||
]
|
||||
|
||||
def init(_), do: []
|
||||
|
|
|
@ -9,7 +9,7 @@ defmodule AshHqWeb.RedirectToHex do
|
|||
AshHq.Docs.Module
|
||||
|> Ash.Query.filter(name == ^dsl_target or sanitized_name == ^dsl_target)
|
||||
|> Ash.Query.load(to_load)
|
||||
|> AshHq.Docs.read_one()
|
||||
|> Ash.read_one()
|
||||
|> case do
|
||||
{:ok, module} when not is_nil(module) ->
|
||||
{:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))}
|
||||
|
@ -30,7 +30,7 @@ defmodule AshHqWeb.RedirectToHex do
|
|||
AshHq.Docs.MixTask
|
||||
|> Ash.Query.filter(name == ^mix_task or sanitized_name == ^mix_task)
|
||||
|> Ash.Query.load(to_load)
|
||||
|> AshHq.Docs.read_one()
|
||||
|> Ash.read_one()
|
||||
|> case do
|
||||
{:ok, module} when not is_nil(module) ->
|
||||
{:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))}
|
||||
|
@ -51,7 +51,7 @@ defmodule AshHqWeb.RedirectToHex do
|
|||
AshHq.Docs.Module
|
||||
|> Ash.Query.filter(name == ^module or sanitized_name == ^module)
|
||||
|> Ash.Query.load(to_load)
|
||||
|> AshHq.Docs.read_one()
|
||||
|> Ash.read_one()
|
||||
|> case do
|
||||
{:ok, module} when not is_nil(module) ->
|
||||
{:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))}
|
||||
|
@ -67,7 +67,7 @@ defmodule AshHqWeb.RedirectToHex do
|
|||
AshHq.Docs.Module
|
||||
|> Ash.Query.filter(name == ^module or sanitized_name == ^module)
|
||||
|> Ash.Query.load(to_load)
|
||||
|> AshHq.Docs.read_one()
|
||||
|> Ash.read_one()
|
||||
|> case do
|
||||
{:ok, module} when not is_nil(module) ->
|
||||
{:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))}
|
||||
|
|
|
@ -10,12 +10,10 @@ defmodule AshHqWeb.Router do
|
|||
plug(:put_root_layout, {AshHqWeb.LayoutView, :root})
|
||||
plug(:protect_from_forgery)
|
||||
plug(AshHqWeb.SessionPlug)
|
||||
plug(:load_from_session)
|
||||
end
|
||||
|
||||
pipeline :api do
|
||||
plug(:accepts, ["json"])
|
||||
plug(:load_from_bearer)
|
||||
end
|
||||
|
||||
pipeline :admin_basic_auth do
|
||||
|
|
|
@ -2,9 +2,9 @@ defmodule AshHqWeb.Schema do
|
|||
@moduledoc "The absinthe graphql schema"
|
||||
use Absinthe.Schema
|
||||
|
||||
@apis [AshHq.Docs]
|
||||
@domains [AshHq.Docs]
|
||||
|
||||
use AshGraphql, apis: @apis
|
||||
use AshGraphql, domains: @domains
|
||||
|
||||
query do
|
||||
end
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" class="<%= "#{@configured_theme}" %>">
|
||||
<html lang="en" class={@configured_theme}>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<%= csrf_meta_tag() %>
|
||||
<%= live_title_tag assigns[:page_title] || "Ash Framework" %>
|
||||
<.live_title>
|
||||
<%= assigns[:page_title] || "Ash Framework" %>
|
||||
</.live_title>
|
||||
<%= if Application.get_env(:ash_hq, :analytics?) do %>
|
||||
<script defer data-domain="ash-hq.org" src="https://plausible.io/js/plausible.js"></script>
|
||||
<% end %>
|
||||
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.css" />
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.2/jquery.min.js"></script>
|
||||
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/assets/app.css") %>"/>
|
||||
<link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
|
||||
</head>
|
||||
<body class="h-full">
|
||||
<%= case live_flash(@flash, :info) do %>
|
||||
|
@ -34,6 +36,6 @@
|
|||
<%= if @live_action == :media do %>
|
||||
<script src="https://platform.twitter.com/widgets.js" charset="utf-8" ></script>
|
||||
<% end %>
|
||||
<script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/assets/app.js") %>"></script>
|
||||
<script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
|
||||
</body>
|
||||
</html>
|
|
@ -41,7 +41,6 @@ defmodule AshHqWeb.AppViewLive do
|
|||
uri={@uri}
|
||||
close={close_search()}
|
||||
libraries={@libraries}
|
||||
selected_types={@selected_types}
|
||||
change_types="change-types"
|
||||
change_versions="change-versions"
|
||||
remove_version="remove_version"
|
||||
|
@ -158,23 +157,6 @@ defmodule AshHqWeb.AppViewLive do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("change-types", %{"types" => types}, socket) do
|
||||
types =
|
||||
types
|
||||
|> Enum.filter(fn {_, value} ->
|
||||
value == "true"
|
||||
end)
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(
|
||||
:selected_types,
|
||||
types
|
||||
)
|
||||
|> push_event("selected-types", %{types: types})}
|
||||
end
|
||||
|
||||
def handle_event("toggle_theme", _, socket) do
|
||||
theme =
|
||||
case socket.assigns.configured_theme do
|
||||
|
@ -206,19 +188,6 @@ defmodule AshHqWeb.AppViewLive do
|
|||
|
||||
configured_theme = session["theme"] || "system"
|
||||
|
||||
all_types = AshHq.Docs.Extensions.Search.Types.types()
|
||||
|
||||
selected_types =
|
||||
case session["selected_types"] do
|
||||
nil ->
|
||||
AshHq.Docs.Extensions.Search.Types.types()
|
||||
|
||||
types ->
|
||||
types
|
||||
|> String.split(",")
|
||||
|> Enum.filter(&(&1 in all_types))
|
||||
end
|
||||
|
||||
versions_query =
|
||||
AshHq.Docs.LibraryVersion
|
||||
|> Ash.Query.sort(version: :desc)
|
||||
|
@ -228,12 +197,7 @@ defmodule AshHqWeb.AppViewLive do
|
|||
{:ok,
|
||||
socket
|
||||
|> assign(:libraries, libraries)
|
||||
|> assign(
|
||||
:selected_types,
|
||||
selected_types
|
||||
)
|
||||
|> assign(configured_theme: configured_theme)
|
||||
|> push_event("selected_types", %{types: selected_types})}
|
||||
|> assign(configured_theme: configured_theme)}
|
||||
end
|
||||
|
||||
def toggle_search(js \\ %JS{}) do
|
||||
|
|
4
mix.exs
4
mix.exs
|
@ -39,7 +39,8 @@ defmodule AshHq.MixProject do
|
|||
# Type `mix help deps` for examples and options.
|
||||
defp deps do
|
||||
[
|
||||
{:ash, "~> 3.0.0-rc"},
|
||||
# {:ash, "~> 3.0.0-rc"},
|
||||
{:ash, path: "../../ash/ash", override: true},
|
||||
{:ash_postgres, "~> 2.0.0-rc"},
|
||||
{:ash_admin, "~> 0.10.10-rc"},
|
||||
{:ash_phoenix, "~> 2.0.0-rc"},
|
||||
|
@ -99,6 +100,7 @@ defmodule AshHq.MixProject do
|
|||
{:phoenix_html, "~> 4.0"},
|
||||
{:phoenix_live_reload, "~> 1.2", only: :dev},
|
||||
{:phoenix_live_view, "~> 0.18"},
|
||||
{:html_entities, "~> 0.5"},
|
||||
# locked for compatibility
|
||||
{:finch, "~> 0.10"},
|
||||
{:floki, "~> 0.30"},
|
||||
|
|
3
mix.lock
3
mix.lock
|
@ -44,7 +44,7 @@
|
|||
"equivalex": {:hex, :equivalex, "1.0.3", "170d9a82ae066e0020dfe1cf7811381669565922eb3359f6c91d7e9a1124ff74", [:mix], [], "hexpm", "46fa311adb855117d36e461b9c0ad2598f72110ad17ad73d7533c78020e045fc"},
|
||||
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
|
||||
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
|
||||
"ets": {:hex, :ets, "0.8.1", "8ff9bcda5682b98493f8878fc9dbd990e48d566cba8cce59f7c2a78130da29ea", [:mix], [], "hexpm", "6be41b50adb5bc5c43626f25ea2d0af1f4a242fb3fad8d53f0c67c20b78915cc"},
|
||||
"ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"},
|
||||
"ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"},
|
||||
"excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"},
|
||||
|
@ -61,6 +61,7 @@
|
|||
"hackney": {:hex, :hackney, "1.17.1", "08463f93d2cc1a03817bf28d8dae6021543f773bd436c9377047224856c4422c", [:rebar3], [{:certifi, "~> 2.5", [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", [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", "d2cba9e3c8103ad0320623e9f1c33e8d378a15eaabe2ee8ae441898f3d35a18c"},
|
||||
"haystack": {:hex, :haystack, "0.1.0", "6cb9c72caf40ed4a5f9a094e6b09993c68c3fda0e01280c60c331a19860c504c", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:stemmer, "~> 1.1", [hex: :stemmer, repo: "hexpm", optional: false]}], "hexpm", "27a582513ef933c1b11345b96f8d41ee137d03b25312bd85068ffe8fec503635"},
|
||||
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
|
||||
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
|
||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
|
||||
"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"},
|
||||
|
|
Loading…
Reference in a new issue