Compare commits

..

18 Commits

Author SHA1 Message Date
CI
64788e73de chore: release version v1.68.1 2025-06-09 12:25:10 +00:00
Dmitry Popov
114fd471e8 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-06-09 14:24:37 +02:00
Dmitry Popov
b24a3120d3 fix(Core): Fixed auth from welcome page if invites disabled 2025-06-09 14:24:35 +02:00
CI
c5f93b3d0a chore: release version v1.68.0
Some checks failed
Build / 🛠 Build (1.17, 18.x, 27) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/amd64) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/arm64) (push) Has been cancelled
Build / merge (push) Has been cancelled
Build / 🏷 Create Release (push) Has been cancelled
2025-06-09 08:20:31 +00:00
Dmitry Popov
79290e4721 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-06-09 10:19:56 +02:00
Dmitry Popov
984e126f23 feat(Core): Added invites store support 2025-06-09 10:19:53 +02:00
CI
cd1ad31aed chore: release version v1.67.5
Some checks failed
Build / 🛠 Build (1.17, 18.x, 27) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/amd64) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/arm64) (push) Has been cancelled
Build / merge (push) Has been cancelled
Build / 🏷 Create Release (push) Has been cancelled
2025-06-08 19:05:08 +00:00
Dmitry Popov
1e3f6cf9e7 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-06-08 21:04:38 +02:00
Dmitry Popov
9c6ccd9a8a fix(Core): Added back ARM docker image build 2025-06-08 21:04:34 +02:00
CI
681ba21d39 chore: release version v1.67.4 2025-06-08 18:56:40 +00:00
Dmitry Popov
aef62189ee Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-06-08 20:56:07 +02:00
Dmitry Popov
09f70ac817 fix(Core): Fixed issue with system splash updates 2025-06-08 20:55:57 +02:00
CI
1eacb22143 chore: release version v1.67.3 2025-06-08 18:55:40 +00:00
Dmitry Popov
8524bad377 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-06-08 20:55:10 +02:00
Dmitry Popov
9d899243d1 fix(Core): Fixed issue with system splash updates 2025-06-08 20:54:59 +02:00
CI
9acf20a639 chore: release version v1.67.2 2025-06-08 16:57:01 +00:00
Dmitry Popov
71ef6b2e82 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-06-08 18:56:35 +02:00
Dmitry Popov
5e34d95dd2 chore: release version v1.66.25 2025-06-08 18:56:32 +02:00
20 changed files with 685 additions and 83 deletions

View File

@@ -116,7 +116,7 @@ jobs:
matrix:
platform:
- linux/amd64
- linux/arm64
steps:
- name: Prepare
run: |

View File

@@ -2,6 +2,56 @@
<!-- changelog -->
## [v1.68.1](https://github.com/wanderer-industries/wanderer/compare/v1.68.0...v1.68.1) (2025-06-09)
### Bug Fixes:
* Core: Fixed auth from welcome page if invites disabled
## [v1.68.0](https://github.com/wanderer-industries/wanderer/compare/v1.67.5...v1.68.0) (2025-06-09)
### Features:
* Core: Added invites store support
## [v1.67.5](https://github.com/wanderer-industries/wanderer/compare/v1.67.4...v1.67.5) (2025-06-08)
### Bug Fixes:
* Core: Added back ARM docker image build
## [v1.67.4](https://github.com/wanderer-industries/wanderer/compare/v1.67.3...v1.67.4) (2025-06-08)
### Bug Fixes:
* Core: Fixed issue with system splash updates
## [v1.67.3](https://github.com/wanderer-industries/wanderer/compare/v1.67.2...v1.67.3) (2025-06-08)
### Bug Fixes:
* Core: Fixed issue with system splash updates
## [v1.67.2](https://github.com/wanderer-industries/wanderer/compare/v1.67.1...v1.67.2) (2025-06-08)
## [v1.67.1](https://github.com/wanderer-industries/wanderer/compare/v1.67.0...v1.67.1) (2025-06-08)

View File

@@ -117,6 +117,7 @@ config :wanderer_app,
admins: admins,
corp_id: System.get_env("WANDERER_CORP_ID", "-1") |> String.to_integer(),
corp_wallet: System.get_env("WANDERER_CORP_WALLET", ""),
corp_wallet_eve_id: System.get_env("WANDERER_CORP_WALLET_EVE_ID", "-1") |> String.to_integer(),
public_api_disabled: public_api_disabled,
character_tracking_pause_disabled:
System.get_env("WANDERER_CHARACTER_TRACKING_PAUSE_DISABLED", "true")

