Compare commits

..

3 Commits

Author SHA1 Message Date
Dmitry Popov
b1f1098df6 chore: release version v1.13.7 2024-10-31 22:56:59 +01:00
Dmitry Popov
ed5d824c0a refactor(Map): Map event handling refactoring 2024-10-31 19:19:23 +01:00
Dmitry Popov
d8e4631981 refactor(Map): Map event handling refactoring 2024-10-31 19:19:07 +01:00
43 changed files with 573 additions and 1338 deletions

View File

@@ -1,7 +1,12 @@
FROM elixir:1.17-otp-27
FROM elixir:1.16-otp-25
RUN apt install -yq curl gnupg
RUN apt update -yq
RUN apt install -yq curl gnupg mc inotify-tools
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

View File

@@ -2,7 +2,7 @@ version: "0.1"
services:
db:
image: postgres:13-alpine
image: postgres:14.3
restart: always
environment:
POSTGRES_USER: postgres
@@ -10,13 +10,13 @@ services:
ports:
- "5432:5432"
volumes:
- db-new:/var/lib/postgresql/data
- db:/var/lib/postgresql/data
wanderer:
environment:
PORT: 8000
DB_HOST: db
WEB_APP_URL: "http://localhost:8000"
WEB_APP_URL: "http://localhost:4444"
ERL_AFLAGS: "-kernel shell_history enabled"
build:
context: .
@@ -33,4 +33,4 @@ services:
volumes:
elixir-artifacts: {}
db-new: {}
db: {}

View File

@@ -18,4 +18,4 @@ jobs:
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.PORT }}
script: |
/home/wanderer/app/deploy.sh ${{ github.event.release.tag_name }}
/app/release/linux/deploy.sh ${{ github.event.release.tag_name }}

View File

@@ -1,3 +1,3 @@
erlang 26.2.5.5
elixir 1.17.3-otp-26
erlang 25.3
elixir 1.16-otp-25
nodejs 18.0.0

View File

@@ -1,130 +1,6 @@
# Change Log
<!-- changelog -->
## [v1.17.0](https://github.com/wanderer-industries/wanderer/compare/v1.16.1...v1.17.0) (2024-11-15)
### Features:
* Signatures: Add user setting to show Description in a separate column
## [v1.16.1](https://github.com/wanderer-industries/wanderer/compare/v1.16.0...v1.16.1) (2024-11-15)
### Bug Fixes:
* Signatures: Fix signature stored filters
## [v1.16.0](https://github.com/wanderer-industries/wanderer/compare/v1.15.5...v1.16.0) (2024-11-15)
### Features:
* Signatures: Add additional filters support to signature list, show description icon
## [v1.15.5](https://github.com/wanderer-industries/wanderer/compare/v1.15.4...v1.15.5) (2024-11-14)
## [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)

View File

