mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-11-19 23:56:11 +00:00
Compare commits
91 Commits
tracking-c
...
v1.70.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6e9fee2a0 | ||
|
|
c403a1cee5 | ||
|
|
02d25b370a | ||
|
|
e5a3eec8a1 | ||
|
|
910352d66c | ||
|
|
c4f02e7d55 | ||
|
|
6a1197ad83 | ||
|
|
84c31bbb88 | ||
|
|
33f6c32306 | ||
|
|
5c71304d41 | ||
|
|
bbaf04e977 | ||
|
|
ad5b2d2eb3 | ||
|
|
3c064baf8a | ||
|
|
9e11b10d74 | ||
|
|
2fc45e00b4 | ||
|
|
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 | ||
|
|
c5f93b3d0a | ||
|
|
79290e4721 | ||
|
|
984e126f23 | ||
|
|
cd1ad31aed | ||
|
|
1e3f6cf9e7 | ||
|
|
9c6ccd9a8a | ||
|
|
681ba21d39 | ||
|
|
aef62189ee | ||
|
|
09f70ac817 | ||
|
|
1eacb22143 | ||
|
|
8524bad377 | ||
|
|
9d899243d1 | ||
|
|
9acf20a639 | ||
|
|
71ef6b2e82 | ||
|
|
5e34d95dd2 | ||
|
|
25a809c064 | ||
|
|
f760498150 | ||
|
|
328301a375 | ||
|
|
f28e7ebbbb | ||
|
|
bfa84af71e | ||
|
|
42cd1ba976 | ||
|
|
88cba866fd | ||
|
|
af2876a84b | ||
|
|
c5b15bfa78 | ||
|
|
85f00a63c2 | ||
|
|
05f427bcd7 | ||
|
|
69f4c41534 | ||
|
|
30b9239a8b | ||
|
|
2061a83c59 | ||
|
|
24e723de07 | ||
|
|
5a927e5ba5 | ||
|
|
10fafcf59f | ||
|
|
be87591801 | ||
|
|
086d4378d3 | ||
|
|
e982275905 | ||
|
|
77c02703e9 | ||
|
|
0ef27d4f95 | ||
|
|
5edc27744e | ||
|
|
02ff887fee | ||
|
|
3a30eeb59f | ||
|
|
79af8fb601 | ||
|
|
f9f00faa0e | ||
|
|
a3c41e84e4 | ||
|
|
7f21f33351 | ||
|
|
568f682cee | ||
|
|
901c4c8ca4 | ||
|
|
3dbba97f9c | ||
|
|
3475620267 | ||
|
|
8936a5e5d8 | ||
|
|
719e34f9bc |
235
CHANGELOG.md
235
CHANGELOG.md
@@ -2,6 +2,241 @@
|
|||||||
|
|
||||||
<!-- changelog -->
|
<!-- changelog -->
|
||||||
|
|
||||||
|
## [v1.70.5](https://github.com/wanderer-industries/wanderer/compare/v1.70.4...v1.70.5) (2025-06-17)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Fixed character caching issues
|
||||||
|
|
||||||
|
## [v1.70.4](https://github.com/wanderer-industries/wanderer/compare/v1.70.3...v1.70.4) (2025-06-16)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Distribute tracking to minimal pool first
|
||||||
|
|
||||||
|
## [v1.70.3](https://github.com/wanderer-industries/wanderer/compare/v1.70.2...v1.70.3) (2025-06-16)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Don't pause tracking for new pools
|
||||||
|
|
||||||
|
## [v1.70.2](https://github.com/wanderer-industries/wanderer/compare/v1.70.1...v1.70.2) (2025-06-15)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Invalidate character copr and ally data on map server start
|
||||||
|
|
||||||
|
## [v1.70.1](https://github.com/wanderer-industries/wanderer/compare/v1.70.0...v1.70.1) (2025-06-14)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* resolve api issue with custom name
|
||||||
|
|
||||||
|
## [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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.67.0](https://github.com/wanderer-industries/wanderer/compare/v1.66.25...v1.67.0) (2025-06-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Features:
|
||||||
|
|
||||||
|
* Core: Added support for WANDERER_CHARACTER_TRACKING_PAUSE_DISABLED env variable to pause inactive character trackers
|
||||||
|
|
||||||
|
## [v1.66.25](https://github.com/wanderer-industries/wanderer/compare/v1.66.24...v1.66.25) (2025-06-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Disabled kills fetching based on env settings
|
||||||
|
|
||||||
|
## [v1.66.24](https://github.com/wanderer-industries/wanderer/compare/v1.66.23...v1.66.24) (2025-06-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.66.23](https://github.com/wanderer-industries/wanderer/compare/v1.66.22...v1.66.23) (2025-06-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.66.22](https://github.com/wanderer-industries/wanderer/compare/v1.66.21...v1.66.22) (2025-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.66.21](https://github.com/wanderer-industries/wanderer/compare/v1.66.20...v1.66.21) (2025-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Fixed kills fetching based on env settings
|
||||||
|
|
||||||
|
## [v1.66.20](https://github.com/wanderer-industries/wanderer/compare/v1.66.19...v1.66.20) (2025-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.66.19](https://github.com/wanderer-industries/wanderer/compare/v1.66.18...v1.66.19) (2025-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Added check for offline characters timeouts
|
||||||
|
|
||||||
|
## [v1.66.18](https://github.com/wanderer-industries/wanderer/compare/v1.66.17...v1.66.18) (2025-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.66.17](https://github.com/wanderer-industries/wanderer/compare/v1.66.16...v1.66.17) (2025-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Increased tracking pause timeout for offline characters up to 10 hours
|
||||||
|
|
||||||
|
## [v1.66.16](https://github.com/wanderer-industries/wanderer/compare/v1.66.15...v1.66.16) (2025-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
|
||||||
|
* Core: Increased tracking pause timeout for offline characters up to 10 hours
|
||||||
|
|
||||||
## [v1.66.15](https://github.com/wanderer-industries/wanderer/compare/v1.66.14...v1.66.15) (2025-06-07)
|
## [v1.66.15](https://github.com/wanderer-industries/wanderer/compare/v1.66.14...v1.66.15) (2025-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ export const Characters = ({ data }: CharactersProps) => {
|
|||||||
<>
|
<>
|
||||||
<span
|
<span
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'absolute top-[2px] left-[2px] w-[9px] h-[9px]',
|
'absolute flex flex-col p-[2px] top-[0px] left-[0px] w-[35px] h-[35px]',
|
||||||
'text-yellow-500 text-[9px] rounded-[1px] z-10 hover:hidden',
|
'text-yellow-500 text-[9px] z-10 bg-gray-800/40',
|
||||||
'pi',
|
'pi',
|
||||||
PrimeIcons.PAUSE,
|
PrimeIcons.PAUSE,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -117,7 +117,14 @@ config :wanderer_app,
|
|||||||
admins: admins,
|
admins: admins,
|
||||||
corp_id: System.get_env("WANDERER_CORP_ID", "-1") |> String.to_integer(),
|
corp_id: System.get_env("WANDERER_CORP_ID", "-1") |> String.to_integer(),
|
||||||
corp_wallet: System.get_env("WANDERER_CORP_WALLET", ""),
|
corp_wallet: System.get_env("WANDERER_CORP_WALLET", ""),
|
||||||
|
corp_wallet_eve_id: System.get_env("WANDERER_CORP_WALLET_EVE_ID", "-1"),
|
||||||
public_api_disabled: public_api_disabled,
|
public_api_disabled: public_api_disabled,
|
||||||
|
active_tracking_pool: System.get_env("WANDERER_ACTIVE_TRACKING_POOL", "default"),
|
||||||
|
tracking_pool_max_size:
|
||||||
|
System.get_env("WANDERER_TRACKING_POOL_MAX_SIZE", "300") |> String.to_integer(),
|
||||||
|
character_tracking_pause_disabled:
|
||||||
|
System.get_env("WANDERER_CHARACTER_TRACKING_PAUSE_DISABLED", "true")
|
||||||
|
|> String.to_existing_atom(),
|
||||||
character_api_disabled:
|
character_api_disabled:
|
||||||
System.get_env("WANDERER_CHARACTER_API_DISABLED", "true") |> String.to_existing_atom(),
|
System.get_env("WANDERER_CHARACTER_API_DISABLED", "true") |> String.to_existing_atom(),
|
||||||
zkill_preload_disabled:
|
zkill_preload_disabled:
|
||||||
@@ -170,11 +177,31 @@ config :ueberauth, WandererApp.Ueberauth.Strategy.Eve.OAuth,
|
|||||||
client_id: {WandererApp.Ueberauth, :client_id},
|
client_id: {WandererApp.Ueberauth, :client_id},
|
||||||
client_secret: {WandererApp.Ueberauth, :client_secret},
|
client_secret: {WandererApp.Ueberauth, :client_secret},
|
||||||
client_id_default: System.get_env("EVE_CLIENT_ID", "<EVE_CLIENT_ID>"),
|
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:
|
client_id_with_wallet:
|
||||||
System.get_env("EVE_CLIENT_WITH_WALLET_ID", "<EVE_CLIENT_WITH_WALLET_ID>"),
|
System.get_env("EVE_CLIENT_WITH_WALLET_ID", "<EVE_CLIENT_WITH_WALLET_ID>"),
|
||||||
client_id_with_corp_wallet:
|
client_id_with_corp_wallet:
|
||||||
System.get_env("EVE_CLIENT_WITH_CORP_WALLET_ID", "<EVE_CLIENT_WITH_CORP_WALLET_ID>"),
|
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_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:
|
client_secret_with_wallet:
|
||||||
System.get_env("EVE_CLIENT_WITH_WALLET_SECRET", "<EVE_CLIENT_WITH_WALLET_SECRET>"),
|
System.get_env("EVE_CLIENT_WITH_WALLET_SECRET", "<EVE_CLIENT_WITH_WALLET_SECRET>"),
|
||||||
client_secret_with_corp_wallet:
|
client_secret_with_corp_wallet:
|
||||||
|
|||||||
@@ -29,5 +29,6 @@ defmodule WandererApp.Api do
|
|||||||
resource WandererApp.Api.CorpWalletTransaction
|
resource WandererApp.Api.CorpWalletTransaction
|
||||||
resource WandererApp.Api.License
|
resource WandererApp.Api.License
|
||||||
resource WandererApp.Api.MapPing
|
resource WandererApp.Api.MapPing
|
||||||
|
resource WandererApp.Api.MapInvite
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ defmodule WandererApp.Api.Character do
|
|||||||
define(:update_alliance, action: :update_alliance)
|
define(:update_alliance, action: :update_alliance)
|
||||||
define(:update_wallet_balance, action: :update_wallet_balance)
|
define(:update_wallet_balance, action: :update_wallet_balance)
|
||||||
define(:mark_as_deleted, action: :mark_as_deleted)
|
define(:mark_as_deleted, action: :mark_as_deleted)
|
||||||
|
define(:last_active, action: :last_active)
|
||||||
|
|
||||||
define(:by_id,
|
define(:by_id,
|
||||||
get_by: [:id],
|
get_by: [:id],
|
||||||
@@ -47,7 +48,8 @@ defmodule WandererApp.Api.Character do
|
|||||||
:access_token,
|
:access_token,
|
||||||
:refresh_token,
|
:refresh_token,
|
||||||
:expires_at,
|
:expires_at,
|
||||||
:scopes
|
:scopes,
|
||||||
|
:tracking_pool
|
||||||
]
|
]
|
||||||
|
|
||||||
defaults [:create, :read, :destroy]
|
defaults [:create, :read, :destroy]
|
||||||
@@ -72,6 +74,12 @@ defmodule WandererApp.Api.Character do
|
|||||||
filter(expr(user_id == ^arg(:user_id) and deleted == false))
|
filter(expr(user_id == ^arg(:user_id) and deleted == false))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
read :last_active do
|
||||||
|
argument(:from, :utc_datetime, allow_nil?: false)
|
||||||
|
|
||||||
|
filter(expr(updated_at > ^arg(:from)))
|
||||||
|
end
|
||||||
|
|
||||||
update :assign do
|
update :assign do
|
||||||
accept []
|
accept []
|
||||||
require_atomic? false
|
require_atomic? false
|
||||||
@@ -85,7 +93,7 @@ defmodule WandererApp.Api.Character do
|
|||||||
|
|
||||||
update :update do
|
update :update do
|
||||||
require_atomic? false
|
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))
|
change(set_attribute(:deleted, false))
|
||||||
end
|
end
|
||||||
@@ -198,6 +206,7 @@ defmodule WandererApp.Api.Character do
|
|||||||
attribute :alliance_name, :string
|
attribute :alliance_name, :string
|
||||||
attribute :alliance_ticker, :string
|
attribute :alliance_ticker, :string
|
||||||
attribute :eve_wallet_balance, :float
|
attribute :eve_wallet_balance, :float
|
||||||
|
attribute :tracking_pool, :string
|
||||||
|
|
||||||
create_timestamp(:inserted_at)
|
create_timestamp(:inserted_at)
|
||||||
update_timestamp(:updated_at)
|
update_timestamp(:updated_at)
|
||||||
|
|||||||
96
lib/wanderer_app/api/map_invite.ex
Normal file
96
lib/wanderer_app/api/map_invite.ex
Normal 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
|
||||||
@@ -27,6 +27,7 @@ defmodule WandererApp.Application do
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
WandererApp.Cache,
|
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: :api_cache}, id: :api_cache_worker),
|
||||||
Supervisor.child_spec({Cachex, name: :system_static_info_cache},
|
Supervisor.child_spec({Cachex, name: :system_static_info_cache},
|
||||||
id: :system_static_info_cache_worker
|
id: :system_static_info_cache_worker
|
||||||
@@ -40,6 +41,7 @@ defmodule WandererApp.Application do
|
|||||||
Supervisor.child_spec({Cachex, name: :tracked_characters},
|
Supervisor.child_spec({Cachex, name: :tracked_characters},
|
||||||
id: :tracked_characters_cache_worker
|
id: :tracked_characters_cache_worker
|
||||||
),
|
),
|
||||||
|
WandererApp.Esi.InitClientsTask,
|
||||||
WandererApp.Scheduler,
|
WandererApp.Scheduler,
|
||||||
{Registry, keys: :unique, name: WandererApp.MapRegistry},
|
{Registry, keys: :unique, name: WandererApp.MapRegistry},
|
||||||
{Registry, keys: :unique, name: WandererApp.Character.TrackerRegistry},
|
{Registry, keys: :unique, name: WandererApp.Character.TrackerRegistry},
|
||||||
@@ -47,17 +49,16 @@ defmodule WandererApp.Application do
|
|||||||
child_spec: DynamicSupervisor, name: WandererApp.Map.DynamicSupervisors},
|
child_spec: DynamicSupervisor, name: WandererApp.Map.DynamicSupervisors},
|
||||||
{PartitionSupervisor,
|
{PartitionSupervisor,
|
||||||
child_spec: DynamicSupervisor, name: WandererApp.Character.DynamicSupervisors},
|
child_spec: DynamicSupervisor, name: WandererApp.Character.DynamicSupervisors},
|
||||||
WandererApp.Zkb.Supervisor,
|
|
||||||
WandererApp.Server.ServerStatusTracker,
|
WandererApp.Server.ServerStatusTracker,
|
||||||
WandererApp.Server.TheraDataFetcher,
|
WandererApp.Server.TheraDataFetcher,
|
||||||
{WandererApp.Character.TrackerPoolSupervisor, []},
|
{WandererApp.Character.TrackerPoolSupervisor, []},
|
||||||
WandererApp.Character.TrackerManager,
|
WandererApp.Character.TrackerManager,
|
||||||
WandererApp.Map.Manager,
|
WandererApp.Map.Manager,
|
||||||
WandererApp.Map.ZkbDataFetcher,
|
|
||||||
WandererAppWeb.Presence,
|
WandererAppWeb.Presence,
|
||||||
WandererAppWeb.Endpoint
|
WandererAppWeb.Endpoint
|
||||||
] ++
|
] ++
|
||||||
maybe_start_corp_wallet_tracker(WandererApp.Env.map_subscriptions_enabled?())
|
maybe_start_corp_wallet_tracker(WandererApp.Env.map_subscriptions_enabled?()) ++
|
||||||
|
maybe_start_zkb(WandererApp.Env.zkill_preload_disabled?())
|
||||||
|
|
||||||
opts = [strategy: :one_for_one, name: WandererApp.Supervisor]
|
opts = [strategy: :one_for_one, name: WandererApp.Supervisor]
|
||||||
|
|
||||||
@@ -78,6 +79,12 @@ defmodule WandererApp.Application do
|
|||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp maybe_start_zkb(false),
|
||||||
|
do: [WandererApp.Zkb.Supervisor, WandererApp.Map.ZkbDataFetcher]
|
||||||
|
|
||||||
|
defp maybe_start_zkb(_),
|
||||||
|
do: []
|
||||||
|
|
||||||
defp maybe_start_corp_wallet_tracker(true),
|
defp maybe_start_corp_wallet_tracker(true),
|
||||||
do: [
|
do: [
|
||||||
WandererApp.StartCorpWalletTrackerTask
|
WandererApp.StartCorpWalletTrackerTask
|
||||||
|
|||||||
@@ -16,10 +16,6 @@ defmodule WandererApp.Character do
|
|||||||
ship_item_id: nil
|
ship_item_id: nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@decorate cacheable(
|
|
||||||
cache: WandererApp.Cache,
|
|
||||||
key: "characters-#{character_eve_id}"
|
|
||||||
)
|
|
||||||
def get_by_eve_id(character_eve_id) when is_binary(character_eve_id) do
|
def get_by_eve_id(character_eve_id) when is_binary(character_eve_id) do
|
||||||
WandererApp.Api.Character.by_eve_id(character_eve_id)
|
WandererApp.Api.Character.by_eve_id(character_eve_id)
|
||||||
end
|
end
|
||||||
@@ -179,9 +175,9 @@ defmodule WandererApp.Character do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def search(character_id, opts \\ []) do
|
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(),
|
case WandererApp.Esi.search(eve_id |> String.to_integer(),
|
||||||
access_token: access_token,
|
access_token: access_token,
|
||||||
character_id: character_id,
|
character_id: character_id,
|
||||||
@@ -195,20 +191,36 @@ defmodule WandererApp.Character do
|
|||||||
Logger.warning("#{__MODULE__} failed search: #{inspect(error)}")
|
Logger.warning("#{__MODULE__} failed search: #{inspect(error)}")
|
||||||
{:ok, []}
|
{:ok, []}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
error ->
|
||||||
|
{:ok, []}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_track_wallet?(%{scopes: scopes} = _character) when not is_nil(scopes) do
|
def can_track_wallet?(%{scopes: scopes, id: character_id} = _character)
|
||||||
scopes |> String.split(" ") |> Enum.member?(@read_character_wallet_scope)
|
when is_binary(scopes) and is_binary(character_id),
|
||||||
end
|
do: scopes |> String.split(" ") |> Enum.member?(@read_character_wallet_scope)
|
||||||
|
|
||||||
def can_track_wallet?(_), do: false
|
def can_track_wallet?(_), do: false
|
||||||
|
|
||||||
def can_track_corp_wallet?(%{scopes: scopes} = _character) when not is_nil(scopes) do
|
def can_track_corp_wallet?(%{scopes: scopes} = _character)
|
||||||
scopes |> String.split(" ") |> Enum.member?(@read_corp_wallet_scope)
|
when not is_nil(scopes),
|
||||||
end
|
do: scopes |> String.split(" ") |> Enum.member?(@read_corp_wallet_scope)
|
||||||
|
|
||||||
def can_track_corp_wallet?(_), do: false
|
def can_track_corp_wallet?(_), do: false
|
||||||
|
|
||||||
|
def can_pause_tracking?(character_id) do
|
||||||
|
case get_character(character_id) do
|
||||||
|
{:ok, %{tracking_pool: tracking_pool} = character} when not is_nil(character) ->
|
||||||
|
not WandererApp.Env.character_tracking_pause_disabled?() &&
|
||||||
|
not can_track_wallet?(character) &&
|
||||||
|
(is_nil(tracking_pool) || tracking_pool == "default")
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_ship(%{ship: ship_type_id, ship_name: ship_name} = _character)
|
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
|
when not is_nil(ship_type_id) and is_integer(ship_type_id) do
|
||||||
ship_type_id
|
ship_type_id
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
status: binary()
|
status: binary()
|
||||||
}
|
}
|
||||||
|
|
||||||
@pause_tracking_timeout :timer.minutes(60 * 24)
|
@pause_tracking_timeout :timer.minutes(60 * 10)
|
||||||
@offline_timeout :timer.minutes(5)
|
@offline_timeout :timer.minutes(5)
|
||||||
@online_error_timeout :timer.minutes(2)
|
@online_error_timeout :timer.minutes(2)
|
||||||
@ship_error_timeout :timer.minutes(2)
|
@ship_error_timeout :timer.minutes(2)
|
||||||
@@ -61,7 +61,11 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
WandererApp.Cache.lookup!("character:#{character_id}:last_online_time")
|
WandererApp.Cache.lookup!("character:#{character_id}:last_online_time")
|
||||||
|> case do
|
|> case do
|
||||||
nil ->
|
nil ->
|
||||||
pause_tracking(character_id)
|
WandererApp.Cache.insert(
|
||||||
|
"character:#{character_id}:last_online_time",
|
||||||
|
DateTime.utc_now()
|
||||||
|
)
|
||||||
|
|
||||||
:ok
|
:ok
|
||||||
|
|
||||||
last_online_time ->
|
last_online_time ->
|
||||||
@@ -106,7 +110,8 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp pause_tracking(character_id) do
|
defp pause_tracking(character_id) do
|
||||||
if not WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused") do
|
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_forbidden")
|
||||||
WandererApp.Cache.delete("character:#{character_id}:online_error_time")
|
WandererApp.Cache.delete("character:#{character_id}:online_error_time")
|
||||||
WandererApp.Cache.delete("character:#{character_id}:ship_error_time")
|
WandererApp.Cache.delete("character:#{character_id}:ship_error_time")
|
||||||
@@ -161,7 +166,7 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
|
|
||||||
def update_online(%{track_online: true, character_id: character_id} = character_state) do
|
def update_online(%{track_online: true, character_id: character_id} = character_state) do
|
||||||
case WandererApp.Character.get_character(character_id) do
|
case WandererApp.Character.get_character(character_id) do
|
||||||
{:ok, %{eve_id: eve_id, access_token: access_token}}
|
{:ok, %{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool}}
|
||||||
when not is_nil(access_token) ->
|
when not is_nil(access_token) ->
|
||||||
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
|
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
|
||||||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|
||||||
@@ -182,8 +187,6 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
"character:#{character_id}:last_online_time",
|
"character:#{character_id}:last_online_time",
|
||||||
DateTime.utc_now()
|
DateTime.utc_now()
|
||||||
)
|
)
|
||||||
else
|
|
||||||
WandererApp.Cache.delete("character:#{character_id}:last_online_time")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
WandererApp.Cache.delete("character:#{character_id}:online_forbidden")
|
WandererApp.Cache.delete("character:#{character_id}:online_forbidden")
|
||||||
@@ -230,9 +233,7 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
{:error, :error_limited, headers} ->
|
{:error, :error_limited, headers} ->
|
||||||
reset_timeout = get_reset_timeout(headers)
|
reset_timeout = get_reset_timeout(headers)
|
||||||
|
|
||||||
Logger.warning(
|
Logger.warning("#{inspect(tracking_pool)} ..")
|
||||||
"#{__MODULE__} failed to update_online: #{inspect(:error_limited)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
WandererApp.Cache.put(
|
WandererApp.Cache.put(
|
||||||
"character:#{character_id}:online_forbidden",
|
"character:#{character_id}:online_forbidden",
|
||||||
@@ -286,15 +287,15 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
defp get_reset_timeout(_headers, default_timeout), do: default_timeout
|
defp get_reset_timeout(_headers, default_timeout), do: default_timeout
|
||||||
|
|
||||||
def update_info(character_id) do
|
def update_info(character_id) do
|
||||||
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
|
(WandererApp.Cache.has_key?("character:#{character_id}:info_forbidden") ||
|
||||||
WandererApp.Cache.has_key?("character:#{character_id}:info_forbidden") ||
|
|
||||||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|
||||||
|> case do
|
|> case do
|
||||||
true ->
|
true ->
|
||||||
{:error, :skipped}
|
{:error, :skipped}
|
||||||
|
|
||||||
false ->
|
false ->
|
||||||
{:ok, %{eve_id: eve_id}} = WandererApp.Character.get_character(character_id)
|
{:ok, %{eve_id: eve_id, tracking_pool: tracking_pool}} =
|
||||||
|
WandererApp.Character.get_character(character_id)
|
||||||
|
|
||||||
case WandererApp.Esi.get_character_info(eve_id) do
|
case WandererApp.Esi.get_character_info(eve_id) do
|
||||||
{:ok, _info} ->
|
{:ok, _info} ->
|
||||||
@@ -319,9 +320,7 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
{:error, :error_limited, headers} ->
|
{:error, :error_limited, headers} ->
|
||||||
reset_timeout = get_reset_timeout(headers)
|
reset_timeout = get_reset_timeout(headers)
|
||||||
|
|
||||||
Logger.warning(
|
Logger.warning("#{inspect(tracking_pool)} ..")
|
||||||
"#{__MODULE__} failed to get_character_info: #{inspect(:error_limited)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
WandererApp.Cache.put(
|
WandererApp.Cache.put(
|
||||||
"character:#{character_id}:info_forbidden",
|
"character:#{character_id}:info_forbidden",
|
||||||
@@ -359,7 +358,8 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
character_id
|
character_id
|
||||||
|> WandererApp.Character.get_character()
|
|> WandererApp.Character.get_character()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, %{eve_id: eve_id, access_token: access_token}} when not is_nil(access_token) ->
|
{:ok, %{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool}}
|
||||||
|
when not is_nil(access_token) ->
|
||||||
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
|
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
|
||||||
WandererApp.Cache.has_key?("character:#{character_id}:ship_forbidden") ||
|
WandererApp.Cache.has_key?("character:#{character_id}:ship_forbidden") ||
|
||||||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|
||||||
@@ -398,7 +398,7 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
{:error, :error_limited, headers} ->
|
{:error, :error_limited, headers} ->
|
||||||
reset_timeout = get_reset_timeout(headers)
|
reset_timeout = get_reset_timeout(headers)
|
||||||
|
|
||||||
Logger.warning("#{__MODULE__} failed to update_ship: #{inspect(:error_limited)}")
|
Logger.warning("#{inspect(tracking_pool)} ..")
|
||||||
|
|
||||||
WandererApp.Cache.put(
|
WandererApp.Cache.put(
|
||||||
"character:#{character_id}:ship_forbidden",
|
"character:#{character_id}:ship_forbidden",
|
||||||
@@ -463,9 +463,9 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
%{track_location: true, is_online: true, character_id: character_id} = character_state
|
%{track_location: true, is_online: true, character_id: character_id} = character_state
|
||||||
) do
|
) do
|
||||||
case WandererApp.Character.get_character(character_id) do
|
case WandererApp.Character.get_character(character_id) do
|
||||||
{:ok, %{eve_id: eve_id, access_token: access_token}} when not is_nil(access_token) ->
|
{:ok, %{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool}}
|
||||||
(WandererApp.Cache.has_key?("character:#{character_id}:location_forbidden") ||
|
when not is_nil(access_token) ->
|
||||||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused")
|
||||||
|> case do
|
|> case do
|
||||||
true ->
|
true ->
|
||||||
{:error, :skipped}
|
{:error, :skipped}
|
||||||
@@ -496,9 +496,7 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
{:error, :skipped}
|
{:error, :skipped}
|
||||||
|
|
||||||
{:error, :error_limited, headers} ->
|
{:error, :error_limited, headers} ->
|
||||||
Logger.warning(
|
Logger.warning("#{inspect(tracking_pool)} ..")
|
||||||
"#{__MODULE__} failed to update_location: #{inspect(:error_limited)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
reset_timeout = get_reset_timeout(headers, @location_limit_ttl)
|
reset_timeout = get_reset_timeout(headers, @location_limit_ttl)
|
||||||
|
|
||||||
@@ -554,7 +552,8 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
character_id
|
character_id
|
||||||
|> WandererApp.Character.get_character()
|
|> WandererApp.Character.get_character()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, %{eve_id: eve_id, access_token: access_token} = character}
|
{:ok,
|
||||||
|
%{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool} = character}
|
||||||
when not is_nil(access_token) ->
|
when not is_nil(access_token) ->
|
||||||
character
|
character
|
||||||
|> WandererApp.Character.can_track_wallet?()
|
|> WandererApp.Character.can_track_wallet?()
|
||||||
@@ -593,9 +592,7 @@ defmodule WandererApp.Character.Tracker do
|
|||||||
{:error, :error_limited, headers} ->
|
{:error, :error_limited, headers} ->
|
||||||
reset_timeout = get_reset_timeout(headers)
|
reset_timeout = get_reset_timeout(headers)
|
||||||
|
|
||||||
Logger.warning(
|
Logger.warning("#{inspect(tracking_pool)} ..")
|
||||||
"#{__MODULE__} failed to update_wallet: #{inspect(:error_limited)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
WandererApp.Cache.put(
|
WandererApp.Cache.put(
|
||||||
"character:#{character_id}:wallet_forbidden",
|
"character:#{character_id}:wallet_forbidden",
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
|||||||
|
|
||||||
@garbage_collection_interval :timer.minutes(15)
|
@garbage_collection_interval :timer.minutes(15)
|
||||||
@untrack_characters_interval :timer.minutes(1)
|
@untrack_characters_interval :timer.minutes(1)
|
||||||
@inactive_character_timeout :timer.minutes(5)
|
@inactive_character_timeout :timer.minutes(10)
|
||||||
|
@untrack_character_timeout :timer.minutes(10)
|
||||||
|
|
||||||
@logger Application.compile_env(:wanderer_app, :logger)
|
@logger Application.compile_env(:wanderer_app, :logger)
|
||||||
|
|
||||||
@@ -107,20 +108,27 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
|||||||
} = track_settings
|
} = track_settings
|
||||||
) do
|
) do
|
||||||
if track do
|
if track do
|
||||||
WandererApp.Cache.insert_or_update(
|
remove_from_untrack_queue(map_id, character_id)
|
||||||
"character_untrack_queue",
|
|
||||||
[],
|
|
||||||
fn untrack_queue ->
|
|
||||||
untrack_queue
|
|
||||||
|> Enum.reject(fn {m_id, c_id} -> m_id == map_id and c_id == character_id end)
|
|
||||||
end
|
|
||||||
)
|
|
||||||
|
|
||||||
{:ok, character_state} =
|
{:ok, character_state} =
|
||||||
WandererApp.Character.Tracker.update_settings(character_id, track_settings)
|
WandererApp.Character.Tracker.update_settings(character_id, track_settings)
|
||||||
|
|
||||||
WandererApp.Character.update_character_state(character_id, character_state)
|
WandererApp.Character.update_character_state(character_id, character_state)
|
||||||
else
|
else
|
||||||
|
add_to_untrack_queue(map_id, character_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
state
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_to_untrack_queue(map_id, character_id) do
|
||||||
|
if not WandererApp.Cache.has_key?("#{map_id}:#{character_id}:untrack_requested") do
|
||||||
|
WandererApp.Cache.insert(
|
||||||
|
"#{map_id}:#{character_id}:untrack_requested",
|
||||||
|
DateTime.utc_now()
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
WandererApp.Cache.insert_or_update(
|
WandererApp.Cache.insert_or_update(
|
||||||
"character_untrack_queue",
|
"character_untrack_queue",
|
||||||
[{map_id, character_id}],
|
[{map_id, character_id}],
|
||||||
@@ -130,7 +138,17 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
state
|
def remove_from_untrack_queue(map_id, character_id) do
|
||||||
|
WandererApp.Cache.delete("#{map_id}:#{character_id}:untrack_requested")
|
||||||
|
|
||||||
|
WandererApp.Cache.insert_or_update(
|
||||||
|
"character_untrack_queue",
|
||||||
|
[],
|
||||||
|
fn untrack_queue ->
|
||||||
|
untrack_queue
|
||||||
|
|> Enum.reject(fn {m_id, c_id} -> m_id == map_id and c_id == character_id end)
|
||||||
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_characters(
|
def get_characters(
|
||||||
@@ -208,10 +226,28 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
|||||||
) do
|
) do
|
||||||
Process.send_after(self(), :untrack_characters, @untrack_characters_interval)
|
Process.send_after(self(), :untrack_characters, @untrack_characters_interval)
|
||||||
|
|
||||||
WandererApp.Cache.get_and_remove!("character_untrack_queue", [])
|
WandererApp.Cache.lookup!("character_untrack_queue", [])
|
||||||
|> Task.async_stream(
|
|> Task.async_stream(
|
||||||
fn {map_id, character_id} ->
|
fn {map_id, character_id} ->
|
||||||
if not character_is_present(map_id, character_id) do
|
untrack_timeout_reached =
|
||||||
|
if WandererApp.Cache.has_key?("#{map_id}:#{character_id}:untrack_requested") do
|
||||||
|
untrack_requested =
|
||||||
|
WandererApp.Cache.lookup!(
|
||||||
|
"#{map_id}:#{character_id}:untrack_requested",
|
||||||
|
DateTime.utc_now()
|
||||||
|
)
|
||||||
|
|
||||||
|
duration = DateTime.diff(DateTime.utc_now(), untrack_requested, :millisecond)
|
||||||
|
duration >= @untrack_character_timeout
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
Logger.debug(fn -> "Untrack timeout reached: #{inspect(untrack_timeout_reached)}" end)
|
||||||
|
|
||||||
|
if untrack_timeout_reached do
|
||||||
|
remove_from_untrack_queue(map_id, character_id)
|
||||||
|
|
||||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:solar_system_id")
|
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:solar_system_id")
|
||||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:station_id")
|
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:station_id")
|
||||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:structure_id")
|
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:structure_id")
|
||||||
@@ -235,6 +271,7 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
|||||||
})
|
})
|
||||||
|
|
||||||
WandererApp.Character.update_character_state(character_id, character_state)
|
WandererApp.Character.update_character_state(character_id, character_state)
|
||||||
|
WandererApp.Map.Server.Impl.broadcast!(map_id, :untrack_character, character_id)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
max_concurrency: System.schedulers_online(),
|
max_concurrency: System.schedulers_online(),
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ defmodule WandererApp.Character.TrackerPool do
|
|||||||
|
|
||||||
@update_location_interval :timer.seconds(1)
|
@update_location_interval :timer.seconds(1)
|
||||||
@update_online_interval :timer.seconds(5)
|
@update_online_interval :timer.seconds(5)
|
||||||
@check_online_errors_interval :timer.seconds(30)
|
@check_offline_characters_interval :timer.minutes(2)
|
||||||
|
@check_online_errors_interval :timer.minutes(1)
|
||||||
|
@check_ship_errors_interval :timer.minutes(1)
|
||||||
|
@check_location_errors_interval :timer.minutes(1)
|
||||||
@update_ship_interval :timer.seconds(2)
|
@update_ship_interval :timer.seconds(2)
|
||||||
@update_info_interval :timer.minutes(1)
|
@update_info_interval :timer.minutes(1)
|
||||||
@update_wallet_interval :timer.minutes(1)
|
@update_wallet_interval :timer.minutes(1)
|
||||||
@@ -130,7 +133,10 @@ defmodule WandererApp.Character.TrackerPool do
|
|||||||
)
|
)
|
||||||
|
|
||||||
Process.send_after(self(), :update_online, 100)
|
Process.send_after(self(), :update_online, 100)
|
||||||
Process.send_after(self(), :check_online_errors, @check_online_errors_interval)
|
Process.send_after(self(), :check_online_errors, :timer.seconds(60))
|
||||||
|
Process.send_after(self(), :check_ship_errors, :timer.seconds(90))
|
||||||
|
Process.send_after(self(), :check_location_errors, :timer.seconds(120))
|
||||||
|
Process.send_after(self(), :check_offline_characters, @check_offline_characters_interval)
|
||||||
Process.send_after(self(), :update_location, 300)
|
Process.send_after(self(), :update_location, 300)
|
||||||
Process.send_after(self(), :update_ship, 500)
|
Process.send_after(self(), :update_ship, 500)
|
||||||
Process.send_after(self(), :update_info, 1500)
|
Process.send_after(self(), :update_info, 1500)
|
||||||
@@ -217,6 +223,50 @@ defmodule WandererApp.Character.TrackerPool do
|
|||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_info(
|
||||||
|
:check_offline_characters,
|
||||||
|
%{
|
||||||
|
characters: characters
|
||||||
|
} =
|
||||||
|
state
|
||||||
|
) do
|
||||||
|
Process.send_after(self(), :check_offline_characters, @check_offline_characters_interval)
|
||||||
|
|
||||||
|
try do
|
||||||
|
characters
|
||||||
|
|> Task.async_stream(
|
||||||
|
fn 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(),
|
||||||
|
on_timeout: :kill_task
|
||||||
|
)
|
||||||
|
|> Enum.each(fn
|
||||||
|
{:ok, _result} -> :ok
|
||||||
|
{:error, reason} -> @logger.error("Error in check_offline: #{inspect(reason)}")
|
||||||
|
end)
|
||||||
|
rescue
|
||||||
|
e ->
|
||||||
|
Logger.error("""
|
||||||
|
[Tracker Pool] check_offline => exception: #{Exception.message(e)}
|
||||||
|
#{Exception.format_stacktrace(__STACKTRACE__)}
|
||||||
|
""")
|
||||||
|
end
|
||||||
|
|
||||||
|
{:noreply, state}
|
||||||
|
end
|
||||||
|
|
||||||
def handle_info(
|
def handle_info(
|
||||||
:check_online_errors,
|
:check_online_errors,
|
||||||
%{
|
%{
|
||||||
@@ -257,6 +307,86 @@ defmodule WandererApp.Character.TrackerPool do
|
|||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_info(
|
||||||
|
:check_ship_errors,
|
||||||
|
%{
|
||||||
|
characters: characters
|
||||||
|
} =
|
||||||
|
state
|
||||||
|
) do
|
||||||
|
Process.send_after(self(), :check_ship_errors, @check_ship_errors_interval)
|
||||||
|
|
||||||
|
try do
|
||||||
|
characters
|
||||||
|
|> Task.async_stream(
|
||||||
|
fn character_id ->
|
||||||
|
WandererApp.TaskWrapper.start_link(
|
||||||
|
WandererApp.Character.Tracker,
|
||||||
|
:check_ship_errors,
|
||||||
|
[
|
||||||
|
character_id
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
timeout: :timer.seconds(15),
|
||||||
|
max_concurrency: System.schedulers_online(),
|
||||||
|
on_timeout: :kill_task
|
||||||
|
)
|
||||||
|
|> Enum.each(fn
|
||||||
|
{:ok, _result} -> :ok
|
||||||
|
{:error, reason} -> @logger.error("Error in check_ship_errors: #{inspect(reason)}")
|
||||||
|
end)
|
||||||
|
rescue
|
||||||
|
e ->
|
||||||
|
Logger.error("""
|
||||||
|
[Tracker Pool] check_ship_errors => exception: #{Exception.message(e)}
|
||||||
|
#{Exception.format_stacktrace(__STACKTRACE__)}
|
||||||
|
""")
|
||||||
|
end
|
||||||
|
|
||||||
|
{:noreply, state}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_info(
|
||||||
|
:check_location_errors,
|
||||||
|
%{
|
||||||
|
characters: characters
|
||||||
|
} =
|
||||||
|
state
|
||||||
|
) do
|
||||||
|
Process.send_after(self(), :check_location_errors, @check_location_errors_interval)
|
||||||
|
|
||||||
|
try do
|
||||||
|
characters
|
||||||
|
|> Task.async_stream(
|
||||||
|
fn character_id ->
|
||||||
|
WandererApp.TaskWrapper.start_link(
|
||||||
|
WandererApp.Character.Tracker,
|
||||||
|
:check_location_errors,
|
||||||
|
[
|
||||||
|
character_id
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
timeout: :timer.seconds(15),
|
||||||
|
max_concurrency: System.schedulers_online(),
|
||||||
|
on_timeout: :kill_task
|
||||||
|
)
|
||||||
|
|> Enum.each(fn
|
||||||
|
{:ok, _result} -> :ok
|
||||||
|
{:error, reason} -> @logger.error("Error in check_location_errors: #{inspect(reason)}")
|
||||||
|
end)
|
||||||
|
rescue
|
||||||
|
e ->
|
||||||
|
Logger.error("""
|
||||||
|
[Tracker Pool] check_location_errors => exception: #{Exception.message(e)}
|
||||||
|
#{Exception.format_stacktrace(__STACKTRACE__)}
|
||||||
|
""")
|
||||||
|
end
|
||||||
|
|
||||||
|
{:noreply, state}
|
||||||
|
end
|
||||||
|
|
||||||
def handle_info(
|
def handle_info(
|
||||||
:update_location,
|
:update_location,
|
||||||
%{
|
%{
|
||||||
|
|||||||
142
lib/wanderer_app/character/tracking_config_utils.ex
Normal file
142
lib/wanderer_app/character/tracking_config_utils.ex
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
defmodule WandererApp.Character.TrackingConfigUtils do
|
||||||
|
use Nebulex.Caching
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
@ttl :timer.minutes(5)
|
||||||
|
@last_active_character_minutes -1 * 60 * 24 * 7
|
||||||
|
|
||||||
|
@decorate cacheable(
|
||||||
|
cache: WandererApp.Cache,
|
||||||
|
key: "tracker-stats",
|
||||||
|
opts: [ttl: @ttl]
|
||||||
|
)
|
||||||
|
def load_tracker_stats() do
|
||||||
|
{:ok, characters} = get_active_characters()
|
||||||
|
|
||||||
|
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 = [
|
||||||
|
%{id: "admins", title: "Admins", value: admins_count},
|
||||||
|
%{id: "wallet", title: "With Wallet", value: with_wallets_count},
|
||||||
|
%{id: "default", title: "Default", value: default_count}
|
||||||
|
]
|
||||||
|
|
||||||
|
{:ok, pools_count} =
|
||||||
|
Cachex.get(
|
||||||
|
:esi_auth_cache,
|
||||||
|
"configs_total_count"
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, pools} = get_pools_info(characters)
|
||||||
|
|
||||||
|
{:ok, result ++ pools}
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_active_tracking_pool() do
|
||||||
|
{:ok, pools_count} =
|
||||||
|
Cachex.get(
|
||||||
|
:esi_auth_cache,
|
||||||
|
"configs_total_count"
|
||||||
|
)
|
||||||
|
|
||||||
|
active_pool =
|
||||||
|
if not is_nil(pools_count) && pools_count != 0 do
|
||||||
|
tracking_pool_max_size = WandererApp.Env.tracking_pool_max_size()
|
||||||
|
{:ok, characters} = get_active_characters()
|
||||||
|
{:ok, pools} = get_pools_info(characters)
|
||||||
|
|
||||||
|
minimal_pool_id =
|
||||||
|
pools
|
||||||
|
|> Enum.filter(&(&1.value < tracking_pool_max_size))
|
||||||
|
|> Enum.min_by(& &1.value)
|
||||||
|
|> Map.get(:id)
|
||||||
|
|
||||||
|
if not is_nil(minimal_pool_id) do
|
||||||
|
minimal_pool_id
|
||||||
|
else
|
||||||
|
"default"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
"default"
|
||||||
|
end
|
||||||
|
|
||||||
|
Cachex.put(
|
||||||
|
:esi_auth_cache,
|
||||||
|
"active_pool",
|
||||||
|
active_pool
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_active_pool!() do
|
||||||
|
Cachex.get(
|
||||||
|
:esi_auth_cache,
|
||||||
|
"active_pool"
|
||||||
|
)
|
||||||
|
|> case do
|
||||||
|
{:ok, active_pool} when not is_nil(active_pool) ->
|
||||||
|
active_pool
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
"default"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_active_characters() do
|
||||||
|
WandererApp.Api.Character.last_active(%{
|
||||||
|
from:
|
||||||
|
DateTime.utc_now()
|
||||||
|
|> DateTime.add(@last_active_character_minutes, :minute)
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
@decorate cacheable(
|
||||||
|
cache: WandererApp.Cache,
|
||||||
|
key: "character-pools-info",
|
||||||
|
opts: [ttl: @ttl]
|
||||||
|
)
|
||||||
|
defp get_pools_info(characters) do
|
||||||
|
{:ok, pools_count} =
|
||||||
|
Cachex.get(
|
||||||
|
:esi_auth_cache,
|
||||||
|
"configs_total_count"
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
%{id: "#{pool_id}", title: "Pool #{pool_id}", value: pools_character_count}
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:ok, pools}
|
||||||
|
else
|
||||||
|
{:ok, []}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -54,7 +54,8 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
|
|||||||
|
|
||||||
{:ok, latest_transactions} = WandererApp.Api.CorpWalletTransaction.latest()
|
{: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 ->
|
true ->
|
||||||
Process.send_after(self(), :update_corp_wallets, 500)
|
Process.send_after(self(), :update_corp_wallets, 500)
|
||||||
Process.send_after(self(), :check_wallets, 500)
|
Process.send_after(self(), :check_wallets, 500)
|
||||||
@@ -145,7 +146,12 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp get_wallet_journal(
|
defp get_wallet_journal(
|
||||||
%{id: character_id, corporation_id: corporation_id, access_token: access_token} =
|
%{
|
||||||
|
id: character_id,
|
||||||
|
corporation_id: corporation_id,
|
||||||
|
access_token: access_token,
|
||||||
|
tracking_pool: tracking_pool
|
||||||
|
} =
|
||||||
_character,
|
_character,
|
||||||
division
|
division
|
||||||
)
|
)
|
||||||
@@ -163,7 +169,7 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
|
|||||||
{:error, :forbidden}
|
{:error, :forbidden}
|
||||||
|
|
||||||
{:error, :error_limited, _headers} ->
|
{:error, :error_limited, _headers} ->
|
||||||
Logger.warning("#{__MODULE__} failed to get_wallet_journal: error_limited")
|
Logger.warning("#{inspect(tracking_pool)} ..")
|
||||||
{:error, :error_limited}
|
{:error, :error_limited}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
@@ -175,7 +181,12 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
|
|||||||
defp get_wallet_journal(_character, _division), do: {:error, :skipped}
|
defp get_wallet_journal(_character, _division), do: {:error, :skipped}
|
||||||
|
|
||||||
defp update_corp_wallets(
|
defp update_corp_wallets(
|
||||||
%{id: character_id, corporation_id: corporation_id, access_token: access_token} =
|
%{
|
||||||
|
id: character_id,
|
||||||
|
corporation_id: corporation_id,
|
||||||
|
access_token: access_token,
|
||||||
|
tracking_pool: tracking_pool
|
||||||
|
} =
|
||||||
_character
|
_character
|
||||||
)
|
)
|
||||||
when not is_nil(access_token) do
|
when not is_nil(access_token) do
|
||||||
@@ -192,7 +203,7 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
|
|||||||
{:error, :forbidden}
|
{:error, :forbidden}
|
||||||
|
|
||||||
{:error, :error_limited, _headers} ->
|
{:error, :error_limited, _headers} ->
|
||||||
Logger.warning("#{__MODULE__} failed to update_corp_wallets: error_limited")
|
Logger.warning("#{inspect(tracking_pool)} ..")
|
||||||
{:error, :error_limited}
|
{:error, :error_limited}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
|
|||||||
@@ -16,6 +16,19 @@ defmodule WandererApp.Env do
|
|||||||
def invites, do: get_key(:invites, false)
|
def invites, do: get_key(:invites, false)
|
||||||
def map_subscriptions_enabled?, do: get_key(:map_subscriptions_enabled, false)
|
def map_subscriptions_enabled?, do: get_key(:map_subscriptions_enabled, false)
|
||||||
def public_api_disabled?, do: get_key(:public_api_disabled, 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")
|
||||||
|
|
||||||
|
@decorate cacheable(
|
||||||
|
cache: WandererApp.Cache,
|
||||||
|
key: "tracking_pool_max_size"
|
||||||
|
)
|
||||||
|
def tracking_pool_max_size, do: get_key(:tracking_pool_max_size, 300)
|
||||||
|
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 character_api_disabled?, do: get_key(:character_api_disabled, false)
|
||||||
def zkill_preload_disabled?, do: get_key(:zkill_preload_disabled, false)
|
def zkill_preload_disabled?, do: get_key(:zkill_preload_disabled, false)
|
||||||
def wallet_tracking_enabled?, do: get_key(:wallet_tracking_enabled, false)
|
def wallet_tracking_enabled?, do: get_key(:wallet_tracking_enabled, false)
|
||||||
@@ -23,6 +36,7 @@ defmodule WandererApp.Env do
|
|||||||
def admin_username, do: get_key(:admin_username)
|
def admin_username, do: get_key(:admin_username)
|
||||||
def admin_password, do: get_key(:admin_password)
|
def admin_password, do: get_key(:admin_password)
|
||||||
def corp_wallet, do: get_key(:corp_wallet, "")
|
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 corp_eve_id, do: get_key(:corp_id, -1)
|
||||||
def subscription_settings, do: get_key(:subscription_settings)
|
def subscription_settings, do: get_key(:subscription_settings)
|
||||||
|
|
||||||
|
|||||||
@@ -536,7 +536,6 @@ defmodule WandererApp.Esi.ApiClient do
|
|||||||
{:error, :not_found}
|
{:error, :not_found}
|
||||||
|
|
||||||
{:ok, %{status: 420, headers: headers} = _error} ->
|
{:ok, %{status: 420, headers: headers} = _error} ->
|
||||||
Logger.warning("#{path} error_limited error: #{inspect(headers)}")
|
|
||||||
{:error, :error_limited, headers}
|
{:error, :error_limited, headers}
|
||||||
|
|
||||||
{:ok, %{status: status} = _error} when status in [401, 403] ->
|
{:ok, %{status: status} = _error} when status in [401, 403] ->
|
||||||
@@ -593,7 +592,6 @@ defmodule WandererApp.Esi.ApiClient do
|
|||||||
{:error, :forbidden}
|
{:error, :forbidden}
|
||||||
|
|
||||||
{:ok, %{status: 420, headers: headers} = _error} ->
|
{:ok, %{status: 420, headers: headers} = _error} ->
|
||||||
Logger.warning("#{url} error_limited error: #{inspect(headers)}")
|
|
||||||
{:error, :error_limited, headers}
|
{:error, :error_limited, headers}
|
||||||
|
|
||||||
{:ok, %{status: status}} ->
|
{:ok, %{status: status}} ->
|
||||||
@@ -632,7 +630,6 @@ defmodule WandererApp.Esi.ApiClient do
|
|||||||
{:error, :forbidden}
|
{:error, :forbidden}
|
||||||
|
|
||||||
{:ok, %{status: 420, headers: headers} = _error} ->
|
{:ok, %{status: 420, headers: headers} = _error} ->
|
||||||
Logger.warning("#{url} error_limited error: #{inspect(headers)}")
|
|
||||||
{:error, :error_limited, headers}
|
{:error, :error_limited, headers}
|
||||||
|
|
||||||
{:ok, %{status: status}} ->
|
{:ok, %{status: status}} ->
|
||||||
@@ -674,13 +671,20 @@ defmodule WandererApp.Esi.ApiClient do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp refresh_token(character_id) do
|
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)
|
WandererApp.Character.get_character(character_id)
|
||||||
|
|
||||||
refresh_token_result =
|
refresh_token_result =
|
||||||
WandererApp.Ueberauth.Strategy.Eve.OAuth.get_refresh_token([],
|
WandererApp.Ueberauth.Strategy.Eve.OAuth.get_refresh_token([],
|
||||||
with_wallet: WandererApp.Character.can_track_wallet?(character),
|
with_wallet: WandererApp.Character.can_track_wallet?(character),
|
||||||
is_admin?: WandererApp.Character.can_track_corp_wallet?(character),
|
is_admin?: WandererApp.Character.can_track_corp_wallet?(character),
|
||||||
|
tracking_pool: tracking_pool,
|
||||||
token: %OAuth2.AccessToken{refresh_token: refresh_token}
|
token: %OAuth2.AccessToken{refresh_token: refresh_token}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ defmodule WandererApp.StartCorpWalletTrackerTask do
|
|||||||
|
|
||||||
user_hash ->
|
user_hash ->
|
||||||
user_hash
|
user_hash
|
||||||
|> _get_user_characters()
|
|> get_user_characters()
|
||||||
|> maybe_start_corp_wallet_tracker()
|
|> maybe_start_corp_wallet_tracker()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -25,6 +25,7 @@ defmodule WandererApp.StartCorpWalletTrackerTask do
|
|||||||
admin_character =
|
admin_character =
|
||||||
user_characters
|
user_characters
|
||||||
|> Enum.find(fn character ->
|
|> Enum.find(fn character ->
|
||||||
|
character.eve_id == WandererApp.Env.corp_wallet_eve_id() &&
|
||||||
WandererApp.Character.can_track_corp_wallet?(character)
|
WandererApp.Character.can_track_corp_wallet?(character)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -41,12 +42,12 @@ defmodule WandererApp.StartCorpWalletTrackerTask do
|
|||||||
|
|
||||||
def maybe_start_corp_wallet_tracker(_), do: :ok
|
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
|
case WandererApp.Api.User.by_hash(user_hash, load: :characters) do
|
||||||
{:ok, user} -> {:ok, user.characters}
|
{:ok, user} -> {:ok, user.characters}
|
||||||
{:error, _} -> {:ok, []}
|
{:error, _} -> {:ok, []}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp _get_user_characters(_), do: {:ok, []}
|
defp get_user_characters(_), do: {:ok, []}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -138,13 +138,8 @@ defmodule WandererApp.Map do
|
|||||||
def add_characters!(map, []), do: map
|
def add_characters!(map, []), do: map
|
||||||
|
|
||||||
def add_characters!(%{map_id: map_id} = map, [character | rest]) do
|
def add_characters!(%{map_id: map_id} = map, [character | rest]) do
|
||||||
case add_character(map_id, character) do
|
add_character(map_id, character)
|
||||||
:ok ->
|
|
||||||
add_characters!(map, rest)
|
add_characters!(map, rest)
|
||||||
|
|
||||||
{:error, :already_exists} ->
|
|
||||||
add_characters!(map, rest)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_character(
|
def add_character(
|
||||||
@@ -172,15 +167,15 @@ defmodule WandererApp.Map do
|
|||||||
map_id
|
map_id
|
||||||
|> update_map(%{characters: [character_id | characters]})
|
|> update_map(%{characters: [character_id | characters]})
|
||||||
|
|
||||||
WandererApp.Cache.insert(
|
# WandererApp.Cache.insert(
|
||||||
"map:#{map_id}:character:#{character_id}:alliance_id",
|
# "map:#{map_id}:character:#{character_id}:alliance_id",
|
||||||
alliance_id
|
# alliance_id
|
||||||
)
|
# )
|
||||||
|
|
||||||
WandererApp.Cache.insert(
|
# WandererApp.Cache.insert(
|
||||||
"map:#{map_id}:character:#{character_id}:corporation_id",
|
# "map:#{map_id}:character:#{character_id}:corporation_id",
|
||||||
corporation_id
|
# corporation_id
|
||||||
)
|
# )
|
||||||
|
|
||||||
# WandererApp.Cache.insert(
|
# WandererApp.Cache.insert(
|
||||||
# "map:#{map_id}:character:#{character_id}:solar_system_id",
|
# "map:#{map_id}:character:#{character_id}:solar_system_id",
|
||||||
@@ -294,14 +289,16 @@ defmodule WandererApp.Map do
|
|||||||
map_id
|
map_id
|
||||||
|> update_map(%{characters_limit: characters_limit, hubs_limit: hubs_limit})
|
|> update_map(%{characters_limit: characters_limit, hubs_limit: hubs_limit})
|
||||||
|
|
||||||
map
|
map_id
|
||||||
|
|> get_map!()
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_options!(%{map_id: map_id} = map, options) do
|
def update_options!(%{map_id: map_id} = map, options) do
|
||||||
map_id
|
map_id
|
||||||
|> update_map(%{options: options})
|
|> update_map(%{options: options})
|
||||||
|
|
||||||
map
|
map_id
|
||||||
|
|> get_map!()
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_systems!(map, []), do: map
|
def add_systems!(map, []), do: map
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ defmodule WandererApp.Map.Operations do
|
|||||||
{:ok, map()} | {:skip, :exists} | {:error, String.t()}
|
{:ok, map()} | {:skip, :exists} | {:error, String.t()}
|
||||||
defdelegate create_connection(map_id, attrs, char_id), to: Connections
|
defdelegate create_connection(map_id, attrs, char_id), to: Connections
|
||||||
|
|
||||||
|
@doc "Create a connection from a Plug.Conn"
|
||||||
|
@spec create_connection(Plug.Conn.t(), map()) ::
|
||||||
|
{:ok, :created} | {:skip, :exists} | {:error, atom()}
|
||||||
|
defdelegate create_connection(conn, attrs), to: Connections
|
||||||
|
|
||||||
@doc "Update a connection"
|
@doc "Update a connection"
|
||||||
@spec update_connection(String.t(), String.t(), map()) ::
|
@spec update_connection(String.t(), String.t(), map()) ::
|
||||||
{:ok, map()} | {:error, String.t()}
|
{:ok, map()} | {:error, String.t()}
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ defmodule WandererApp.Map.Server do
|
|||||||
do:
|
do:
|
||||||
map_id
|
map_id
|
||||||
|> map_pid!
|
|> 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),
|
def delete_connection(map_id, connection_info) when is_binary(map_id),
|
||||||
do:
|
do:
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ defmodule WandererApp.Map.Operations.Connections do
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
alias WandererApp.Map.Server.{ConnectionsImpl, Server}
|
alias WandererApp.Map.Server
|
||||||
alias Ash.Error.Invalid
|
alias Ash.Error.Invalid
|
||||||
alias WandererApp.MapConnectionRepo
|
alias WandererApp.MapConnectionRepo
|
||||||
|
alias WandererApp.CachedInfo
|
||||||
|
|
||||||
# Connection type constants
|
# Connection type constants
|
||||||
@connection_type_wormhole 0
|
@connection_type_wormhole 0
|
||||||
@@ -20,7 +21,7 @@ defmodule WandererApp.Map.Operations.Connections do
|
|||||||
@xlarge_ship_size 3
|
@xlarge_ship_size 3
|
||||||
|
|
||||||
# System class constants
|
# System class constants
|
||||||
@c1_system_class "C1"
|
@c1_system_class 1
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates a connection between two systems, applying special rules for C1 wormholes.
|
Creates a connection between two systems, applying special rules for C1 wormholes.
|
||||||
@@ -34,8 +35,8 @@ defmodule WandererApp.Map.Operations.Connections do
|
|||||||
defp do_create(attrs, map_id, char_id) do
|
defp do_create(attrs, map_id, char_id) do
|
||||||
with {:ok, source} <- parse_int(attrs["solar_system_source"], "solar_system_source"),
|
with {:ok, source} <- parse_int(attrs["solar_system_source"], "solar_system_source"),
|
||||||
{:ok, target} <- parse_int(attrs["solar_system_target"], "solar_system_target"),
|
{:ok, target} <- parse_int(attrs["solar_system_target"], "solar_system_target"),
|
||||||
{:ok, src_info} <- ConnectionsImpl.get_system_static_info(source),
|
{:ok, src_info} <- CachedInfo.get_system_static_info(source),
|
||||||
{:ok, tgt_info} <- ConnectionsImpl.get_system_static_info(target) do
|
{:ok, tgt_info} <- CachedInfo.get_system_static_info(target) do
|
||||||
build_and_add_connection(attrs, map_id, char_id, src_info, tgt_info)
|
build_and_add_connection(attrs, map_id, char_id, src_info, tgt_info)
|
||||||
else
|
else
|
||||||
{:error, reason} -> handle_precondition_error(reason, attrs)
|
{:error, reason} -> handle_precondition_error(reason, attrs)
|
||||||
@@ -45,6 +46,12 @@ defmodule WandererApp.Map.Operations.Connections do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp build_and_add_connection(attrs, map_id, char_id, src_info, tgt_info) do
|
defp build_and_add_connection(attrs, map_id, char_id, src_info, tgt_info) do
|
||||||
|
Logger.debug("[Connections] build_and_add_connection called with src_info: #{inspect(src_info)}, tgt_info: #{inspect(tgt_info)}")
|
||||||
|
|
||||||
|
# Guard against nil info
|
||||||
|
if is_nil(src_info) or is_nil(tgt_info) do
|
||||||
|
{:error, :invalid_system_info}
|
||||||
|
else
|
||||||
info = %{
|
info = %{
|
||||||
solar_system_source_id: src_info.solar_system_id,
|
solar_system_source_id: src_info.solar_system_id,
|
||||||
solar_system_target_id: tgt_info.solar_system_id,
|
solar_system_target_id: tgt_info.solar_system_id,
|
||||||
@@ -62,6 +69,7 @@ defmodule WandererApp.Map.Operations.Connections do
|
|||||||
other -> Logger.error("[add_connection] unexpected: #{inspect(other)}"); {:error, :unexpected_error}
|
other -> Logger.error("[add_connection] unexpected: #{inspect(other)}"); {:error, :unexpected_error}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp resolve_ship_size(attrs, src_info, tgt_info) do
|
defp resolve_ship_size(attrs, src_info, tgt_info) do
|
||||||
type = parse_type(attrs["type"])
|
type = parse_type(attrs["type"])
|
||||||
|
|||||||
@@ -86,19 +86,24 @@ defmodule WandererApp.Map.Server.CharactersImpl do
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def untrack_characters(map_id, character_ids),
|
def untrack_characters(map_id, character_ids) do
|
||||||
do:
|
|
||||||
character_ids
|
character_ids
|
||||||
|> Enum.each(fn character_id ->
|
|> Enum.each(fn character_id ->
|
||||||
if is_character_map_active?(map_id, character_id) do
|
is_character_map_active?(map_id, character_id)
|
||||||
|
|> untrack_character(map_id, character_id)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def untrack_character(true, map_id, character_id) do
|
||||||
WandererApp.Character.TrackerManager.update_track_settings(character_id, %{
|
WandererApp.Character.TrackerManager.update_track_settings(character_id, %{
|
||||||
map_id: map_id,
|
map_id: map_id,
|
||||||
track: false
|
track: false
|
||||||
})
|
})
|
||||||
|
|
||||||
Impl.broadcast!(map_id, :untrack_character, character_id)
|
|
||||||
end
|
end
|
||||||
end)
|
|
||||||
|
def untrack_character(_is_character_map_active, _map_id, character_id) do
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
def is_character_map_active?(map_id, character_id) do
|
def is_character_map_active?(map_id, character_id) do
|
||||||
case WandererApp.Character.get_character_state(character_id) do
|
case WandererApp.Character.get_character_state(character_id) do
|
||||||
@@ -219,8 +224,7 @@ defmodule WandererApp.Map.Server.CharactersImpl do
|
|||||||
Task.start_link(fn ->
|
Task.start_link(fn ->
|
||||||
character_updates =
|
character_updates =
|
||||||
maybe_update_online(map_id, character_id) ++
|
maybe_update_online(map_id, character_id) ++
|
||||||
maybe_update_tracking_status(map_id, character_id)
|
maybe_update_tracking_status(map_id, character_id) ++
|
||||||
|
|
||||||
maybe_update_location(map_id, character_id) ++
|
maybe_update_location(map_id, character_id) ++
|
||||||
maybe_update_ship(map_id, character_id) ++
|
maybe_update_ship(map_id, character_id) ++
|
||||||
maybe_update_alliance(map_id, character_id) ++
|
maybe_update_alliance(map_id, character_id) ++
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ defmodule WandererApp.Map.Server.Impl do
|
|||||||
|
|
||||||
@pubsub_client Application.compile_env(:wanderer_app, :pubsub_client)
|
@pubsub_client Application.compile_env(:wanderer_app, :pubsub_client)
|
||||||
@backup_state_timeout :timer.minutes(1)
|
@backup_state_timeout :timer.minutes(1)
|
||||||
@update_presence_timeout :timer.seconds(1)
|
@update_presence_timeout :timer.seconds(5)
|
||||||
@update_characters_timeout :timer.seconds(1)
|
@update_characters_timeout :timer.seconds(1)
|
||||||
@update_tracked_characters_timeout :timer.seconds(1)
|
@update_tracked_characters_timeout :timer.seconds(1)
|
||||||
|
|
||||||
|
|||||||
@@ -20,17 +20,9 @@ defmodule WandererApp.Ueberauth.Strategy.Eve do
|
|||||||
is_admin? = Map.get(params, "admin", "false") in ~w(true 1)
|
is_admin? = Map.get(params, "admin", "false") in ~w(true 1)
|
||||||
invite_token = Map.get(params, "invite", nil)
|
invite_token = Map.get(params, "invite", nil)
|
||||||
|
|
||||||
invite_token_valid =
|
{invite_token_valid, invite_type} = check_invite_valid(invite_token)
|
||||||
case WandererApp.Env.invites() do
|
|
||||||
true ->
|
|
||||||
case invite_token do
|
|
||||||
nil -> false
|
|
||||||
token -> WandererApp.Cache.lookup!("invite_#{token}", false)
|
|
||||||
end
|
|
||||||
|
|
||||||
_ ->
|
is_admin? = is_admin? || invite_type == :admin
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
case invite_token_valid do
|
case invite_token_valid do
|
||||||
true ->
|
true ->
|
||||||
@@ -200,10 +192,13 @@ defmodule WandererApp.Ueberauth.Strategy.Eve do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp oauth_client_options_from_conn(conn, with_wallet, is_admin?) do
|
defp oauth_client_options_from_conn(conn, with_wallet, is_admin?) do
|
||||||
|
tracking_pool = WandererApp.Character.TrackingConfigUtils.get_active_pool!()
|
||||||
|
|
||||||
base_options = [
|
base_options = [
|
||||||
redirect_uri: callback_url(conn),
|
redirect_uri: callback_url(conn),
|
||||||
with_wallet: with_wallet,
|
with_wallet: with_wallet,
|
||||||
is_admin?: is_admin?
|
is_admin?: is_admin?,
|
||||||
|
tracking_pool: tracking_pool
|
||||||
]
|
]
|
||||||
|
|
||||||
request_options = conn.private[:ueberauth_request_options].options
|
request_options = conn.private[:ueberauth_request_options].options
|
||||||
@@ -218,4 +213,33 @@ defmodule WandererApp.Ueberauth.Strategy.Eve do
|
|||||||
defp option(conn, key) do
|
defp option(conn, key) do
|
||||||
Keyword.get(options(conn), key, Keyword.get(default_options(), key))
|
Keyword.get(options(conn), key, Keyword.get(default_options(), key))
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
79
lib/wanderer_app/ueberauth/strategy/eve/init_configs_task.ex
Normal file
79
lib/wanderer_app/ueberauth/strategy/eve/init_configs_task.ex
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
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")
|
||||||
|
|
||||||
|
cache_clients()
|
||||||
|
WandererApp.Character.TrackingConfigUtils.update_active_tracking_pool()
|
||||||
|
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
|
@moduledoc false
|
||||||
|
|
||||||
def client_id(opts \\ []) do
|
def client_id(opts \\ []) do
|
||||||
config = _get_config()
|
config = get_config()
|
||||||
|
tracking_pool = Keyword.get(opts, :tracking_pool)
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
Keyword.get(opts, :is_admin?) -> config[:client_id_with_corp_wallet]
|
Keyword.get(opts, :is_admin?) -> config[:client_id_with_corp_wallet]
|
||||||
Keyword.get(opts, :with_wallet) -> config[:client_id_with_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]
|
true -> config[:client_id_default]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def client_secret(opts \\ []) do
|
def client_secret(opts \\ []) do
|
||||||
config = _get_config()
|
config = get_config()
|
||||||
|
tracking_pool = Keyword.get(opts, :tracking_pool)
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
Keyword.get(opts, :is_admin?) -> config[:client_secret_with_corp_wallet]
|
Keyword.get(opts, :is_admin?) -> config[:client_secret_with_corp_wallet]
|
||||||
Keyword.get(opts, :with_wallet) -> config[:client_secret_with_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]
|
true -> config[:client_secret_default]
|
||||||
end
|
end
|
||||||
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, [])
|
Application.get_env(:ueberauth, WandererApp.Ueberauth.Strategy.Eve.OAuth, [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ defmodule WandererApp.Zkb.KillsProvider.Fetcher do
|
|||||||
Returns `{:ok, kills, updated_state}` on success, or `{:error, reason, updated_state}`.
|
Returns `{:ok, kills, updated_state}` on success, or `{:error, reason, updated_state}`.
|
||||||
"""
|
"""
|
||||||
def fetch_kills_for_system(system_id, since_hours, state, opts \\ []) do
|
def fetch_kills_for_system(system_id, since_hours, state, opts \\ []) do
|
||||||
|
zkill_preload_disabled = WandererApp.Env.zkill_preload_disabled?()
|
||||||
|
|
||||||
|
if not zkill_preload_disabled do
|
||||||
limit = Keyword.get(opts, :limit, nil)
|
limit = Keyword.get(opts, :limit, nil)
|
||||||
force? = Keyword.get(opts, :force, false)
|
force? = Keyword.get(opts, :force, false)
|
||||||
|
|
||||||
@@ -119,6 +122,9 @@ defmodule WandererApp.Zkb.KillsProvider.Fetcher do
|
|||||||
{:error, error, state}
|
{:error, error, state}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
raise ":kills_disabled"
|
||||||
|
end
|
||||||
rescue
|
rescue
|
||||||
e ->
|
e ->
|
||||||
Logger.error("[Fetcher] EXCEPTION in fetch_kills_for_system => #{Exception.message(e)}")
|
Logger.error("[Fetcher] EXCEPTION in fetch_kills_for_system => #{Exception.message(e)}")
|
||||||
|
|||||||
@@ -8,13 +8,16 @@ defmodule WandererAppWeb.AuthController do
|
|||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
def callback(%{assigns: %{ueberauth_auth: auth, current_user: user} = _assigns} = conn, _params) do
|
def callback(%{assigns: %{ueberauth_auth: auth, current_user: user} = _assigns} = conn, _params) do
|
||||||
|
active_tracking_pool = WandererApp.Character.TrackingConfigUtils.get_active_pool!()
|
||||||
|
|
||||||
character_data = %{
|
character_data = %{
|
||||||
eve_id: "#{auth.info.email}",
|
eve_id: "#{auth.info.email}",
|
||||||
name: auth.info.name,
|
name: auth.info.name,
|
||||||
access_token: auth.credentials.token,
|
access_token: auth.credentials.token,
|
||||||
refresh_token: auth.credentials.refresh_token,
|
refresh_token: auth.credentials.refresh_token,
|
||||||
expires_at: auth.credentials.expires_at,
|
expires_at: auth.credentials.expires_at,
|
||||||
scopes: auth.credentials.scopes
|
scopes: auth.credentials.scopes,
|
||||||
|
tracking_pool: active_tracking_pool
|
||||||
}
|
}
|
||||||
|
|
||||||
%{
|
%{
|
||||||
@@ -29,7 +32,8 @@ defmodule WandererAppWeb.AuthController do
|
|||||||
access_token: auth.credentials.token,
|
access_token: auth.credentials.token,
|
||||||
refresh_token: auth.credentials.refresh_token,
|
refresh_token: auth.credentials.refresh_token,
|
||||||
expires_at: auth.credentials.expires_at,
|
expires_at: auth.credentials.expires_at,
|
||||||
scopes: auth.credentials.scopes
|
scopes: auth.credentials.scopes,
|
||||||
|
tracking_pool: active_tracking_pool
|
||||||
}
|
}
|
||||||
|
|
||||||
{:ok, character} =
|
{:ok, character} =
|
||||||
@@ -78,6 +82,8 @@ defmodule WandererAppWeb.AuthController do
|
|||||||
|
|
||||||
maybe_update_character_user_id(character, user_id)
|
maybe_update_character_user_id(character, user_id)
|
||||||
|
|
||||||
|
WandererApp.Character.TrackingConfigUtils.update_active_tracking_pool()
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_session(:user_id, user_id)
|
|> put_session(:user_id, user_id)
|
||||||
|> redirect(to: "/characters")
|
|> redirect(to: "/characters")
|
||||||
|
|||||||
@@ -266,6 +266,10 @@ defmodule WandererAppWeb.MapConnectionAPIController do
|
|||||||
conn
|
conn
|
||||||
|> put_status(:bad_request)
|
|> put_status(:bad_request)
|
||||||
|> json(%{error: reason})
|
|> json(%{error: reason})
|
||||||
|
{:error, :precondition_failed, _reason} ->
|
||||||
|
conn
|
||||||
|
|> put_status(:bad_request)
|
||||||
|
|> json(%{error: "Invalid request parameters"})
|
||||||
_other ->
|
_other ->
|
||||||
conn
|
conn
|
||||||
|> put_status(:internal_server_error)
|
|> put_status(:internal_server_error)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
|||||||
solar_system_id: %Schema{type: :integer, description: "EVE solar system ID"},
|
solar_system_id: %Schema{type: :integer, description: "EVE solar system ID"},
|
||||||
solar_system_name: %Schema{type: :string, description: "EVE solar system name"},
|
solar_system_name: %Schema{type: :string, description: "EVE solar system name"},
|
||||||
region_name: %Schema{type: :string, description: "EVE region name"},
|
region_name: %Schema{type: :string, description: "EVE region name"},
|
||||||
|
custom_name: %Schema{type: :string, nullable: true, description: "Custom name for the system"},
|
||||||
position_x: %Schema{type: :integer, description: "X coordinate"},
|
position_x: %Schema{type: :integer, description: "X coordinate"},
|
||||||
position_y: %Schema{type: :integer, description: "Y coordinate"},
|
position_y: %Schema{type: :integer, description: "Y coordinate"},
|
||||||
status: %Schema{
|
status: %Schema{
|
||||||
@@ -137,6 +138,7 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
|||||||
solar_system_id: 30_000_142,
|
solar_system_id: 30_000_142,
|
||||||
solar_system_name: "Jita",
|
solar_system_name: "Jita",
|
||||||
region_name: "The Forge",
|
region_name: "The Forge",
|
||||||
|
custom_name: "Trade Hub Central",
|
||||||
position_x: 100.5,
|
position_x: 100.5,
|
||||||
position_y: 200.3,
|
position_y: 200.3,
|
||||||
status: "active",
|
status: "active",
|
||||||
@@ -179,6 +181,7 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
|||||||
solar_system_id: 30_000_142,
|
solar_system_id: 30_000_142,
|
||||||
solar_system_name: "Jita",
|
solar_system_name: "Jita",
|
||||||
region_name: "The Forge",
|
region_name: "The Forge",
|
||||||
|
custom_name: "Trade Hub Central",
|
||||||
position_x: 100.5,
|
position_x: 100.5,
|
||||||
position_y: 200.3,
|
position_y: 200.3,
|
||||||
status: "active",
|
status: "active",
|
||||||
|
|||||||
@@ -262,13 +262,18 @@ defmodule WandererAppWeb.Helpers.APIUtils do
|
|||||||
|
|
||||||
@spec map_system_to_json(struct()) :: map()
|
@spec map_system_to_json(struct()) :: map()
|
||||||
def map_system_to_json(system) do
|
def map_system_to_json(system) do
|
||||||
|
original = get_original_name(system.solar_system_id)
|
||||||
|
|
||||||
|
# Determine the actual custom_name: if name differs from original, use it as custom_name
|
||||||
|
actual_custom_name = if system.name != original and system.name not in [nil, ""], do: system.name, else: system.custom_name
|
||||||
|
|
||||||
base =
|
base =
|
||||||
Map.take(system, ~w(
|
Map.take(system, ~w(
|
||||||
id map_id solar_system_id custom_name temporary_name description tag labels
|
id map_id solar_system_id temporary_name description tag labels
|
||||||
locked visible status position_x position_y inserted_at updated_at
|
locked visible status position_x position_y inserted_at updated_at
|
||||||
)a)
|
)a)
|
||||||
|
|> Map.put(:custom_name, actual_custom_name)
|
||||||
|
|
||||||
original = get_original_name(system.solar_system_id)
|
|
||||||
name = pick_name(system)
|
name = pick_name(system)
|
||||||
|
|
||||||
base
|
base
|
||||||
@@ -283,11 +288,15 @@ defmodule WandererAppWeb.Helpers.APIUtils do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp pick_name(%{temporary_name: t, custom_name: c, solar_system_id: id}) do
|
defp pick_name(%{temporary_name: t, custom_name: c, name: n, solar_system_id: id} = system) do
|
||||||
|
original = get_original_name(id)
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
t not in [nil, ""] -> t
|
t not in [nil, ""] -> t
|
||||||
c not in [nil, ""] -> c
|
c not in [nil, ""] -> c
|
||||||
true -> get_original_name(id)
|
# If name differs from original, it's a custom name
|
||||||
|
n not in [nil, ""] and n != original -> n
|
||||||
|
true -> original
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ defmodule WandererAppWeb.AdminLive do
|
|||||||
corp_wallet_character =
|
corp_wallet_character =
|
||||||
socket.assigns.current_user.characters
|
socket.assigns.current_user.characters
|
||||||
|> Enum.find(fn character ->
|
|> Enum.find(fn character ->
|
||||||
|
character.eve_id == WandererApp.Env.corp_wallet_eve_id() &&
|
||||||
WandererApp.Character.can_track_corp_wallet?(character)
|
WandererApp.Character.can_track_corp_wallet?(character)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -58,10 +59,11 @@ defmodule WandererAppWeb.AdminLive do
|
|||||||
socket
|
socket
|
||||||
|> assign(
|
|> assign(
|
||||||
active_map_subscriptions: active_map_subscriptions,
|
active_map_subscriptions: active_map_subscriptions,
|
||||||
show_invites?: WandererApp.Env.invites(),
|
|
||||||
user_character_ids: user_character_ids,
|
user_character_ids: user_character_ids,
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
invite_link: nil,
|
invite_link: nil,
|
||||||
|
tracker_stats: [],
|
||||||
|
active_tracking_pool: "default",
|
||||||
map_subscriptions_enabled?: WandererApp.Env.map_subscriptions_enabled?(),
|
map_subscriptions_enabled?: WandererApp.Env.map_subscriptions_enabled?(),
|
||||||
restrict_maps_creation?: WandererApp.Env.restrict_maps_creation?()
|
restrict_maps_creation?: WandererApp.Env.restrict_maps_creation?()
|
||||||
)}
|
)}
|
||||||
@@ -77,21 +79,6 @@ defmodule WandererAppWeb.AdminLive do
|
|||||||
{:noreply, apply_action(socket, socket.assigns.live_action, params, uri)}
|
{:noreply, apply_action(socket, socket.assigns.live_action, params, uri)}
|
||||||
end
|
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
|
@impl true
|
||||||
def handle_event("update-eve-db-data", _params, socket) do
|
def handle_event("update-eve-db-data", _params, socket) do
|
||||||
WandererApp.EveDataService.update_eve_data()
|
WandererApp.EveDataService.update_eve_data()
|
||||||
@@ -224,6 +211,58 @@ defmodule WandererAppWeb.AdminLive do
|
|||||||
|> push_navigate(to: ~p"/maps/new")}
|
|> push_navigate(to: ~p"/maps/new")}
|
||||||
end
|
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
|
@impl true
|
||||||
def handle_event(event, body, socket) do
|
def handle_event(event, body, socket) do
|
||||||
Logger.warning(fn -> "unhandled event: #{event} #{inspect(body)}" end)
|
Logger.warning(fn -> "unhandled event: #{event} #{inspect(body)}" end)
|
||||||
@@ -255,6 +294,11 @@ defmodule WandererAppWeb.AdminLive do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp apply_action(socket, :index, _params, uri) do
|
defp apply_action(socket, :index, _params, uri) do
|
||||||
|
{:ok, invites} = WandererApp.Api.MapInvite.read()
|
||||||
|
|
||||||
|
{:ok, tracker_stats} = WandererApp.Character.TrackingConfigUtils.load_tracker_stats()
|
||||||
|
active_tracking_pool = WandererApp.Character.TrackingConfigUtils.get_active_pool!()
|
||||||
|
|
||||||
socket
|
socket
|
||||||
|> assign(:active_page, :admin)
|
|> assign(:active_page, :admin)
|
||||||
|> assign(:uri, URI.parse(uri))
|
|> assign(:uri, URI.parse(uri))
|
||||||
@@ -268,6 +312,50 @@ defmodule WandererAppWeb.AdminLive do
|
|||||||
])
|
])
|
||||||
|> assign(:form, to_form(%{"amount" => 500_000_000}))
|
|> assign(:form, to_form(%{"amount" => 500_000_000}))
|
||||||
|> assign(:unlink_character_form, to_form(%{}))
|
|> assign(:unlink_character_form, to_form(%{}))
|
||||||
|
|> assign(:invites, invites)
|
||||||
|
|> assign(:tracker_stats, tracker_stats)
|
||||||
|
|> assign(:active_tracking_pool, active_tracking_pool)
|
||||||
|
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
|
end
|
||||||
|
|
||||||
defp search(search) do
|
defp search(search) do
|
||||||
@@ -290,11 +378,29 @@ defmodule WandererAppWeb.AdminLive do
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span :if={@option.value == :loading} <span class="loading loading-spinner loading-xs"></span>
|
<span :if={@option.value == :loading} <span class="loading loading-spinner loading-xs"></span>
|
||||||
<%= @option.label %>
|
{@option.label}
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
end
|
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),
|
def search_member_icon_url(%{character: true} = option),
|
||||||
do: member_icon_url(%{eve_character_id: option.value})
|
do: member_icon_url(%{eve_character_id: option.value})
|
||||||
|
|
||||||
|
|||||||
@@ -112,27 +112,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</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="card-body">
|
||||||
<div class="col-span-6">
|
<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">
|
<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">
|
<.link class="btn mt-2 w-full btn-neutral rounded-none" patch={~p"/admin/invite"}>
|
||||||
Generate
|
<.icon name="hero-plus-solid" class="w-6 h-6" />
|
||||||
</.button>
|
<h3 class="card-title text-center text-md">New Invite</h3>
|
||||||
|
</.link>
|
||||||
<div :if={not is_nil(@invite_link)} class="join">
|
</h4>
|
||||||
<input
|
<.table
|
||||||
class="input input-bordered join-item"
|
id="invites"
|
||||||
readonly
|
rows={@invites}
|
||||||
type="text"
|
class="!max-h-[40vh] !overflow-y-auto"
|
||||||
value={@invite_link}
|
>
|
||||||
/>
|
<: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
|
<.button
|
||||||
phx-hook="CopyToClipboard"
|
phx-hook="CopyToClipboard"
|
||||||
id="copy-to-clipboard"
|
id="copy-to-clipboard"
|
||||||
class="copy-link btn join-item rounded-r-full"
|
class="copy-link btn btn-neutral rounded-none"
|
||||||
data-url={@invite_link}
|
data-url={get_invite_link(@uri, invite.token)}
|
||||||
>
|
>
|
||||||
Copy
|
Copy
|
||||||
<div class="absolute w-[100px] !mr-[-170px] link-copied hidden">
|
<div class="absolute w-[100px] !mr-[-170px] link-copied hidden">
|
||||||
@@ -140,7 +142,52 @@
|
|||||||
</div>
|
</div>
|
||||||
</.button>
|
</.button>
|
||||||
</div>
|
</div>
|
||||||
</h4>
|
</: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="tracking_pools"
|
||||||
|
rows={@tracker_stats}
|
||||||
|
class="!max-h-[40vh] !overflow-y-auto"
|
||||||
|
>
|
||||||
|
<:col :let={stat} label="Pool">
|
||||||
|
<div class="w-[200px] no-wrap truncate">{stat.title}</div>
|
||||||
|
</:col>
|
||||||
|
<:col :let={stat} label="Active">
|
||||||
|
<div :if={stat.id == @active_tracking_pool}>true</div>
|
||||||
|
</:col>
|
||||||
|
<:col :let={stat} label="Count">
|
||||||
|
{stat.value}
|
||||||
|
</:col>
|
||||||
|
</.table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -261,4 +308,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</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>
|
</main>
|
||||||
|
|||||||
@@ -56,17 +56,27 @@ defmodule WandererAppWeb.CharactersLive do
|
|||||||
@impl true
|
@impl true
|
||||||
def handle_event("authorize", form, socket) do
|
def handle_event("authorize", form, socket) do
|
||||||
track_wallet = form |> Map.get("track_wallet", false)
|
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}")}
|
active_pool = WandererApp.Character.TrackingConfigUtils.get_active_pool!()
|
||||||
|
|
||||||
|
{:ok, esi_config} =
|
||||||
|
Cachex.get(
|
||||||
|
:esi_auth_cache,
|
||||||
|
"config_#{active_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
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("delete", %{"character_id" => character_id}, socket) do
|
def handle_event("delete", %{"character_id" => character_id}, socket) do
|
||||||
WandererApp.Character.TrackerManager.stop_tracking(character_id)
|
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
|
map_user_settings
|
||||||
|> Enum.each(fn settings ->
|
|> Enum.each(fn settings ->
|
||||||
@@ -87,6 +97,15 @@ defmodule WandererAppWeb.CharactersLive do
|
|||||||
{:noreply, socket |> assign(characters: characters |> Enum.map(&map_ui_character/1))}
|
{:noreply, socket |> assign(characters: characters |> Enum.map(&map_ui_character/1))}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_event(
|
||||||
|
"validate",
|
||||||
|
params,
|
||||||
|
socket
|
||||||
|
) do
|
||||||
|
{:noreply, assign(socket, form: params)}
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("show_table", %{"value" => "on"}, socket) do
|
def handle_event("show_table", %{"value" => "on"}, socket) do
|
||||||
{:noreply, socket |> assign(mode: :table)}
|
{:noreply, socket |> assign(mode: :table)}
|
||||||
@@ -148,7 +167,7 @@ defmodule WandererAppWeb.CharactersLive do
|
|||||||
socket
|
socket
|
||||||
|> assign(:active_page, :characters)
|
|> assign(:active_page, :characters)
|
||||||
|> assign(:page_title, "Authorize Character - Characters")
|
|> assign(:page_title, "Authorize Character - Characters")
|
||||||
|> assign(:form, to_form(%{"track_wallet" => false}))
|
|> assign(:form, to_form(%{}))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp map_ui_character(character) do
|
defp map_ui_character(character) do
|
||||||
|
|||||||
@@ -242,10 +242,13 @@
|
|||||||
show
|
show
|
||||||
on_cancel={JS.patch(~p"/characters")}
|
on_cancel={JS.patch(~p"/characters")}
|
||||||
>
|
>
|
||||||
<.form :let={f} for={@form} phx-submit="authorize">
|
<div class="flex flex-col gap-3">
|
||||||
<div :if={@wallet_tracking_enabled?} class="pb-2 -mt-8">
|
|
||||||
|
<.form :let={f} for={@form} phx-submit="authorize" phx-change="validate">
|
||||||
|
<div :if={@wallet_tracking_enabled?} class="pb-2">
|
||||||
<.input
|
<.input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|
||||||
field={f[:track_wallet]}
|
field={f[:track_wallet]}
|
||||||
label="Access to character wallet information"
|
label="Access to character wallet information"
|
||||||
/>
|
/>
|
||||||
@@ -254,5 +257,6 @@
|
|||||||
<.button type="submit">AUTHORIZE</.button>
|
<.button type="submit">AUTHORIZE</.button>
|
||||||
</div>
|
</div>
|
||||||
</.form>
|
</.form>
|
||||||
|
</div>
|
||||||
</.modal>
|
</.modal>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ defmodule WandererAppWeb.ServerStatusLive do
|
|||||||
"server_status"
|
"server_status"
|
||||||
)
|
)
|
||||||
|
|
||||||
{:ok, socket |> assign(server_online: false)}
|
{:ok, socket |> assign(server_online: true)}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|||||||
@@ -230,7 +230,11 @@ defmodule WandererAppWeb.Router do
|
|||||||
delete "/connections", MapConnectionAPIController, :delete
|
delete "/connections", MapConnectionAPIController, :delete
|
||||||
delete "/systems", MapSystemAPIController, :delete
|
delete "/systems", MapSystemAPIController, :delete
|
||||||
resources "/systems", MapSystemAPIController, only: [:index, :show, :create, :update, :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]
|
resources "/structures", MapSystemStructureAPIController, except: [:new, :edit]
|
||||||
get "/structure-timers", MapSystemStructureAPIController, :structure_timers
|
get "/structure-timers", MapSystemStructureAPIController, :structure_timers
|
||||||
resources "/signatures", MapSystemSignatureAPIController, except: [:new, :edit]
|
resources "/signatures", MapSystemSignatureAPIController, except: [:new, :edit]
|
||||||
@@ -238,8 +242,6 @@ defmodule WandererAppWeb.Router do
|
|||||||
get "/tracked-characters", MapAPIController, :show_tracked_characters
|
get "/tracked-characters", MapAPIController, :show_tracked_characters
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Other API routes
|
# Other API routes
|
||||||
#
|
#
|
||||||
@@ -359,6 +361,7 @@ defmodule WandererAppWeb.Router do
|
|||||||
WandererAppWeb.Nav
|
WandererAppWeb.Nav
|
||||||
] do
|
] do
|
||||||
live("/", AdminLive, :index)
|
live("/", AdminLive, :index)
|
||||||
|
live("/invite", AdminLive, :add_invite_link)
|
||||||
end
|
end
|
||||||
|
|
||||||
error_tracker_dashboard("/errors",
|
error_tracker_dashboard("/errors",
|
||||||
|
|||||||
2
mix.exs
2
mix.exs
@@ -3,7 +3,7 @@ defmodule WandererApp.MixProject do
|
|||||||
|
|
||||||
@source_url "https://github.com/wanderer-industries/wanderer"
|
@source_url "https://github.com/wanderer-industries/wanderer"
|
||||||
|
|
||||||
@version "1.66.15"
|
@version "1.70.5"
|
||||||
|
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
|
|||||||
40
priv/repo/migrations/20250608220906_add_map_invites.exs
Normal file
40
priv/repo/migrations/20250608220906_add_map_invites.exs
Normal 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
|
||||||
21
priv/repo/migrations/20250608221356_add_map_invite_type.exs
Normal file
21
priv/repo/migrations/20250608221356_add_map_invite_type.exs
Normal 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
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
108
priv/resource_snapshots/repo/map_invites_v1/20250608221356.json
Normal file
108
priv/resource_snapshots/repo/map_invites_v1/20250608221356.json
Normal 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"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user