View File

@@ -29,5 +29,6 @@ defmodule WandererApp.Api do
resource WandererApp.Api.CorpWalletTransaction
resource WandererApp.Api.License
resource WandererApp.Api.MapPing
resource WandererApp.Api.MapInvite
end
end

View File

@@ -0,0 +1,96 @@
defmodule WandererApp.Api.MapInvite do
@moduledoc false
use Ash.Resource,
domain: WandererApp.Api,
data_layer: AshPostgres.DataLayer
postgres do
repo(WandererApp.Repo)
table("map_invites_v1")
end
code_interface do
define(:new, action: :new)
define(:read, action: :read)
define(:destroy, action: :destroy)
define(:by_id,
get_by: [:id],
action: :read
)
define(:by_map,
action: :by_map
)
end
actions do
default_accept [
:token
]
defaults [:read, :update, :destroy]
create :new do
accept [
:map_id,
:token,
:type,
:valid_until
]
primary?(true)
argument :map_id, :uuid, allow_nil?: true
change manage_relationship(:map_id, :map, on_lookup: :relate, on_no_match: nil)
end
read :by_map do
argument(:map_id, :string, allow_nil?: false)
filter(expr(map_id == ^arg(:map_id)))
end
end
attributes do
uuid_primary_key :id
attribute :token, :string do
allow_nil? true
end
attribute :type, :atom do
default "user"
constraints(
one_of: [
:user,
:admin
]
)
allow_nil?(false)
end
attribute :valid_until, :utc_datetime do
allow_nil? true
end
create_timestamp(:inserted_at)
update_timestamp(:updated_at)
end
relationships do
belongs_to :map, WandererApp.Api.Map do
attribute_writable? true
end
end
postgres do
references do
reference :map, on_delete: :delete
end
end
end

View File

@@ -179,20 +179,24 @@ defmodule WandererApp.Character do
end
def search(character_id, opts \\ []) do
{:ok, %{access_token: access_token, eve_id: eve_id} = _character} =
get_character(character_id)
get_character(character_id)
|> case do
{:ok, %{access_token: access_token, eve_id: eve_id} = _character} ->
case WandererApp.Esi.search(eve_id |> String.to_integer(),
access_token: access_token,
character_id: character_id,
refresh_token?: true,
params: opts[:params]
) do
{:ok, result} ->
{:ok, result |> prepare_search_results()}
case WandererApp.Esi.search(eve_id |> String.to_integer(),
access_token: access_token,
character_id: character_id,
refresh_token?: true,
params: opts[:params]
) do
{:ok, result} ->
{:ok, result |> prepare_search_results()}
error ->
Logger.warning("#{__MODULE__} failed search: #{inspect(error)}")
{:ok, []}
end
error ->
Logger.warning("#{__MODULE__} failed search: #{inspect(error)}")
{:ok, []}
end
end
@@ -203,9 +207,9 @@ defmodule WandererApp.Character do
def can_track_wallet?(_), do: false
def can_track_corp_wallet?(%{scopes: scopes} = _character) when not is_nil(scopes) do
scopes |> String.split(" ") |> Enum.member?(@read_corp_wallet_scope)
end
def can_track_corp_wallet?(%{scopes: scopes} = _character)
when not is_nil(scopes),
do: scopes |> String.split(" ") |> Enum.member?(@read_corp_wallet_scope)
def can_track_corp_wallet?(_), do: false

View File

