mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-11-08 10:24:27 +00:00
Compare commits
27 Commits
map-events
...
v1.15.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29c840c64a | ||
|
|
65e0f89f33 | ||
|
|
d3b9b36332 | ||
|
|
90bbf29ea1 | ||
|
|
57f73684e8 | ||
|
|
7833cdebb2 | ||
|
|
67a5ae2985 | ||
|
|
f58c52d26b | ||
|
|
41e7739461 | ||
|
|
332152b677 | ||
|
|
85b49fe1f0 | ||
|
|
e7924532be | ||
|
|
475d950ad6 | ||
|
|
e6cfb29c6f | ||
|
|
dee6e86db1 | ||
|
|
72f088331f | ||
|
|
bbf536d10e | ||
|
|
149ac98297 | ||
|
|
b90a2910c9 | ||
|
|
c4da8a3a8d | ||
|
|
3ca75583d2 | ||
|
|
5f4607ae6f | ||
|
|
d880c6873f | ||
|
|
937649b2ed | ||
|
|
78e912c886 | ||
|
|
696c7d2cd1 | ||
|
|
49c0cb026b |
@@ -1,12 +1,7 @@
|
||||
FROM elixir:1.16-otp-25
|
||||
FROM elixir:1.17-otp-27
|
||||
|
||||
RUN apt update -yq
|
||||
RUN apt install -yq curl gnupg mc inotify-tools
|
||||
RUN apt install -yq curl gnupg
|
||||
RUN apt --fix-broken install
|
||||
RUN apt remove -y nodejs nodejs-doc
|
||||
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash -
|
||||
RUN apt install -y nodejs
|
||||
RUN npm install --global yarn
|
||||
|
||||
RUN mix local.hex --force
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "0.1"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:14.3
|
||||
image: postgres:13-alpine
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
@@ -10,13 +10,13 @@ services:
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- db:/var/lib/postgresql/data
|
||||
- db-new:/var/lib/postgresql/data
|
||||
|
||||
wanderer:
|
||||
environment:
|
||||
PORT: 8000
|
||||
DB_HOST: db
|
||||
WEB_APP_URL: "http://localhost:4444"
|
||||
WEB_APP_URL: "http://localhost:8000"
|
||||
ERL_AFLAGS: "-kernel shell_history enabled"
|
||||
build:
|
||||
context: .
|
||||
@@ -33,4 +33,4 @@ services:
|
||||
|
||||
volumes:
|
||||
elixir-artifacts: {}
|
||||
db: {}
|
||||
db-new: {}
|
||||
|
||||
2
.github/workflows/release_actions.yml
vendored
2
.github/workflows/release_actions.yml
vendored
@@ -18,4 +18,4 @@ jobs:
|
||||
key: ${{ secrets.SSH_KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: |
|
||||
/app/release/linux/deploy.sh ${{ github.event.release.tag_name }}
|
||||
/home/wanderer/app/deploy.sh ${{ github.event.release.tag_name }}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
erlang 25.3
|
||||
elixir 1.16-otp-25
|
||||
erlang 26.2.5.5
|
||||
elixir 1.17.3-otp-26
|
||||
nodejs 18.0.0
|
||||
|
||||
92
CHANGELOG.md
92
CHANGELOG.md
@@ -1,6 +1,98 @@
|
||||
# Change Log
|
||||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v1.15.4](https://github.com/wanderer-industries/wanderer/compare/v1.15.3...v1.15.4) (2024-11-14)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Untracked characters still tracked on map (#63)
|
||||
|
||||
## [v1.15.3](https://github.com/wanderer-industries/wanderer/compare/v1.15.2...v1.15.3) (2024-11-13)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.15.2](https://github.com/wanderer-industries/wanderer/compare/v1.15.1...v1.15.2) (2024-11-07)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.15.1](https://github.com/wanderer-industries/wanderer/compare/v1.15.0...v1.15.1) (2024-11-07)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Dev: Update .devcontainer instructions
|
||||
|
||||
## [v1.15.0](https://github.com/wanderer-industries/wanderer/compare/v1.14.1...v1.15.0) (2024-11-07)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Connections: Add connection mark EOL time (#56)
|
||||
|
||||
## [v1.14.1](https://github.com/wanderer-industries/wanderer/compare/v1.14.0...v1.14.1) (2024-11-06)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fix character tracking permissions
|
||||
|
||||
## [v1.14.0](https://github.com/wanderer-industries/wanderer/compare/v1.13.12...v1.14.0) (2024-11-05)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* ACL: Add an ability to assign member role without DnD
|
||||
|
||||
## [v1.13.12](https://github.com/wanderer-industries/wanderer/compare/v1.13.11...v1.13.12) (2024-11-04)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Map: Fix system revert issues
|
||||
|
||||
## [v1.13.11](https://github.com/wanderer-industries/wanderer/compare/v1.13.10...v1.13.11) (2024-11-02)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Map: Fix system revert issues
|
||||
|
||||
## [v1.13.10](https://github.com/wanderer-industries/wanderer/compare/v1.13.9...v1.13.10) (2024-11-01)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Map: Fix system revert issues
|
||||
|
||||
## [v1.13.9](https://github.com/wanderer-industries/wanderer/compare/v1.13.8...v1.13.9) (2024-11-01)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.13.8](https://github.com/wanderer-industries/wanderer/compare/v1.13.7...v1.13.8) (2024-10-28)
|
||||
|
||||
|
||||
|
||||
## [v1.13.0](https://github.com/wanderer-industries/wanderer/compare/v1.12.11...v1.13.0) (2024-10-28)
|
||||
|
||||
|
||||
|
||||
18
README.md
18
README.md
@@ -20,11 +20,11 @@ Interested to learn more? [Check more on our website](https://wanderer.ltd/news)
|
||||
|
||||
Wanderer is open source project and we have a free as in beer and self-hosted solution called [Wanderer Community Edition (CE)](https://wanderer.ltd/news/community-edition). Here are the differences between Wanderer and Wanderer CE:
|
||||
|
||||
| | Wanderer Cloud | Wanderer Community Edition |
|
||||
| ------------- | ------------- | ------------- |
|
||||
| **Infrastructure management** | Easy and convenient. It takes 2 minutes to register your character and create a map. We manage everything so you don’t have to worry about anything and can focus on gameplay. | You do it all yourself. You need to get a server and you need to manage your infrastructure. You are responsible for installation, maintenance, upgrades, server capacity, uptime, backup, security, stability, consistency, loading time and so on.|
|
||||
| **Release schedule** | Continuously developed and improved with new features and updates multiple times per week. | Latest features and improvements won't be immediately available.|
|
||||
| **Server location** | All visitor data is exclusively processed on EU-owned cloud infrastructure. We keep your site data on a secure, encrypted and green energy powered server in Germany. This ensures that your site data is protected by the strict European Union data privacy laws and ensures compliance with GDPR. Your website data never leaves the EU. | You have full control and can host your instance on any server in any country that you wish. Host it on a server in your basement or host it with any cloud provider wherever you want, even those that are not GDPR compliant.|
|
||||
| | Wanderer Cloud | Wanderer Community Edition |
|
||||
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Infrastructure management** | Easy and convenient. It takes 2 minutes to register your character and create a map. We manage everything so you don’t have to worry about anything and can focus on gameplay. | You do it all yourself. You need to get a server and you need to manage your infrastructure. You are responsible for installation, maintenance, upgrades, server capacity, uptime, backup, security, stability, consistency, loading time and so on. |
|
||||
| **Release schedule** | Continuously developed and improved with new features and updates multiple times per week. | Latest features and improvements won't be immediately available. |
|
||||
| **Server location** | All visitor data is exclusively processed on EU-owned cloud infrastructure. We keep your site data on a secure, encrypted and green energy powered server in Germany. This ensures that your site data is protected by the strict European Union data privacy laws and ensures compliance with GDPR. Your website data never leaves the EU. | You have full control and can host your instance on any server in any country that you wish. Host it on a server in your basement or host it with any cloud provider wherever you want, even those that are not GDPR compliant. |
|
||||
|
||||
Interested in self-hosting Wanderer CE on your server? Take a look at our [Wanderer CE installation instructions](https://github.com/wanderer-industries/community-edition/).
|
||||
|
||||
@@ -54,7 +54,13 @@ Now you can visit [`localhost:8000`](http://localhost:8000) from your browser.
|
||||
#### Using .devcontainer
|
||||
|
||||
- Run devcontainer
|
||||
- See how to start server in #setup section
|
||||
- Install additional dependencies inside Dev container
|
||||
- `root@0d0a785313b6:/app# apt update`
|
||||
- `root@0d0a785313b6:/app# curl -sL https://deb.nodesource.com/setup_18.x | bash -`
|
||||
- `root@0d0a785313b6:/app# apt-get install nodejs inotify-tools -y`
|
||||
- `root@0d0a785313b6:/app# mix setup`
|
||||
|
||||
- See how to run server in #Run section
|
||||
|
||||
#### Using nix flakes
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
|
||||
|
||||
// @ts-ignore
|
||||
const handleInput = useCallback(e => {
|
||||
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9[\](){}]/g, '');
|
||||
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9\-[\](){}]/g, '');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -90,7 +90,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
|
||||
}, []);
|
||||
|
||||
const handleInput = useCallback((e: any) => {
|
||||
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9[\](){}]/g, '');
|
||||
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9\-[\](){}]/g, '');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
import classes from './Connections.module.scss';
|
||||
import { Sidebar } from 'primereact/sidebar';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useState, useCallback } from 'react';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { VirtualScroller, VirtualScrollerTemplateOptions } from 'primereact/virtualscroller';
|
||||
import clsx from 'clsx';
|
||||
import { ConnectionOutput, OutCommand, Passage, SolarSystemConnection } from '@/hooks/Mapper/types';
|
||||
import {
|
||||
ConnectionOutput,
|
||||
ConnectionInfoOutput,
|
||||
OutCommand,
|
||||
Passage,
|
||||
SolarSystemConnection,
|
||||
} from '@/hooks/Mapper/types';
|
||||
import { PassageCard } from './PassageCard';
|
||||
import { InfoDrawer, SystemView } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { kgToTons } from '@/hooks/Mapper/utils/kgToTons.ts';
|
||||
import { TimeAgo } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
const sortByDate = (a: string, b: string) => new Date(a).getTime() - new Date(b).getTime();
|
||||
|
||||
@@ -69,25 +76,44 @@ export const Connections = ({ selectedConnection, onHide }: OnTheMapProps) => {
|
||||
}, [connections, selectedConnection]);
|
||||
|
||||
const [passages, setPassages] = useState<Passage[]>([]);
|
||||
const [info, setInfo] = useState<ConnectionInfoOutput>(null);
|
||||
|
||||
const loadInfo = useCallback(
|
||||
async (connection: SolarSystemConnection) => {
|
||||
const result = await outCommand<ConnectionInfoOutput>({
|
||||
type: OutCommand.getConnectionInfo,
|
||||
data: {
|
||||
from: connection.source,
|
||||
to: connection.target,
|
||||
},
|
||||
});
|
||||
|
||||
setInfo(result);
|
||||
},
|
||||
[outCommand],
|
||||
);
|
||||
|
||||
const loadPassages = useCallback(
|
||||
async (connection: SolarSystemConnection) => {
|
||||
const result = await outCommand<ConnectionOutput>({
|
||||
type: OutCommand.getPassages,
|
||||
data: {
|
||||
from: connection.source,
|
||||
to: connection.target,
|
||||
},
|
||||
});
|
||||
|
||||
setPassages(result.passages.sort((a, b) => sortByDate(b.inserted_at, a.inserted_at)));
|
||||
},
|
||||
[outCommand],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const loadInfo = async () => {
|
||||
const result = await outCommand<ConnectionOutput>({
|
||||
type: OutCommand.getPassages,
|
||||
data: {
|
||||
from: selectedConnection.source,
|
||||
to: selectedConnection.target,
|
||||
},
|
||||
});
|
||||
|
||||
setPassages(result.passages.sort((a, b) => sortByDate(b.inserted_at, a.inserted_at)));
|
||||
};
|
||||
|
||||
loadInfo();
|
||||
loadInfo(selectedConnection);
|
||||
loadPassages(selectedConnection);
|
||||
}, [selectedConnection]);
|
||||
|
||||
const approximateMass = useMemo(() => {
|
||||
@@ -132,6 +158,10 @@ export const Connections = ({ selectedConnection, onHide }: OnTheMapProps) => {
|
||||
{kgToTons(approximateMass)}
|
||||
</InfoDrawer>
|
||||
|
||||
<InfoDrawer title="Mark EOL Time" rightSide>
|
||||
{info?.marl_eol_time ? <TimeAgo timestamp={info.marl_eol_time} /> : ' unknown '}
|
||||
</InfoDrawer>
|
||||
|
||||
<div className="flex gap-2"></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ export type Passage = {
|
||||
character: PassageLimitedCharacterType;
|
||||
};
|
||||
|
||||
export type ConnectionInfoOutput = {
|
||||
marl_eol_time: string;
|
||||
};
|
||||
|
||||
export type ConnectionOutput = {
|
||||
passages: Passage[];
|
||||
};
|
||||
|
||||
@@ -118,6 +118,7 @@ export enum OutCommand {
|
||||
getCharacterJumps = 'get_character_jumps',
|
||||
getSignatures = 'get_signatures',
|
||||
getSystemStaticInfos = 'get_system_static_infos',
|
||||
getConnectionInfo = 'get_connection_info',
|
||||
updateConnectionTimeStatus = 'update_connection_time_status',
|
||||
updateConnectionMassStatus = 'update_connection_mass_status',
|
||||
updateConnectionShipSizeType = 'update_connection_ship_size_type',
|
||||
|
||||
@@ -8,7 +8,7 @@ export default {
|
||||
const selector = '#' + this.el.id;
|
||||
|
||||
const droppable = new Droppable(containers, {
|
||||
delay: 150,
|
||||
delay: 100,
|
||||
draggable: '.draggable',
|
||||
dropzone: '.dropzone',
|
||||
mirror: {
|
||||
|
||||
@@ -55,11 +55,11 @@ map_subscriptions_enabled =
|
||||
|
||||
map_subscription_characters_limit =
|
||||
config_dir
|
||||
|> get_int_from_path_or_env("WANDERER_MAP_SUBSCRIPTION_CHARACTERS_LIMIT", 100)
|
||||
|> get_int_from_path_or_env("WANDERER_MAP_SUBSCRIPTION_CHARACTERS_LIMIT", 10_000)
|
||||
|
||||
map_subscription_hubs_limit =
|
||||
config_dir
|
||||
|> get_int_from_path_or_env("WANDERER_MAP_SUBSCRIPTION_HUBS_LIMIT", 10)
|
||||
|> get_int_from_path_or_env("WANDERER_MAP_SUBSCRIPTION_HUBS_LIMIT", 100)
|
||||
|
||||
wallet_tracking_enabled =
|
||||
config_dir
|
||||
@@ -138,6 +138,7 @@ config :ueberauth, WandererApp.Ueberauth.Strategy.Eve.OAuth,
|
||||
System.get_env("EVE_CLIENT_WITH_CORP_WALLET_SECRET", "<EVE_CLIENT_WITH_CORP_WALLET_SECRET>")
|
||||
|
||||
config :logger,
|
||||
truncate: :infinity,
|
||||
level:
|
||||
String.to_existing_atom(
|
||||
System.get_env(
|
||||
@@ -171,43 +172,65 @@ config :wanderer_app, WandererApp.Scheduler,
|
||||
timeout: :infinity
|
||||
|
||||
if config_env() == :prod do
|
||||
database_url =
|
||||
System.get_env("DATABASE_URL") ||
|
||||
raise """
|
||||
environment variable DATABASE_URL is missing.
|
||||
For example: ecto://USER:PASS@HOST/DATABASE
|
||||
"""
|
||||
database_unix_socket =
|
||||
System.get_env("DATABASE_UNIX_SOCKET")
|
||||
|
||||
maybe_ipv6 =
|
||||
config_dir
|
||||
|> get_var_from_path_or_env("ECTO_IPV6", "false")
|
||||
|> String.to_existing_atom()
|
||||
database =
|
||||
database_unix_socket
|
||||
|> case do
|
||||
true -> [:inet6]
|
||||
_ -> []
|
||||
end
|
||||
nil ->
|
||||
System.get_env("DATABASE_URL") ||
|
||||
raise """
|
||||
environment variable DATABASE_URL is missing.
|
||||
For example: ecto://USER:PASS@HOST/DATABASE
|
||||
"""
|
||||
|
||||
db_ssl_enabled =
|
||||
config_dir
|
||||
|> get_var_from_path_or_env("DATABASE_SSL_ENABLED", "false")
|
||||
|> String.to_existing_atom()
|
||||
|
||||
db_ssl_verify_none =
|
||||
config_dir
|
||||
|> get_var_from_path_or_env("DATABASE_SSL_VERIFY_NONE", "false")
|
||||
|> String.to_existing_atom()
|
||||
|
||||
client_opts =
|
||||
if db_ssl_verify_none do
|
||||
[verify: :verify_none]
|
||||
_ ->
|
||||
System.get_env("DATABASE_NAME") ||
|
||||
raise """
|
||||
environment variable DATABASE_NAME is missing.
|
||||
For example: "wanderer"
|
||||
"""
|
||||
end
|
||||
|
||||
config :wanderer_app, WandererApp.Repo,
|
||||
url: database_url,
|
||||
ssl: db_ssl_enabled,
|
||||
ssl_opts: client_opts,
|
||||
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
|
||||
socket_options: maybe_ipv6
|
||||
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
|
||||
|
||||
if not is_nil(database_unix_socket) do
|
||||
config :wanderer_app, WandererApp.Repo,
|
||||
socket_dir: database_unix_socket,
|
||||
database: database
|
||||
else
|
||||
db_ssl_enabled =
|
||||
config_dir
|
||||
|> get_var_from_path_or_env("DATABASE_SSL_ENABLED", "false")
|
||||
|> String.to_existing_atom()
|
||||
|
||||
db_ssl_verify_none =
|
||||
config_dir
|
||||
|> get_var_from_path_or_env("DATABASE_SSL_VERIFY_NONE", "false")
|
||||
|> String.to_existing_atom()
|
||||
|
||||
client_opts =
|
||||
if db_ssl_verify_none do
|
||||
[verify: :verify_none]
|
||||
end
|
||||
|
||||
maybe_ipv6 =
|
||||
config_dir
|
||||
|> get_var_from_path_or_env("ECTO_IPV6", "false")
|
||||
|> String.to_existing_atom()
|
||||
|> case do
|
||||
true -> [:inet6]
|
||||
_ -> []
|
||||
end
|
||||
|
||||
config :wanderer_app, WandererApp.Repo,
|
||||
url: database,
|
||||
ssl: db_ssl_enabled,
|
||||
ssl_opts: client_opts,
|
||||
socket_options: maybe_ipv6
|
||||
end
|
||||
|
||||
# The secret key base is used to sign/encrypt cookies and other secrets.
|
||||
# A default value is used in config/dev.exs and config/test.exs but you
|
||||
|
||||
3
fly.toml
3
fly.toml
@@ -6,6 +6,7 @@
|
||||
app = 'wanderer'
|
||||
primary_region = 'ams'
|
||||
kill_signal = 'SIGTERM'
|
||||
swap_size_mb = 512
|
||||
|
||||
[build]
|
||||
|
||||
@@ -35,6 +36,6 @@ path = "/metrics"
|
||||
soft_limit = 1000
|
||||
|
||||
[[vm]]
|
||||
memory = '1gb'
|
||||
memory = '256mb'
|
||||
cpu_kind = 'shared'
|
||||
cpus = 1
|
||||
|
||||
@@ -7,6 +7,8 @@ defmodule WandererApp do
|
||||
if it comes from the database, an external API or others.
|
||||
"""
|
||||
|
||||
require Logger
|
||||
|
||||
@doc """
|
||||
When used, dispatch to the appropriate domain service
|
||||
"""
|
||||
|
||||
@@ -4,8 +4,6 @@ defmodule WandererApp.Api.Calculations.CalcMapPermissions do
|
||||
use Ash.Resource.Calculation
|
||||
require Ash.Query
|
||||
|
||||
import Bitwise
|
||||
|
||||
@impl true
|
||||
def load(_query, _opts, _context) do
|
||||
[
|
||||
@@ -17,116 +15,8 @@ defmodule WandererApp.Api.Calculations.CalcMapPermissions do
|
||||
end
|
||||
|
||||
@impl true
|
||||
def calculate([record], _opts, %{actor: actor}) do
|
||||
characters = actor.characters
|
||||
|
||||
character_ids = characters |> Enum.map(& &1.id)
|
||||
character_eve_ids = characters |> Enum.map(& &1.eve_id)
|
||||
|
||||
character_corporation_ids =
|
||||
characters |> Enum.map(& &1.corporation_id) |> Enum.map(&to_string/1)
|
||||
|
||||
character_alliance_ids = characters |> Enum.map(& &1.alliance_id) |> Enum.map(&to_string/1)
|
||||
|
||||
result =
|
||||
record.acls
|
||||
|> Enum.reduce([0, 0], fn acl, acc ->
|
||||
is_owner? = acl.owner_id in character_ids
|
||||
|
||||
is_character_member? =
|
||||
acl.members |> Enum.any?(fn member -> member.eve_character_id in character_eve_ids end)
|
||||
|
||||
is_corporation_member? =
|
||||
acl.members
|
||||
|> Enum.any?(fn member -> member.eve_corporation_id in character_corporation_ids end)
|
||||
|
||||
is_alliance_member? =
|
||||
acl.members
|
||||
|> Enum.any?(fn member -> member.eve_alliance_id in character_alliance_ids end)
|
||||
|
||||
if is_owner? || is_character_member? || is_corporation_member? || is_alliance_member? do
|
||||
case acc do
|
||||
[_, -1] ->
|
||||
[-1, -1]
|
||||
|
||||
[-1, char_acc] ->
|
||||
char_acl_mask =
|
||||
acl.members
|
||||
|> Enum.filter(fn member ->
|
||||
member.eve_character_id in character_eve_ids
|
||||
end)
|
||||
|> Enum.reduce(0, fn member, acc ->
|
||||
case acc do
|
||||
-1 -> -1
|
||||
_ -> WandererApp.Permissions.calc_role_mask(member.role, acc)
|
||||
end
|
||||
end)
|
||||
|
||||
char_acc =
|
||||
case char_acl_mask do
|
||||
-1 -> -1
|
||||
_ -> char_acc ||| char_acl_mask
|
||||
end
|
||||
|
||||
[-1, char_acc]
|
||||
|
||||
[any_acc, char_acc] ->
|
||||
any_acl_mask =
|
||||
acl.members
|
||||
|> Enum.filter(fn member ->
|
||||
member.eve_character_id in character_eve_ids ||
|
||||
member.eve_corporation_id in character_corporation_ids ||
|
||||
member.eve_alliance_id in character_alliance_ids
|
||||
end)
|
||||
|> Enum.reduce(0, fn member, acc ->
|
||||
case acc do
|
||||
-1 -> -1
|
||||
_ -> WandererApp.Permissions.calc_role_mask(member.role, acc)
|
||||
end
|
||||
end)
|
||||
|
||||
char_acl_mask =
|
||||
acl.members
|
||||
|> Enum.filter(fn member ->
|
||||
member.eve_character_id in character_eve_ids
|
||||
end)
|
||||
|> Enum.reduce(0, fn member, acc ->
|
||||
case acc do
|
||||
-1 -> -1
|
||||
_ -> WandererApp.Permissions.calc_role_mask(member.role, acc)
|
||||
end
|
||||
end)
|
||||
|
||||
any_acc =
|
||||
case any_acl_mask do
|
||||
-1 -> -1
|
||||
_ -> any_acc ||| any_acl_mask
|
||||
end
|
||||
|
||||
char_acc =
|
||||
case char_acl_mask do
|
||||
-1 -> -1
|
||||
_ -> char_acc ||| char_acl_mask
|
||||
end
|
||||
|
||||
[any_acc, char_acc]
|
||||
end
|
||||
else
|
||||
acc
|
||||
end
|
||||
end)
|
||||
|
||||
case result do
|
||||
[_, -1] ->
|
||||
[-1]
|
||||
|
||||
[-1, char_acc] ->
|
||||
[char_acc]
|
||||
|
||||
[any_acc, _char_acc] ->
|
||||
[any_acc]
|
||||
end
|
||||
end
|
||||
def calculate([record], _opts, %{actor: actor}),
|
||||
do: WandererApp.Permissions.check_characters_access(actor.characters, record.acls)
|
||||
|
||||
@impl true
|
||||
def calculate(_records, _opts, _context) do
|
||||
|
||||
@@ -17,12 +17,12 @@ defmodule WandererApp.Api.MapCharacterSettings do
|
||||
action: :read_by_map
|
||||
)
|
||||
|
||||
define(:tracked_by_map,
|
||||
action: :tracked_by_map
|
||||
define(:tracked_by_map_filtered,
|
||||
action: :tracked_by_map_filtered
|
||||
)
|
||||
|
||||
define(:tracked_by_map_all,
|
||||
action: :read_tracked_by_map
|
||||
action: :tracked_by_map_all
|
||||
)
|
||||
|
||||
define(:track, action: :track)
|
||||
@@ -38,7 +38,7 @@ defmodule WandererApp.Api.MapCharacterSettings do
|
||||
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
|
||||
read :tracked_by_map do
|
||||
read :tracked_by_map_filtered do
|
||||
argument(:map_id, :string, allow_nil?: false)
|
||||
argument(:character_ids, {:array, :uuid}, allow_nil?: false)
|
||||
|
||||
@@ -52,7 +52,7 @@ defmodule WandererApp.Api.MapCharacterSettings do
|
||||
filter(expr(map_id == ^arg(:map_id)))
|
||||
end
|
||||
|
||||
read :read_tracked_by_map do
|
||||
read :tracked_by_map_all do
|
||||
argument(:map_id, :string, allow_nil?: false)
|
||||
filter(expr(map_id == ^arg(:map_id) and tracked == true))
|
||||
end
|
||||
|
||||
@@ -3,6 +3,8 @@ defmodule WandererApp.Application do
|
||||
|
||||
use Application
|
||||
|
||||
require Logger
|
||||
|
||||
@impl true
|
||||
def start(_type, _args) do
|
||||
children =
|
||||
@@ -45,7 +47,16 @@ defmodule WandererApp.Application do
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
# for other strategies and supported options
|
||||
opts = [strategy: :one_for_one, name: WandererApp.Supervisor]
|
||||
|
||||
Supervisor.start_link(children, opts)
|
||||
|> case do
|
||||
{:ok, _pid} = ok ->
|
||||
ok
|
||||
|
||||
{:error, info} = e ->
|
||||
Logger.error("Failed to start application: #{inspect(info)}")
|
||||
e
|
||||
end
|
||||
end
|
||||
|
||||
# Tell Phoenix to update the endpoint configuration
|
||||
|
||||
@@ -37,32 +37,32 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
|
||||
@logger Application.compile_env(:wanderer_app, :logger)
|
||||
|
||||
def get_server_status, do: _get("/status")
|
||||
def get_server_status, do: get("/status")
|
||||
|
||||
def set_autopilot_waypoint(add_to_beginning, clear_other_waypoints, destination_id, opts \\ []) do
|
||||
_post_esi(
|
||||
"/ui/autopilot/waypoint",
|
||||
opts
|
||||
|> Keyword.merge(
|
||||
params: %{
|
||||
add_to_beginning: add_to_beginning,
|
||||
clear_other_waypoints: clear_other_waypoints,
|
||||
destination_id: destination_id
|
||||
}
|
||||
def set_autopilot_waypoint(add_to_beginning, clear_other_waypoints, destination_id, opts \\ []),
|
||||
do:
|
||||
post_esi(
|
||||
"/ui/autopilot/waypoint",
|
||||
opts
|
||||
|> Keyword.merge(
|
||||
params: %{
|
||||
add_to_beginning: add_to_beginning,
|
||||
clear_other_waypoints: clear_other_waypoints,
|
||||
destination_id: destination_id
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def post_characters_affiliation(character_eve_ids, _opts)
|
||||
when is_list(character_eve_ids) do
|
||||
_post(
|
||||
"#{@base_url}/characters/affiliation/",
|
||||
json: character_eve_ids,
|
||||
params: %{
|
||||
datasource: "tranquility"
|
||||
}
|
||||
)
|
||||
end
|
||||
when is_list(character_eve_ids),
|
||||
do:
|
||||
post(
|
||||
"#{@base_url}/characters/affiliation/",
|
||||
json: character_eve_ids,
|
||||
params: %{
|
||||
datasource: "tranquility"
|
||||
}
|
||||
)
|
||||
|
||||
def find_routes(map_id, origin, hubs, routes_settings) do
|
||||
origin = origin |> String.to_integer()
|
||||
@@ -184,7 +184,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
routes =
|
||||
all_routes
|
||||
|> Enum.map(fn route_info ->
|
||||
_map_route_info(route_info)
|
||||
map_route_info(route_info)
|
||||
end)
|
||||
|> Enum.filter(fn route_info -> not is_nil(route_info) end)
|
||||
|
||||
@@ -200,7 +200,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
{:ok, result}
|
||||
|
||||
_ ->
|
||||
case _get_all_routes_custom(hubs, origin, params) do
|
||||
case get_all_routes_custom(hubs, origin, params) do
|
||||
{:ok, result} ->
|
||||
WandererApp.Cache.insert(
|
||||
cache_key,
|
||||
@@ -210,22 +210,21 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
|
||||
{:ok, result}
|
||||
|
||||
{:error, error} ->
|
||||
@logger.error("Error getting custom routes for #{inspect(origin)}: #{inspect(error)}")
|
||||
{:error, _error} ->
|
||||
@logger.error("Error getting custom routes for #{inspect(origin)}: #{inspect(hubs)}")
|
||||
|
||||
@logger.error(
|
||||
"Error getting custom routes for #{inspect(origin)}: #{inspect(params)}"
|
||||
)
|
||||
|
||||
_get_all_routes_eve(hubs, origin, params, opts)
|
||||
get_all_routes_eve(hubs, origin, params, opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp _get_all_routes_custom(hubs, origin, params),
|
||||
defp get_all_routes_custom(hubs, origin, params),
|
||||
do:
|
||||
_post(
|
||||
post(
|
||||
"#{get_custom_route_base_url()}/route/multiple",
|
||||
[
|
||||
json: %{
|
||||
@@ -239,7 +238,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
|> Keyword.merge(@timeout_opts)
|
||||
)
|
||||
|
||||
def _get_all_routes_eve(hubs, origin, params, opts),
|
||||
def get_all_routes_eve(hubs, origin, params, opts),
|
||||
do:
|
||||
{:ok,
|
||||
hubs
|
||||
@@ -308,7 +307,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
opts: [ttl: @ttl]
|
||||
)
|
||||
def get_character_info(eve_id, opts \\ []) do
|
||||
case _get(
|
||||
case get(
|
||||
"/characters/#{eve_id}/",
|
||||
opts |> _with_cache_opts()
|
||||
) do
|
||||
@@ -385,7 +384,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
|
||||
defp _get_routes_eve(origin, destination, params, opts),
|
||||
do:
|
||||
_get(
|
||||
get(
|
||||
"/route/#{origin}/#{destination}/?#{params |> Plug.Conn.Query.encode()}",
|
||||
opts |> _with_cache_opts()
|
||||
)
|
||||
@@ -394,14 +393,14 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
|
||||
defp _get_alliance_info(alliance_eve_id, info_path, opts),
|
||||
do:
|
||||
_get(
|
||||
get(
|
||||
"/alliances/#{alliance_eve_id}/#{info_path}",
|
||||
opts |> _with_cache_opts()
|
||||
)
|
||||
|
||||
defp _get_corporation_info(corporation_eve_id, info_path, opts),
|
||||
do:
|
||||
_get(
|
||||
get(
|
||||
"/corporations/#{corporation_eve_id}/#{info_path}",
|
||||
opts |> _with_cache_opts()
|
||||
)
|
||||
@@ -416,7 +415,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
character_id = opts |> Keyword.get(:character_id, nil)
|
||||
|
||||
if not _is_access_token_expired?(character_id) do
|
||||
_get(
|
||||
get(
|
||||
path,
|
||||
auth_opts,
|
||||
opts
|
||||
@@ -437,7 +436,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
|
||||
defp _get_corporation_auth_data(corporation_eve_id, info_path, opts),
|
||||
do:
|
||||
_get(
|
||||
get(
|
||||
"/corporations/#{corporation_eve_id}/#{info_path}",
|
||||
[params: opts[:params] || []] ++
|
||||
(opts |> _get_auth_opts() |> _with_cache_opts()),
|
||||
@@ -448,14 +447,14 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
opts |> Keyword.merge(@cache_opts) |> Keyword.merge(cache_dir: System.tmp_dir!())
|
||||
end
|
||||
|
||||
defp _post_esi(path, opts),
|
||||
defp post_esi(path, opts),
|
||||
do:
|
||||
_post(
|
||||
post(
|
||||
"#{@base_url}#{path}",
|
||||
[params: opts[:params] || []] ++ (opts |> _get_auth_opts())
|
||||
)
|
||||
|
||||
defp _get(path, api_opts \\ [], opts \\ []) do
|
||||
defp get(path, api_opts \\ [], opts \\ []) do
|
||||
try do
|
||||
case Req.get("#{@base_url}#{path}", api_opts |> Keyword.merge(@retry_opts)) do
|
||||
{:ok, %{status: 200, body: body}} ->
|
||||
@@ -487,7 +486,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
end
|
||||
end
|
||||
|
||||
defp _post(url, opts) do
|
||||
defp post(url, opts) do
|
||||
try do
|
||||
case Req.post("#{url}", opts) do
|
||||
{:ok, %{status: status, body: body}} when status in [200, 201] ->
|
||||
@@ -525,7 +524,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
{:ok, token} ->
|
||||
auth_opts = [access_token: token.access_token] |> _get_auth_opts()
|
||||
|
||||
_get(
|
||||
get(
|
||||
path,
|
||||
api_opts |> Keyword.merge(auth_opts),
|
||||
opts |> Keyword.merge(retry_count: retry_count + 1)
|
||||
@@ -600,7 +599,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
end
|
||||
end
|
||||
|
||||
defp _map_route_info(
|
||||
defp map_route_info(
|
||||
%{
|
||||
"origin" => origin,
|
||||
"destination" => destination,
|
||||
@@ -609,14 +608,14 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
} = _route_info
|
||||
),
|
||||
do:
|
||||
_map_route_info(%{
|
||||
map_route_info(%{
|
||||
origin: origin,
|
||||
destination: destination,
|
||||
systems: result_systems,
|
||||
success: success
|
||||
})
|
||||
|
||||
defp _map_route_info(
|
||||
defp map_route_info(
|
||||
%{origin: origin, destination: destination, systems: result_systems, success: success} =
|
||||
_route_info
|
||||
) do
|
||||
@@ -638,5 +637,5 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
}
|
||||
end
|
||||
|
||||
defp _map_route_info(_), do: nil
|
||||
defp map_route_info(_), do: nil
|
||||
end
|
||||
|
||||
@@ -8,6 +8,7 @@ defmodule WandererApp.Map do
|
||||
defstruct map_id: nil,
|
||||
name: nil,
|
||||
scope: :none,
|
||||
owner_id: nil,
|
||||
characters: [],
|
||||
systems: Map.new(),
|
||||
hubs: [],
|
||||
@@ -16,11 +17,12 @@ defmodule WandererApp.Map do
|
||||
characters_limit: nil,
|
||||
hubs_limit: nil
|
||||
|
||||
def new(%{id: map_id, name: name, scope: scope, acls: acls, hubs: hubs}) do
|
||||
def new(%{id: map_id, name: name, scope: scope, owner_id: owner_id, acls: acls, hubs: hubs}) do
|
||||
map =
|
||||
struct!(__MODULE__,
|
||||
map_id: map_id,
|
||||
scope: scope,
|
||||
owner_id: owner_id,
|
||||
name: name,
|
||||
acls: acls,
|
||||
hubs: hubs
|
||||
@@ -214,7 +216,7 @@ defmodule WandererApp.Map do
|
||||
%{visible: true} = system ->
|
||||
system
|
||||
|
||||
_ ->
|
||||
_system ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
@@ -262,7 +264,7 @@ defmodule WandererApp.Map do
|
||||
case not Map.has_key?(systems, solar_system_id) do
|
||||
true ->
|
||||
map_id
|
||||
|> update_map(%{systems: Map.put_new(systems, solar_system_id, system)})
|
||||
|> update_map(%{systems: Map.put(systems, solar_system_id, system)})
|
||||
|
||||
:ok
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ defmodule WandererApp.Map.PositionCalculator do
|
||||
def get_available_positions(level, x, y, opts),
|
||||
do: adjusted_coordinates(1 + level * 2, x, y, opts)
|
||||
|
||||
defp edge_coordinates(n, opts) when n > 1 do
|
||||
defp edge_coordinates(n, _opts) when n > 1 do
|
||||
min = -div(n, 2)
|
||||
max = div(n, 2)
|
||||
# Top edge
|
||||
|
||||
@@ -183,6 +183,12 @@ defmodule WandererApp.Map.Server do
|
||||
|> map_pid!
|
||||
|> GenServer.cast({&Impl.delete_connection/2, [connection_info]})
|
||||
|
||||
def get_connection_info(map_id, connection_info) when is_binary(map_id),
|
||||
do:
|
||||
map_id
|
||||
|> map_pid!
|
||||
|> GenServer.call({&Impl.get_connection_info/2, [connection_info]}, :timer.minutes(1))
|
||||
|
||||
def update_connection_time_status(map_id, connection_info) when is_binary(map_id),
|
||||
do:
|
||||
map_id
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -87,4 +87,113 @@ defmodule WandererApp.Permissions do
|
||||
delete_map: check_permission(user_permissions, @delete_map)
|
||||
}
|
||||
end
|
||||
|
||||
def check_characters_access(characters, acls) do
|
||||
character_ids = characters |> Enum.map(& &1.id)
|
||||
character_eve_ids = characters |> Enum.map(& &1.eve_id)
|
||||
|
||||
character_corporation_ids =
|
||||
characters |> Enum.map(& &1.corporation_id) |> Enum.map(&to_string/1)
|
||||
|
||||
character_alliance_ids = characters |> Enum.map(& &1.alliance_id) |> Enum.map(&to_string/1)
|
||||
|
||||
result =
|
||||
acls
|
||||
|> Enum.reduce([0, 0], fn acl, acc ->
|
||||
is_owner? = acl.owner_id in character_ids
|
||||
|
||||
is_character_member? =
|
||||
acl.members |> Enum.any?(fn member -> member.eve_character_id in character_eve_ids end)
|
||||
|
||||
is_corporation_member? =
|
||||
acl.members
|
||||
|> Enum.any?(fn member -> member.eve_corporation_id in character_corporation_ids end)
|
||||
|
||||
is_alliance_member? =
|
||||
acl.members
|
||||
|> Enum.any?(fn member -> member.eve_alliance_id in character_alliance_ids end)
|
||||
|
||||
if is_owner? || is_character_member? || is_corporation_member? || is_alliance_member? do
|
||||
case acc do
|
||||
[_, -1] ->
|
||||
[-1, -1]
|
||||
|
||||
[-1, char_acc] ->
|
||||
char_acl_mask =
|
||||
acl.members
|
||||
|> Enum.filter(fn member ->
|
||||
member.eve_character_id in character_eve_ids
|
||||
end)
|
||||
|> Enum.reduce(0, fn member, acc ->
|
||||
case acc do
|
||||
-1 -> -1
|
||||
_ -> calc_role_mask(member.role, acc)
|
||||
end
|
||||
end)
|
||||
|
||||
char_acc =
|
||||
case char_acl_mask do
|
||||
-1 -> -1
|
||||
_ -> char_acc ||| char_acl_mask
|
||||
end
|
||||
|
||||
[-1, char_acc]
|
||||
|
||||
[any_acc, char_acc] ->
|
||||
any_acl_mask =
|
||||
acl.members
|
||||
|> Enum.filter(fn member ->
|
||||
member.eve_character_id in character_eve_ids ||
|
||||
member.eve_corporation_id in character_corporation_ids ||
|
||||
member.eve_alliance_id in character_alliance_ids
|
||||
end)
|
||||
|> Enum.reduce(0, fn member, acc ->
|
||||
case acc do
|
||||
-1 -> -1
|
||||
_ -> calc_role_mask(member.role, acc)
|
||||
end
|
||||
end)
|
||||
|
||||
char_acl_mask =
|
||||
acl.members
|
||||
|> Enum.filter(fn member ->
|
||||
member.eve_character_id in character_eve_ids
|
||||
end)
|
||||
|> Enum.reduce(0, fn member, acc ->
|
||||
case acc do
|
||||
-1 -> -1
|
||||
_ -> calc_role_mask(member.role, acc)
|
||||
end
|
||||
end)
|
||||
|
||||
any_acc =
|
||||
case any_acl_mask do
|
||||
-1 -> -1
|
||||
_ -> any_acc ||| any_acl_mask
|
||||
end
|
||||
|
||||
char_acc =
|
||||
case char_acl_mask do
|
||||
-1 -> -1
|
||||
_ -> char_acc ||| char_acl_mask
|
||||
end
|
||||
|
||||
[any_acc, char_acc]
|
||||
end
|
||||
else
|
||||
acc
|
||||
end
|
||||
end)
|
||||
|
||||
case result do
|
||||
[_, -1] ->
|
||||
[-1]
|
||||
|
||||
[-1, char_acc] ->
|
||||
[char_acc]
|
||||
|
||||
[any_acc, _char_acc] ->
|
||||
[any_acc]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,4 +3,23 @@ defmodule WandererApp.MapCharacterSettingsRepo do
|
||||
|
||||
def create(settings),
|
||||
do: WandererApp.Api.MapCharacterSettings.create(settings)
|
||||
|
||||
def get_tracked_by_map_filtered(map_id, character_ids),
|
||||
do:
|
||||
WandererApp.Api.MapCharacterSettings.tracked_by_map_filtered(%{
|
||||
map_id: map_id,
|
||||
character_ids: character_ids
|
||||
})
|
||||
|
||||
def get_all_by_map(map_id),
|
||||
do: WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map_id})
|
||||
|
||||
def get_tracked_by_map_all(map_id),
|
||||
do: WandererApp.Api.MapCharacterSettings.tracked_by_map_all(%{map_id: map_id})
|
||||
|
||||
def track(settings), do: settings |> WandererApp.Api.MapCharacterSettings.track()
|
||||
def untrack(settings), do: settings |> WandererApp.Api.MapCharacterSettings.untrack()
|
||||
|
||||
def track!(settings), do: settings |> WandererApp.Api.MapCharacterSettings.track!()
|
||||
def untrack!(settings), do: settings |> WandererApp.Api.MapCharacterSettings.untrack!()
|
||||
end
|
||||
|
||||
@@ -33,19 +33,26 @@ defmodule WandererApp.MapSystemRepo do
|
||||
{:error, error}
|
||||
end
|
||||
|
||||
def cleanup_labels(%{labels: labels} = system, opts) do
|
||||
def cleanup_labels!(%{labels: labels} = system, opts) do
|
||||
store_custom_labels? =
|
||||
Keyword.get(opts, :store_custom_labels, "false") |> String.to_existing_atom()
|
||||
Keyword.get(opts, :store_custom_labels)
|
||||
|
||||
labels = get_filtered_labels(labels, store_custom_labels?)
|
||||
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_labels!(%{
|
||||
|> update_labels!(%{
|
||||
labels: labels
|
||||
})
|
||||
end
|
||||
|
||||
def cleanup_tags(system) do
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_tag(%{
|
||||
tag: nil
|
||||
})
|
||||
end
|
||||
|
||||
def cleanup_tags!(system) do
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_tag!(%{
|
||||
tag: nil
|
||||
@@ -56,7 +63,7 @@ defmodule WandererApp.MapSystemRepo do
|
||||
labels
|
||||
|> Jason.decode!()
|
||||
|> case do
|
||||
%{"customLabel" => customLabel} = labels when is_binary(customLabel) ->
|
||||
%{"customLabel" => customLabel} when is_binary(customLabel) ->
|
||||
%{"customLabel" => customLabel, "labels" => []}
|
||||
|> Jason.encode!()
|
||||
|
||||
@@ -97,6 +104,11 @@ defmodule WandererApp.MapSystemRepo do
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_labels(update)
|
||||
|
||||
def update_labels!(system, update),
|
||||
do:
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_labels!(update)
|
||||
|
||||
def update_position(system, update),
|
||||
do:
|
||||
system
|
||||
@@ -106,4 +118,14 @@ defmodule WandererApp.MapSystemRepo do
|
||||
do:
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_position!(update)
|
||||
|
||||
def update_visible(system, update),
|
||||
do:
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_visible(update)
|
||||
|
||||
def update_visible!(system, update),
|
||||
do:
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_visible!(update)
|
||||
end
|
||||
|
||||
@@ -12,6 +12,7 @@ defmodule WandererAppWeb.MapPicker do
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def update(
|
||||
%{
|
||||
current_user: current_user,
|
||||
@@ -29,6 +30,7 @@ defmodule WandererAppWeb.MapPicker do
|
||||
end)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div id={@id}>
|
||||
@@ -56,6 +58,7 @@ defmodule WandererAppWeb.MapPicker do
|
||||
"""
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("select", %{"map_slug" => map_slug} = _params, socket) do
|
||||
notify_to(socket.assigns.notify_to, socket.assigns.event_name, map_slug)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
defmodule WandererAppWeb.AccessListsLive do
|
||||
alias Pathex.Builder.Viewer
|
||||
use WandererAppWeb, :live_view
|
||||
|
||||
require Logger
|
||||
@@ -89,7 +90,10 @@ defmodule WandererAppWeb.AccessListsLive do
|
||||
|> assign(:page_title, "Access Lists - Members")
|
||||
|> assign(:selected_acl_id, acl_id)
|
||||
|> assign(:access_list, access_list)
|
||||
|> assign(:members, members)
|
||||
|> assign(
|
||||
:members,
|
||||
members
|
||||
)
|
||||
else
|
||||
_ ->
|
||||
socket
|
||||
@@ -145,7 +149,7 @@ defmodule WandererAppWeb.AccessListsLive do
|
||||
:send_after,
|
||||
[self(), {:search, text}, 100],
|
||||
"member_search_#{socket.assigns.selected_acl_id}",
|
||||
500
|
||||
250
|
||||
)
|
||||
|
||||
[%{label: "Loading...", value: :loading, disabled: true}]
|
||||
@@ -288,7 +292,11 @@ defmodule WandererAppWeb.AccessListsLive do
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("dropped", %{"draggedId" => dragged_id, "dropzoneId" => dropzone_id}, socket) do
|
||||
def handle_event(
|
||||
"dropped",
|
||||
%{"draggedId" => dragged_id, "dropzoneId" => dropzone_id},
|
||||
%{assigns: %{access_list: access_list, members: members}} = socket
|
||||
) do
|
||||
role_atom =
|
||||
[:admin, :manager, :member, :viewer, :blocked]
|
||||
|> Enum.find(fn role_atom -> to_string(role_atom) == dropzone_id end)
|
||||
@@ -299,13 +307,27 @@ defmodule WandererAppWeb.AccessListsLive do
|
||||
|
||||
role_atom ->
|
||||
member =
|
||||
socket.assigns.members
|
||||
members
|
||||
|> Enum.find(&(&1.id == dragged_id))
|
||||
|
||||
{:noreply, socket |> maybe_update_role(member, role_atom, socket.assigns.access_list)}
|
||||
{:noreply, socket |> maybe_update_role(member, role_atom, access_list)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(
|
||||
{"update_role", %{member_id: member_id, role: role}},
|
||||
%{assigns: %{access_list: access_list, members: members}} = socket
|
||||
) do
|
||||
role_atom = role |> String.to_existing_atom()
|
||||
|
||||
member =
|
||||
members
|
||||
|> Enum.find(&(&1.id == member_id))
|
||||
|
||||
{:noreply, socket |> maybe_update_role(member, role_atom, access_list)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("noop", _, socket) do
|
||||
{:noreply, socket}
|
||||
@@ -325,10 +347,33 @@ defmodule WandererAppWeb.AccessListsLive do
|
||||
|> Enum.map(& &1.id)
|
||||
|> Enum.at(0)
|
||||
|
||||
{:ok, options} = search(active_character_id, text)
|
||||
uniq_search_req_id = UUID.uuid4(:default)
|
||||
|
||||
send_update(LiveSelect.Component, options: options, id: socket.assigns.member_search_id)
|
||||
{:noreply, socket |> assign(member_search_options: options)}
|
||||
Task.async(fn ->
|
||||
{:ok, options} = search(active_character_id, text)
|
||||
|
||||
{:search_results, uniq_search_req_id, options}
|
||||
end)
|
||||
|
||||
{:noreply, socket |> assign(uniq_search_req_id: uniq_search_req_id)}
|
||||
end
|
||||
|
||||
def handle_info(
|
||||
{ref, result},
|
||||
%{assigns: %{member_search_id: member_search_id, uniq_search_req_id: uniq_search_req_id}} =
|
||||
socket
|
||||
)
|
||||
when is_reference(ref) do
|
||||
Process.demonitor(ref, [:flush])
|
||||
|
||||
case result do
|
||||
{:search_results, ^uniq_search_req_id, options} ->
|
||||
send_update(LiveSelect.Component, options: options, id: member_search_id)
|
||||
{:noreply, socket |> assign(member_search_options: options)}
|
||||
|
||||
_ ->
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -403,6 +448,7 @@ defmodule WandererAppWeb.AccessListsLive do
|
||||
_ ->
|
||||
socket
|
||||
|> put_flash(:error, "You're not allowed to assign this role")
|
||||
|> push_navigate(to: ~p"/access-lists/#{socket.assigns.selected_acl_id}")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -411,10 +457,11 @@ defmodule WandererAppWeb.AccessListsLive do
|
||||
_member,
|
||||
_role_atom,
|
||||
_access_list
|
||||
) do
|
||||
socket
|
||||
|> put_flash(:info, "Only Characters can have Admin or Manager roles")
|
||||
end
|
||||
),
|
||||
do:
|
||||
socket
|
||||
|> put_flash(:info, "Only Characters can have Admin or Manager roles")
|
||||
|> push_navigate(to: ~p"/access-lists/#{socket.assigns.selected_acl_id}")
|
||||
|
||||
defp characters_has_role?(character_eve_ids, access_list, role_atom) do
|
||||
access_list.members
|
||||
@@ -614,27 +661,6 @@ defmodule WandererAppWeb.AccessListsLive do
|
||||
"""
|
||||
end
|
||||
|
||||
def member_item(assigns) do
|
||||
~H"""
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon :if={not is_nil(@member.role)} name={member_role_icon(@member.role)} class="w-6 h-6" />
|
||||
<div class="avatar">
|
||||
<div class="rounded-md w-8 h-8">
|
||||
<img src={member_icon_url(@member)} alt={@member.name} />
|
||||
</div>
|
||||
</div>
|
||||
<%= @member.name %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def member_role_icon(:admin), do: "hero-user-group-solid"
|
||||
def member_role_icon(:manager), do: "hero-academic-cap-solid"
|
||||
def member_role_icon(:member), do: "hero-user-solid"
|
||||
def member_role_icon(:viewer), do: "hero-eye-solid"
|
||||
def member_role_icon(:blocked), do: "hero-no-symbol-solid text-red-500"
|
||||
def member_role_icon(_), do: "hero-cake-solid"
|
||||
|
||||
def search_member_icon_url(%{character: true} = option),
|
||||
do: member_icon_url(%{eve_character_id: option.value})
|
||||
|
||||
|
||||
@@ -82,14 +82,20 @@
|
||||
id="acl_members"
|
||||
>
|
||||
<div
|
||||
:for={member <- @members |> Enum.sort(&(&1.name < &2.name))}
|
||||
:for={member <- @members |> Enum.sort_by(&{&1.role, &1.name}, &<=/2)}
|
||||
draggable="true"
|
||||
id={member.id}
|
||||
class="draggable !p-1 h-10 cursor-move bg-black bg-opacity-25 hover:text-white"
|
||||
data-dropzone="pool"
|
||||
>
|
||||
<div class="flex justify-between relative">
|
||||
<.member_item member={member} />
|
||||
<.live_component
|
||||
module={WandererAppWeb.AclMember}
|
||||
id={"select_role_" <> member.id}
|
||||
notify_to={self()}
|
||||
member={member}
|
||||
event_name="update_role"
|
||||
/>
|
||||
<button
|
||||
:if={can_delete_member?(member, @access_list, @current_user)}
|
||||
class="z-10 absolute top-0 right-2"
|
||||
@@ -150,6 +156,71 @@
|
||||
show
|
||||
on_cancel={JS.patch(~p"/access-lists/#{@selected_acl_id}")}
|
||||
>
|
||||
<%!-- <div class="mt-4 mb-2 p-tabmenu p-component " data-pc-section="tabmenu">
|
||||
<ul
|
||||
class="p-tabmenu-nav border-none h-[25px] w-full flex"
|
||||
role="menubar"
|
||||
data-pc-section="menu"
|
||||
>
|
||||
<li
|
||||
id="pr_id_17_0"
|
||||
class="p-tabmenuitem p-highlight"
|
||||
role="presentation"
|
||||
data-p-highlight="true"
|
||||
data-p-disabled="false"
|
||||
data-pc-section="menuitem"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
role="menuitem"
|
||||
aria-label="Router Link"
|
||||
tabindex="0"
|
||||
class="p-menuitem-link"
|
||||
data-pc-section="action"
|
||||
>
|
||||
<span class="p-menuitem-text" data-pc-section="label">Character</span>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
id="pr_id_17_1"
|
||||
class="p-tabmenuitem"
|
||||
role="presentation"
|
||||
data-p-highlight="false"
|
||||
data-p-disabled="false"
|
||||
data-pc-section="menuitem"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
role="menuitem"
|
||||
aria-label="Programmatic"
|
||||
tabindex="-1"
|
||||
class="p-menuitem-link"
|
||||
data-pc-section="action"
|
||||
>
|
||||
<span class="p-menuitem-text" data-pc-section="label">Corporation</span>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
id="pr_id_17_2"
|
||||
class="p-tabmenuitem"
|
||||
role="presentation"
|
||||
data-p-highlight="false"
|
||||
data-p-disabled="false"
|
||||
data-pc-section="menuitem"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
role="menuitem"
|
||||
aria-label="External"
|
||||
tabindex="-1"
|
||||
class="p-menuitem-link"
|
||||
data-pc-section="action"
|
||||
>
|
||||
<span class="p-menuitem-text" data-pc-section="label">Alliance</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> --%>
|
||||
<.form :let={f} for={@member_form} phx-submit={@live_action}>
|
||||
<.live_select
|
||||
field={f[:member_id]}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
defmodule WandererAppWeb.AclMember do
|
||||
use WandererAppWeb, :live_component
|
||||
|
||||
use LiveViewEvents
|
||||
|
||||
@roles [
|
||||
:admin,
|
||||
:manager,
|
||||
:member,
|
||||
:viewer,
|
||||
:blocked
|
||||
]
|
||||
|
||||
@impl true
|
||||
def mount(socket) do
|
||||
{:ok, socket |> assign(roles: get_roles())}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def update(
|
||||
%{
|
||||
member: member
|
||||
} = assigns,
|
||||
socket
|
||||
) do
|
||||
socket = handle_info_or_assign(socket, assigns)
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(member: member, form: to_form(%{"role" => member.role}))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div id={@id} class="flex items-center gap-2">
|
||||
<.icon :if={not is_nil(@member.role)} name={member_role_icon(@member.role)} class="w-6 h-6" />
|
||||
<.form :let={f} id={"role_form_" <> @id} for={@form} phx-change="select" phx-target={@myself}>
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:role]}
|
||||
class="select h-8 min-h-[0px] !pt-1 !pb-1 text-sm bg-neutral-900 w-[70px]"
|
||||
placeholder="Select a role..."
|
||||
options={Enum.map(@roles, fn role -> {role.label, role.value} end)}
|
||||
/>
|
||||
</.form>
|
||||
<div class="avatar">
|
||||
<div class="rounded-md w-8 h-8">
|
||||
<img src={member_icon_url(@member)} alt={@member.name} />
|
||||
</div>
|
||||
</div>
|
||||
<%= @member.name %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event(
|
||||
"select",
|
||||
%{"role" => role} = _params,
|
||||
%{assigns: %{event_name: event_name, member: member, notify_to: notify_to}} = socket
|
||||
) do
|
||||
notify_to(notify_to, event_name, %{
|
||||
member_id: member.id,
|
||||
role: role
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def member_role_icon(:admin), do: "hero-user-group-solid"
|
||||
def member_role_icon(:manager), do: "hero-academic-cap-solid"
|
||||
def member_role_icon(:member), do: "hero-user-solid"
|
||||
def member_role_icon(:viewer), do: "hero-eye-solid"
|
||||
def member_role_icon(:blocked), do: "hero-no-symbol-solid text-red-500"
|
||||
def member_role_icon(_), do: "hero-cake-solid"
|
||||
|
||||
def member_role_title(:admin), do: "Admin"
|
||||
def member_role_title(:manager), do: "Manager"
|
||||
def member_role_title(:member), do: "Member"
|
||||
def member_role_title(:viewer), do: "Viewer"
|
||||
def member_role_title(:blocked), do: "-blocked-"
|
||||
def member_role_title(_), do: "-"
|
||||
|
||||
defp get_roles(), do: @roles |> Enum.map(&%{label: member_role_title(&1), value: &1})
|
||||
end
|
||||
@@ -41,7 +41,7 @@ defmodule WandererAppWeb.CharactersTrackingLive do
|
||||
selected_map = socket.assigns.maps |> Enum.find(&(&1.slug == map_slug))
|
||||
|
||||
{:ok, character_settings} =
|
||||
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: selected_map.id}) do
|
||||
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(selected_map.id) do
|
||||
{:ok, settings} ->
|
||||
{:ok, settings}
|
||||
|
||||
@@ -83,7 +83,7 @@ defmodule WandererAppWeb.CharactersTrackingLive do
|
||||
|
||||
case character_settings |> Enum.find(&(&1.character_id == character_id)) do
|
||||
nil ->
|
||||
WandererApp.Api.MapCharacterSettings.create(%{
|
||||
WandererApp.MapCharacterSettingsRepo.create(%{
|
||||
character_id: character_id,
|
||||
map_id: selected_map.id,
|
||||
tracked: true
|
||||
@@ -95,18 +95,18 @@ defmodule WandererAppWeb.CharactersTrackingLive do
|
||||
case character_setting.tracked do
|
||||
true ->
|
||||
character_setting
|
||||
|> WandererApp.Api.MapCharacterSettings.untrack!()
|
||||
|> WandererApp.MapCharacterSettingsRepo.untrack!()
|
||||
|
||||
_ ->
|
||||
character_setting
|
||||
|> WandererApp.Api.MapCharacterSettings.track!()
|
||||
|> WandererApp.MapCharacterSettingsRepo.track!()
|
||||
end
|
||||
end
|
||||
|
||||
%{result: characters} = socket.assigns.characters
|
||||
|
||||
{:ok, character_settings} =
|
||||
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: selected_map.id}) do
|
||||
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(selected_map.id) do
|
||||
{:ok, settings} -> {:ok, settings}
|
||||
_ -> {:ok, []}
|
||||
end
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
defmodule WandererAppWeb.MapActivityEventHandler do
|
||||
use WandererAppWeb, :live_component
|
||||
use Phoenix.Component
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{MapEventHandler, MapCoreEventHandler}
|
||||
|
||||
def handle_server_event(
|
||||
%{
|
||||
event: :character_activity,
|
||||
payload: character_activity
|
||||
},
|
||||
socket
|
||||
),
|
||||
do: socket |> assign(:character_activity, character_activity)
|
||||
|
||||
def handle_server_event(event, socket),
|
||||
do: MapCoreEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_ui_event("show_activity", _, %{assigns: %{map_id: map_id}} = socket) do
|
||||
Task.async(fn ->
|
||||
{:ok, character_activity} = map_id |> get_character_activity()
|
||||
|
||||
{:character_activity, character_activity}
|
||||
end)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:show_activity?, true)}
|
||||
end
|
||||
|
||||
def handle_ui_event("hide_activity", _, socket),
|
||||
do: {:noreply, socket |> assign(show_activity?: false)}
|
||||
|
||||
def handle_ui_event(event, body, socket),
|
||||
do: MapCoreEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
defp get_character_activity(map_id) do
|
||||
{:ok, jumps} = WandererApp.Api.MapChainPassages.by_map_id(%{map_id: map_id})
|
||||
|
||||
jumps =
|
||||
jumps
|
||||
|> Enum.map(fn p ->
|
||||
%{p | character: p.character |> MapEventHandler.map_ui_character_stat()}
|
||||
end)
|
||||
|
||||
{:ok, %{jumps: jumps}}
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,388 @@
|
||||
defmodule WandererAppWeb.MapCharactersEventHandler do
|
||||
use WandererAppWeb, :live_component
|
||||
use Phoenix.Component
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{MapEventHandler, MapCoreEventHandler}
|
||||
|
||||
def handle_server_event(%{event: :character_added, payload: character}, socket) do
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"character_added",
|
||||
character |> map_ui_character()
|
||||
)
|
||||
end
|
||||
|
||||
def handle_server_event(%{event: :character_removed, payload: character}, socket) do
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"character_removed",
|
||||
character |> map_ui_character()
|
||||
)
|
||||
end
|
||||
|
||||
def handle_server_event(%{event: :character_updated, payload: character}, socket) do
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"character_updated",
|
||||
character |> map_ui_character()
|
||||
)
|
||||
end
|
||||
|
||||
def handle_server_event(
|
||||
%{event: :characters_updated},
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
characters =
|
||||
map_id
|
||||
|> WandererApp.Map.list_characters()
|
||||
|> Enum.map(&map_ui_character/1)
|
||||
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"characters_updated",
|
||||
characters
|
||||
)
|
||||
end
|
||||
|
||||
def handle_server_event(
|
||||
%{event: :present_characters_updated, payload: present_character_eve_ids},
|
||||
socket
|
||||
),
|
||||
do:
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"present_characters",
|
||||
present_character_eve_ids
|
||||
)
|
||||
|
||||
def handle_server_event(event, socket),
|
||||
do: MapCoreEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_ui_event(
|
||||
"add_character",
|
||||
_,
|
||||
%{
|
||||
assigns: %{
|
||||
current_user: current_user,
|
||||
map_id: map_id,
|
||||
user_permissions: %{track_character: true}
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
{:ok, character_settings} =
|
||||
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(map_id) do
|
||||
{:ok, settings} -> {:ok, settings}
|
||||
_ -> {:ok, []}
|
||||
end
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(
|
||||
show_tracking?: true,
|
||||
character_settings: character_settings
|
||||
)
|
||||
|> assign_async(:characters, fn ->
|
||||
{:ok, map} =
|
||||
map_id
|
||||
|> WandererApp.MapRepo.get([:acls])
|
||||
|
||||
map
|
||||
|> WandererApp.Maps.load_characters(
|
||||
character_settings,
|
||||
current_user.id
|
||||
)
|
||||
end)}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"add_character",
|
||||
_,
|
||||
%{
|
||||
assigns: %{
|
||||
user_permissions: %{track_character: false}
|
||||
}
|
||||
} = socket
|
||||
),
|
||||
do:
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"You don't have permissions to track characters. Please contact administrator."
|
||||
)}
|
||||
|
||||
def handle_ui_event(
|
||||
"toggle_track",
|
||||
%{"character-id" => character_id},
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
character_settings: character_settings,
|
||||
current_user: current_user,
|
||||
only_tracked_characters: only_tracked_characters
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
socket =
|
||||
case character_settings |> Enum.find(&(&1.character_id == character_id)) do
|
||||
nil ->
|
||||
{:ok, map_character_settings} =
|
||||
WandererApp.MapCharacterSettingsRepo.create(%{
|
||||
character_id: character_id,
|
||||
map_id: map_id,
|
||||
tracked: true
|
||||
})
|
||||
|
||||
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
|
||||
|
||||
:ok = track_characters([character], map_id, true)
|
||||
:ok = add_characters([character], map_id, true)
|
||||
|
||||
socket
|
||||
|
||||
character_setting ->
|
||||
case character_setting.tracked do
|
||||
true ->
|
||||
{:ok, map_character_settings} =
|
||||
character_setting
|
||||
|> WandererApp.MapCharacterSettingsRepo.untrack()
|
||||
|
||||
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
|
||||
|
||||
:ok = untrack_characters([character], map_id)
|
||||
:ok = remove_characters([character], map_id)
|
||||
|
||||
if only_tracked_characters do
|
||||
Process.send_after(self(), :not_all_characters_tracked, 10)
|
||||
end
|
||||
|
||||
socket
|
||||
|
||||
_ ->
|
||||
{:ok, map_character_settings} =
|
||||
character_setting
|
||||
|> WandererApp.MapCharacterSettingsRepo.track()
|
||||
|
||||
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
|
||||
|
||||
:ok = track_characters([character], map_id, true)
|
||||
:ok = add_characters([character], map_id, true)
|
||||
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
%{result: characters} = socket.assigns.characters
|
||||
|
||||
{:ok, map_characters} = get_tracked_map_characters(map_id, current_user)
|
||||
|
||||
user_character_eve_ids = map_characters |> Enum.map(& &1.eve_id)
|
||||
|
||||
{:ok, character_settings} =
|
||||
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(map_id) do
|
||||
{:ok, settings} -> {:ok, settings}
|
||||
_ -> {:ok, []}
|
||||
end
|
||||
|
||||
characters =
|
||||
characters
|
||||
|> Enum.map(fn c ->
|
||||
WandererApp.Maps.map_character(
|
||||
c,
|
||||
character_settings |> Enum.find(&(&1.character_id == c.id))
|
||||
)
|
||||
end)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(user_characters: user_character_eve_ids)
|
||||
|> assign(has_tracked_characters?: has_tracked_characters?(user_character_eve_ids))
|
||||
|> assign(character_settings: character_settings)
|
||||
|> assign_async(:characters, fn ->
|
||||
{:ok, %{characters: characters}}
|
||||
end)
|
||||
|> MapEventHandler.push_map_event(
|
||||
"init",
|
||||
%{
|
||||
user_characters: user_character_eve_ids,
|
||||
reset: false
|
||||
}
|
||||
)}
|
||||
end
|
||||
|
||||
def handle_ui_event("hide_tracking", _, socket),
|
||||
do: {:noreply, socket |> assign(show_tracking?: false)}
|
||||
|
||||
def handle_ui_event(event, body, socket),
|
||||
do: MapCoreEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
def has_tracked_characters?([]), do: false
|
||||
def has_tracked_characters?(_user_characters), do: true
|
||||
|
||||
def get_tracked_map_characters(map_id, current_user) do
|
||||
case WandererApp.MapCharacterSettingsRepo.get_tracked_by_map_filtered(
|
||||
map_id,
|
||||
current_user.characters |> Enum.map(& &1.id)
|
||||
) do
|
||||
{:ok, settings} ->
|
||||
{:ok,
|
||||
settings
|
||||
|> Enum.map(fn s -> s |> Ash.load!(:character) |> Map.get(:character) end)}
|
||||
|
||||
_ ->
|
||||
{:ok, []}
|
||||
end
|
||||
end
|
||||
|
||||
def map_ui_character(character),
|
||||
do:
|
||||
character
|
||||
|> Map.take([
|
||||
:eve_id,
|
||||
:name,
|
||||
:online,
|
||||
:corporation_id,
|
||||
:corporation_name,
|
||||
:corporation_ticker,
|
||||
:alliance_id,
|
||||
:alliance_name,
|
||||
:alliance_ticker
|
||||
])
|
||||
|> Map.put_new(:ship, WandererApp.Character.get_ship(character))
|
||||
|> Map.put_new(:location, get_location(character))
|
||||
|
||||
def add_characters([], _map_id, _track_character), do: :ok
|
||||
|
||||
def add_characters([character | characters], map_id, track_character) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.add_character(character, track_character)
|
||||
|
||||
add_characters(characters, map_id, track_character)
|
||||
end
|
||||
|
||||
def remove_characters([], _map_id), do: :ok
|
||||
|
||||
def remove_characters([character | characters], map_id) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.remove_character(character.id)
|
||||
|
||||
remove_characters(characters, map_id)
|
||||
end
|
||||
|
||||
def untrack_characters(characters, map_id) do
|
||||
characters
|
||||
|> Enum.each(fn character ->
|
||||
WandererAppWeb.Presence.untrack(self(), map_id, character.id)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"#{inspect(self())}_map_#{map_id}:character_#{character.id}:tracked",
|
||||
false
|
||||
)
|
||||
|
||||
:ok =
|
||||
Phoenix.PubSub.unsubscribe(
|
||||
WandererApp.PubSub,
|
||||
"character:#{character.eve_id}"
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
def track_characters(_, _, false), do: :ok
|
||||
|
||||
def track_characters([], _map_id, _is_track_character?), do: :ok
|
||||
|
||||
def track_characters(
|
||||
[character | characters],
|
||||
map_id,
|
||||
true
|
||||
) do
|
||||
track_character(character, map_id)
|
||||
|
||||
track_characters(characters, map_id, true)
|
||||
end
|
||||
|
||||
def track_character(
|
||||
%{
|
||||
id: character_id,
|
||||
eve_id: eve_id,
|
||||
corporation_id: corporation_id,
|
||||
alliance_id: alliance_id
|
||||
},
|
||||
map_id
|
||||
) do
|
||||
WandererAppWeb.Presence.track(self(), map_id, character_id, %{})
|
||||
|
||||
case WandererApp.Cache.lookup!(
|
||||
"#{inspect(self())}_map_#{map_id}:character_#{character_id}:tracked",
|
||||
false
|
||||
) do
|
||||
true ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
:ok =
|
||||
Phoenix.PubSub.subscribe(
|
||||
WandererApp.PubSub,
|
||||
"character:#{eve_id}"
|
||||
)
|
||||
|
||||
:ok =
|
||||
WandererApp.Cache.put(
|
||||
"#{inspect(self())}_map_#{map_id}:character_#{character_id}:tracked",
|
||||
true
|
||||
)
|
||||
end
|
||||
|
||||
case WandererApp.Cache.lookup(
|
||||
"#{inspect(self())}_map_#{map_id}:corporation_#{corporation_id}:tracked",
|
||||
false
|
||||
) do
|
||||
{:ok, true} ->
|
||||
:ok
|
||||
|
||||
{:ok, false} ->
|
||||
:ok =
|
||||
Phoenix.PubSub.subscribe(
|
||||
WandererApp.PubSub,
|
||||
"corporation:#{corporation_id}"
|
||||
)
|
||||
|
||||
:ok =
|
||||
WandererApp.Cache.put(
|
||||
"#{inspect(self())}_map_#{map_id}:corporation_#{corporation_id}:tracked",
|
||||
true
|
||||
)
|
||||
end
|
||||
|
||||
case WandererApp.Cache.lookup(
|
||||
"#{inspect(self())}_map_#{map_id}:alliance_#{alliance_id}:tracked",
|
||||
false
|
||||
) do
|
||||
{:ok, true} ->
|
||||
:ok
|
||||
|
||||
{:ok, false} ->
|
||||
:ok =
|
||||
Phoenix.PubSub.subscribe(
|
||||
WandererApp.PubSub,
|
||||
"alliance:#{alliance_id}"
|
||||
)
|
||||
|
||||
:ok =
|
||||
WandererApp.Cache.put(
|
||||
"#{inspect(self())}_map_#{map_id}:alliance_#{alliance_id}:tracked",
|
||||
true
|
||||
)
|
||||
end
|
||||
|
||||
:ok = WandererApp.Character.TrackerManager.start_tracking(character_id)
|
||||
end
|
||||
|
||||
defp get_location(character),
|
||||
do: %{solar_system_id: character.solar_system_id, structure_id: character.structure_id}
|
||||
end
|
||||
@@ -0,0 +1,222 @@
|
||||
defmodule WandererAppWeb.MapConnectionsEventHandler do
|
||||
use WandererAppWeb, :live_component
|
||||
use Phoenix.Component
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{MapEventHandler, MapCoreEventHandler}
|
||||
|
||||
def handle_server_event(%{event: :update_connection, payload: connection}, socket),
|
||||
do:
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"update_connection",
|
||||
MapEventHandler.map_ui_connection(connection)
|
||||
)
|
||||
|
||||
def handle_server_event(%{event: :remove_connections, payload: connections}, socket) do
|
||||
connection_ids =
|
||||
connections |> Enum.map(&MapEventHandler.map_ui_connection/1) |> Enum.map(& &1.id)
|
||||
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"remove_connections",
|
||||
connection_ids
|
||||
)
|
||||
end
|
||||
|
||||
def handle_server_event(%{event: :add_connection, payload: connection}, socket) do
|
||||
connections = [MapEventHandler.map_ui_connection(connection)]
|
||||
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"add_connections",
|
||||
connections
|
||||
)
|
||||
end
|
||||
|
||||
def handle_server_event(event, socket),
|
||||
do: MapCoreEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_ui_event(
|
||||
"manual_add_connection",
|
||||
%{"source" => solar_system_source_id, "target" => solar_system_target_id} = _event,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
current_user: current_user,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{add_connection: true}
|
||||
}
|
||||
} =
|
||||
socket
|
||||
) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.add_connection(%{
|
||||
solar_system_source_id: solar_system_source_id |> String.to_integer(),
|
||||
solar_system_target_id: solar_system_target_id |> String.to_integer()
|
||||
})
|
||||
|
||||
{:ok, _} =
|
||||
WandererApp.User.ActivityTracker.track_map_event(:map_connection_added, %{
|
||||
character_id: tracked_character_ids |> List.first(),
|
||||
user_id: current_user.id,
|
||||
map_id: map_id,
|
||||
solar_system_source_id: "#{solar_system_source_id}" |> String.to_integer(),
|
||||
solar_system_target_id: "#{solar_system_target_id}" |> String.to_integer()
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"manual_delete_connection",
|
||||
%{"source" => solar_system_source_id, "target" => solar_system_target_id} = _event,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
current_user: current_user,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{delete_connection: true}
|
||||
}
|
||||
} =
|
||||
socket
|
||||
) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.delete_connection(%{
|
||||
solar_system_source_id: solar_system_source_id |> String.to_integer(),
|
||||
solar_system_target_id: solar_system_target_id |> String.to_integer()
|
||||
})
|
||||
|
||||
{:ok, _} =
|
||||
WandererApp.User.ActivityTracker.track_map_event(:map_connection_removed, %{
|
||||
character_id: tracked_character_ids |> List.first(),
|
||||
user_id: current_user.id,
|
||||
map_id: map_id,
|
||||
solar_system_source_id: "#{solar_system_source_id}" |> String.to_integer(),
|
||||
solar_system_target_id: "#{solar_system_target_id}" |> String.to_integer()
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"update_connection_" <> param,
|
||||
%{
|
||||
"source" => solar_system_source_id,
|
||||
"target" => solar_system_target_id,
|
||||
"value" => value
|
||||
} = _event,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
current_user: current_user,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} =
|
||||
socket
|
||||
) do
|
||||
method_atom =
|
||||
case param do
|
||||
"time_status" -> :update_connection_time_status
|
||||
"mass_status" -> :update_connection_mass_status
|
||||
"ship_size_type" -> :update_connection_ship_size_type
|
||||
"locked" -> :update_connection_locked
|
||||
"custom_info" -> :update_connection_custom_info
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
key_atom =
|
||||
case param do
|
||||
"time_status" -> :time_status
|
||||
"mass_status" -> :mass_status
|
||||
"ship_size_type" -> :ship_size_type
|
||||
"locked" -> :locked
|
||||
"custom_info" -> :custom_info
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
{:ok, _} =
|
||||
WandererApp.User.ActivityTracker.track_map_event(:map_connection_updated, %{
|
||||
character_id: tracked_character_ids |> List.first(),
|
||||
user_id: current_user.id,
|
||||
map_id: map_id,
|
||||
solar_system_source_id: "#{solar_system_source_id}" |> String.to_integer(),
|
||||
solar_system_target_id: "#{solar_system_target_id}" |> String.to_integer(),
|
||||
key: key_atom,
|
||||
value: value
|
||||
})
|
||||
|
||||
apply(WandererApp.Map.Server, method_atom, [
|
||||
map_id,
|
||||
%{
|
||||
solar_system_source_id: "#{solar_system_source_id}" |> String.to_integer(),
|
||||
solar_system_target_id: "#{solar_system_target_id}" |> String.to_integer()
|
||||
}
|
||||
|> Map.put_new(key_atom, value)
|
||||
])
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"get_connection_info",
|
||||
%{"from" => from, "to" => to} = _event,
|
||||
%{assigns: %{map_id: map_id}} = socket
|
||||
) do
|
||||
{:ok, info} = map_id |> get_connection_info(from, to)
|
||||
|
||||
{:reply, info, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"get_passages",
|
||||
%{"from" => from, "to" => to} = _event,
|
||||
%{assigns: %{map_id: map_id}} = socket
|
||||
) do
|
||||
{:ok, passages} = map_id |> get_connection_passages(from, to)
|
||||
|
||||
{:reply, passages, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(event, body, socket),
|
||||
do: MapCoreEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
defp get_connection_passages(map_id, from, to) do
|
||||
{:ok, passages} = WandererApp.MapChainPassagesRepo.by_connection(map_id, from, to)
|
||||
|
||||
passages =
|
||||
passages
|
||||
|> Enum.map(fn p ->
|
||||
%{
|
||||
p
|
||||
| character: p.character |> MapEventHandler.map_ui_character_stat()
|
||||
}
|
||||
|> Map.put_new(
|
||||
:ship,
|
||||
WandererApp.Character.get_ship(%{ship: p.ship_type_id, ship_name: p.ship_name})
|
||||
)
|
||||
|> Map.drop([:ship_type_id, :ship_name])
|
||||
end)
|
||||
|
||||
{:ok, %{passages: passages}}
|
||||
end
|
||||
|
||||
defp get_connection_info(map_id, from, to) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.get_connection_info(%{
|
||||
solar_system_source_id: "#{from}" |> String.to_integer(),
|
||||
solar_system_target_id: "#{to}" |> String.to_integer()
|
||||
})
|
||||
|> case do
|
||||
{:ok, info} ->
|
||||
{:ok, info}
|
||||
|
||||
_ ->
|
||||
{:ok, %{}}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,544 @@
|
||||
defmodule WandererAppWeb.MapCoreEventHandler do
|
||||
use WandererAppWeb, :live_component
|
||||
use Phoenix.Component
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{MapEventHandler, MapCharactersEventHandler}
|
||||
|
||||
def handle_server_event(:update_permissions, socket) do
|
||||
DebounceAndThrottle.Debounce.apply(
|
||||
Process,
|
||||
:send_after,
|
||||
[self(), :refresh_permissions, 100],
|
||||
"update_permissions_#{inspect(self())}",
|
||||
1000
|
||||
)
|
||||
|
||||
socket
|
||||
end
|
||||
|
||||
def handle_server_event(
|
||||
:refresh_permissions,
|
||||
%{assigns: %{current_user: current_user, map_slug: map_slug}} = socket
|
||||
) do
|
||||
{:ok, %{id: map_id, user_permissions: user_permissions, owner_id: owner_id}} =
|
||||
map_slug
|
||||
|> WandererApp.Api.Map.get_map_by_slug!()
|
||||
|> Ash.load(:user_permissions, actor: current_user)
|
||||
|
||||
user_permissions =
|
||||
WandererApp.Permissions.get_map_permissions(
|
||||
user_permissions,
|
||||
owner_id,
|
||||
current_user.characters |> Enum.map(& &1.id)
|
||||
)
|
||||
|
||||
case user_permissions do
|
||||
%{view_system: false} ->
|
||||
socket
|
||||
|> Phoenix.LiveView.put_flash(:error, "Your access to the map have been revoked.")
|
||||
|> Phoenix.LiveView.push_navigate(to: ~p"/maps")
|
||||
|
||||
%{track_character: track_character} ->
|
||||
{:ok, map_characters} =
|
||||
case WandererApp.MapCharacterSettingsRepo.get_tracked_by_map_filtered(
|
||||
map_id,
|
||||
current_user.characters |> Enum.map(& &1.id)
|
||||
) do
|
||||
{:ok, settings} ->
|
||||
{:ok,
|
||||
settings
|
||||
|> Enum.map(fn s -> s |> Ash.load!(:character) |> Map.get(:character) end)}
|
||||
|
||||
_ ->
|
||||
{:ok, []}
|
||||
end
|
||||
|
||||
case track_character do
|
||||
false ->
|
||||
:ok = MapCharactersEventHandler.untrack_characters(map_characters, map_id)
|
||||
:ok = MapCharactersEventHandler.remove_characters(map_characters, map_id)
|
||||
|
||||
_ ->
|
||||
:ok = MapCharactersEventHandler.track_characters(map_characters, map_id, true)
|
||||
|
||||
:ok =
|
||||
MapCharactersEventHandler.add_characters(map_characters, map_id, track_character)
|
||||
end
|
||||
|
||||
socket
|
||||
|> assign(user_permissions: user_permissions)
|
||||
|> MapEventHandler.push_map_event(
|
||||
"user_permissions",
|
||||
user_permissions
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_server_event(
|
||||
%{
|
||||
event: :load_map
|
||||
},
|
||||
%{assigns: %{current_user: current_user, map_slug: map_slug}} = socket
|
||||
) do
|
||||
ErrorTracker.set_context(%{user_id: current_user.id})
|
||||
|
||||
map_slug
|
||||
|> WandererApp.MapRepo.get_by_slug_with_permissions(current_user)
|
||||
|> case do
|
||||
{:ok, map} ->
|
||||
socket |> init_map(map)
|
||||
|
||||
{:error, _} ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Something went wrong. Please try one more time or submit an issue."
|
||||
)
|
||||
|> push_navigate(to: ~p"/maps")
|
||||
end
|
||||
end
|
||||
|
||||
def handle_server_event(
|
||||
%{event: :map_server_started},
|
||||
socket
|
||||
),
|
||||
do: socket |> handle_map_server_started()
|
||||
|
||||
def handle_server_event(%{event: :update_map, payload: map_diff}, socket),
|
||||
do:
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"map_updated",
|
||||
map_diff
|
||||
)
|
||||
|
||||
def handle_server_event(
|
||||
%{event: "presence_diff"},
|
||||
socket
|
||||
),
|
||||
do: socket
|
||||
|
||||
def handle_server_event(event, socket) do
|
||||
Logger.warning(fn -> "unhandled map core event: #{inspect(event)}" end)
|
||||
socket
|
||||
end
|
||||
|
||||
def handle_ui_event("ui_loaded", _body, %{assigns: %{map_slug: map_slug} = assigns} = socket) do
|
||||
assigns
|
||||
|> Map.get(:map_id)
|
||||
|> case do
|
||||
map_id when not is_nil(map_id) ->
|
||||
maybe_start_map(map_id)
|
||||
|
||||
_ ->
|
||||
WandererApp.Cache.insert("map_#{map_slug}:ui_loaded", true)
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"live_select_change",
|
||||
%{"id" => id, "text" => text},
|
||||
socket
|
||||
)
|
||||
when id == "_system_id_live_select_component" do
|
||||
options =
|
||||
WandererApp.Api.MapSolarSystem.find_by_name!(%{name: text})
|
||||
|> Enum.take(100)
|
||||
|> Enum.map(&map_system/1)
|
||||
|
||||
send_update(LiveSelect.Component, options: options, id: id)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event("toggle_track_" <> character_id, _, socket),
|
||||
do:
|
||||
MapCharactersEventHandler.handle_ui_event(
|
||||
"toggle_track",
|
||||
%{"character-id" => character_id},
|
||||
socket
|
||||
)
|
||||
|
||||
def handle_ui_event(
|
||||
"get_user_settings",
|
||||
_,
|
||||
%{assigns: %{map_id: map_id, current_user: current_user}} = socket
|
||||
) do
|
||||
{:ok, user_settings} =
|
||||
WandererApp.MapUserSettingsRepo.get!(map_id, current_user.id)
|
||||
|> WandererApp.MapUserSettingsRepo.to_form_data()
|
||||
|
||||
{:reply, %{user_settings: user_settings}, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"update_user_settings",
|
||||
user_settings_form,
|
||||
%{assigns: %{map_id: map_id, current_user: current_user}} = socket
|
||||
) do
|
||||
settings =
|
||||
user_settings_form
|
||||
|> Map.take(["select_on_spash", "link_signature_on_splash", "delete_connection_with_sigs"])
|
||||
|> Jason.encode!()
|
||||
|
||||
{:ok, user_settings} =
|
||||
WandererApp.MapUserSettingsRepo.create_or_update(map_id, current_user.id, settings)
|
||||
|
||||
{:noreply,
|
||||
socket |> assign(user_settings_form: user_settings_form, map_user_settings: user_settings)}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"log_map_error",
|
||||
%{"componentStack" => component_stack, "error" => error},
|
||||
socket
|
||||
) do
|
||||
Logger.error(fn -> "map_ui_error: #{error} \n#{component_stack} " end)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, "Something went wrong. Please try refresh page or submit an issue.")
|
||||
|> push_event("js-exec", %{
|
||||
to: "#map-loader",
|
||||
attr: "data-loading",
|
||||
timeout: 100
|
||||
})}
|
||||
end
|
||||
|
||||
def handle_ui_event("noop", _, socket), do: {:noreply, socket}
|
||||
|
||||
def handle_ui_event(
|
||||
_event,
|
||||
_body,
|
||||
%{assigns: %{has_tracked_characters?: false}} =
|
||||
socket
|
||||
),
|
||||
do:
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"You should enable tracking for at least one character."
|
||||
)}
|
||||
|
||||
def handle_ui_event(event, body, socket) do
|
||||
Logger.warning(fn -> "unhandled map ui event: #{event} #{inspect(body)}" end)
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
defp maybe_start_map(map_id) do
|
||||
{:ok, map_server_started} = WandererApp.Cache.lookup("map_#{map_id}:started", false)
|
||||
|
||||
if map_server_started do
|
||||
Process.send_after(self(), %{event: :map_server_started}, 10)
|
||||
else
|
||||
WandererApp.Map.Manager.start_map(map_id)
|
||||
end
|
||||
end
|
||||
|
||||
defp init_map(
|
||||
%{assigns: %{current_user: current_user, map_slug: map_slug}} = socket,
|
||||
%{
|
||||
id: map_id,
|
||||
deleted: false,
|
||||
only_tracked_characters: only_tracked_characters,
|
||||
user_permissions: user_permissions,
|
||||
name: map_name,
|
||||
owner_id: owner_id
|
||||
} = map
|
||||
) do
|
||||
user_permissions =
|
||||
WandererApp.Permissions.get_map_permissions(
|
||||
user_permissions,
|
||||
owner_id,
|
||||
current_user.characters |> Enum.map(& &1.id)
|
||||
)
|
||||
|
||||
{:ok, character_settings} =
|
||||
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(map_id) do
|
||||
{:ok, settings} -> {:ok, settings}
|
||||
_ -> {:ok, []}
|
||||
end
|
||||
|
||||
{:ok, %{characters: availaible_map_characters}} =
|
||||
WandererApp.Maps.load_characters(map, character_settings, current_user.id)
|
||||
|
||||
can_view? = user_permissions.view_system
|
||||
can_track? = user_permissions.track_character
|
||||
|
||||
tracked_character_ids =
|
||||
availaible_map_characters |> Enum.filter(& &1.tracked) |> Enum.map(& &1.id)
|
||||
|
||||
all_character_tracked? =
|
||||
not (availaible_map_characters |> Enum.empty?()) and
|
||||
availaible_map_characters |> Enum.all?(& &1.tracked)
|
||||
|
||||
cond do
|
||||
(only_tracked_characters and can_track? and all_character_tracked?) or
|
||||
(not only_tracked_characters and can_view?) ->
|
||||
Phoenix.PubSub.subscribe(WandererApp.PubSub, map_id)
|
||||
{:ok, ui_loaded} = WandererApp.Cache.get_and_remove("map_#{map_slug}:ui_loaded", false)
|
||||
|
||||
if ui_loaded do
|
||||
maybe_start_map(map_id)
|
||||
end
|
||||
|
||||
socket
|
||||
|> assign(
|
||||
map_id: map_id,
|
||||
page_title: map_name,
|
||||
user_permissions: user_permissions,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
only_tracked_characters: only_tracked_characters
|
||||
)
|
||||
|
||||
only_tracked_characters and can_track? and not all_character_tracked? ->
|
||||
Process.send_after(self(), :not_all_characters_tracked, 10)
|
||||
socket
|
||||
|
||||
true ->
|
||||
Process.send_after(self(), :no_permissions, 10)
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
defp init_map(socket, _map) do
|
||||
Process.send_after(self(), :no_access, 10)
|
||||
socket
|
||||
end
|
||||
|
||||
defp handle_map_server_started(
|
||||
%{
|
||||
assigns: %{
|
||||
current_user: current_user,
|
||||
map_id: map_id,
|
||||
user_permissions:
|
||||
%{view_system: true, track_character: track_character} = user_permissions
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
with {:ok, _} <- current_user |> WandererApp.Api.User.update_last_map(%{last_map_id: map_id}),
|
||||
{:ok, map_user_settings} <- WandererApp.MapUserSettingsRepo.get(map_id, current_user.id),
|
||||
{:ok, tracked_map_characters} <-
|
||||
MapCharactersEventHandler.get_tracked_map_characters(map_id, current_user),
|
||||
{:ok, characters_limit} <- map_id |> WandererApp.Map.get_characters_limit(),
|
||||
{:ok, present_character_ids} <-
|
||||
WandererApp.Cache.lookup("map_#{map_id}:presence_character_ids", []),
|
||||
{:ok, kills} <- WandererApp.Cache.lookup("map_#{map_id}:zkb_kills", Map.new()) do
|
||||
user_character_eve_ids = tracked_map_characters |> Enum.map(& &1.eve_id)
|
||||
|
||||
events =
|
||||
case tracked_map_characters |> Enum.any?(&(&1.access_token == nil)) do
|
||||
true ->
|
||||
[:invalid_token_message]
|
||||
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
|
||||
events =
|
||||
case tracked_map_characters |> Enum.empty?() do
|
||||
true ->
|
||||
events ++ [:empty_tracked_characters]
|
||||
|
||||
_ ->
|
||||
events
|
||||
end
|
||||
|
||||
events =
|
||||
case present_character_ids |> Enum.count() < characters_limit do
|
||||
true ->
|
||||
events ++ [{:track_characters, tracked_map_characters, track_character}]
|
||||
|
||||
_ ->
|
||||
events ++ [:map_character_limit]
|
||||
end
|
||||
|
||||
initial_data =
|
||||
map_id
|
||||
|> get_map_data()
|
||||
|> Map.merge(%{
|
||||
kills:
|
||||
kills
|
||||
|> Enum.filter(fn {_, kills} -> kills > 0 end)
|
||||
|> Enum.map(&MapEventHandler.map_ui_kill/1),
|
||||
present_characters:
|
||||
present_character_ids
|
||||
|> WandererApp.Character.get_character_eve_ids!(),
|
||||
user_characters: user_character_eve_ids,
|
||||
user_permissions: user_permissions,
|
||||
system_static_infos: nil,
|
||||
wormhole_types: nil,
|
||||
effects: nil,
|
||||
reset: false
|
||||
})
|
||||
|
||||
system_static_infos =
|
||||
map_id
|
||||
|> WandererApp.Map.list_systems!()
|
||||
|> Enum.map(&WandererApp.CachedInfo.get_system_static_info!(&1.solar_system_id))
|
||||
|> Enum.map(&MapEventHandler.map_ui_system_static_info/1)
|
||||
|
||||
initial_data =
|
||||
initial_data
|
||||
|> Map.put(
|
||||
:wormholes,
|
||||
WandererApp.CachedInfo.get_wormhole_types!()
|
||||
)
|
||||
|> Map.put(
|
||||
:effects,
|
||||
WandererApp.CachedInfo.get_effects!()
|
||||
)
|
||||
|> Map.put(
|
||||
:system_static_infos,
|
||||
system_static_infos
|
||||
)
|
||||
|> Map.put(:reset, true)
|
||||
|
||||
socket
|
||||
|> map_start(%{
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
initial_data: initial_data,
|
||||
events: events
|
||||
})
|
||||
else
|
||||
error ->
|
||||
Logger.error(fn -> "map_start_error: #{error}" end)
|
||||
Process.send_after(self(), :no_access, 10)
|
||||
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_map_server_started(socket) do
|
||||
Process.send_after(self(), :no_access, 10)
|
||||
socket
|
||||
end
|
||||
|
||||
defp map_start(
|
||||
socket,
|
||||
%{
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
initial_data: initial_data,
|
||||
events: events
|
||||
} = _started_data
|
||||
) do
|
||||
socket =
|
||||
socket
|
||||
|> handle_map_start_events(map_id, events)
|
||||
|
||||
map_characters = map_id |> WandererApp.Map.list_characters()
|
||||
|
||||
socket
|
||||
|> assign(
|
||||
map_loaded?: true,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
has_tracked_characters?:
|
||||
MapCharactersEventHandler.has_tracked_characters?(user_character_eve_ids)
|
||||
)
|
||||
|> MapEventHandler.push_map_event(
|
||||
"init",
|
||||
initial_data
|
||||
|> Map.put(
|
||||
:characters,
|
||||
map_characters |> Enum.map(&MapCharactersEventHandler.map_ui_character/1)
|
||||
)
|
||||
)
|
||||
|> push_event("js-exec", %{
|
||||
to: "#map-loader",
|
||||
attr: "data-loaded"
|
||||
})
|
||||
end
|
||||
|
||||
defp handle_map_start_events(socket, map_id, events) do
|
||||
events
|
||||
|> Enum.reduce(socket, fn event, socket ->
|
||||
case event do
|
||||
{:track_characters, map_characters, track_character} ->
|
||||
:ok =
|
||||
MapCharactersEventHandler.track_characters(map_characters, map_id, track_character)
|
||||
|
||||
:ok = MapCharactersEventHandler.add_characters(map_characters, map_id, track_character)
|
||||
socket
|
||||
|
||||
:invalid_token_message ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"One of your characters has expired token. Please refresh it on characters page."
|
||||
)
|
||||
|
||||
:empty_tracked_characters ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:info,
|
||||
"You should enable tracking for at least one character to work with map."
|
||||
)
|
||||
|
||||
:map_character_limit ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Map reached its character limit, your characters won't be tracked. Please contact administrator."
|
||||
)
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp get_map_data(map_id, include_static_data? \\ true) do
|
||||
{:ok, hubs} = map_id |> WandererApp.Map.list_hubs()
|
||||
{:ok, connections} = map_id |> WandererApp.Map.list_connections()
|
||||
{:ok, systems} = map_id |> WandererApp.Map.list_systems()
|
||||
|
||||
%{
|
||||
systems:
|
||||
systems
|
||||
|> Enum.map(fn system -> MapEventHandler.map_ui_system(system, include_static_data?) end),
|
||||
hubs: hubs,
|
||||
connections: connections |> Enum.map(&MapEventHandler.map_ui_connection/1)
|
||||
}
|
||||
end
|
||||
|
||||
defp get_tracked_map_characters(map_id, current_user) do
|
||||
case WandererApp.MapCharacterSettingsRepo.get_tracked_by_map_filtered(
|
||||
map_id,
|
||||
current_user.characters |> Enum.map(& &1.id)
|
||||
) do
|
||||
{:ok, settings} ->
|
||||
{:ok,
|
||||
settings
|
||||
|> Enum.map(fn s -> s |> Ash.load!(:character) |> Map.get(:character) end)}
|
||||
|
||||
_ ->
|
||||
{:ok, []}
|
||||
end
|
||||
end
|
||||
|
||||
defp map_system(
|
||||
%{
|
||||
solar_system_name: solar_system_name,
|
||||
constellation_name: constellation_name,
|
||||
region_name: region_name,
|
||||
solar_system_id: solar_system_id,
|
||||
class_title: class_title
|
||||
} = _system
|
||||
),
|
||||
do: %{
|
||||
label: solar_system_name,
|
||||
value: solar_system_id,
|
||||
constellation_name: constellation_name,
|
||||
region_name: region_name,
|
||||
class_title: class_title
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,131 @@
|
||||
defmodule WandererAppWeb.MapRoutesEventHandler do
|
||||
use WandererAppWeb, :live_component
|
||||
use Phoenix.Component
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{MapEventHandler, MapCoreEventHandler}
|
||||
|
||||
def handle_server_event(
|
||||
%{
|
||||
event: :routes,
|
||||
payload: {solar_system_id, %{routes: routes, systems_static_data: systems_static_data}}
|
||||
},
|
||||
socket
|
||||
),
|
||||
do:
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"routes",
|
||||
%{
|
||||
solar_system_id: solar_system_id,
|
||||
loading: false,
|
||||
routes: routes,
|
||||
systems_static_data: systems_static_data
|
||||
}
|
||||
)
|
||||
|
||||
def handle_server_event(event, socket),
|
||||
do: MapCoreEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_ui_event(
|
||||
"get_routes",
|
||||
%{"system_id" => solar_system_id, "routes_settings" => routes_settings} = _event,
|
||||
%{assigns: %{map_id: map_id, map_loaded?: true}} = socket
|
||||
) do
|
||||
Task.async(fn ->
|
||||
{:ok, hubs} = map_id |> WandererApp.Map.list_hubs()
|
||||
|
||||
{:ok, routes} =
|
||||
WandererApp.Maps.find_routes(
|
||||
map_id,
|
||||
hubs,
|
||||
solar_system_id,
|
||||
get_routes_settings(routes_settings)
|
||||
)
|
||||
|
||||
{:routes, {solar_system_id, routes}}
|
||||
end)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"set_autopilot_waypoint",
|
||||
%{
|
||||
"character_eve_ids" => character_eve_ids,
|
||||
"add_to_beginning" => add_to_beginning,
|
||||
"clear_other_waypoints" => clear_other_waypoints,
|
||||
"destination_id" => destination_id
|
||||
} = _event,
|
||||
%{assigns: %{current_user: current_user, has_tracked_characters?: true}} = socket
|
||||
) do
|
||||
character_eve_ids
|
||||
|> Task.async_stream(fn character_eve_id ->
|
||||
set_autopilot_waypoint(
|
||||
current_user,
|
||||
character_eve_id,
|
||||
add_to_beginning,
|
||||
clear_other_waypoints,
|
||||
destination_id
|
||||
)
|
||||
end)
|
||||
|> Enum.map(fn _result -> :skip end)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(event, body, socket),
|
||||
do: MapCoreEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
defp get_routes_settings(%{
|
||||
"path_type" => path_type,
|
||||
"include_mass_crit" => include_mass_crit,
|
||||
"include_eol" => include_eol,
|
||||
"include_frig" => include_frig,
|
||||
"include_cruise" => include_cruise,
|
||||
"avoid_wormholes" => avoid_wormholes,
|
||||
"avoid_pochven" => avoid_pochven,
|
||||
"avoid_edencom" => avoid_edencom,
|
||||
"avoid_triglavian" => avoid_triglavian,
|
||||
"include_thera" => include_thera,
|
||||
"avoid" => avoid
|
||||
}),
|
||||
do: %{
|
||||
path_type: path_type,
|
||||
include_mass_crit: include_mass_crit,
|
||||
include_eol: include_eol,
|
||||
include_frig: include_frig,
|
||||
include_cruise: include_cruise,
|
||||
avoid_wormholes: avoid_wormholes,
|
||||
avoid_pochven: avoid_pochven,
|
||||
avoid_edencom: avoid_edencom,
|
||||
avoid_triglavian: avoid_triglavian,
|
||||
include_thera: include_thera,
|
||||
avoid: avoid
|
||||
}
|
||||
|
||||
defp get_routes_settings(_), do: %{}
|
||||
|
||||
defp set_autopilot_waypoint(
|
||||
current_user,
|
||||
character_eve_id,
|
||||
add_to_beginning,
|
||||
clear_other_waypoints,
|
||||
destination_id
|
||||
) do
|
||||
case current_user.characters
|
||||
|> Enum.find(fn c -> c.eve_id == character_eve_id end) do
|
||||
nil ->
|
||||
:skip
|
||||
|
||||
%{id: character_id} = _character ->
|
||||
character_id
|
||||
|> WandererApp.Character.set_autopilot_waypoint(destination_id,
|
||||
add_to_beginning: add_to_beginning,
|
||||
clear_other_waypoints: clear_other_waypoints
|
||||
)
|
||||
|
||||
:skip
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,350 @@
|
||||
defmodule WandererAppWeb.MapSignaturesEventHandler do
|
||||
use WandererAppWeb, :live_component
|
||||
use Phoenix.Component
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{MapEventHandler, MapCoreEventHandler}
|
||||
|
||||
def handle_server_event(
|
||||
%{
|
||||
event: :maybe_link_signature,
|
||||
payload: %{
|
||||
character_id: character_id,
|
||||
solar_system_source: solar_system_source,
|
||||
solar_system_target: solar_system_target
|
||||
}
|
||||
},
|
||||
%{
|
||||
assigns: %{
|
||||
current_user: current_user,
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
is_user_character =
|
||||
current_user.characters |> Enum.map(& &1.id) |> Enum.member?(character_id)
|
||||
|
||||
is_link_signature_on_splash =
|
||||
map_user_settings
|
||||
|> WandererApp.MapUserSettingsRepo.to_form_data!()
|
||||
|> WandererApp.MapUserSettingsRepo.get_boolean_setting("link_signature_on_splash")
|
||||
|
||||
{:ok, signatures} =
|
||||
WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_source
|
||||
})
|
||||
|> case do
|
||||
{:ok, system} ->
|
||||
{:ok, get_system_signatures(system.id)}
|
||||
|
||||
_ ->
|
||||
{:ok, []}
|
||||
end
|
||||
|
||||
(is_user_character && is_link_signature_on_splash && not (signatures |> Enum.empty?()))
|
||||
|> case do
|
||||
true ->
|
||||
socket
|
||||
|> MapEventHandler.push_map_event("link_signature_to_system", %{
|
||||
solar_system_source: solar_system_source,
|
||||
solar_system_target: solar_system_target
|
||||
})
|
||||
|
||||
false ->
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
def handle_server_event(
|
||||
%{event: :signatures_updated, payload: solar_system_id},
|
||||
socket
|
||||
),
|
||||
do:
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"signatures_updated",
|
||||
solar_system_id
|
||||
)
|
||||
|
||||
def handle_server_event(event, socket),
|
||||
do: MapCoreEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_ui_event(
|
||||
"update_signatures",
|
||||
%{
|
||||
"system_id" => solar_system_id,
|
||||
"added" => added_signatures,
|
||||
"updated" => updated_signatures,
|
||||
"removed" => removed_signatures
|
||||
},
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_characters,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id |> String.to_integer()
|
||||
})
|
||||
|> case do
|
||||
{:ok, system} ->
|
||||
first_character_eve_id =
|
||||
user_characters |> List.first()
|
||||
|
||||
case not is_nil(first_character_eve_id) do
|
||||
true ->
|
||||
added_signatures =
|
||||
added_signatures
|
||||
|> parse_signatures(first_character_eve_id, system.id)
|
||||
|
||||
updated_signatures =
|
||||
updated_signatures
|
||||
|> parse_signatures(first_character_eve_id, system.id)
|
||||
|
||||
updated_signatures_eve_ids =
|
||||
updated_signatures
|
||||
|> Enum.map(fn s -> s.eve_id end)
|
||||
|
||||
removed_signatures_eve_ids =
|
||||
removed_signatures
|
||||
|> parse_signatures(first_character_eve_id, system.id)
|
||||
|> Enum.map(fn s -> s.eve_id end)
|
||||
|
||||
delete_connection_with_sigs =
|
||||
map_user_settings
|
||||
|> WandererApp.MapUserSettingsRepo.to_form_data!()
|
||||
|> WandererApp.MapUserSettingsRepo.get_boolean_setting(
|
||||
"delete_connection_with_sigs"
|
||||
)
|
||||
|
||||
WandererApp.Api.MapSystemSignature.by_system_id!(system.id)
|
||||
|> Enum.filter(fn s -> s.eve_id in removed_signatures_eve_ids end)
|
||||
|> Enum.each(fn s ->
|
||||
if delete_connection_with_sigs && not is_nil(s.linked_system_id) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.delete_connection(%{
|
||||
solar_system_source_id: solar_system_id |> String.to_integer(),
|
||||
solar_system_target_id: s.linked_system_id
|
||||
})
|
||||
end
|
||||
|
||||
s
|
||||
|> Ash.destroy!()
|
||||
end)
|
||||
|
||||
WandererApp.Api.MapSystemSignature.by_system_id!(system.id)
|
||||
|> Enum.filter(fn s -> s.eve_id in updated_signatures_eve_ids end)
|
||||
|> Enum.each(fn s ->
|
||||
updated = updated_signatures |> Enum.find(fn u -> u.eve_id == s.eve_id end)
|
||||
|
||||
if not is_nil(updated) do
|
||||
s
|
||||
|> WandererApp.Api.MapSystemSignature.update(updated)
|
||||
end
|
||||
end)
|
||||
|
||||
added_signatures
|
||||
|> Enum.map(fn s ->
|
||||
s |> WandererApp.Api.MapSystemSignature.create!()
|
||||
end)
|
||||
|
||||
Phoenix.PubSub.broadcast!(WandererApp.PubSub, map_id, %{
|
||||
event: :signatures_updated,
|
||||
payload: system.solar_system_id
|
||||
})
|
||||
|
||||
{:reply, %{signatures: get_system_signatures(system.id)}, socket}
|
||||
|
||||
_ ->
|
||||
{:reply, %{signatures: []},
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"You should enable tracking for at least one character to work with signatures."
|
||||
)}
|
||||
end
|
||||
|
||||
_ ->
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"get_signatures",
|
||||
%{"system_id" => solar_system_id},
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
case WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id |> String.to_integer()
|
||||
}) do
|
||||
{:ok, system} ->
|
||||
{:reply, %{signatures: get_system_signatures(system.id)}, socket}
|
||||
|
||||
_ ->
|
||||
{:reply, %{signatures: []}, socket}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"link_signature_to_system",
|
||||
%{
|
||||
"signature_eve_id" => signature_eve_id,
|
||||
"solar_system_source" => solar_system_source,
|
||||
"solar_system_target" => solar_system_target
|
||||
},
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
user_characters: user_characters,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
case WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_source
|
||||
}) do
|
||||
{:ok, system} ->
|
||||
first_character_eve_id =
|
||||
user_characters |> List.first()
|
||||
|
||||
case not is_nil(first_character_eve_id) do
|
||||
true ->
|
||||
WandererApp.Api.MapSystemSignature.by_system_id!(system.id)
|
||||
|> Enum.filter(fn s -> s.eve_id == signature_eve_id end)
|
||||
|> Enum.each(fn s ->
|
||||
s
|
||||
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{
|
||||
linked_system_id: solar_system_target
|
||||
})
|
||||
end)
|
||||
|
||||
Phoenix.PubSub.broadcast!(WandererApp.PubSub, map_id, %{
|
||||
event: :signatures_updated,
|
||||
payload: solar_system_source
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
|
||||
_ ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"You should enable tracking for at least one character to work with signatures."
|
||||
)}
|
||||
end
|
||||
|
||||
_ ->
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"unlink_signature",
|
||||
%{
|
||||
"signature_eve_id" => signature_eve_id,
|
||||
"solar_system_source" => solar_system_source
|
||||
},
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
user_characters: user_characters,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
case WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_source
|
||||
}) do
|
||||
{:ok, system} ->
|
||||
first_character_eve_id =
|
||||
user_characters |> List.first()
|
||||
|
||||
case not is_nil(first_character_eve_id) do
|
||||
true ->
|
||||
WandererApp.Api.MapSystemSignature.by_system_id!(system.id)
|
||||
|> Enum.filter(fn s -> s.eve_id == signature_eve_id end)
|
||||
|> Enum.each(fn s ->
|
||||
s
|
||||
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{
|
||||
linked_system_id: nil
|
||||
})
|
||||
end)
|
||||
|
||||
Phoenix.PubSub.broadcast!(WandererApp.PubSub, map_id, %{
|
||||
event: :signatures_updated,
|
||||
payload: solar_system_source
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
|
||||
_ ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"You should enable tracking for at least one character to work with signatures."
|
||||
)}
|
||||
end
|
||||
|
||||
_ ->
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_ui_event(event, body, socket),
|
||||
do: MapCoreEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
defp get_system_signatures(system_id),
|
||||
do:
|
||||
system_id
|
||||
|> WandererApp.Api.MapSystemSignature.by_system_id!()
|
||||
|> Enum.map(fn %{updated_at: updated_at, linked_system_id: linked_system_id} = s ->
|
||||
s
|
||||
|> Map.take([
|
||||
:eve_id,
|
||||
:name,
|
||||
:description,
|
||||
:kind,
|
||||
:group,
|
||||
:type,
|
||||
:updated_at
|
||||
])
|
||||
|> Map.put(:linked_system, MapEventHandler.get_system_static_info(linked_system_id))
|
||||
|> Map.put(:updated_at, updated_at |> Calendar.strftime("%Y/%m/%d %H:%M:%S"))
|
||||
end)
|
||||
|
||||
defp parse_signatures(signatures, character_eve_id, system_id),
|
||||
do:
|
||||
signatures
|
||||
|> Enum.map(fn %{
|
||||
"eve_id" => eve_id,
|
||||
"name" => name,
|
||||
"kind" => kind,
|
||||
"group" => group
|
||||
} = signature ->
|
||||
%{
|
||||
system_id: system_id,
|
||||
eve_id: eve_id,
|
||||
name: name,
|
||||
description: Map.get(signature, "description"),
|
||||
kind: kind,
|
||||
group: group,
|
||||
type: Map.get(signature, "type"),
|
||||
character_eve_id: character_eve_id
|
||||
}
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,326 @@
|
||||
defmodule WandererAppWeb.MapSystemsEventHandler do
|
||||
use WandererAppWeb, :live_component
|
||||
use Phoenix.Component
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{MapEventHandler, MapCoreEventHandler}
|
||||
|
||||
def handle_server_event(%{event: :add_system, payload: system}, socket),
|
||||
do:
|
||||
socket
|
||||
|> MapEventHandler.push_map_event("add_systems", [MapEventHandler.map_ui_system(system)])
|
||||
|
||||
def handle_server_event(%{event: :update_system, payload: system}, socket),
|
||||
do:
|
||||
socket
|
||||
|> MapEventHandler.push_map_event("update_systems", [MapEventHandler.map_ui_system(system)])
|
||||
|
||||
def handle_server_event(%{event: :systems_removed, payload: solar_system_ids}, socket),
|
||||
do:
|
||||
socket
|
||||
|> MapEventHandler.push_map_event("remove_systems", solar_system_ids)
|
||||
|
||||
def handle_server_event(
|
||||
%{
|
||||
event: :maybe_select_system,
|
||||
payload: %{
|
||||
character_id: character_id,
|
||||
solar_system_id: solar_system_id
|
||||
}
|
||||
},
|
||||
%{assigns: %{current_user: current_user, map_user_settings: map_user_settings}} = socket
|
||||
) do
|
||||
is_user_character =
|
||||
current_user.characters |> Enum.map(& &1.id) |> Enum.member?(character_id)
|
||||
|
||||
is_select_on_spash =
|
||||
map_user_settings
|
||||
|> WandererApp.MapUserSettingsRepo.to_form_data!()
|
||||
|> WandererApp.MapUserSettingsRepo.get_boolean_setting("select_on_spash")
|
||||
|
||||
(is_user_character && is_select_on_spash)
|
||||
|> case do
|
||||
true ->
|
||||
socket
|
||||
|> MapEventHandler.push_map_event("select_system", solar_system_id)
|
||||
|
||||
false ->
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
def handle_server_event(%{event: :kills_updated, payload: kills}, socket) do
|
||||
kills =
|
||||
kills
|
||||
|> Enum.map(&MapEventHandler.map_ui_kill/1)
|
||||
|
||||
socket
|
||||
|> MapEventHandler.push_map_event(
|
||||
"kills_updated",
|
||||
kills
|
||||
)
|
||||
end
|
||||
|
||||
def handle_server_event(event, socket),
|
||||
do: MapCoreEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_ui_event(
|
||||
"add_system",
|
||||
%{"system_id" => solar_system_id} = _event,
|
||||
%{
|
||||
assigns:
|
||||
%{
|
||||
map_id: map_id,
|
||||
map_slug: map_slug,
|
||||
current_user: current_user,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
user_permissions: %{add_system: true}
|
||||
} = assigns
|
||||
} = socket
|
||||
)
|
||||
when is_binary(solar_system_id) and solar_system_id != "" do
|
||||
coordinates = Map.get(assigns, :coordinates)
|
||||
|
||||
WandererApp.Map.Server.add_system(
|
||||
map_id,
|
||||
%{
|
||||
solar_system_id: solar_system_id |> String.to_integer(),
|
||||
coordinates: coordinates
|
||||
},
|
||||
current_user.id,
|
||||
tracked_character_ids |> List.first()
|
||||
)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> push_patch(to: ~p"/#{map_slug}")}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"manual_add_system",
|
||||
%{"coordinates" => coordinates} = _event,
|
||||
%{
|
||||
assigns: %{
|
||||
has_tracked_characters?: true,
|
||||
map_slug: map_slug,
|
||||
user_permissions: %{add_system: true}
|
||||
}
|
||||
} =
|
||||
socket
|
||||
),
|
||||
do:
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(coordinates: coordinates)
|
||||
|> push_patch(to: ~p"/#{map_slug}/add-system")}
|
||||
|
||||
def handle_ui_event(
|
||||
"add_hub",
|
||||
%{"system_id" => solar_system_id} = _event,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
current_user: current_user,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} =
|
||||
socket
|
||||
) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.add_hub(%{
|
||||
solar_system_id: solar_system_id
|
||||
})
|
||||
|
||||
{:ok, _} =
|
||||
WandererApp.User.ActivityTracker.track_map_event(:hub_added, %{
|
||||
character_id: tracked_character_ids |> List.first(),
|
||||
user_id: current_user.id,
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"delete_hub",
|
||||
%{"system_id" => solar_system_id} = _event,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
current_user: current_user,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} =
|
||||
socket
|
||||
) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.remove_hub(%{
|
||||
solar_system_id: solar_system_id
|
||||
})
|
||||
|
||||
{:ok, _} =
|
||||
WandererApp.User.ActivityTracker.track_map_event(:hub_removed, %{
|
||||
character_id: tracked_character_ids |> List.first(),
|
||||
user_id: current_user.id,
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"update_system_position",
|
||||
position,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
map_id
|
||||
|> update_system_position(position)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"update_system_positions",
|
||||
positions,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
map_id
|
||||
|> update_system_positions(positions)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"update_system_" <> param,
|
||||
%{"system_id" => solar_system_id, "value" => value} = _event,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
current_user: current_user,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{update_system: true}
|
||||
}
|
||||
} =
|
||||
socket
|
||||
) do
|
||||
method_atom =
|
||||
case param do
|
||||
"name" -> :update_system_name
|
||||
"description" -> :update_system_description
|
||||
"labels" -> :update_system_labels
|
||||
"locked" -> :update_system_locked
|
||||
"tag" -> :update_system_tag
|
||||
"status" -> :update_system_status
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
key_atom =
|
||||
case param do
|
||||
"name" -> :name
|
||||
"description" -> :description
|
||||
"labels" -> :labels
|
||||
"locked" -> :locked
|
||||
"tag" -> :tag
|
||||
"status" -> :status
|
||||
_ -> :none
|
||||
end
|
||||
|
||||
apply(WandererApp.Map.Server, method_atom, [
|
||||
map_id,
|
||||
%{
|
||||
solar_system_id: "#{solar_system_id}" |> String.to_integer()
|
||||
}
|
||||
|> Map.put_new(key_atom, value)
|
||||
])
|
||||
|
||||
{:ok, _} =
|
||||
WandererApp.User.ActivityTracker.track_map_event(:system_updated, %{
|
||||
character_id: tracked_character_ids |> List.first(),
|
||||
user_id: current_user.id,
|
||||
map_id: map_id,
|
||||
solar_system_id: "#{solar_system_id}" |> String.to_integer(),
|
||||
key: key_atom,
|
||||
value: value
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"get_system_static_infos",
|
||||
%{"solar_system_ids" => solar_system_ids} = _event,
|
||||
socket
|
||||
) do
|
||||
system_static_infos =
|
||||
solar_system_ids
|
||||
|> Enum.map(&WandererApp.CachedInfo.get_system_static_info!/1)
|
||||
|> Enum.map(&MapEventHandler.map_ui_system_static_info/1)
|
||||
|
||||
{:reply, %{system_static_infos: system_static_infos}, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(
|
||||
"delete_systems",
|
||||
solar_system_ids,
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
current_user: current_user,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
has_tracked_characters?: true,
|
||||
user_permissions: %{delete_system: true}
|
||||
}
|
||||
} =
|
||||
socket
|
||||
) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.delete_systems(
|
||||
solar_system_ids |> Enum.map(&String.to_integer/1),
|
||||
current_user.id,
|
||||
tracked_character_ids |> List.first()
|
||||
)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_ui_event(event, body, socket),
|
||||
do: MapCoreEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
defp update_system_positions(_map_id, []), do: :ok
|
||||
|
||||
defp update_system_positions(map_id, [position | rest]) do
|
||||
update_system_position(map_id, position)
|
||||
update_system_positions(map_id, rest)
|
||||
end
|
||||
|
||||
defp update_system_position(map_id, %{
|
||||
"position" => %{"x" => x, "y" => y},
|
||||
"solar_system_id" => solar_system_id
|
||||
}),
|
||||
do:
|
||||
map_id
|
||||
|> WandererApp.Map.Server.update_system_position(%{
|
||||
solar_system_id: solar_system_id |> String.to_integer(),
|
||||
position_x: x,
|
||||
position_y: y
|
||||
})
|
||||
end
|
||||
293
lib/wanderer_app_web/live/maps/map_event_handler.ex
Normal file
293
lib/wanderer_app_web/live/maps/map_event_handler.ex
Normal file
@@ -0,0 +1,293 @@
|
||||
defmodule WandererAppWeb.MapEventHandler do
|
||||
use WandererAppWeb, :live_component
|
||||
use Phoenix.Component
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{
|
||||
MapActivityEventHandler,
|
||||
MapCharactersEventHandler,
|
||||
MapConnectionsEventHandler,
|
||||
MapCoreEventHandler,
|
||||
MapRoutesEventHandler,
|
||||
MapSignaturesEventHandler,
|
||||
MapSystemsEventHandler
|
||||
}
|
||||
|
||||
@map_characters_events [
|
||||
:character_added,
|
||||
:character_removed,
|
||||
:character_updated,
|
||||
:characters_updated,
|
||||
:present_characters_updated
|
||||
]
|
||||
|
||||
@map_characters_ui_events [
|
||||
"add_character",
|
||||
"toggle_track",
|
||||
"hide_tracking"
|
||||
]
|
||||
|
||||
@map_system_events [
|
||||
:add_system,
|
||||
:update_system,
|
||||
:systems_removed,
|
||||
:maybe_select_system,
|
||||
:kills_updated
|
||||
]
|
||||
|
||||
@map_system_ui_events [
|
||||
"add_hub",
|
||||
"delete_hub",
|
||||
"add_system",
|
||||
"delete_systems",
|
||||
"manual_add_system",
|
||||
"get_system_static_infos",
|
||||
"update_system_position",
|
||||
"update_system_positions",
|
||||
"update_system_name",
|
||||
"update_system_description",
|
||||
"update_system_labels",
|
||||
"update_system_locked",
|
||||
"update_system_tag",
|
||||
"update_system_status"
|
||||
]
|
||||
|
||||
@map_connection_events [
|
||||
:add_connection,
|
||||
:remove_connections,
|
||||
:update_connection
|
||||
]
|
||||
|
||||
@map_connection_ui_events [
|
||||
"manual_add_connection",
|
||||
"manual_delete_connection",
|
||||
"get_connection_info",
|
||||
"get_passages",
|
||||
"update_connection_time_status",
|
||||
"update_connection_mass_status",
|
||||
"update_connection_ship_size_type",
|
||||
"update_connection_locked",
|
||||
"update_connection_custom_info"
|
||||
]
|
||||
|
||||
@map_activity_events [
|
||||
:character_activity
|
||||
]
|
||||
|
||||
@map_activity_ui_events [
|
||||
"show_activity",
|
||||
"hide_activity"
|
||||
]
|
||||
|
||||
@map_routes_events [
|
||||
:routes
|
||||
]
|
||||
|
||||
@map_routes_ui_events [
|
||||
"get_routes",
|
||||
"set_autopilot_waypoint"
|
||||
]
|
||||
|
||||
@map_signatures_events [
|
||||
:maybe_link_signature,
|
||||
:signatures_updated
|
||||
]
|
||||
|
||||
@map_signatures_ui_events [
|
||||
"update_signatures",
|
||||
"get_signatures",
|
||||
"link_signature_to_system",
|
||||
"unlink_signature"
|
||||
]
|
||||
|
||||
def handle_event(socket, %{event: event_name} = event)
|
||||
when event_name in @map_characters_events,
|
||||
do: MapCharactersEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_event(socket, %{event: event_name} = event)
|
||||
when event_name in @map_system_events,
|
||||
do: MapSystemsEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_event(socket, %{event: event_name} = event)
|
||||
when event_name in @map_connection_events,
|
||||
do: MapConnectionsEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_event(socket, %{event: event_name} = event)
|
||||
when event_name in @map_activity_events,
|
||||
do: MapActivityEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_event(socket, %{event: event_name} = event)
|
||||
when event_name in @map_routes_events,
|
||||
do: MapRoutesEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_event(socket, %{event: event_name} = event)
|
||||
when event_name in @map_signatures_events,
|
||||
do: MapSignaturesEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_event(socket, {ref, result}) when is_reference(ref) do
|
||||
Process.demonitor(ref, [:flush])
|
||||
|
||||
case result do
|
||||
{:map_error, map_error} ->
|
||||
Process.send_after(self(), map_error, 100)
|
||||
socket
|
||||
|
||||
{event, payload} ->
|
||||
Process.send_after(
|
||||
self(),
|
||||
%{
|
||||
event: event,
|
||||
payload: payload
|
||||
},
|
||||
10
|
||||
)
|
||||
|
||||
socket
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event(socket, event),
|
||||
do: MapCoreEventHandler.handle_server_event(event, socket)
|
||||
|
||||
def handle_ui_event(event, body, socket)
|
||||
when event in @map_characters_ui_events,
|
||||
do: MapCharactersEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
def handle_ui_event(event, body, socket)
|
||||
when event in @map_system_ui_events,
|
||||
do: MapSystemsEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
def handle_ui_event(event, body, socket)
|
||||
when event in @map_connection_ui_events,
|
||||
do: MapConnectionsEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
def handle_ui_event(event, body, socket)
|
||||
when event in @map_routes_ui_events,
|
||||
do: MapRoutesEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
def handle_ui_event(event, body, socket)
|
||||
when event in @map_signatures_ui_events,
|
||||
do: MapSignaturesEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
def handle_ui_event(event, body, socket)
|
||||
when event in @map_activity_ui_events,
|
||||
do: MapActivityEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
def handle_ui_event(event, body, socket),
|
||||
do: MapCoreEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
def get_system_static_info(nil), do: nil
|
||||
|
||||
def get_system_static_info(solar_system_id) do
|
||||
case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do
|
||||
{:ok, system_static_info} ->
|
||||
map_ui_system_static_info(system_static_info)
|
||||
|
||||
_ ->
|
||||
%{}
|
||||
end
|
||||
end
|
||||
|
||||
def push_map_event(socket, type, body),
|
||||
do:
|
||||
socket
|
||||
|> Phoenix.LiveView.Utils.push_event("map_event", %{
|
||||
type: type,
|
||||
body: body
|
||||
})
|
||||
|
||||
def map_ui_character_stat(character),
|
||||
do:
|
||||
character
|
||||
|> Map.take([
|
||||
:eve_id,
|
||||
:name,
|
||||
:corporation_ticker,
|
||||
:alliance_ticker
|
||||
])
|
||||
|
||||
def map_ui_connection(
|
||||
%{
|
||||
solar_system_source: solar_system_source,
|
||||
solar_system_target: solar_system_target,
|
||||
mass_status: mass_status,
|
||||
time_status: time_status,
|
||||
ship_size_type: ship_size_type,
|
||||
locked: locked
|
||||
} = _connection
|
||||
),
|
||||
do: %{
|
||||
id: "#{solar_system_source}_#{solar_system_target}",
|
||||
mass_status: mass_status,
|
||||
time_status: time_status,
|
||||
ship_size_type: ship_size_type,
|
||||
locked: locked,
|
||||
source: "#{solar_system_source}",
|
||||
target: "#{solar_system_target}"
|
||||
}
|
||||
|
||||
def map_ui_system(
|
||||
%{
|
||||
solar_system_id: solar_system_id,
|
||||
name: name,
|
||||
description: description,
|
||||
position_x: position_x,
|
||||
position_y: position_y,
|
||||
locked: locked,
|
||||
tag: tag,
|
||||
labels: labels,
|
||||
status: status,
|
||||
visible: visible
|
||||
} = _system,
|
||||
_include_static_data? \\ true
|
||||
) do
|
||||
system_static_info = get_system_static_info(solar_system_id)
|
||||
|
||||
%{
|
||||
id: "#{solar_system_id}",
|
||||
position: %{x: position_x, y: position_y},
|
||||
description: description,
|
||||
name: name,
|
||||
system_static_info: system_static_info,
|
||||
labels: labels,
|
||||
locked: locked,
|
||||
status: status,
|
||||
tag: tag,
|
||||
visible: visible
|
||||
}
|
||||
end
|
||||
|
||||
def map_ui_system_static_info(nil), do: %{}
|
||||
|
||||
def map_ui_system_static_info(system_static_info),
|
||||
do:
|
||||
system_static_info
|
||||
|> Map.take([
|
||||
:region_id,
|
||||
:constellation_id,
|
||||
:solar_system_id,
|
||||
:solar_system_name,
|
||||
:solar_system_name_lc,
|
||||
:constellation_name,
|
||||
:region_name,
|
||||
:system_class,
|
||||
:security,
|
||||
:type_description,
|
||||
:class_title,
|
||||
:is_shattered,
|
||||
:effect_name,
|
||||
:effect_power,
|
||||
:statics,
|
||||
:wandering,
|
||||
:triglavian_invasion_status,
|
||||
:sun_type_id
|
||||
])
|
||||
|
||||
def map_ui_kill({solar_system_id, kills}),
|
||||
do: %{solar_system_id: solar_system_id, kills: kills}
|
||||
|
||||
def map_ui_kill(_kill), do: %{}
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -104,20 +104,18 @@
|
||||
id="characters-tracking-table"
|
||||
class="h-[400px] !overflow-y-auto"
|
||||
rows={characters}
|
||||
row_click={fn character -> send(self(), "toggle_track_#{character.id}") end}
|
||||
|
||||
>
|
||||
<:col :let={character} label="Tracked">
|
||||
<div class="flex items-center gap-3">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
phx-click="toggle_track"
|
||||
phx-value-character-id={character.id}
|
||||
id={"character-track-#{character.id}"}
|
||||
checked={character.tracked}
|
||||
/>
|
||||
</label>
|
||||
<label class="flex items-center gap-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
phx-click="toggle_track"
|
||||
phx-value-character-id={character.id}
|
||||
id={"character-track-#{character.id}"}
|
||||
checked={character.tracked}
|
||||
/>
|
||||
<div class="flex items-center gap-3">
|
||||
<.avatar url={member_icon_url(character.eve_id)} label={character.name} />
|
||||
<div>
|
||||
@@ -127,7 +125,7 @@
|
||||
<div class="text-sm opacity-50"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</:col>
|
||||
</.table>
|
||||
</.async_result>
|
||||
|
||||
@@ -8,11 +8,14 @@ defmodule WandererAppWeb.MapsLive do
|
||||
@pubsub_client Application.compile_env(:wanderer_app, :pubsub_client)
|
||||
|
||||
@impl true
|
||||
def mount(_params, %{"user_id" => user_id} = _session, socket) when not is_nil(user_id) do
|
||||
def mount(
|
||||
_params,
|
||||
%{"user_id" => user_id} = _session,
|
||||
%{assigns: %{current_user: current_user}} = socket
|
||||
)
|
||||
when not is_nil(user_id) do
|
||||
{:ok, active_characters} = WandererApp.Api.Character.active_by_user(%{user_id: user_id})
|
||||
|
||||
current_user = socket.assigns.current_user
|
||||
|
||||
user_characters =
|
||||
active_characters
|
||||
|> Enum.map(&map_character/1)
|
||||
@@ -601,16 +604,6 @@ defmodule WandererAppWeb.MapsLive do
|
||||
|
||||
{added_acls, removed_acls} = map.acls |> Enum.map(& &1.id) |> _get_acls_diff(form["acls"])
|
||||
|
||||
added_acls
|
||||
|> Enum.each(fn acl_id ->
|
||||
:telemetry.execute([:wanderer_app, :map, :acl, :add], %{count: 1})
|
||||
end)
|
||||
|
||||
removed_acls
|
||||
|> Enum.each(fn acl_id ->
|
||||
:telemetry.execute([:wanderer_app, :map, :acl, :remove], %{count: 1})
|
||||
end)
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
WandererApp.PubSub,
|
||||
"maps:#{map.id}",
|
||||
@@ -855,9 +848,9 @@ defmodule WandererAppWeb.MapsLive do
|
||||
|> Enum.map(fn acl -> acl |> Ash.load!(:members) end)
|
||||
|
||||
{:ok, characters_count} =
|
||||
case WandererApp.Api.MapCharacterSettings.tracked_by_map_all(%{
|
||||
map_id: map.id
|
||||
}) do
|
||||
map.id
|
||||
|> WandererApp.MapCharacterSettingsRepo.get_tracked_by_map_all()
|
||||
|> case do
|
||||
{:ok, settings} ->
|
||||
{:ok,
|
||||
settings
|
||||
|
||||
2
mix.exs
2
mix.exs
@@ -2,7 +2,7 @@ defmodule WandererApp.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@source_url "https://github.com/wanderer-industries/wanderer"
|
||||
@version "1.13.7"
|
||||
@version "1.15.4"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
defmodule WandererApp.Repo.Migrations.InstallAshFunctionsExtension420240922090427 do
|
||||
@moduledoc """
|
||||
Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback
|
||||
|
||||
This file was autogenerated with `mix ash_postgres.generate_migrations`
|
||||
"""
|
||||
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
execute("""
|
||||
CREATE OR REPLACE FUNCTION uuid_generate_v7()
|
||||
RETURNS UUID
|
||||
AS $$
|
||||
DECLARE
|
||||
timestamp TIMESTAMPTZ;
|
||||
microseconds INT;
|
||||
BEGIN
|
||||
timestamp = clock_timestamp();
|
||||
microseconds = (cast(extract(microseconds FROM timestamp)::INT - (floor(extract(milliseconds FROM timestamp))::INT * 1000) AS DOUBLE PRECISION) * 4.096)::INT;
|
||||
|
||||
RETURN encode(
|
||||
set_byte(
|
||||
set_byte(
|
||||
overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch FROM timestamp) * 1000)::BIGINT) FROM 3) FROM 1 FOR 6
|
||||
),
|
||||
6, (b'0111' || (microseconds >> 8)::bit(4))::bit(8)::int
|
||||
),
|
||||
7, microseconds::bit(8)::int
|
||||
),
|
||||
'hex')::UUID;
|
||||
END
|
||||
$$
|
||||
LANGUAGE PLPGSQL
|
||||
VOLATILE;
|
||||
""")
|
||||
|
||||
execute("""
|
||||
CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7(_uuid uuid)
|
||||
RETURNS TIMESTAMP WITHOUT TIME ZONE
|
||||
AS $$
|
||||
SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000);
|
||||
$$
|
||||
LANGUAGE SQL
|
||||
IMMUTABLE PARALLEL SAFE STRICT;
|
||||
""")
|
||||
end
|
||||
|
||||
def down do
|
||||
# Uncomment this if you actually want to uninstall the extensions
|
||||
# when this migration is rolled back:
|
||||
execute("DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid)")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user