mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-10 01:35:33 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45eb08fc3a | ||
|
|
fbcfae0200 | ||
|
|
9c4ce013ec | ||
|
|
5dba7c12f0 | ||
|
|
db793c80c8 | ||
|
|
aa4a3f1aa9 | ||
|
|
3424639309 | ||
|
|
0f309a29ba | ||
|
|
e13b8846b8 | ||
|
|
d5ea4d6129 | ||
|
|
9d50bfedbd | ||
|
|
b03410083c | ||
|
|
a314b1e448 | ||
|
|
e8a51a85c4 | ||
|
|
d4074f966c | ||
|
|
1413b41824 | ||
|
|
379c1edec3 | ||
|
|
58b5bade9e | ||
|
|
71aee4cd3e | ||
|
|
10bab0cfa1 | ||
|
|
698350b0f7 | ||
|
|
a97cf25031 | ||
|
|
8302d088bd | ||
|
|
64788e73de | ||
|
|
114fd471e8 | ||
|
|
b24a3120d3 |
65
CHANGELOG.md
65
CHANGELOG.md
@@ -2,6 +2,71 @@
|
||||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v1.70.0](https://github.com/wanderer-industries/wanderer/compare/v1.69.1...v1.70.0) (2025-06-11)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Core: Fix admin page error
|
||||
|
||||
## [v1.69.1](https://github.com/wanderer-industries/wanderer/compare/v1.69.0...v1.69.1) (2025-06-11)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.69.0](https://github.com/wanderer-industries/wanderer/compare/v1.68.6...v1.69.0) (2025-06-11)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Core: Added multiple tracking pools support
|
||||
|
||||
## [v1.68.6](https://github.com/wanderer-industries/wanderer/compare/v1.68.5...v1.68.6) (2025-06-10)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.68.5](https://github.com/wanderer-industries/wanderer/compare/v1.68.4...v1.68.5) (2025-06-10)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed updating map options
|
||||
|
||||
## [v1.68.4](https://github.com/wanderer-industries/wanderer/compare/v1.68.3...v1.68.4) (2025-06-10)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.68.3](https://github.com/wanderer-industries/wanderer/compare/v1.68.2...v1.68.3) (2025-06-09)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.68.2](https://github.com/wanderer-industries/wanderer/compare/v1.68.1...v1.68.2) (2025-06-09)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed character auth with wallet (on characters page)
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
|
||||
@@ -117,8 +117,9 @@ 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(),
|
||||
corp_wallet_eve_id: System.get_env("WANDERER_CORP_WALLET_EVE_ID", "-1"),
|
||||
public_api_disabled: public_api_disabled,
|
||||
active_tracking_pool: System.get_env("WANDERER_ACTIVE_TRACKING_POOL", "default"),
|
||||
character_tracking_pause_disabled:
|
||||
System.get_env("WANDERER_CHARACTER_TRACKING_PAUSE_DISABLED", "true")
|
||||
|> String.to_existing_atom(),
|
||||
@@ -174,11 +175,31 @@ config :ueberauth, WandererApp.Ueberauth.Strategy.Eve.OAuth,
|
||||
client_id: {WandererApp.Ueberauth, :client_id},
|
||||
client_secret: {WandererApp.Ueberauth, :client_secret},
|
||||
client_id_default: System.get_env("EVE_CLIENT_ID", "<EVE_CLIENT_ID>"),
|
||||
client_id_1: System.get_env("EVE_CLIENT_ID_1", ""),
|
||||
client_id_2: System.get_env("EVE_CLIENT_ID_2", ""),
|
||||
client_id_3: System.get_env("EVE_CLIENT_ID_3", ""),
|
||||
client_id_4: System.get_env("EVE_CLIENT_ID_4", ""),
|
||||
client_id_5: System.get_env("EVE_CLIENT_ID_5", ""),
|
||||
client_id_6: System.get_env("EVE_CLIENT_ID_6", ""),
|
||||
client_id_7: System.get_env("EVE_CLIENT_ID_7", ""),
|
||||
client_id_8: System.get_env("EVE_CLIENT_ID_8", ""),
|
||||
client_id_9: System.get_env("EVE_CLIENT_ID_9", ""),
|
||||
client_id_10: System.get_env("EVE_CLIENT_ID_10", ""),
|
||||
client_id_with_wallet:
|
||||
System.get_env("EVE_CLIENT_WITH_WALLET_ID", "<EVE_CLIENT_WITH_WALLET_ID>"),
|
||||
client_id_with_corp_wallet:
|
||||
System.get_env("EVE_CLIENT_WITH_CORP_WALLET_ID", "<EVE_CLIENT_WITH_CORP_WALLET_ID>"),
|
||||
client_secret_default: System.get_env("EVE_CLIENT_SECRET", "<EVE_CLIENT_SECRET>"),
|
||||
client_secret_1: System.get_env("EVE_CLIENT_SECRET_1", ""),
|
||||
client_secret_2: System.get_env("EVE_CLIENT_SECRET_2", ""),
|
||||
client_secret_3: System.get_env("EVE_CLIENT_SECRET_3", ""),
|
||||
client_secret_4: System.get_env("EVE_CLIENT_SECRET_4", ""),
|
||||
client_secret_5: System.get_env("EVE_CLIENT_SECRET_5", ""),
|
||||
client_secret_6: System.get_env("EVE_CLIENT_SECRET_6", ""),
|
||||
client_secret_7: System.get_env("EVE_CLIENT_SECRET_7", ""),
|
||||
client_secret_8: System.get_env("EVE_CLIENT_SECRET_8", ""),
|
||||
client_secret_9: System.get_env("EVE_CLIENT_SECRET_9", ""),
|
||||
client_secret_10: System.get_env("EVE_CLIENT_SECRET_10", ""),
|
||||
client_secret_with_wallet:
|
||||
System.get_env("EVE_CLIENT_WITH_WALLET_SECRET", "<EVE_CLIENT_WITH_WALLET_SECRET>"),
|
||||
client_secret_with_corp_wallet:
|
||||
|
||||
@@ -24,6 +24,7 @@ defmodule WandererApp.Api.Character do
|
||||
define(:update_alliance, action: :update_alliance)
|
||||
define(:update_wallet_balance, action: :update_wallet_balance)
|
||||
define(:mark_as_deleted, action: :mark_as_deleted)
|
||||
define(:last_active, action: :last_active)
|
||||
|
||||
define(:by_id,
|
||||
get_by: [:id],
|
||||
@@ -47,7 +48,8 @@ defmodule WandererApp.Api.Character do
|
||||
:access_token,
|
||||
:refresh_token,
|
||||
:expires_at,
|
||||
:scopes
|
||||
:scopes,
|
||||
:tracking_pool
|
||||
]
|
||||
|
||||
defaults [:create, :read, :destroy]
|
||||
@@ -72,6 +74,12 @@ defmodule WandererApp.Api.Character do
|
||||
filter(expr(user_id == ^arg(:user_id) and deleted == false))
|
||||
end
|
||||
|
||||
read :last_active do
|
||||
argument(:from, :utc_datetime, allow_nil?: false)
|
||||
|
||||
filter(expr(updated_at > ^arg(:from)))
|
||||
end
|
||||
|
||||
update :assign do
|
||||
accept []
|
||||
require_atomic? false
|
||||
@@ -85,7 +93,7 @@ defmodule WandererApp.Api.Character do
|
||||
|
||||
update :update do
|
||||
require_atomic? false
|
||||
accept([:name, :access_token, :refresh_token, :expires_at, :scopes])
|
||||
accept([:name, :access_token, :refresh_token, :expires_at, :scopes, :tracking_pool])
|
||||
|
||||
change(set_attribute(:deleted, false))
|
||||
end
|
||||
@@ -198,6 +206,7 @@ defmodule WandererApp.Api.Character do
|
||||
attribute :alliance_name, :string
|
||||
attribute :alliance_ticker, :string
|
||||
attribute :eve_wallet_balance, :float
|
||||
attribute :tracking_pool, :string
|
||||
|
||||
create_timestamp(:inserted_at)
|
||||
update_timestamp(:updated_at)
|
||||
|
||||
@@ -27,6 +27,7 @@ defmodule WandererApp.Application do
|
||||
}
|
||||
},
|
||||
WandererApp.Cache,
|
||||
Supervisor.child_spec({Cachex, name: :esi_auth_cache}, id: :esi_auth_cache_worker),
|
||||
Supervisor.child_spec({Cachex, name: :api_cache}, id: :api_cache_worker),
|
||||
Supervisor.child_spec({Cachex, name: :system_static_info_cache},
|
||||
id: :system_static_info_cache_worker
|
||||
@@ -40,6 +41,7 @@ defmodule WandererApp.Application do
|
||||
Supervisor.child_spec({Cachex, name: :tracked_characters},
|
||||
id: :tracked_characters_cache_worker
|
||||
),
|
||||
WandererApp.Esi.InitClientsTask,
|
||||
WandererApp.Scheduler,
|
||||
{Registry, keys: :unique, name: WandererApp.MapRegistry},
|
||||
{Registry, keys: :unique, name: WandererApp.Character.TrackerRegistry},
|
||||
|
||||
@@ -213,6 +213,21 @@ defmodule WandererApp.Character do
|
||||
|
||||
def can_track_corp_wallet?(_), do: false
|
||||
|
||||
@decorate cacheable(
|
||||
cache: WandererApp.Cache,
|
||||
key: "can_pause_tracking-#{character_id}"
|
||||
)
|
||||
def can_pause_tracking?(character_id) do
|
||||
case get_character(character_id) do
|
||||
{:ok, character} when not is_nil(character) ->
|
||||
not WandererApp.Env.character_tracking_pause_disabled?() &&
|
||||
not can_track_corp_wallet?(character)
|
||||
|
||||
_ ->
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def get_ship(%{ship: ship_type_id, ship_name: ship_name} = _character)
|
||||
when not is_nil(ship_type_id) and is_integer(ship_type_id) do
|
||||
ship_type_id
|
||||
|
||||
@@ -110,7 +110,7 @@ defmodule WandererApp.Character.Tracker do
|
||||
end
|
||||
|
||||
defp pause_tracking(character_id) do
|
||||
if not WandererApp.Env.character_tracking_pause_disabled?() &&
|
||||
if WandererApp.Character.can_pause_tracking?(character_id) &&
|
||||
not WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused") do
|
||||
WandererApp.Cache.delete("character:#{character_id}:online_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:online_error_time")
|
||||
|
||||
@@ -236,13 +236,17 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
characters
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
WandererApp.TaskWrapper.start_link(
|
||||
WandererApp.Character.Tracker,
|
||||
:check_offline,
|
||||
[
|
||||
character_id
|
||||
]
|
||||
)
|
||||
if WandererApp.Character.can_pause_tracking?(character_id) do
|
||||
WandererApp.TaskWrapper.start_link(
|
||||
WandererApp.Character.Tracker,
|
||||
:check_offline,
|
||||
[
|
||||
character_id
|
||||
]
|
||||
)
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
|
||||
@@ -16,6 +16,12 @@ defmodule WandererApp.Env do
|
||||
def invites, do: get_key(:invites, false)
|
||||
def map_subscriptions_enabled?, do: get_key(:map_subscriptions_enabled, false)
|
||||
def public_api_disabled?, do: get_key(:public_api_disabled, false)
|
||||
|
||||
@decorate cacheable(
|
||||
cache: WandererApp.Cache,
|
||||
key: "active_tracking_pool"
|
||||
)
|
||||
def active_tracking_pool, do: get_key(:active_tracking_pool, "default")
|
||||
def character_tracking_pause_disabled?, do: get_key(:character_tracking_pause_disabled, true)
|
||||
def character_api_disabled?, do: get_key(:character_api_disabled, false)
|
||||
def zkill_preload_disabled?, do: get_key(:zkill_preload_disabled, false)
|
||||
@@ -24,7 +30,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_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)
|
||||
|
||||
|
||||
@@ -671,13 +671,20 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
end
|
||||
|
||||
defp refresh_token(character_id) do
|
||||
{:ok, %{expires_at: expires_at, refresh_token: refresh_token, scopes: scopes} = character} =
|
||||
{:ok,
|
||||
%{
|
||||
expires_at: expires_at,
|
||||
refresh_token: refresh_token,
|
||||
scopes: scopes,
|
||||
tracking_pool: tracking_pool
|
||||
} = character} =
|
||||
WandererApp.Character.get_character(character_id)
|
||||
|
||||
refresh_token_result =
|
||||
WandererApp.Ueberauth.Strategy.Eve.OAuth.get_refresh_token([],
|
||||
with_wallet: WandererApp.Character.can_track_wallet?(character),
|
||||
is_admin?: WandererApp.Character.can_track_corp_wallet?(character),
|
||||
tracking_pool: tracking_pool,
|
||||
token: %OAuth2.AccessToken{refresh_token: refresh_token}
|
||||
)
|
||||
|
||||
|
||||
@@ -294,14 +294,16 @@ defmodule WandererApp.Map do
|
||||
map_id
|
||||
|> update_map(%{characters_limit: characters_limit, hubs_limit: hubs_limit})
|
||||
|
||||
map
|
||||
map_id
|
||||
|> get_map!()
|
||||
end
|
||||
|
||||
def update_options!(%{map_id: map_id} = map, options) do
|
||||
map_id
|
||||
|> update_map(%{options: options})
|
||||
|
||||
map
|
||||
map_id
|
||||
|> get_map!()
|
||||
end
|
||||
|
||||
def add_systems!(map, []), do: map
|
||||
|
||||
@@ -212,7 +212,7 @@ defmodule WandererApp.Map.Server do
|
||||
do:
|
||||
map_id
|
||||
|> map_pid!
|
||||
|> GenServer.call({&Impl.update_subscription_settings/2, [settings]})
|
||||
|> GenServer.cast({&Impl.update_subscription_settings/2, [settings]})
|
||||
|
||||
def delete_connection(map_id, connection_info) when is_binary(map_id),
|
||||
do:
|
||||
|
||||
@@ -192,10 +192,13 @@ defmodule WandererApp.Ueberauth.Strategy.Eve do
|
||||
end
|
||||
|
||||
defp oauth_client_options_from_conn(conn, with_wallet, is_admin?) do
|
||||
tracking_pool = WandererApp.Env.active_tracking_pool()
|
||||
|
||||
base_options = [
|
||||
redirect_uri: callback_url(conn),
|
||||
with_wallet: with_wallet,
|
||||
is_admin?: is_admin?
|
||||
is_admin?: is_admin?,
|
||||
tracking_pool: tracking_pool
|
||||
]
|
||||
|
||||
request_options = conn.private[:ueberauth_request_options].options
|
||||
@@ -213,11 +216,11 @@ defmodule WandererApp.Ueberauth.Strategy.Eve do
|
||||
|
||||
defp check_invite_valid(invite_token) do
|
||||
case invite_token do
|
||||
nil ->
|
||||
{false, nil}
|
||||
|
||||
token ->
|
||||
token when not is_nil(token) and token != "" ->
|
||||
check_token_valid(token)
|
||||
|
||||
_ ->
|
||||
{not WandererApp.Env.invites(), :user}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
84
lib/wanderer_app/ueberauth/strategy/eve/init_configs_task.ex
Normal file
84
lib/wanderer_app/ueberauth/strategy/eve/init_configs_task.ex
Normal file
@@ -0,0 +1,84 @@
|
||||
defmodule WandererApp.Esi.InitClientsTask do
|
||||
use Task
|
||||
|
||||
require Logger
|
||||
|
||||
def start_link(arg) do
|
||||
Task.start_link(__MODULE__, :run, [arg])
|
||||
end
|
||||
|
||||
def run(_arg) do
|
||||
Logger.info("starting")
|
||||
|
||||
Cachex.put(
|
||||
:esi_auth_cache,
|
||||
:active_config,
|
||||
"config_#{WandererApp.Env.active_tracking_pool()}"
|
||||
)
|
||||
|
||||
cache_clients()
|
||||
end
|
||||
|
||||
defp cache_clients() do
|
||||
config = Application.get_env(:ueberauth, WandererApp.Ueberauth.Strategy.Eve.OAuth, [])
|
||||
|
||||
cache_client("default", %{
|
||||
client_id: config[:client_id_default],
|
||||
client_secret: config[:client_secret_default]
|
||||
})
|
||||
|
||||
Enum.each(1..10, fn index ->
|
||||
client_id = config["client_id_#{index}" |> String.to_atom()]
|
||||
client_secret = config["client_secret_#{index}" |> String.to_atom()]
|
||||
|
||||
if client_id != "" && client_secret != "" do
|
||||
cache_client(index, %{
|
||||
client_id: client_id,
|
||||
client_secret: client_secret
|
||||
})
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp cache_client(id, config) do
|
||||
config_uuid = UUID.uuid4()
|
||||
|
||||
config =
|
||||
config
|
||||
|> Map.merge(%{
|
||||
id: id,
|
||||
uuid: config_uuid
|
||||
})
|
||||
|
||||
Cachex.put(
|
||||
:esi_auth_cache,
|
||||
"config_#{id}",
|
||||
config
|
||||
)
|
||||
|
||||
Cachex.put(
|
||||
:esi_auth_cache,
|
||||
config_uuid,
|
||||
config
|
||||
)
|
||||
|
||||
# Cachex.put(
|
||||
# :esi_auth_cache,
|
||||
# "config_uuid_#{id}",
|
||||
# config_uuid
|
||||
# )
|
||||
|
||||
configs_total_count =
|
||||
if id == "default" do
|
||||
0
|
||||
else
|
||||
id
|
||||
end
|
||||
|
||||
Cachex.put(
|
||||
:esi_auth_cache,
|
||||
"configs_total_count",
|
||||
configs_total_count
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -2,26 +2,50 @@ defmodule WandererApp.Ueberauth do
|
||||
@moduledoc false
|
||||
|
||||
def client_id(opts \\ []) do
|
||||
config = _get_config()
|
||||
config = get_config()
|
||||
tracking_pool = Keyword.get(opts, :tracking_pool)
|
||||
|
||||
cond do
|
||||
Keyword.get(opts, :is_admin?) -> config[:client_id_with_corp_wallet]
|
||||
Keyword.get(opts, :with_wallet) -> config[:client_id_with_wallet]
|
||||
not is_nil(tracking_pool) -> get_settings(tracking_pool)[:client_id]
|
||||
true -> config[:client_id_default]
|
||||
end
|
||||
end
|
||||
|
||||
def client_secret(opts \\ []) do
|
||||
config = _get_config()
|
||||
config = get_config()
|
||||
tracking_pool = Keyword.get(opts, :tracking_pool)
|
||||
|
||||
cond do
|
||||
Keyword.get(opts, :is_admin?) -> config[:client_secret_with_corp_wallet]
|
||||
Keyword.get(opts, :with_wallet) -> config[:client_secret_with_wallet]
|
||||
not is_nil(tracking_pool) -> get_settings(tracking_pool)[:client_secret]
|
||||
true -> config[:client_secret_default]
|
||||
end
|
||||
end
|
||||
|
||||
defp _get_config() do
|
||||
defp get_settings(nil) do
|
||||
{:ok, esi_config} =
|
||||
Cachex.get(
|
||||
:esi_auth_cache,
|
||||
"config_default"
|
||||
)
|
||||
|
||||
esi_config
|
||||
end
|
||||
|
||||
defp get_settings(tracking_pool) do
|
||||
{:ok, esi_config} =
|
||||
Cachex.get(
|
||||
:esi_auth_cache,
|
||||
"config_#{tracking_pool}"
|
||||
)
|
||||
|
||||
esi_config
|
||||
end
|
||||
|
||||
defp get_config() do
|
||||
Application.get_env(:ueberauth, WandererApp.Ueberauth.Strategy.Eve.OAuth, [])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,7 +14,8 @@ defmodule WandererAppWeb.AuthController do
|
||||
access_token: auth.credentials.token,
|
||||
refresh_token: auth.credentials.refresh_token,
|
||||
expires_at: auth.credentials.expires_at,
|
||||
scopes: auth.credentials.scopes
|
||||
scopes: auth.credentials.scopes,
|
||||
tracking_pool: WandererApp.Env.active_tracking_pool()
|
||||
}
|
||||
|
||||
%{
|
||||
@@ -29,7 +30,8 @@ defmodule WandererAppWeb.AuthController do
|
||||
access_token: auth.credentials.token,
|
||||
refresh_token: auth.credentials.refresh_token,
|
||||
expires_at: auth.credentials.expires_at,
|
||||
scopes: auth.credentials.scopes
|
||||
scopes: auth.credentials.scopes,
|
||||
tracking_pool: WandererApp.Env.active_tracking_pool()
|
||||
}
|
||||
|
||||
{:ok, character} =
|
||||
|
||||
@@ -62,6 +62,7 @@ defmodule WandererAppWeb.AdminLive do
|
||||
user_character_ids: user_character_ids,
|
||||
user_id: user_id,
|
||||
invite_link: nil,
|
||||
tracker_stats: [],
|
||||
map_subscriptions_enabled?: WandererApp.Env.map_subscriptions_enabled?(),
|
||||
restrict_maps_creation?: WandererApp.Env.restrict_maps_creation?()
|
||||
)}
|
||||
@@ -294,6 +295,8 @@ defmodule WandererAppWeb.AdminLive do
|
||||
defp apply_action(socket, :index, _params, uri) do
|
||||
{:ok, invites} = WandererApp.Api.MapInvite.read()
|
||||
|
||||
{:ok, tracker_stats} = load_tracker_stats()
|
||||
|
||||
socket
|
||||
|> assign(:active_page, :admin)
|
||||
|> assign(:uri, URI.parse(uri))
|
||||
@@ -308,6 +311,7 @@ defmodule WandererAppWeb.AdminLive do
|
||||
|> assign(:form, to_form(%{"amount" => 500_000_000}))
|
||||
|> assign(:unlink_character_form, to_form(%{}))
|
||||
|> assign(:invites, invites)
|
||||
|> assign(:tracker_stats, tracker_stats)
|
||||
end
|
||||
|
||||
defp apply_action(socket, :add_invite_link, _params, uri) do
|
||||
@@ -344,6 +348,70 @@ defmodule WandererAppWeb.AdminLive do
|
||||
|> assign(:invites, [])
|
||||
end
|
||||
|
||||
defp load_tracker_stats() do
|
||||
{:ok, characters} =
|
||||
WandererApp.Api.Character.last_active(%{
|
||||
from:
|
||||
DateTime.utc_now()
|
||||
|> DateTime.add(-1 * 60 * 24 * 7, :minute)
|
||||
})
|
||||
|
||||
admins_count =
|
||||
characters |> Enum.filter(&WandererApp.Character.can_track_corp_wallet?/1) |> Enum.count()
|
||||
|
||||
with_wallets_count =
|
||||
characters
|
||||
|> Enum.filter(
|
||||
&(WandererApp.Character.can_track_wallet?(&1) and
|
||||
not WandererApp.Character.can_track_corp_wallet?(&1))
|
||||
)
|
||||
|> Enum.count()
|
||||
|
||||
default_count =
|
||||
characters
|
||||
|> Enum.filter(
|
||||
&(is_nil(&1.tracking_pool) and not WandererApp.Character.can_track_wallet?(&1) and
|
||||
not WandererApp.Character.can_track_corp_wallet?(&1))
|
||||
)
|
||||
|> Enum.count()
|
||||
|
||||
result = [
|
||||
%{title: "Admins", value: admins_count},
|
||||
%{title: "With Wallet", value: with_wallets_count},
|
||||
%{title: "Default", value: default_count}
|
||||
]
|
||||
|
||||
{:ok, pools_count} =
|
||||
Cachex.get(
|
||||
:esi_auth_cache,
|
||||
"configs_total_count"
|
||||
)
|
||||
|
||||
result =
|
||||
if not is_nil(pools_count) && pools_count != 0 do
|
||||
pools =
|
||||
1..pools_count
|
||||
|> Enum.map(fn pool_id ->
|
||||
pools_character_count =
|
||||
characters
|
||||
|> Enum.filter(
|
||||
&(&1.tracking_pool == "#{pool_id}" and
|
||||
not WandererApp.Character.can_track_wallet?(&1) and
|
||||
not WandererApp.Character.can_track_corp_wallet?(&1))
|
||||
)
|
||||
|> Enum.count()
|
||||
|
||||
%{title: "Pool #{pool_id}", value: pools_character_count}
|
||||
end)
|
||||
|
||||
result ++ pools
|
||||
else
|
||||
result
|
||||
end
|
||||
|
||||
{:ok, result}
|
||||
end
|
||||
|
||||
defp get_invite_link(uri, token) do
|
||||
uri
|
||||
|> Map.put(:path, "/auth/eve")
|
||||
|
||||
@@ -121,50 +121,69 @@
|
||||
<.icon name="hero-plus-solid" class="w-6 h-6" />
|
||||
<h3 class="card-title text-center text-md">New Invite</h3>
|
||||
</.link>
|
||||
</h4>
|
||||
<.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>
|
||||
</: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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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">Tracking Pools</span>
|
||||
<.table
|
||||
id="invites"
|
||||
rows={@invites}
|
||||
id="tracking_pools"
|
||||
rows={@tracker_stats}
|
||||
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>
|
||||
<:col :let={stat} label="Pool">
|
||||
<div class="w-[200px] no-wrap truncate">{stat.title}</div>
|
||||
</:col>
|
||||
<:col :let={invite} label="Type">
|
||||
<%= invite.type %>
|
||||
<:col :let={stat} label="Count">
|
||||
{stat.value}
|
||||
</: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>
|
||||
</div>
|
||||
@@ -293,6 +312,7 @@
|
||||
show
|
||||
on_cancel={JS.patch(~p"/admin")}
|
||||
>
|
||||
|
||||
<.form :let={f} for={@form} phx-change="validate" phx-submit={@live_action}>
|
||||
<.input
|
||||
type="select"
|
||||
|
||||
@@ -5,6 +5,8 @@ defmodule WandererAppWeb.CharactersLive do
|
||||
|
||||
alias BetterNumber, as: Number
|
||||
|
||||
@active_tracking_pool 1
|
||||
|
||||
def mount(_params, %{"user_id" => user_id} = _session, socket)
|
||||
when not is_nil(user_id) do
|
||||
{:ok, characters} = WandererApp.Api.Character.active_by_user(%{user_id: user_id})
|
||||
@@ -56,17 +58,25 @@ defmodule WandererAppWeb.CharactersLive do
|
||||
@impl true
|
||||
def handle_event("authorize", form, socket) do
|
||||
track_wallet = form |> Map.get("track_wallet", false)
|
||||
token = UUID.uuid4(:default)
|
||||
WandererApp.Cache.put("invite_#{token}", true, ttl: :timer.minutes(30))
|
||||
|
||||
{:noreply, socket |> push_navigate(to: ~p"/auth/eve?invite=#{token}&w=#{track_wallet}")}
|
||||
{:ok, esi_config} =
|
||||
Cachex.get(
|
||||
:esi_auth_cache,
|
||||
"config_#{WandererApp.Env.active_tracking_pool()}"
|
||||
)
|
||||
|
||||
WandererApp.Cache.put("invite_#{esi_config.uuid}", true, ttl: :timer.minutes(30))
|
||||
|
||||
{:noreply,
|
||||
socket |> push_navigate(to: ~p"/auth/eve?invite=#{esi_config.uuid}&w=#{track_wallet}")}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"character_id" => character_id}, socket) do
|
||||
WandererApp.Character.TrackerManager.stop_tracking(character_id)
|
||||
|
||||
{:ok, map_user_settings} = WandererApp.Api.MapCharacterSettings.tracked_by_character(%{character_id: character_id})
|
||||
{:ok, map_user_settings} =
|
||||
WandererApp.Api.MapCharacterSettings.tracked_by_character(%{character_id: character_id})
|
||||
|
||||
map_user_settings
|
||||
|> Enum.each(fn settings ->
|
||||
@@ -87,6 +97,15 @@ defmodule WandererAppWeb.CharactersLive do
|
||||
{:noreply, socket |> assign(characters: characters |> Enum.map(&map_ui_character/1))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event(
|
||||
"validate",
|
||||
params,
|
||||
socket
|
||||
) do
|
||||
{:noreply, assign(socket, form: params)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("show_table", %{"value" => "on"}, socket) do
|
||||
{:noreply, socket |> assign(mode: :table)}
|
||||
@@ -148,7 +167,7 @@ defmodule WandererAppWeb.CharactersLive do
|
||||
socket
|
||||
|> assign(:active_page, :characters)
|
||||
|> assign(:page_title, "Authorize Character - Characters")
|
||||
|> assign(:form, to_form(%{"track_wallet" => false}))
|
||||
|> assign(:form, to_form(%{}))
|
||||
end
|
||||
|
||||
defp map_ui_character(character) do
|
||||
|
||||
@@ -242,10 +242,13 @@
|
||||
show
|
||||
on_cancel={JS.patch(~p"/characters")}
|
||||
>
|
||||
<.form :let={f} for={@form} phx-submit="authorize">
|
||||
<div :if={@wallet_tracking_enabled?} class="pb-2 -mt-8">
|
||||
<div class="flex flex-col gap-3">
|
||||
|
||||
<.form :let={f} for={@form} phx-submit="authorize" phx-change="validate">
|
||||
<div :if={@wallet_tracking_enabled?} class="pb-2">
|
||||
<.input
|
||||
type="checkbox"
|
||||
|
||||
field={f[:track_wallet]}
|
||||
label="Access to character wallet information"
|
||||
/>
|
||||
@@ -254,5 +257,6 @@
|
||||
<.button type="submit">AUTHORIZE</.button>
|
||||
</div>
|
||||
</.form>
|
||||
</div>
|
||||
</.modal>
|
||||
</main>
|
||||
|
||||
2
mix.exs
2
mix.exs
@@ -3,7 +3,7 @@ defmodule WandererApp.MixProject do
|
||||
|
||||
@source_url "https://github.com/wanderer-industries/wanderer"
|
||||
|
||||
@version "1.68.0"
|
||||
@version "1.70.0"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
defmodule WandererApp.Repo.Migrations.AddCharacterTrackingPool 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(:character_v1) do
|
||||
add :tracking_pool, :text
|
||||
end
|
||||
end
|
||||
|
||||
def down do
|
||||
alter table(:character_v1) do
|
||||
remove :tracking_pool
|
||||
end
|
||||
end
|
||||
end
|
||||
343
priv/resource_snapshots/repo/character_v1/20250611074436.json
Normal file
343
priv/resource_snapshots/repo/character_v1/20250611074436.json
Normal file
@@ -0,0 +1,343 @@
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "fragment(\"gen_random_uuid()\")",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "id",
|
||||
"type": "uuid"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "eve_id",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "name",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "false",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "online",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "false",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "deleted",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "scopes",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "character_owner_hash",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "token_type",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "expires_at",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "ship_name",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "ship_item_id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "corporation_id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "corporation_name",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "corporation_ticker",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "alliance_id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "alliance_name",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "alliance_ticker",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "tracking_pool",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"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": "character_v1_user_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"primary_key?": true,
|
||||
"schema": "public",
|
||||
"table": "user_v1"
|
||||
},
|
||||
"size": null,
|
||||
"source": "user_id",
|
||||
"type": "uuid"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "encrypted_eve_wallet_balance",
|
||||
"type": "binary"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "encrypted_location",
|
||||
"type": "binary"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "encrypted_ship",
|
||||
"type": "binary"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "encrypted_solar_system_id",
|
||||
"type": "binary"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "encrypted_structure_id",
|
||||
"type": "binary"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "encrypted_station_id",
|
||||
"type": "binary"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "encrypted_access_token",
|
||||
"type": "binary"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "encrypted_refresh_token",
|
||||
"type": "binary"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "4C6974D764592ED3279CFD3FF85CE89B146C7E16628F0A4278E319A4A5E5FD8C",
|
||||
"identities": [
|
||||
{
|
||||
"all_tenants?": false,
|
||||
"base_filter": null,
|
||||
"index_name": "character_v1_unique_eve_id_index",
|
||||
"keys": [
|
||||
{
|
||||
"type": "atom",
|
||||
"value": "eve_id"
|
||||
}
|
||||
],
|
||||
"name": "unique_eve_id",
|
||||
"nils_distinct?": true,
|
||||
"where": null
|
||||
}
|
||||
],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.WandererApp.Repo",
|
||||
"schema": null,
|
||||
"table": "character_v1"
|
||||
}
|
||||
Reference in New Issue
Block a user