@@ -463,8 +463,7 @@ defmodule WandererApp.Character.Tracker do
) do
case WandererApp.Character.get_character(character_id) do
{:ok, %{eve_id: eve_id, access_token: access_token}} when not is_nil(access_token) ->
(WandererApp.Cache.has_key?("character:#{character_id}:location_forbidden") ||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused")
|> case do
true ->
{:error, :skipped}

View File

@@ -54,7 +54,8 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
{:ok, latest_transactions} = WandererApp.Api.CorpWalletTransaction.latest()
case WandererApp.Character.can_track_corp_wallet?(character) do
case character.eve_id == WandererApp.Env.corp_wallet_eve_id() &&
WandererApp.Character.can_track_corp_wallet?(character) do
true ->
Process.send_after(self(), :update_corp_wallets, 500)
Process.send_after(self(), :check_wallets, 500)

View File

@@ -24,6 +24,7 @@ defmodule WandererApp.Env do
def admin_username, do: get_key(:admin_username)
def admin_password, do: get_key(:admin_password)
def corp_wallet, do: get_key(:corp_wallet, "")
def corp_wallet_eve_id, do: get_key(:corp_wallet_eve_id, -1)
def corp_eve_id, do: get_key(:corp_id, -1)
def subscription_settings, do: get_key(:subscription_settings)

View File

@@ -16,7 +16,7 @@ defmodule WandererApp.StartCorpWalletTrackerTask do
user_hash ->
user_hash
|> _get_user_characters()
|> get_user_characters()
|> maybe_start_corp_wallet_tracker()
end
end
@@ -25,7 +25,8 @@ defmodule WandererApp.StartCorpWalletTrackerTask do
admin_character =
user_characters
|> Enum.find(fn character ->
WandererApp.Character.can_track_corp_wallet?(character)
character.eve_id == WandererApp.Env.corp_wallet_eve_id() &&
WandererApp.Character.can_track_corp_wallet?(character)
end)
if not is_nil(admin_character) do
@@ -41,12 +42,12 @@ defmodule WandererApp.StartCorpWalletTrackerTask do
def maybe_start_corp_wallet_tracker(_), do: :ok
defp _get_user_characters(user_hash) when not is_nil(user_hash) and is_binary(user_hash) do
defp get_user_characters(user_hash) when not is_nil(user_hash) and is_binary(user_hash) do
case WandererApp.Api.User.by_hash(user_hash, load: :characters) do
{:ok, user} -> {:ok, user.characters}
{:error, _} -> {:ok, []}
end
end
defp _get_user_characters(_), do: {:ok, []}
defp get_user_characters(_), do: {:ok, []}
end

View File

@@ -224,12 +224,11 @@ defmodule WandererApp.Map.Server.CharactersImpl do
Task.start_link(fn ->
character_updates =
maybe_update_online(map_id, character_id) ++
maybe_update_tracking_status(map_id, character_id)
maybe_update_location(map_id, character_id) ++
maybe_update_ship(map_id, character_id) ++
maybe_update_alliance(map_id, character_id) ++
maybe_update_corporation(map_id, character_id)
maybe_update_tracking_status(map_id, character_id) ++
maybe_update_location(map_id, character_id) ++
maybe_update_ship(map_id, character_id) ++
maybe_update_alliance(map_id, character_id) ++
maybe_update_corporation(map_id, character_id)
character_updates
|> Enum.filter(fn update -> update != :skip end)

View File

@@ -20,17 +20,9 @@ defmodule WandererApp.Ueberauth.Strategy.Eve do
is_admin? = Map.get(params, "admin", "false") in ~w(true 1)
invite_token = Map.get(params, "invite", nil)
invite_token_valid =
case WandererApp.Env.invites() do
true ->
case invite_token do
nil -> false
token -> WandererApp.Cache.lookup!("invite_#{token}", false)
end
{invite_token_valid, invite_type} = check_invite_valid(invite_token)
_ ->
true
end
is_admin? = is_admin? || invite_type == :admin
case invite_token_valid do
true ->
@@ -218,4 +210,33 @@ defmodule WandererApp.Ueberauth.Strategy.Eve do
defp option(conn, key) do
Keyword.get(options(conn), key, Keyword.get(default_options(), key))
end
defp check_invite_valid(invite_token) do
case invite_token do
token when not is_nil(token) and token != "" ->
check_token_valid(token)
_ ->
{not WandererApp.Env.invites(), :user}
end
end
defp check_token_valid(token) do
WandererApp.Cache.lookup!("invite_#{token}", false)
|> case do
true -> {true, :user}
_ -> check_map_token_valid(token)
end
end
def check_map_token_valid(token) do
{:ok, invites} = WandererApp.Api.MapInvite.read()
invites
|> Enum.find(fn invite -> invite.token == token end)
|> case do
nil -> {false, nil}
invite -> {true, invite.type}
end
end
end

View File

@@ -15,7 +15,8 @@ defmodule WandererAppWeb.AdminLive do
corp_wallet_character =
socket.assigns.current_user.characters
|> Enum.find(fn character ->
WandererApp.Character.can_track_corp_wallet?(character)
character.eve_id == WandererApp.Env.corp_wallet_eve_id() &&
WandererApp.Character.can_track_corp_wallet?(character)
end)
Phoenix.PubSub.subscribe(
@@ -58,7 +59,6 @@ defmodule WandererAppWeb.AdminLive do
socket
|> assign(
active_map_subscriptions: active_map_subscriptions,
show_invites?: WandererApp.Env.invites(),
user_character_ids: user_character_ids,
user_id: user_id,
invite_link: nil,
@@ -77,21 +77,6 @@ defmodule WandererAppWeb.AdminLive do
{:noreply, apply_action(socket, socket.assigns.live_action, params, uri)}
end
def handle_event("generate-invite-link", _params, socket) do
uuid = UUID.uuid4(:default)
WandererApp.Cache.put("invite_#{uuid}", true, ttl: @invite_link_ttl)
invite_link =
socket.assigns.uri
|> Map.put(:path, "/welcome")
|> Map.put(:query, URI.encode_query(%{invite: uuid}))
|> URI.to_string()
{:noreply,
socket
|> assign(invite_link: invite_link)}
end
@impl true
def handle_event("update-eve-db-data", _params, socket) do
WandererApp.EveDataService.update_eve_data()
@@ -224,6 +209,58 @@ defmodule WandererAppWeb.AdminLive do
|> push_navigate(to: ~p"/maps/new")}
end
def handle_event("validate", %{"form" => params}, socket) do
form = AshPhoenix.Form.validate(socket.assigns.form, params)
{:noreply, assign(socket, form: form)}
end
def handle_event("generate-invite-link", _params, socket) do
token = UUID.uuid4()
new_params = Map.put(socket.assigns.form.params || %{}, "token", token)
form = AshPhoenix.Form.validate(socket.assigns.form, new_params)
invite_link =
socket.assigns.uri
|> get_invite_link(token)
{:noreply, assign(socket, form: form, invite_link: invite_link)}
end
def handle_event(
"add_invite_link",
%{"form" => %{"type" => type, "valid_until" => valid_until}},
socket
) do
%{
type: type |> String.to_existing_atom(),
valid_until: get_valid_until(valid_until),
token: UUID.uuid4(),
map_id: nil
}
|> WandererApp.Api.MapInvite.new()
|> case do
{:ok, _invite} ->
{:noreply, socket |> push_patch(to: ~p"/admin")}
error ->
{:noreply, socket |> put_flash(:error, "Failed to add invite. Try again.")}
end
end
def handle_event(
"delete-invite",
%{"id" => id},
socket
) do
id
|> WandererApp.Api.MapInvite.by_id!()
|> WandererApp.Api.MapInvite.destroy!()
{:ok, invites} = WandererApp.Api.MapInvite.read()
{:noreply, socket |> assign(:invites, invites)}
end
@impl true
def handle_event(event, body, socket) do
Logger.warning(fn -> "unhandled event: #{event} #{inspect(body)}" end)
@@ -255,6 +292,8 @@ defmodule WandererAppWeb.AdminLive do
end
defp apply_action(socket, :index, _params, uri) do
{:ok, invites} = WandererApp.Api.MapInvite.read()
socket
|> assign(:active_page, :admin)
|> assign(:uri, URI.parse(uri))
@@ -268,6 +307,48 @@ defmodule WandererAppWeb.AdminLive do
])
|> assign(:form, to_form(%{"amount" => 500_000_000}))
|> assign(:unlink_character_form, to_form(%{}))
|> assign(:invites, invites)
end
defp apply_action(socket, :add_invite_link, _params, uri) do
socket
|> assign(:active_page, :admin)
|> assign(:uri, URI.parse(uri))
|> assign(:page_title, "Add Invite Link")
|> assign(:invite_types, [%{label: "User", id: :user}, %{label: "Admin", id: :admin}])
|> assign(:valid_types, [
%{label: "1D", id: 1},
%{label: "1W", id: 7},
%{label: "1M", id: 30},
%{label: "1Y", id: 365}
])
|> assign(:unlink_character_form, to_form(%{}))
|> assign(:character_search_options, [])
|> assign(:amounts, [
%{label: "500M", value: 500_000_000},
%{label: "1B", value: 1_000_000_000},
%{label: "5B", value: 5_000_000_000},
%{label: "10B", value: 10_000_000_000}
])
|> assign(:form, to_form(%{"amount" => 500_000_000}))
|> assign(:invite_token, UUID.uuid4())
|> assign(
:form,
AshPhoenix.Form.for_create(WandererApp.Api.MapInvite, :new,
forms: [
auto?: true
]
)
|> to_form()
)
|> assign(:invites, [])
end
defp get_invite_link(uri, token) do
uri
|> Map.put(:path, "/auth/eve")
|> Map.put(:query, URI.encode_query(%{invite: token}))
|> URI.to_string()
end
defp search(search) do
@@ -290,11 +371,29 @@ defmodule WandererAppWeb.AdminLive do
</div>
</div>
<span :if={@option.value == :loading} <span class="loading loading-spinner loading-xs"></span>
&nbsp; <%= @option.label %>
&nbsp; {@option.label}
</div>
"""
end
defp get_valid_until("1") do
DateTime.utc_now() |> DateTime.add(24 * 3600, :second)
end
defp get_valid_until("7") do
DateTime.utc_now() |> DateTime.add(24 * 3600 * 7, :second)
end
defp get_valid_until("30") do
DateTime.utc_now() |> DateTime.add(24 * 3600 * 30, :second)
end
defp get_valid_until("365") do
DateTime.utc_now() |> DateTime.add(24 * 3600 * 365, :second)
end
defp get_valid_until(_), do: get_valid_until("1")
def search_member_icon_url(%{character: true} = option),
do: member_icon_url(%{eve_character_id: option.value})

View File

@@ -112,34 +112,58 @@
</div>
</div>
<div :if={@show_invites?} class="card dark:bg-zinc-800 dark:border-zinc-600">
<div class="card dark:bg-zinc-800 dark:border-zinc-600">
<div class="card-body">
<div class="col-span-6">
<span class="text-gray-400 dark:text-gray-400">Invite Link</span>
<span class="text-gray-400 dark:text-gray-400">Invites</span>
<h4 class="my-4 font-medium text-gray-800 text-4xl dark:text-gray-100">
<.button class="btn btn-primary" phx-click="generate-invite-link">
Generate
</.button>
<.link class="btn mt-2 w-full btn-neutral rounded-none" patch={~p"/admin/invite"}>
<.icon name="hero-plus-solid" class="w-6 h-6" />
<h3 class="card-title text-center text-md">New Invite</h3>
</.link>
<div :if={not is_nil(@invite_link)} class="join">
<input
class="input input-bordered join-item"
readonly
type="text"
value={@invite_link}
/>
<.button
phx-hook="CopyToClipboard"
id="copy-to-clipboard"
class="copy-link btn join-item rounded-r-full"
data-url={@invite_link}
>
Copy
<div class="absolute w-[100px] !mr-[-170px] link-copied hidden">
Link copied
<.table
id="invites"
rows={@invites}
class="!max-h-[40vh] !overflow-y-auto"
>
<:col :let={invite} label="Link">
<div class="flex items-center">
<div class="w-[200px] no-wrap truncate"><%= get_invite_link(@uri, invite.token) %></div>
<.button
phx-hook="CopyToClipboard"
id="copy-to-clipboard"
class="copy-link btn btn-neutral rounded-none"
data-url={get_invite_link(@uri, invite.token)}
>
Copy
<div class="absolute w-[100px] !mr-[-170px] link-copied hidden">
Link copied
</div>
</.button>
</div>
</.button>
</div>
</:col>
<:col :let={invite} label="Type">
<%= invite.type %>
</:col>
<:col :let={invite} label="Valid Until">
<div>
<p class="mb-0 text-xs text-gray-600 dark:text-zinc-100 whitespace-nowrap">
<.local_time id={invite.id} at={invite.valid_until} />
</p>
</div>
</:col>
<:action :let={invite}>
<.button
phx-click="delete-invite"
phx-value-id={invite.id}
data={[confirm: "Please confirm to delete invite!"]}
class="hover:text-white"
>
<.icon name="hero-trash-solid" class="w-4 h-4" />
</.button>
</:action>
</.table>
</h4>
</div>
</div>
@@ -261,4 +285,39 @@
</div>
</div>
</div>
<.modal
:if={@live_action in [:add_invite_link]}
title={"New Invite"}
class="!w-[500px]"
id="add_invite_link_modal"
show
on_cancel={JS.patch(~p"/admin")}
>
<.form :let={f} for={@form} phx-change="validate" phx-submit={@live_action}>
<.input
type="select"
field={f[:type]}
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
wrapper_class="mt-2"
label="Type"
options={Enum.map(@invite_types, fn invite_type -> {invite_type.label, invite_type.id} end)}
/>
<.input
type="select"
field={f[:valid_until]}
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
wrapper_class="mt-2"
label="Valid"
options={Enum.map(@valid_types, fn valid_type -> {valid_type.label, valid_type.id} end)}
/>
<!-- API Key Section with grid layout -->
<div class="modal-action">
<.button class="mt-2" type="submit" phx-disable-with="Saving...">
<%= (@live_action == :add_invite_link && "Add") || "Save" %>
</.button>
</div>
</.form>
</.modal>
</main>

View File

@@ -230,7 +230,11 @@ defmodule WandererAppWeb.Router do
delete "/connections", MapConnectionAPIController, :delete
delete "/systems", MapSystemAPIController, :delete
resources "/systems", MapSystemAPIController, only: [:index, :show, :create, :update, :delete]
resources "/connections", MapConnectionAPIController, only: [:index, :show, :create, :update, :delete], param: "id"
resources "/connections", MapConnectionAPIController,
only: [:index, :show, :create, :update, :delete],
param: "id"
resources "/structures", MapSystemStructureAPIController, except: [:new, :edit]
get "/structure-timers", MapSystemStructureAPIController, :structure_timers
resources "/signatures", MapSystemSignatureAPIController, except: [:new, :edit]
@@ -238,8 +242,6 @@ defmodule WandererAppWeb.Router do
get "/tracked-characters", MapAPIController, :show_tracked_characters
end
#
# Other API routes
#
@@ -359,6 +361,7 @@ defmodule WandererAppWeb.Router do
WandererAppWeb.Nav
] do
live("/", AdminLive, :index)
live("/invite", AdminLive, :add_invite_link)
end
error_tracker_dashboard("/errors",

View File

@@ -3,7 +3,7 @@ defmodule WandererApp.MixProject do
@source_url "https://github.com/wanderer-industries/wanderer"
@version "1.67.1"
@version "1.68.1"
def project do
[

View File

@@ -0,0 +1,40 @@
defmodule WandererApp.Repo.Migrations.AddMapInvites 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(:map_invites_v1, primary_key: false) do
add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true
add :token, :text
add :valid_until, :utc_datetime
add :inserted_at, :utc_datetime_usec,
null: false,
default: fragment("(now() AT TIME ZONE 'utc')")
add :updated_at, :utc_datetime_usec,
null: false,
default: fragment("(now() AT TIME ZONE 'utc')")
add :map_id,
references(:maps_v1,
column: :id,
name: "map_invites_v1_map_id_fkey",
type: :uuid,
prefix: "public",
on_delete: :delete_all
)
end
end
def down do
drop constraint(:map_invites_v1, "map_invites_v1_map_id_fkey")
drop table(:map_invites_v1)
end
end

View File

@@ -0,0 +1,21 @@
defmodule WandererApp.Repo.Migrations.AddMapInviteType 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
alter table(:map_invites_v1) do
add :type, :text, null: false, default: "user"
end
end
def down do
alter table(:map_invites_v1) do
remove :type
end
end
end

View File

@@ -0,0 +1,98 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"gen_random_uuid()\")",
"generated?": false,
"primary_key?": true,
"references": null,
"size": null,
"source": "id",
"type": "uuid"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "token",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "valid_until",
"type": "utc_datetime"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "inserted_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "updated_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "map_invites_v1_map_id_fkey",
"on_delete": "delete",
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "maps_v1"
},
"size": null,
"source": "map_id",
"type": "uuid"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"custom_statements": [],
"has_create_action": true,
"hash": "B4122C666C9DCF20E420209F604765AB1A3C4979D4134916F7EF9292162B250C",
"identities": [],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.WandererApp.Repo",
"schema": null,
"table": "map_invites_v1"
}

View File

@@ -0,0 +1,108 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"gen_random_uuid()\")",
"generated?": false,
"primary_key?": true,
"references": null,
"size": null,
"source": "id",
"type": "uuid"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "token",
"type": "text"
},
{
"allow_nil?": false,
"default": "\"user\"",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "type",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "valid_until",
"type": "utc_datetime"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "inserted_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "updated_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "map_invites_v1_map_id_fkey",
"on_delete": "delete",
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "maps_v1"
},
"size": null,
"source": "map_id",
"type": "uuid"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"custom_statements": [],
"has_create_action": true,
"hash": "99662C7392D745B0B2D22445A3A703DC2287EBBA185BB7818D58F472B5D033D3",
"identities": [],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.WandererApp.Repo",
"schema": null,
"table": "map_invites_v1"
}