@@ -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 dont 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 dont 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,13 +54,7 @@ Now you can visit [`localhost:8000`](http://localhost:8000) from your browser.
#### Using .devcontainer
- Run devcontainer
- 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
- See how to start server in #setup section
#### Using nix flakes

View File

@@ -10,17 +10,13 @@ import {
Setting,
COSMIC_SIGNATURE,
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog';
import { SignatureGroup } from '@/hooks/Mapper/types';
interface SystemLinkSignatureDialogProps {
data: CommandLinkSignatureToSystem;
setVisible: (visible: boolean) => void;
}
const signatureSettings: Setting[] = [
{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true },
{ key: SignatureGroup.Wormhole, name: 'Wormhole', value: true },
];
const signatureSettings: Setting[] = [{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true }];
export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignatureDialogProps) => {
const { outCommand } = useMapRootState();
@@ -63,7 +59,6 @@ export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignat
>
<SystemSignaturesContent
systemId={`${data.solar_system_source}`}
hideLinkedSignatures
settings={signatureSettings}
onSelect={handleSelect}
selectable={true}

View File

@@ -1,79 +0,0 @@
.verticalTabsContainer {
display: flex;
width: 100%;
min-height: 300px;
:global {
.p-tabview {
width: 100%;
display: flex;
align-items: flex-start;
}
.p-tabview-panels {
padding: 6px 1rem !important;
flex-grow: 1;
}
.p-tabview-nav-container {
border-right: none;
height: 100%;
}
.p-tabview-nav {
flex-direction: column;
width: 150px;
min-height: 100%;
border: none;
li {
width: 100%;
border-right: 4px solid var(--surface-hover);
background-color: var(--surface-card);
transition:
background-color 200ms,
border-right-color 200ms;
&:hover {
background-color: var(--surface-hover);
border-right: 4px solid var(--surface-100);
}
.p-tabview-nav-link {
transition: color 200ms;
justify-content: flex-end;
padding: 10px;
//background-color: var(--surface-card);
background-color: initial;
border: none;
color: var(--gray-400);
border-radius: initial;
font-weight: 400;
margin: 0;
}
&.p-tabview-selected {
background-color: var(--surface-50);
border-right: 4px solid var(--primary-color);
.p-tabview-nav-link {
font-weight: 600;
color: var(--primary-color);
}
&:hover {
//background-color: var(--surface-hover);
border-right: 4px solid var(--primary-color);
}
}
}
}
.p-tabview-panel {
flex-grow: 1;
}
}
}

View File

@@ -2,10 +2,8 @@ import { Dialog } from 'primereact/dialog';
import { useCallback, useState } from 'react';
import { Button } from 'primereact/button';
import { Checkbox } from 'primereact/checkbox';
import { TabPanel, TabView } from 'primereact/tabview';
import styles from './SystemSignatureSettingsDialog.module.scss';
export type Setting = { key: string; name: string; value: boolean; isFilter?: boolean };
export type Setting = { key: string; name: string; value: boolean };
export const COSMIC_SIGNATURE = 'Cosmic Signature';
export const COSMIC_ANOMALY = 'Cosmic Anomaly';
@@ -26,12 +24,8 @@ export const SystemSignatureSettingsDialog = ({
onSave,
onCancel,
}: SystemSignatureSettingsDialogProps) => {
const [activeIndex, setActiveIndex] = useState(0);
const [settings, setSettings] = useState<Setting[]>(defaultSettings);
const filterSettings = settings.filter(setting => setting.isFilter);
const userSettings = settings.filter(setting => !setting.isFilter);
const handleSettingsChange = (key: string) => {
setSettings(prevState => prevState.map(item => (item.key === key ? { ...item, value: !item.value } : item)));
};
@@ -41,53 +35,23 @@ export const SystemSignatureSettingsDialog = ({
}, [onSave, settings]);
return (
<Dialog header="System Signatures Settings" visible={true} onHide={onCancel} className="w-full max-w-lg">
<Dialog header="Filter signatures" visible draggable={false} style={{ width: '300px' }} onHide={onCancel}>
<div className="flex flex-col gap-3">
<div className="flex flex-col gap-2">
<div className={styles.verticalTabsContainer}>
<TabView
activeIndex={activeIndex}
onTabChange={e => setActiveIndex(e.index)}
className={styles.verticalTabView}
>
<TabPanel header="Filters" headerClassName={styles.verticalTabHeader}>
<div className="w-full h-full flex flex-col gap-1">
{filterSettings.map(setting => {
return (
<div key={setting.key} className="flex items-center">
<Checkbox
inputId={setting.key}
checked={setting.value}
onChange={() => handleSettingsChange(setting.key)}
/>
<label htmlFor={setting.key} className="ml-2">
{setting.name}
</label>
</div>
);
})}
</div>
</TabPanel>
<TabPanel header="User Interface" headerClassName={styles.verticalTabHeader}>
<div className="w-full h-full flex flex-col gap-1">
{userSettings.map(setting => {
return (
<div key={setting.key} className="flex items-center">
<Checkbox
inputId={setting.key}
checked={setting.value}
onChange={() => handleSettingsChange(setting.key)}
/>
<label htmlFor={setting.key} className="ml-2">
{setting.name}
</label>
</div>
);
})}
</div>
</TabPanel>
</TabView>
</div>
{settings.map(setting => {
return (
<div key={setting.key} className="flex items-center">
<Checkbox
inputId={setting.key}
checked={setting.value}
onChange={() => handleSettingsChange(setting.key)}
/>
<label htmlFor={setting.key} className="ml-2">
{setting.name}
</label>
</div>
);
})}
</div>
<div className="flex gap-2 justify-end">

View File

@@ -12,7 +12,6 @@ import {
SHIP,
DRONE,
} from './SystemSignatureSettingsDialog';
import { SignatureGroup } from '@/hooks/Mapper/types';
import React, { useCallback, useEffect, useState } from 'react';
@@ -20,26 +19,18 @@ import { PrimeIcons } from 'primereact/api';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
const SIGNATURE_SETTINGS_KEY = 'wanderer_system_signature_settings_v3';
export const SHOW_DESCRIPTION_COLUMN_SETTING = 'show_description_column_setting';
const settings: Setting[] = [
{ key: SHOW_DESCRIPTION_COLUMN_SETTING, name: 'Show Description Column', value: false, isFilter: false },
{ key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true, isFilter: true },
{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true, isFilter: true },
{ key: DEPLOYABLE, name: 'Show Deployables', value: true, isFilter: true },
{ key: STRUCTURE, name: 'Show Structures', value: true, isFilter: true },
{ key: STARBASE, name: 'Show Starbase', value: true, isFilter: true },
{ key: SHIP, name: 'Show Ships', value: true, isFilter: true },
{ key: DRONE, name: 'Show Drones And Charges', value: true, isFilter: true },
{ key: SignatureGroup.Wormhole, name: 'Show Wormholes', value: true, isFilter: true },
{ key: SignatureGroup.RelicSite, name: 'Show Relic Sites', value: true, isFilter: true },
{ key: SignatureGroup.DataSite, name: 'Show Data Sites', value: true, isFilter: true },
{ key: SignatureGroup.OreSite, name: 'Show Ore Sites', value: true, isFilter: true },
{ key: SignatureGroup.GasSite, name: 'Show Gas Sites', value: true, isFilter: true },
{ key: SignatureGroup.CombatSite, name: 'Show Combat Sites', value: true, isFilter: true },
{ key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true },
{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true },
{ key: DEPLOYABLE, name: 'Show Deployables', value: true },
{ key: STRUCTURE, name: 'Show Structures', value: true },
{ key: STARBASE, name: 'Show Starbase', value: true },
{ key: SHIP, name: 'Show Ships', value: true },
{ key: DRONE, name: 'Show Drones And Charges', value: true },
];
const SIGNATURE_SETTINGS_KEY = 'wanderer_system_signature_settings';
const defaultSettings = () => {
return [...settings];
};
@@ -100,7 +91,8 @@ export const SystemSignatures = () => {
</InfoDrawer>
<InfoDrawer title={<b className="text-slate-50">How to delete?</b>}>
For delete any signature first of all you need select before
<br /> and then use <b className="text-sky-500">Backspace</b>
<br /> and then use <b className="text-sky-500">Del</b> or{' '}
<b className="text-sky-500">Backspace</b>
</InfoDrawer>
</div>
) as React.ReactNode,

View File

@@ -3,7 +3,6 @@ import { useClipboard } from '@/hooks/Mapper/hooks/useClipboard';
import { parseSignatures } from '@/hooks/Mapper/helpers';
import { Commands, OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts';
import { WdTooltip, WdTooltipHandlers } from '@/hooks/Mapper/components/ui-kit';
import { GROUPS_LIST } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/constants.ts';
import { DataTable, DataTableRowClickEvent, DataTableRowMouseEvent, SortOrder } from 'primereact/datatable';
import { Column } from 'primereact/column';
@@ -22,7 +21,6 @@ import {
getRowColorByTimeLeft,
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers';
import {
renderDescription,
renderIcon,
renderInfoColumn,
renderTimeLeft,
@@ -32,8 +30,7 @@ import { PrimeIcons } from 'primereact/api';
import { SignatureSettings } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings';
import { useMapEventListener } from '@/hooks/Mapper/events';
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog';
import { SHOW_DESCRIPTION_COLUMN_SETTING } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures';
type SystemSignaturesSortSettings = {
sortField: string;
sortOrder: SortOrder;
@@ -47,17 +44,10 @@ const SORT_DEFAULT_VALUES: SystemSignaturesSortSettings = {
interface SystemSignaturesContentProps {
systemId: string;
settings: Setting[];
hideLinkedSignatures?: boolean;
selectable?: boolean;
onSelect?: (signature: SystemSignature) => void;
}
export const SystemSignaturesContent = ({
systemId,
settings,
hideLinkedSignatures,
selectable,
onSelect,
}: SystemSignaturesContentProps) => {
export const SystemSignaturesContent = ({ systemId, settings, selectable, onSelect }: SystemSignaturesContentProps) => {
const { outCommand } = useMapRootState();
const [signatures, setSignatures, signaturesRef] = useRefState<SystemSignature[]>([]);
@@ -90,36 +80,13 @@ export const SystemSignaturesContent = ({
}
}, []);
const groupSettings = useMemo(() => settings.filter(s => (GROUPS_LIST as string[]).includes(s.key)), [settings]);
const showDescriptionColumn = useMemo(
() => settings.find(s => s.key === SHOW_DESCRIPTION_COLUMN_SETTING)?.value,
[settings],
);
const filteredSignatures = useMemo(() => {
return signatures
.filter(x => {
if (hideLinkedSignatures && !!x.linked_system) {
return false;
}
const isCosmicSignature = x.kind === COSMIC_SIGNATURE;
if (isCosmicSignature) {
const showCosmicSignatures = settings.find(y => y.key === COSMIC_SIGNATURE)?.value;
if (showCosmicSignatures) {
return !x.group || groupSettings.find(y => y.key === x.group)?.value;
} else {
return !!x.group && groupSettings.find(y => y.key === x.group)?.value;
}
}
return settings.find(y => y.key === x.kind)?.value;
})
.filter(x => settings.find(y => y.key === x.kind)?.value)
.sort((a, b) => {
return new Date(b.updated_at || 0).getTime() - new Date(a.updated_at || 0).getTime();
});
}, [signatures, settings, groupSettings, hideLinkedSignatures]);
}, [signatures, settings]);
const handleGetSignatures = useCallback(async () => {
const { signatures } = await outCommand({
@@ -131,6 +98,26 @@ export const SystemSignaturesContent = ({
setSignatures(signatures);
}, [outCommand, systemId]);
// const updateSignatures = useCallback(
// async (newSignatures: SystemSignature[], updateOnly: boolean) => {
// const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures, updateOnly);
// const { signatures: updatedSignatures } = await outCommand({
// type: OutCommand.updateSignatures,
// data: {
// system_id: systemId,
// added,
// updated,
// removed,
// },
// });
// setSignatures(() => updatedSignatures);
// setSelectedSignatures([]);
// },
// [outCommand, systemId],
// );
const handleUpdateSignatures = useCallback(
async (newSignatures: SystemSignature[], updateOnly: boolean) => {
const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures, updateOnly);
@@ -194,7 +181,7 @@ export const SystemSignaturesContent = ({
useHotkey(true, ['a'], handleSelectAll);
useHotkey(false, ['Backspace'], handleDeleteSelected);
useHotkey(false, ['Backspace', 'Delete'], handleDeleteSelected);
useEffect(() => {
if (selectable) {
@@ -358,16 +345,6 @@ export const SystemSignaturesContent = ({
style={{ maxWidth: nameColumnWidth }}
hidden={compact || medium}
></Column>
{showDescriptionColumn && (
<Column
field="description"
header="Description"
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
body={renderDescription}
hidden={compact}
sortable
></Column>
)}
<Column
field="updated_at"
header="Updated"
@@ -377,15 +354,13 @@ export const SystemSignaturesContent = ({
sortable
></Column>
{!selectable && (
<Column
bodyClassName="p-0 pl-1 pr-2"
field="group"
body={renderToolbar}
// headerClassName={headerClasses}
style={{ maxWidth: 26, minWidth: 26, width: 26 }}
></Column>
)}
<Column
bodyClassName="p-0 pl-1 pr-2"
field="group"
body={renderToolbar}
// headerClassName={headerClasses}
style={{ maxWidth: 26, minWidth: 26, width: 26 }}
></Column>
</DataTable>
</>
)}
@@ -395,14 +370,12 @@ export const SystemSignaturesContent = ({
content={hoveredSig ? <SignatureView {...hoveredSig} /> : null}
/>
{showSignatureSettings && (
<SignatureSettings
systemId={systemId}
show
onHide={() => setShowSignatureSettings(false)}
signatureData={selectedSignature}
/>
)}
<SignatureSettings
systemId={systemId}
show={showSignatureSettings}
onHide={() => setShowSignatureSettings(false)}
signatureData={selectedSignature}
/>
{askUser && (
<div className="absolute left-[1px] top-[29px] h-[calc(100%-30px)] w-[calc(100%-3px)] bg-stone-900/10 backdrop-blur-sm">

View File

@@ -1,5 +1,4 @@
export * from './renderIcon';
export * from './renderDescription';
export * from './renderName';
export * from './renderTimeLeft';
export * from './renderLinkedSystem';

View File

@@ -1,5 +0,0 @@
import { SystemSignature } from '@/hooks/Mapper/types';
export const renderDescription = (row: SystemSignature) => {
return <span title={row?.description}>{row?.description}</span>;
};

View File

@@ -1,9 +1,5 @@
import { PrimeIcons } from 'primereact/api';
import { SignatureGroup, SystemSignature } from '@/hooks/Mapper/types';
import { SystemViewStandalone, WHClassView } from '@/hooks/Mapper/components/ui-kit';
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
import clsx from 'clsx';
import { renderName } from './renderName.tsx';
import classes from './renderInfoColumn.module.scss';
@@ -36,23 +32,13 @@ export const renderInfoColumn = (row: SystemSignature) => {
</span>
</>
)}
{row.description && (
<WdTooltipWrapper content={row.description}>
<span className={clsx(PrimeIcons.EXCLAMATION_CIRCLE, 'text-[12px]')}></span>
</WdTooltipWrapper>
)}
</div>
);
}
return (
<div className="flex gap-1 items-center">
{renderName(row)}{' '}
{row.description && (
<WdTooltipWrapper content={row.description}>
<span className={clsx(PrimeIcons.EXCLAMATION_CIRCLE, 'text-[12px]')}></span>
</WdTooltipWrapper>
)}
</div>
);
if (row.description != null && row.description.length > 0) {
return <span title={row.description}>{row.description}</span>;
}
return renderName(row);
};

View File

@@ -1,20 +1,13 @@
import classes from './Connections.module.scss';
import { Sidebar } from 'primereact/sidebar';
import { useEffect, useMemo, useState, useCallback } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { VirtualScroller, VirtualScrollerTemplateOptions } from 'primereact/virtualscroller';
import clsx from 'clsx';
import {
ConnectionOutput,
ConnectionInfoOutput,
OutCommand,
Passage,
SolarSystemConnection,
} from '@/hooks/Mapper/types';
import { ConnectionOutput, 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();
@@ -76,44 +69,25 @@ 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;
}
loadInfo(selectedConnection);
loadPassages(selectedConnection);
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();
}, [selectedConnection]);
const approximateMass = useMemo(() => {
@@ -158,10 +132,6 @@ 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>

View File

@@ -11,10 +11,6 @@ export type Passage = {
character: PassageLimitedCharacterType;
};
export type ConnectionInfoOutput = {
marl_eol_time: string;
};
export type ConnectionOutput = {
passages: Passage[];
};

View File

@@ -118,7 +118,6 @@ 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',

View File

@@ -8,7 +8,7 @@ export default {
const selector = '#' + this.el.id;
const droppable = new Droppable(containers, {
delay: 100,
delay: 150,
draggable: '.draggable',
dropzone: '.dropzone',
mirror: {

View File

@@ -138,7 +138,6 @@ 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(
@@ -172,65 +171,43 @@ config :wanderer_app, WandererApp.Scheduler,
timeout: :infinity
if config_env() == :prod do
database_unix_socket =
System.get_env("DATABASE_UNIX_SOCKET")
database_url =
System.get_env("DATABASE_URL") ||
raise """
environment variable DATABASE_URL is missing.
For example: ecto://USER:PASS@HOST/DATABASE
"""
database =
database_unix_socket
maybe_ipv6 =
config_dir
|> get_var_from_path_or_env("ECTO_IPV6", "false")
|> String.to_existing_atom()
|> case do
nil ->
System.get_env("DATABASE_URL") ||
raise """
environment variable DATABASE_URL is missing.
For example: ecto://USER:PASS@HOST/DATABASE
"""
true -> [:inet6]
_ -> []
end
_ ->
System.get_env("DATABASE_NAME") ||
raise """
environment variable DATABASE_NAME is missing.
For example: "wanderer"
"""
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
config :wanderer_app, WandererApp.Repo,
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
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
# 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

View File

@@ -3,10 +3,9 @@
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
app = 'wanderer-test'
app = 'wanderer'
primary_region = 'ams'
kill_signal = 'SIGTERM'
swap_size_mb = 512
[build]
@@ -14,14 +13,18 @@ swap_size_mb = 512
release_command = '/app/bin/migrate.sh'
[env]
PHX_HOST = 'wanderer-test.fly.dev'
PHX_HOST = 'wanderer.fly.dev'
PHX_SERVER = 'true'
PORT = '8080'
[metrics]
port = 4021
path = "/metrics"
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = 'off'
auto_stop_machines = false
auto_start_machines = false
min_machines_running = 0
processes = ['app']
@@ -32,9 +35,6 @@ swap_size_mb = 512
soft_limit = 1000
[[vm]]
size = 'shared-cpu-1x'
[[metrics]]
port = 4021
path = '/metrics'
https = false
memory = '1gb'
cpu_kind = 'shared'
cpus = 1

View File

@@ -4,6 +4,8 @@ defmodule WandererApp.Api.Calculations.CalcMapPermissions do
use Ash.Resource.Calculation
require Ash.Query
import Bitwise
@impl true
def load(_query, _opts, _context) do
[
@@ -15,8 +17,116 @@ defmodule WandererApp.Api.Calculations.CalcMapPermissions do
end
@impl true
def calculate([record], _opts, %{actor: actor}),
do: WandererApp.Permissions.check_characters_access(actor.characters, record.acls)
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
@impl true
def calculate(_records, _opts, _context) do

View File

@@ -17,12 +17,12 @@ defmodule WandererApp.Api.MapCharacterSettings do
action: :read_by_map
)
define(:tracked_by_map_filtered,
action: :tracked_by_map_filtered
define(:tracked_by_map,
action: :tracked_by_map
)
define(:tracked_by_map_all,
action: :tracked_by_map_all
action: :read_tracked_by_map
)
define(:track, action: :track)
@@ -38,7 +38,7 @@ defmodule WandererApp.Api.MapCharacterSettings do
defaults [:create, :read, :update, :destroy]
read :tracked_by_map_filtered do
read :tracked_by_map 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 :tracked_by_map_all do
read :read_tracked_by_map do
argument(:map_id, :string, allow_nil?: false)
filter(expr(map_id == ^arg(:map_id) and tracked == true))
end

View File

@@ -16,7 +16,6 @@ defmodule WandererApp.Api.MapSystemSignature do
define(:update, action: :update)
define(:update_linked_system, action: :update_linked_system)
define(:update_type, action: :update_type)
define(:update_group, action: :update_group)
define(:by_id,
get_by: [:id],
@@ -87,10 +86,6 @@ defmodule WandererApp.Api.MapSystemSignature do
accept [:type]
end
update :update_group do
accept [:group]
end
read :by_system_id do
argument(:system_id, :string, allow_nil?: false)

View File

@@ -3,8 +3,6 @@ defmodule WandererApp.Application do
use Application
require Logger
@impl true
def start(_type, _args) do
children =
@@ -47,16 +45,7 @@ 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

View File

@@ -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"
}
)
when is_list(character_eve_ids) do
_post(
"#{@base_url}/characters/affiliation/",
json: character_eve_ids,
params: %{
datasource: "tranquility"
}
)
end
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,21 +210,22 @@ defmodule WandererApp.Esi.ApiClient do
{:ok, result}
{:error, _error} ->
{:error, error} ->
@logger.error("Error getting custom routes for #{inspect(origin)}: #{inspect(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: %{
@@ -238,7 +239,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
@@ -307,7 +308,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
@@ -384,7 +385,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()
)
@@ -393,14 +394,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()
)
@@ -415,7 +416,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
@@ -436,7 +437,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()),
@@ -447,14 +448,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}} ->
@@ -486,7 +487,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] ->
@@ -524,7 +525,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)
@@ -599,7 +600,7 @@ defmodule WandererApp.Esi.ApiClient do
end
end
defp map_route_info(
defp _map_route_info(
%{
"origin" => origin,
"destination" => destination,
@@ -608,14 +609,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
@@ -637,5 +638,5 @@ defmodule WandererApp.Esi.ApiClient do
}
end
defp map_route_info(_), do: nil
defp _map_route_info(_), do: nil
end

View File

@@ -8,7 +8,6 @@ defmodule WandererApp.Map do
defstruct map_id: nil,
name: nil,
scope: :none,
owner_id: nil,
characters: [],
systems: Map.new(),
hubs: [],
@@ -17,12 +16,11 @@ defmodule WandererApp.Map do
characters_limit: nil,
hubs_limit: nil
def new(%{id: map_id, name: name, scope: scope, owner_id: owner_id, acls: acls, hubs: hubs}) do
def new(%{id: map_id, name: name, scope: scope, acls: acls, hubs: hubs}) do
map =
struct!(__MODULE__,
map_id: map_id,
scope: scope,
owner_id: owner_id,
name: name,
acls: acls,
hubs: hubs
@@ -216,7 +214,7 @@ defmodule WandererApp.Map do
%{visible: true} = system ->
system
_system ->
_ ->
nil
end
end
@@ -264,7 +262,7 @@ defmodule WandererApp.Map do
case not Map.has_key?(systems, solar_system_id) do
true ->
map_id
|> update_map(%{systems: Map.put(systems, solar_system_id, system)})
|> update_map(%{systems: Map.put_new(systems, solar_system_id, system)})
:ok

View File

@@ -183,12 +183,6 @@ 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

View File

@@ -77,7 +77,6 @@ defmodule WandererApp.Map.Server.Impl do
# @unknown 100_100
@systems_cleanup_timeout :timer.minutes(30)
@characters_cleanup_timeout :timer.minutes(1)
@connections_cleanup_timeout :timer.minutes(2)
@connection_time_status_eol 1
@@ -113,28 +112,20 @@ defmodule WandererApp.Map.Server.Impl do
end
def load_state(%__MODULE__{map_id: map_id} = state) do
with {:ok, map} <-
WandererApp.MapRepo.get(map_id, [
:owner,
:characters,
acls: [
:owner_id,
members: [:role, :eve_character_id, :eve_corporation_id, :eve_alliance_id]
]
]),
with {:ok, map} <- WandererApp.MapRepo.get(map_id, [:acls, :characters]),
{:ok, systems} <- WandererApp.MapSystemRepo.get_visible_by_map(map_id),
{:ok, connections} <- WandererApp.MapConnectionRepo.get_by_map(map_id),
{:ok, subscription_settings} <-
WandererApp.Map.SubscriptionManager.get_active_map_subscription(map_id) do
state
|> init_map(
|> _init_map(
map,
subscription_settings,
systems,
connections
)
|> init_map_systems(systems)
|> init_map_cache()
|> _init_map_systems(systems)
|> _init_map_cache()
else
error ->
@logger.error("Failed to load map state: #{inspect(error, pretty: true)}")
@@ -143,7 +134,7 @@ defmodule WandererApp.Map.Server.Impl do
end
def start_map(%__MODULE__{map: map, map_id: map_id} = state) do
with :ok <- track_acls(map.acls |> Enum.map(& &1.id)) do
with :ok <- _track_acls(map.acls |> Enum.map(& &1.id)) do
@pubsub_client.subscribe(
WandererApp.PubSub,
"maps:#{map_id}"
@@ -153,8 +144,7 @@ defmodule WandererApp.Map.Server.Impl do
Process.send_after(self(), :update_tracked_characters, 100)
Process.send_after(self(), :update_presence, @update_presence_timeout)
Process.send_after(self(), :cleanup_connections, 5000)
Process.send_after(self(), :cleanup_systems, 10_000)
Process.send_after(self(), :cleanup_characters, :timer.minutes(5))
Process.send_after(self(), :cleanup_systems, 10000)
Process.send_after(self(), :backup_state, @backup_state_timeout)
WandererApp.Cache.insert("map_#{map_id}:started", true)
@@ -179,7 +169,7 @@ defmodule WandererApp.Map.Server.Impl do
:telemetry.execute([:wanderer_app, :map, :stopped], %{count: 1})
state
|> maybe_stop_rtree()
|> _maybe_stop_rtree()
end
def get_map(%{map: map} = _state), do: {:ok, map}
@@ -259,37 +249,37 @@ defmodule WandererApp.Map.Server.Impl do
state,
update
),
do: state |> update_system(:update_name, [:name], update)
do: state |> _update_system(:update_name, [:name], update)
def update_system_description(
state,
update
),
do: state |> update_system(:update_description, [:description], update)
do: state |> _update_system(:update_description, [:description], update)
def update_system_status(
state,
update
),
do: state |> update_system(:update_status, [:status], update)
do: state |> _update_system(:update_status, [:status], update)
def update_system_tag(
state,
update
),
do: state |> update_system(:update_tag, [:tag], update)
do: state |> _update_system(:update_tag, [:tag], update)
def update_system_locked(
state,
update
),
do: state |> update_system(:update_locked, [:locked], update)
do: state |> _update_system(:update_locked, [:locked], update)
def update_system_labels(
state,
update
),
do: state |> update_system(:update_labels, [:labels], update)
do: state |> _update_system(:update_labels, [:labels], update)
def update_system_position(
%{rtree_name: rtree_name} = state,
@@ -297,7 +287,7 @@ defmodule WandererApp.Map.Server.Impl do
),
do:
state
|> update_system(
|> _update_system(
:update_position,
[:position_x, :position_y],
update,
@@ -445,34 +435,12 @@ defmodule WandererApp.Map.Server.Impl do
state
end
def get_connection_info(
%{map_id: map_id} = _state,
%{
solar_system_source_id: solar_system_source_id,
solar_system_target_id: solar_system_target_id
} = _connection_info
) do
WandererApp.Map.find_connection(
map_id,
solar_system_source_id,
solar_system_target_id
)
|> case do
{:ok, %{id: connection_id}} ->
connection_mark_eol_time = get_connection_mark_eol_time(map_id, connection_id, nil)
{:ok, %{marl_eol_time: connection_mark_eol_time}}
_ ->
{:error, :not_found}
end
end
def update_connection_time_status(
%{map_id: map_id} = state,
connection_update
),
do:
update_connection(state, :update_time_status, [:time_status], connection_update, fn
_update_connection(state, :update_time_status, [:time_status], connection_update, fn
%{id: connection_id, time_status: time_status} ->
case time_status == @connection_time_status_eol do
true ->
@@ -491,25 +459,25 @@ defmodule WandererApp.Map.Server.Impl do
state,
connection_update
),
do: update_connection(state, :update_mass_status, [:mass_status], connection_update)
do: _update_connection(state, :update_mass_status, [:mass_status], connection_update)
def update_connection_ship_size_type(
state,
connection_update
),
do: update_connection(state, :update_ship_size_type, [:ship_size_type], connection_update)
do: _update_connection(state, :update_ship_size_type, [:ship_size_type], connection_update)
def update_connection_locked(
state,
connection_update
),
do: update_connection(state, :update_locked, [:locked], connection_update)
do: _update_connection(state, :update_locked, [:locked], connection_update)
def update_connection_custom_info(
state,
connection_update
),
do: update_connection(state, :update_custom_info, [:custom_info], connection_update)
do: _update_connection(state, :update_custom_info, [:custom_info], connection_update)
def import_settings(%{map_id: map_id} = state, settings, user_id) do
WandererApp.Cache.put(
@@ -519,9 +487,9 @@ defmodule WandererApp.Map.Server.Impl do
state =
state
|> maybe_import_systems(settings, user_id, nil)
|> maybe_import_connections(settings, user_id)
|> maybe_import_hubs(settings, user_id)
|> _maybe_import_systems(settings, user_id, nil)
|> _maybe_import_connections(settings, user_id)
|> _maybe_import_hubs(settings, user_id)
WandererApp.Cache.take("map_#{map_id}:importing")
@@ -541,11 +509,11 @@ defmodule WandererApp.Map.Server.Impl do
|> Enum.map(fn character_id ->
Task.start_link(fn ->
character_updates =
maybe_update_online(map_id, character_id) ++
maybe_update_location(map_id, character_id) ++
maybe_update_ship(map_id, character_id) ++
maybe_update_alliance(map_id, character_id) ++
maybe_update_corporation(map_id, character_id)
_maybe_update_online(map_id, character_id) ++
_maybe_update_location(map_id, character_id) ++
_maybe_update_ship(map_id, character_id) ++
_maybe_update_alliance(map_id, character_id) ++
_maybe_update_corporation(map_id, character_id)
character_updates
|> Enum.filter(fn update -> update != :skip end)
@@ -553,7 +521,7 @@ defmodule WandererApp.Map.Server.Impl do
update
|> case do
{:character_location, location_info, old_location_info} ->
update_location(
_update_location(
character_id,
location_info,
old_location_info,
@@ -569,25 +537,9 @@ defmodule WandererApp.Map.Server.Impl do
:broadcast
{:character_alliance, _info} ->
WandererApp.Cache.insert_or_update(
"map_#{map_id}:invalidate_character_ids",
[character_id],
fn ids ->
[character_id | ids]
end
)
:broadcast
{:character_corporation, _info} ->
WandererApp.Cache.insert_or_update(
"map_#{map_id}:invalidate_character_ids",
[character_id],
fn ids ->
[character_id | ids]
end
)
:broadcast
_ ->
@@ -617,21 +569,17 @@ defmodule WandererApp.Map.Server.Impl do
Process.send_after(self(), :update_tracked_characters, @update_tracked_characters_timeout)
Task.start_link(fn ->
{:ok, map_tracked_character_ids} =
map_characters =
map_id
|> WandererApp.MapCharacterSettingsRepo.get_tracked_by_map_all()
|> case do
{:ok, settings} -> {:ok, settings |> Enum.map(&Map.get(&1, :character_id))}
_ -> {:ok, []}
end
|> WandererApp.Map.get_map!()
|> Map.get(:characters, [])
{:ok, tracked_characters} = WandererApp.Cache.lookup("tracked_characters", [])
map_active_tracked_characters =
map_tracked_character_ids
|> Enum.filter(fn character -> character in tracked_characters end)
map_tracked_characters =
map_characters |> Enum.filter(fn character -> character in tracked_characters end)
WandererApp.Cache.insert("maps:#{map_id}:tracked_characters", map_active_tracked_characters)
WandererApp.Cache.insert("maps:#{map_id}:tracked_characters", map_tracked_characters)
:ok
end)
@@ -642,37 +590,29 @@ defmodule WandererApp.Map.Server.Impl do
def handle_event(:update_presence, %{map_id: map_id} = state) do
Process.send_after(self(), :update_presence, @update_presence_timeout)
update_presence(map_id)
_update_presence(map_id)
state
end
def handle_event(:backup_state, state) do
Process.send_after(self(), :backup_state, @backup_state_timeout)
{:ok, _map_state} = state |> save_map_state()
{:ok, _map_state} = state |> _save_map_state()
state
end
def handle_event(
{:map_acl_updated, added_acls, removed_acls},
%{map_id: map_id, map: old_map} = state
) do
{:ok, map} =
WandererApp.MapRepo.get(map_id,
acls: [
:owner_id,
members: [:role, :eve_character_id, :eve_corporation_id, :eve_alliance_id]
]
)
def handle_event({:map_acl_updated, added_acls, removed_acls}, %{map: old_map} = state) do
{:ok, map} = WandererApp.MapRepo.get(old_map.map_id, [:acls])
track_acls(added_acls)
_track_acls(added_acls)
result =
(added_acls ++ removed_acls)
[added_acls | removed_acls]
|> List.flatten()
|> Task.async_stream(
fn acl_id ->
update_acl(acl_id)
_update_acl(acl_id)
end,
max_concurrency: 10,
timeout: :timer.seconds(15)
@@ -701,45 +641,29 @@ defmodule WandererApp.Map.Server.Impl do
}
error ->
@logger.error("Failed to update map #{map_id} acl: #{inspect(error, pretty: true)}")
@logger.error(
"Failed to update map #{old_map.map_id} acl: #{inspect(error, pretty: true)}"
)
acc
end
end
)
map_update = %{acls: map.acls, scope: map.scope}
_broadcast_acl_updates({:ok, result})
WandererApp.Map.update_map(map_id, map_update)
broadcast_acl_updates({:ok, result}, map_id)
%{state | map: Map.merge(old_map, map_update)}
%{state | map: %{old_map | acls: map.acls, scope: map.scope}}
end
def handle_event({:acl_updated, %{acl_id: acl_id}}, %{map_id: map_id, map: old_map} = state) do
{:ok, map} =
WandererApp.MapRepo.get(map_id,
acls: [
:owner_id,
members: [:role, :eve_character_id, :eve_corporation_id, :eve_alliance_id]
]
)
def handle_event({:acl_updated, %{acl_id: acl_id}}, %{map: map} = state) do
if map.acls |> Enum.map(& &1.id) |> Enum.member?(acl_id) do
map_update = %{acls: map.acls}
WandererApp.Map.update_map(map_id, map_update)
:ok =
acl_id
|> update_acl()
|> broadcast_acl_updates(map_id)
state
else
state
|> _update_acl()
|> _broadcast_acl_updates()
end
state
end
def handle_event(:cleanup_connections, %{map_id: map_id} = state) do
@@ -755,7 +679,7 @@ defmodule WandererApp.Map.Server.Impl do
} ->
DateTime.diff(DateTime.utc_now(), inserted_at, :hour) >=
@connection_auto_eol_hours and
is_connection_valid(
_is_connection_valid(
:wormholes,
solar_system_source_id,
solar_system_target_id
@@ -783,7 +707,7 @@ defmodule WandererApp.Map.Server.Impl do
solar_system_source: solar_system_source_id,
solar_system_target: solar_system_target_id
} ->
connection_mark_eol_time = get_connection_mark_eol_time(map_id, connection_id)
connection_mark_eol_time = _get_connection_mark_eol_time(map_id, connection_id)
reverse_connection =
WandererApp.Map.get_connection(
@@ -793,23 +717,24 @@ defmodule WandererApp.Map.Server.Impl do
)
is_connection_exist =
is_connection_exist(
_is_connection_exist(
map_id,
solar_system_source_id,
solar_system_target_id
) || not is_nil(reverse_connection)
)
is_connection_valid =
is_connection_valid(
_is_connection_valid(
:wormholes,
solar_system_source_id,
solar_system_target_id
)
not is_connection_exist ||
(is_connection_valid &&
not is_connection_exist or
not is_nil(reverse_connection) or
(is_connection_valid and
(DateTime.diff(DateTime.utc_now(), inserted_at, :hour) >=
@connection_auto_expire_hours ||
@connection_auto_expire_hours or
DateTime.diff(DateTime.utc_now(), connection_mark_eol_time, :hour) >=
@connection_auto_expire_hours - @connection_auto_eol_hours))
end)
@@ -828,76 +753,6 @@ defmodule WandererApp.Map.Server.Impl do
state
end
def handle_event(:cleanup_characters, %{map_id: map_id, map: %{owner_id: owner_id}} = state) do
Process.send_after(self(), :cleanup_characters, @characters_cleanup_timeout)
{:ok, invalidate_character_ids} =
WandererApp.Cache.lookup(
"map_#{map_id}:invalidate_character_ids",
[]
)
invalidate_character_ids
|> Task.async_stream(
fn character_id ->
character_id
|> WandererApp.Character.get_character()
|> case do
{:ok, character} ->
acls =
map_id
|> WandererApp.Map.get_map!()
|> Map.get(:acls, [])
[character_permissions] =
WandererApp.Permissions.check_characters_access([character], acls)
map_permissions =
WandererApp.Permissions.get_map_permissions(
character_permissions,
owner_id,
[character_id]
)
case map_permissions do
%{view_system: false} ->
{:remove_character, character_id}
%{track_character: false} ->
{:remove_character, character_id}
_ ->
:ok
end
_ ->
:ok
end
end,
timeout: :timer.seconds(60),
max_concurrency: System.schedulers_online(),
on_timeout: :kill_task
)
|> Enum.each(fn
{:ok, {:remove_character, character_id}} ->
state |> remove_and_untrack_characters([character_id])
:ok
{:ok, _result} ->
:ok
{:error, reason} ->
@logger.error("Error in cleanup_characters: #{inspect(reason)}")
end)
WandererApp.Cache.insert(
"map_#{map_id}:invalidate_character_ids",
[]
)
state
end
def handle_event(:cleanup_systems, %{map_id: map_id} = state) do
Process.send_after(self(), :cleanup_systems, @systems_cleanup_timeout)
@@ -957,9 +812,8 @@ defmodule WandererApp.Map.Server.Impl do
do: %{
state
| map_opts: [
layout: options |> Map.get("layout", "left_to_right"),
store_custom_labels:
options |> Map.get("store_custom_labels", "false") |> String.to_existing_atom()
layout: options |> Map.get("layout"),
store_custom_labels: options |> Map.get("store_custom_labels")
]
}
@@ -970,71 +824,47 @@ defmodule WandererApp.Map.Server.Impl do
end
def handle_event(msg, state) do
Logger.warning("Unhandled event: #{inspect(msg)}")
@logger.warning("Unhandled event: #{inspect(msg)}")
state
end
def broadcast!(map_id, event, payload \\ nil) do
if can_broadcast?(map_id) do
if _can_broadcast?(map_id) do
@pubsub_client.broadcast!(WandererApp.PubSub, map_id, %{event: event, payload: payload})
end
:ok
end
defp remove_and_untrack_characters(%{map_id: map_id} = state, character_ids) do
Logger.warning(fn ->
"Map #{map_id} - remove and untrack characters #{inspect(character_ids)}"
end)
map_id
|> _untrack_characters(character_ids)
map_id
|> WandererApp.MapCharacterSettingsRepo.get_tracked_by_map_filtered(character_ids)
|> case do
{:ok, settings} ->
settings
|> Enum.each(fn s ->
s |> WandererApp.MapCharacterSettingsRepo.untrack()
state |> remove_character(s.character_id)
end)
_ ->
:ok
end
end
defp get_connection_mark_eol_time(map_id, connection_id, default \\ DateTime.utc_now()) do
WandererApp.Cache.get("map_#{map_id}:conn_#{connection_id}:mark_eol_time")
|> case do
defp _get_connection_mark_eol_time(map_id, connection_id) do
case WandererApp.Cache.get("map_#{map_id}:conn_#{connection_id}:mark_eol_time") do
nil ->
default
DateTime.utc_now()
value ->
value
end
end
defp can_broadcast?(map_id),
defp _can_broadcast?(map_id),
do:
not WandererApp.Cache.lookup!("map_#{map_id}:importing", false) and
WandererApp.Cache.lookup!("map_#{map_id}:started", false)
defp update_location(
defp _update_location(
character_id,
location,
old_location,
%{map: map, map_id: map_id, rtree_name: rtree_name, map_opts: map_opts} = _state
) do
case is_nil(old_location.solar_system_id) and
can_add_location(map.scope, location.solar_system_id) do
_can_add_location(map.scope, location.solar_system_id) do
true ->
:ok = maybe_add_system(map_id, location, nil, rtree_name, map_opts)
_ ->
case is_connection_valid(
case _is_connection_valid(
map.scope,
old_location.solar_system_id,
location.solar_system_id
@@ -1050,7 +880,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp maybe_update_location(map_id, character_id) do
defp _maybe_update_location(map_id, character_id) do
WandererApp.Cache.lookup!(
"character:#{character_id}:location_started",
false
@@ -1101,7 +931,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp maybe_update_alliance(map_id, character_id) do
defp _maybe_update_alliance(map_id, character_id) do
with {:ok, old_alliance_id} <-
WandererApp.Cache.lookup("map:#{map_id}:character:#{character_id}:alliance_id"),
{:ok, %{alliance_id: alliance_id}} <-
@@ -1125,7 +955,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp maybe_update_corporation(map_id, character_id) do
defp _maybe_update_corporation(map_id, character_id) do
with {:ok, old_corporation_id} <-
WandererApp.Cache.lookup("map:#{map_id}:character:#{character_id}:corporation_id"),
{:ok, %{corporation_id: corporation_id}} <-
@@ -1149,7 +979,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp maybe_update_online(map_id, character_id) do
defp _maybe_update_online(map_id, character_id) do
with {:ok, old_online} <-
WandererApp.Cache.lookup("map:#{map_id}:character:#{character_id}:online"),
{:ok, %{online: online}} <-
@@ -1173,7 +1003,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp maybe_update_ship(map_id, character_id) do
defp _maybe_update_ship(map_id, character_id) do
with {:ok, old_ship_type_id} <-
WandererApp.Cache.lookup("map:#{map_id}:character:#{character_id}:ship_type_id"),
{:ok, old_ship_name} <-
@@ -1205,7 +1035,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp update_connection(
defp _update_connection(
%{map_id: map_id} = state,
update_method,
attributes,
@@ -1221,7 +1051,7 @@ defmodule WandererApp.Map.Server.Impl do
solar_system_source_id,
solar_system_target_id
),
{:ok, update_map} <- get_update_map(update, attributes),
{:ok, update_map} <- _get_update_map(update, attributes),
:ok <-
WandererApp.Map.update_connection(
map_id,
@@ -1247,7 +1077,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp update_system(
defp _update_system(
%{map_id: map_id} = state,
update_method,
attributes,
@@ -1260,7 +1090,7 @@ defmodule WandererApp.Map.Server.Impl do
map_id,
update.solar_system_id
),
{:ok, update_map} <- get_update_map(update, attributes) do
{:ok, update_map} <- _get_update_map(update, attributes) do
{:ok, updated_system} =
apply(WandererApp.MapSystemRepo, update_method, [
system,
@@ -1271,7 +1101,7 @@ defmodule WandererApp.Map.Server.Impl do
callback_fn.(updated_system)
end
update_map_system_last_activity(map_id, updated_system)
_update_map_system_last_activity(map_id, updated_system)
state
else
@@ -1281,7 +1111,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp get_update_map(update, attributes),
defp _get_update_map(update, attributes),
do:
{:ok,
Enum.reduce(attributes, Map.new(), fn attribute, map ->
@@ -1325,8 +1155,7 @@ defmodule WandererApp.Map.Server.Impl do
rtree_name
)
existing_system
|> WandererApp.MapSystemRepo.update_visible(%{visible: true})
{:ok, existing_system}
else
@ddrt.insert(
{solar_system_id,
@@ -1340,8 +1169,7 @@ defmodule WandererApp.Map.Server.Impl do
existing_system
|> WandererApp.MapSystemRepo.update_position!(%{position_x: x, position_y: y})
|> WandererApp.MapSystemRepo.cleanup_labels!(map_opts)
|> WandererApp.MapSystemRepo.cleanup_tags!()
|> WandererApp.MapSystemRepo.update_visible(%{visible: true})
|> WandererApp.MapSystemRepo.cleanup_tags()
end
_ ->
@@ -1387,7 +1215,7 @@ defmodule WandererApp.Map.Server.Impl do
state
end
defp save_map_state(%{map_id: map_id} = _state) do
defp _save_map_state(%{map_id: map_id} = _state) do
systems_last_activity =
map_id
|> WandererApp.Map.list_systems!()
@@ -1421,7 +1249,7 @@ defmodule WandererApp.Map.Server.Impl do
})
end
defp maybe_stop_rtree(%{rtree_name: rtree_name} = state) do
defp _maybe_stop_rtree(%{rtree_name: rtree_name} = state) do
case Process.whereis(rtree_name) do
nil ->
:ok
@@ -1433,7 +1261,7 @@ defmodule WandererApp.Map.Server.Impl do
state
end
defp init_map_cache(%__MODULE__{map_id: map_id} = state) do
defp _init_map_cache(%__MODULE__{map_id: map_id} = state) do
case WandererApp.Api.MapState.by_map_id(map_id) do
{:ok,
%{
@@ -1465,9 +1293,9 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp init_map(
defp _init_map(
state,
%{id: map_id, characters: characters} = initial_map,
%{characters: characters} = initial_map,
subscription_settings,
systems,
connections
@@ -1483,24 +1311,16 @@ defmodule WandererApp.Map.Server.Impl do
{:ok, map_options} = WandererApp.MapRepo.options_to_form_data(initial_map)
map_opts = [
layout: map_options |> Map.get("layout", "left_to_right"),
store_custom_labels:
map_options |> Map.get("store_custom_labels", "false") |> String.to_existing_atom()
layout: map_options |> Map.get("layout"),
store_custom_labels: map_options |> Map.get("store_custom_labels")
]
character_ids =
map_id
|> WandererApp.Map.get_map!()
|> Map.get(:characters, [])
WandererApp.Cache.insert("map_#{map_id}:invalidate_character_ids", character_ids)
%{state | map: map, map_opts: map_opts}
end
defp init_map_systems(state, [] = _systems), do: state
defp _init_map_systems(state, [] = _systems), do: state
defp init_map_systems(%__MODULE__{map_id: map_id, rtree_name: rtree_name} = state, systems) do
defp _init_map_systems(%__MODULE__{map_id: map_id, rtree_name: rtree_name} = state, systems) do
systems
|> Enum.each(fn %{id: system_id, solar_system_id: solar_system_id} = system ->
@ddrt.insert(
@@ -1518,7 +1338,7 @@ defmodule WandererApp.Map.Server.Impl do
state
end
def maybe_import_systems(state, %{"systems" => systems} = _settings, user_id, character_id) do
def _maybe_import_systems(state, %{"systems" => systems} = _settings, user_id, character_id) do
state =
systems
|> Enum.reduce(state, fn %{
@@ -1562,7 +1382,7 @@ defmodule WandererApp.Map.Server.Impl do
|> delete_systems(removed_system_ids, user_id, character_id)
end
def maybe_import_connections(state, %{"connections" => connections} = _settings, _user_id) do
def _maybe_import_connections(state, %{"connections" => connections} = _settings, _user_id) do
connections
|> Enum.reduce(state, fn %{
"source" => source,
@@ -1598,7 +1418,7 @@ defmodule WandererApp.Map.Server.Impl do
end)
end
def maybe_import_hubs(state, %{"hubs" => hubs} = _settings, _user_id) do
def _maybe_import_hubs(state, %{"hubs" => hubs} = _settings, _user_id) do
hubs
|> Enum.reduce(state, fn hub, acc ->
solar_system_id = hub |> String.to_integer()
@@ -1608,7 +1428,7 @@ defmodule WandererApp.Map.Server.Impl do
end)
end
defp update_map_system_last_activity(
defp _update_map_system_last_activity(
map_id,
updated_system
) do
@@ -1621,13 +1441,13 @@ defmodule WandererApp.Map.Server.Impl do
broadcast!(map_id, :update_system, updated_system)
end
defp can_add_location(_scope, nil), do: false
defp _can_add_location(_scope, nil), do: false
defp can_add_location(:all, _solar_system_id), do: true
defp _can_add_location(:all, _solar_system_id), do: true
defp can_add_location(:none, _solar_system_id), do: false
defp _can_add_location(:none, _solar_system_id), do: false
defp can_add_location(scope, solar_system_id) do
defp _can_add_location(scope, solar_system_id) do
system_static_info =
case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do
{:ok, system_static_info} when not is_nil(system_static_info) ->
@@ -1652,14 +1472,14 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp is_connection_exist(map_id, from_solar_system_id, to_solar_system_id),
defp _is_connection_exist(map_id, from_solar_system_id, to_solar_system_id),
do:
not is_nil(
WandererApp.Map.find_system_by_location(
map_id,
%{solar_system_id: from_solar_system_id}
)
) &&
) and
not is_nil(
WandererApp.Map.find_system_by_location(
map_id,
@@ -1667,13 +1487,13 @@ defmodule WandererApp.Map.Server.Impl do
)
)
defp is_connection_valid(_scope, nil, _to_solar_system_id), do: false
defp _is_connection_valid(_scope, nil, _to_solar_system_id), do: false
defp is_connection_valid(:all, _from_solar_system_id, _to_solar_system_id), do: true
defp _is_connection_valid(:all, _from_solar_system_id, _to_solar_system_id), do: true
defp is_connection_valid(:none, _from_solar_system_id, _to_solar_system_id), do: false
defp _is_connection_valid(:none, _from_solar_system_id, _to_solar_system_id), do: false
defp is_connection_valid(scope, from_solar_system_id, to_solar_system_id) do
defp _is_connection_valid(scope, from_solar_system_id, to_solar_system_id) do
{:ok, known_jumps} =
WandererApp.Api.MapSolarSystemJumps.find(%{
before_system_id: from_solar_system_id,
@@ -1702,7 +1522,7 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp update_presence(map_id) do
defp _update_presence(map_id) do
case WandererApp.Cache.lookup!("map_#{map_id}:started", false) and
WandererApp.Cache.get_and_remove!("map_#{map_id}:presence_updated", false) do
true ->
@@ -1720,7 +1540,7 @@ defmodule WandererApp.Map.Server.Impl do
not Enum.member?(presence_character_ids, character_id)
end)
track_characters(presence_character_ids, map_id)
_track_characters(presence_character_ids, map_id)
map_id
|> _untrack_characters(not_present_character_ids)
@@ -1739,32 +1559,34 @@ defmodule WandererApp.Map.Server.Impl do
end
end
defp track_acls([]), do: :ok
defp _track_acls([]), do: :ok
defp track_acls([acl_id | rest]) do
track_acl(acl_id)
track_acls(rest)
defp _track_acls([acl_id | rest]) do
_track_acl(acl_id)
_track_acls(rest)
end
defp track_acl(acl_id),
do: @pubsub_client.subscribe(WandererApp.PubSub, "acls:#{acl_id}")
defp track_characters([], _map_id), do: :ok
defp track_characters([character_id | rest], map_id) do
track_character(character_id, map_id)
track_characters(rest, map_id)
end
defp track_character(character_id, map_id),
defp _track_acl(acl_id),
do:
WandererApp.Character.TrackerManager.update_track_settings(character_id, %{
map_id: map_id,
track: true,
track_online: true,
track_location: true,
track_ship: true
})
WandererApp.PubSub
|> @pubsub_client.subscribe("acls:#{acl_id}")
defp _track_characters([], _map_id), do: :ok
defp _track_characters([character_id | rest], map_id) do
_track_character(character_id, map_id)
_track_characters(rest, map_id)
end
defp _track_character(character_id, map_id) do
WandererApp.Character.TrackerManager.update_track_settings(character_id, %{
map_id: map_id,
track: true,
track_online: true,
track_location: true,
track_ship: true
})
end
defp _update_character(map_id, character_id) do
{:ok, character} = WandererApp.Character.get_character(character_id)
@@ -1926,14 +1748,12 @@ defmodule WandererApp.Map.Server.Impl do
broadcast!(map_id, :add_system, new_system)
WandererApp.Map.add_system(map_id, new_system)
error ->
@logger.debug("Failed to create system: #{inspect(error, pretty: true)}")
_ ->
:ok
end
end
error ->
@logger.debug("Skip adding system: #{inspect(error, pretty: true)}")
{:error, _} ->
:ok
end
end
@@ -1947,14 +1767,13 @@ defmodule WandererApp.Map.Server.Impl do
|> WandererApp.Map.find_system_by_location(old_location)
|> WandererApp.Map.PositionCalculator.get_new_system_position(rtree_name, opts)}
defp broadcast_acl_updates(
defp _broadcast_acl_updates(
{:ok,
%{
eve_character_ids: eve_character_ids,
eve_corporation_ids: eve_corporation_ids,
eve_alliance_ids: eve_alliance_ids
}},
map_id
}}
) do
eve_character_ids
|> Enum.uniq()
@@ -1986,19 +1805,12 @@ defmodule WandererApp.Map.Server.Impl do
)
end)
character_ids =
map_id
|> WandererApp.Map.get_map!()
|> Map.get(:characters, [])
WandererApp.Cache.insert("map_#{map_id}:invalidate_character_ids", character_ids)
:ok
end
defp broadcast_acl_updates(_, _map_id), do: :ok
defp _broadcast_acl_updates(_), do: :ok
defp update_acl(acl_id) do
defp _update_acl(acl_id) do
{:ok, %{owner: owner, members: members}} =
WandererApp.AccessListRepo.get(acl_id, [:owner, :members])

View File

@@ -87,113 +87,4 @@ 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

View File

@@ -3,23 +3,4 @@ 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

View File

@@ -35,12 +35,12 @@ defmodule WandererApp.MapSystemRepo do
def cleanup_labels!(%{labels: labels} = system, opts) do
store_custom_labels? =
Keyword.get(opts, :store_custom_labels)
Keyword.get(opts, :store_custom_labels, "false") |> String.to_existing_atom()
labels = get_filtered_labels(labels, store_custom_labels?)
system
|> update_labels!(%{
|> WandererApp.Api.MapSystem.update_labels!(%{
labels: labels
})
end
@@ -52,13 +52,6 @@ defmodule WandererApp.MapSystemRepo do
})
end
def cleanup_tags!(system) do
system
|> WandererApp.Api.MapSystem.update_tag!(%{
tag: nil
})
end
def get_filtered_labels(labels, true) when is_binary(labels) do
labels
|> Jason.decode!()
@@ -104,11 +97,6 @@ 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
@@ -118,14 +106,4 @@ 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

View File

@@ -1,5 +1,4 @@
defmodule WandererAppWeb.AccessListsLive do
alias Pathex.Builder.Viewer
use WandererAppWeb, :live_view
require Logger
@@ -90,10 +89,7 @@ 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
@@ -149,7 +145,7 @@ defmodule WandererAppWeb.AccessListsLive do
:send_after,
[self(), {:search, text}, 100],
"member_search_#{socket.assigns.selected_acl_id}",
250
500
)
[%{label: "Loading...", value: :loading, disabled: true}]
@@ -292,11 +288,7 @@ defmodule WandererAppWeb.AccessListsLive do
end
@impl true
def handle_event(
"dropped",
%{"draggedId" => dragged_id, "dropzoneId" => dropzone_id},
%{assigns: %{access_list: access_list, members: members}} = socket
) do
def handle_event("dropped", %{"draggedId" => dragged_id, "dropzoneId" => dropzone_id}, socket) do
role_atom =
[:admin, :manager, :member, :viewer, :blocked]
|> Enum.find(fn role_atom -> to_string(role_atom) == dropzone_id end)
@@ -307,27 +299,13 @@ defmodule WandererAppWeb.AccessListsLive do
role_atom ->
member =
members
socket.assigns.members
|> Enum.find(&(&1.id == dragged_id))
{:noreply, socket |> maybe_update_role(member, role_atom, access_list)}
{:noreply, socket |> maybe_update_role(member, role_atom, socket.assigns.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}
@@ -347,33 +325,10 @@ defmodule WandererAppWeb.AccessListsLive do
|> Enum.map(& &1.id)
|> Enum.at(0)
uniq_search_req_id = UUID.uuid4(:default)
{:ok, options} = search(active_character_id, text)
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
send_update(LiveSelect.Component, options: options, id: socket.assigns.member_search_id)
{:noreply, socket |> assign(member_search_options: options)}
end
@impl true
@@ -448,7 +403,6 @@ 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
@@ -457,11 +411,10 @@ defmodule WandererAppWeb.AccessListsLive do
_member,
_role_atom,
_access_list
),
do:
socket
|> put_flash(:info, "Only Characters can have Admin or Manager roles")
|> push_navigate(to: ~p"/access-lists/#{socket.assigns.selected_acl_id}")
) do
socket
|> put_flash(:info, "Only Characters can have Admin or Manager roles")
end
defp characters_has_role?(character_eve_ids, access_list, role_atom) do
access_list.members
@@ -661,6 +614,27 @@ 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})

View File

@@ -82,20 +82,14 @@
id="acl_members"
>
<div
:for={member <- @members |> Enum.sort_by(&{&1.role, &1.name}, &<=/2)}
:for={member <- @members |> Enum.sort(&(&1.name < &2.name))}
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">
<.live_component
module={WandererAppWeb.AclMember}
id={"select_role_" <> member.id}
notify_to={self()}
member={member}
event_name="update_role"
/>
<.member_item member={member} />
<button
:if={can_delete_member?(member, @access_list, @current_user)}
class="z-10 absolute top-0 right-2"
@@ -156,71 +150,6 @@
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]}

View File

@@ -1,86 +0,0 @@
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

View File

@@ -41,7 +41,7 @@ defmodule WandererAppWeb.CharactersTrackingLive do
selected_map = socket.assigns.maps |> Enum.find(&(&1.slug == map_slug))
{:ok, character_settings} =
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(selected_map.id) do
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: 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.MapCharacterSettingsRepo.create(%{
WandererApp.Api.MapCharacterSettings.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.MapCharacterSettingsRepo.untrack!()
|> WandererApp.Api.MapCharacterSettings.untrack!()
_ ->
character_setting
|> WandererApp.MapCharacterSettingsRepo.track!()
|> WandererApp.Api.MapCharacterSettings.track!()
end
end
%{result: characters} = socket.assigns.characters
{:ok, character_settings} =
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(selected_map.id) do
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: selected_map.id}) do
{:ok, settings} -> {:ok, settings}
_ -> {:ok, []}
end

View File

@@ -75,7 +75,7 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
} = socket
) do
{:ok, character_settings} =
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(map_id) do
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map_id}) do
{:ok, settings} -> {:ok, settings}
_ -> {:ok, []}
end
@@ -132,7 +132,7 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
case character_settings |> Enum.find(&(&1.character_id == character_id)) do
nil ->
{:ok, map_character_settings} =
WandererApp.MapCharacterSettingsRepo.create(%{
WandererApp.Api.MapCharacterSettings.create(%{
character_id: character_id,
map_id: map_id,
tracked: true
@@ -150,7 +150,7 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
true ->
{:ok, map_character_settings} =
character_setting
|> WandererApp.MapCharacterSettingsRepo.untrack()
|> WandererApp.Api.MapCharacterSettings.untrack()
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
@@ -166,7 +166,7 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
_ ->
{:ok, map_character_settings} =
character_setting
|> WandererApp.MapCharacterSettingsRepo.track()
|> WandererApp.Api.MapCharacterSettings.track()
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
@@ -184,7 +184,7 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
user_character_eve_ids = map_characters |> Enum.map(& &1.eve_id)
{:ok, character_settings} =
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(map_id) do
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map_id}) do
{:ok, settings} -> {:ok, settings}
_ -> {:ok, []}
end
@@ -225,10 +225,10 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
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
case WandererApp.Api.MapCharacterSettings.tracked_by_map(%{
map_id: map_id,
character_ids: current_user.characters |> Enum.map(& &1.id)
}) do
{:ok, settings} ->
{:ok,
settings

View File

@@ -162,16 +162,6 @@ defmodule WandererAppWeb.MapConnectionsEventHandler do
{: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,
@@ -204,19 +194,4 @@ defmodule WandererAppWeb.MapConnectionsEventHandler do
{: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

View File

@@ -41,10 +41,10 @@ defmodule WandererAppWeb.MapCoreEventHandler do
%{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
case WandererApp.Api.MapCharacterSettings.tracked_by_map(%{
map_id: map_id,
character_ids: current_user.characters |> Enum.map(& &1.id)
}) do
{:ok, settings} ->
{:ok,
settings
@@ -258,7 +258,7 @@ defmodule WandererAppWeb.MapCoreEventHandler do
)
{:ok, character_settings} =
case WandererApp.MapCharacterSettingsRepo.get_all_by_map(map_id) do
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map_id}) do
{:ok, settings} -> {:ok, settings}
_ -> {:ok, []}
end
@@ -511,10 +511,10 @@ defmodule WandererAppWeb.MapCoreEventHandler do
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
case WandererApp.Api.MapCharacterSettings.tracked_by_map(%{
map_id: map_id,
character_ids: current_user.characters |> Enum.map(& &1.id)
}) do
{:ok, settings} ->
{:ok,
settings

View File

@@ -225,7 +225,6 @@ defmodule WandererAppWeb.MapSignaturesEventHandler do
|> Enum.filter(fn s -> s.eve_id == signature_eve_id end)
|> Enum.each(fn s ->
s
|> WandererApp.Api.MapSystemSignature.update_group!(%{group: "Wormhole"})
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{
linked_system_id: solar_system_target
})

View File

@@ -61,7 +61,6 @@ defmodule WandererAppWeb.MapEventHandler do
@map_connection_ui_events [
"manual_add_connection",
"manual_delete_connection",
"get_connection_info",
"get_passages",
"update_connection_time_status",
"update_connection_mass_status",
@@ -154,7 +153,7 @@ defmodule WandererAppWeb.MapEventHandler do
def handle_ui_event(event, body, socket)
when event in @map_characters_ui_events,
do: MapCharactersEventHandler.handle_ui_event(event, body, socket)
do: MapSystemsEventHandler.handle_ui_event(event, body, socket)
def handle_ui_event(event, body, socket)
when event in @map_system_ui_events,

View File

@@ -848,9 +848,9 @@ defmodule WandererAppWeb.MapsLive do
|> Enum.map(fn acl -> acl |> Ash.load!(:members) end)
{:ok, characters_count} =
map.id
|> WandererApp.MapCharacterSettingsRepo.get_tracked_by_map_all()
|> case do
case WandererApp.Api.MapCharacterSettings.tracked_by_map_all(%{
map_id: map.id
}) do
{:ok, settings} ->
{:ok,
settings

View File

@@ -2,7 +2,7 @@ defmodule WandererApp.MixProject do
use Mix.Project
@source_url "https://github.com/wanderer-industries/wanderer"
@version "1.17.0"
@version "1.13.7"
def project do
[

View File

@@ -0,0 +1,54 @@
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