Compare commits

...

10 Commits

Author SHA1 Message Date
CI
a89c117612 chore: release version v1.0.15 2024-09-21 09:16:33 +00:00
Dmitry Popov
501dbcd76b fix(map): Show a proper user notification if map was deleted/archived 2024-09-21 13:16:04 +04:00
CI
6039ac5d4f chore: release version v1.0.14 2024-09-21 08:35:54 +00:00
Dmitry Popov
48e87f3c47 Create FUNDING.yml 2024-09-21 12:35:30 +04:00
CI
4fadcd5964 chore: release version v1.0.13 2024-09-21 08:14:36 +00:00
Dmitry Popov
6480154d1b Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-09-21 12:13:57 +04:00
Dmitry Popov
9c064531b8 fix(tracking): Ensure user has at least one character tracked to work with map
Show error notification if no character tracked
2024-09-21 12:13:52 +04:00
CI
bee64c2570 chore: release version v1.0.12 2024-09-20 10:06:40 +00:00
Dmitry Popov
5393321953 Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-09-20 14:06:02 +04:00
Dmitry Popov
b44669da87 fix(audit): Hide character for non-character map activities 2024-09-20 14:05:56 +04:00
7 changed files with 378 additions and 210 deletions

15
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: WandererLtd
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -2,6 +2,38 @@
<!-- changelog -->
## [v1.0.15](https://github.com/wanderer-industries/wanderer/compare/v1.0.14...v1.0.15) (2024-09-21)
### Bug Fixes:
* map: Show a proper user notification if map was deleted/archived
## [v1.0.14](https://github.com/wanderer-industries/wanderer/compare/v1.0.13...v1.0.14) (2024-09-21)
## [v1.0.13](https://github.com/wanderer-industries/wanderer/compare/v1.0.12...v1.0.13) (2024-09-21)
### Bug Fixes:
* tracking: Ensure user has at least one character tracked to work with map
## [v1.0.12](https://github.com/wanderer-industries/wanderer/compare/v1.0.11...v1.0.12) (2024-09-20)
### Bug Fixes:
* audit: Hide character for non-character map activities
## [v1.0.11](https://github.com/wanderer-industries/wanderer/compare/v1.0.10...v1.0.11) (2024-09-20)

View File

@@ -51,7 +51,7 @@ defmodule WandererAppWeb.Alerts do
def delayed_fade_out_flash() do
JS.hide(
transition:
{"transition-opacity ease-out delay-2000 duration-1000", "opacity-100", "opacity-0"},
{"transition-opacity ease-out delay-5000 duration-6000", "opacity-100", "opacity-0"},
time: 6000
)
|> JS.push("lv:clear-flash")

View File

@@ -42,27 +42,30 @@
integrity={integrity_hash("https://unpkg.com/react-dom@18/umd/react-dom.production.min.js")}
>
</script>
<script defer phx-track-static type="module" src={~p"/assets/app.js"} crossorigin="anonymous">
</script>
<!-- Appzi: Capture Insightful Feedback -->
<script async src="https://w.appzi.io/w.js?token=yddv0">
<script defer src="https://w.appzi.io/w.js?token=yddv0">
</script>
<!-- End Appzi -->
<!-- Google tag (gtag.js) -->
<script
async
defer
src="https://www.googletagmanager.com/gtag/js?id=G-61PHLLS0LD"
crossorigin="anonymous"
>
</script>
<script>
<script defer>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-61PHLLS0LD');
</script>
<script defer phx-track-static type="module" src={~p"/assets/app.js"} crossorigin="anonymous">
</script>
</head>
<body>
<%= @inner_content %>

View File

@@ -46,7 +46,7 @@ defmodule WandererAppWeb.UserActivity do
<.local_time id={@activity.id} at={@activity.inserted_at} />
</span>
</p>
<p class="flex shrink-0 items-center space-x-1 min-w-[200px]">
<p :if={not is_nil(@activity.character)} class="flex shrink-0 items-center space-x-1 min-w-[200px]">
<.character_item character={@activity.character} />
</p>
</div>

View File

@@ -64,6 +64,18 @@ defmodule WandererAppWeb.MapLive do
timeout: 2000
})
{:ok,
%{
deleted: true
} = map} ->
socket
|> put_flash(
:error,
"Map was deleted by owner or administrator."
)
|> push_navigate(to: ~p"/maps")
{:error, _} ->
socket
|> put_flash(
@@ -386,6 +398,13 @@ defmodule WandererAppWeb.MapLive do
"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(
@@ -400,7 +419,7 @@ defmodule WandererAppWeb.MapLive do
{:noreply,
socket
|> assign(map_loaded?: true, user_characters: user_character_eve_ids)
|> assign(map_loaded?: true, user_characters: user_character_eve_ids, has_tracked_characters?: _has_tracked_characters?(user_character_eve_ids))
|> _push_map_event("init", initial_data)
|> push_event("js-exec", %{
to: "#map-loader",
@@ -470,16 +489,24 @@ defmodule WandererAppWeb.MapLive do
end
@impl true
def handle_event("manual_add_system", %{"coordinates" => coordinates} = _event, socket) do
case _check_user_permissions(socket, :add_system) do
def handle_event("manual_add_system", %{"coordinates" => coordinates} = _event, %{assigns: %{has_tracked_characters?: has_tracked_characters?}} = socket) do
case has_tracked_characters? do
true ->
{:noreply,
socket
|> assign(coordinates: coordinates)
|> push_patch(to: ~p"/#{socket.assigns.map_slug}/add-system")}
case _check_user_permissions(socket, :add_system) do
true ->
{:noreply,
socket
|> assign(coordinates: coordinates)
|> push_patch(to: ~p"/#{socket.assigns.map_slug}/add-system")}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to add system."
)}
end
end
@@ -487,157 +514,189 @@ defmodule WandererAppWeb.MapLive do
def handle_event(
"manual_add_connection",
%{"source" => solar_system_source_id, "target" => solar_system_target_id} = _event,
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids}} =
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids, has_tracked_characters?: has_tracked_characters?}} =
socket
) do
case _check_user_permissions(socket, :add_connection) do
true ->
map_id =
socket
|> map_id()
case has_tracked_characters? do
true ->
case _check_user_permissions(socket, :add_connection) do
true ->
map_id =
socket
|> map_id()
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()
})
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()
})
:telemetry.execute([:wanderer_app, :map, :connection, :add], %{count: 1}, %{
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()
})
:telemetry.execute([:wanderer_app, :map, :connection, :add], %{count: 1}, %{
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}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to add connection."
)}
end
end
@impl true
def handle_event(
"add_hub",
%{"system_id" => solar_system_id} = _event,
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids}} =
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids, has_tracked_characters?: has_tracked_characters?}} =
socket
) do
case _check_user_permissions(socket, :update_system) do
true ->
map_id =
socket
|> map_id()
case has_tracked_characters? do
true ->
case _check_user_permissions(socket, :update_system) do
true ->
map_id =
socket
|> map_id()
:telemetry.execute([:wanderer_app, :map, :hub, :add], %{count: 1}, %{
character_id: tracked_character_ids |> List.first(),
user_id: current_user.id,
map_id: map_id,
solar_system_id: solar_system_id
})
:telemetry.execute([:wanderer_app, :map, :hub, :add], %{count: 1}, %{
character_id: tracked_character_ids |> List.first(),
user_id: current_user.id,
map_id: map_id,
solar_system_id: solar_system_id
})
map_id
|> WandererApp.Map.Server.add_hub(%{
solar_system_id: solar_system_id
})
map_id
|> WandererApp.Map.Server.add_hub(%{
solar_system_id: solar_system_id
})
{:noreply, socket}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to add hub."
)}
end
end
@impl true
def handle_event(
"delete_hub",
%{"system_id" => solar_system_id} = _event,
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids}} =
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids, has_tracked_characters?: has_tracked_characters?}} =
socket
) do
case _check_user_permissions(socket, :update_system) do
true ->
map_id =
socket
|> map_id()
case has_tracked_characters? do
true ->
case _check_user_permissions(socket, :update_system) do
true ->
map_id =
socket
|> map_id()
:telemetry.execute([:wanderer_app, :map, :hub, :remove], %{count: 1}, %{
character_id: tracked_character_ids |> List.first(),
user_id: current_user.id,
map_id: map_id,
solar_system_id: solar_system_id
})
:telemetry.execute([:wanderer_app, :map, :hub, :remove], %{count: 1}, %{
character_id: tracked_character_ids |> List.first(),
user_id: current_user.id,
map_id: map_id,
solar_system_id: solar_system_id
})
map_id
|> WandererApp.Map.Server.remove_hub(%{
solar_system_id: solar_system_id
})
map_id
|> WandererApp.Map.Server.remove_hub(%{
solar_system_id: solar_system_id
})
{:noreply, socket}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to remove hub."
)}
end
end
@impl true
def handle_event(
"update_system_" <> param,
%{"system_id" => solar_system_id, "value" => value} = _event,
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids}} =
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids, has_tracked_characters?: has_tracked_characters?}} =
socket
) do
case _check_user_permissions(socket, :update_system) do
true ->
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
case has_tracked_characters? do
true ->
case _check_user_permissions(socket, :update_system) do
true ->
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
key_atom =
case param do
"name" -> :name
"description" -> :description
"labels" -> :labels
"locked" -> :locked
"tag" -> :tag
"status" -> :status
_ -> :none
end
map_id =
socket
|> map_id()
map_id =
socket
|> map_id()
:telemetry.execute([:wanderer_app, :map, :system, :update], %{count: 1}, %{
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
})
:telemetry.execute([:wanderer_app, :map, :system, :update], %{count: 1}, %{
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
})
apply(WandererApp.Map.Server, method_atom, [
map_id,
%{
solar_system_id: "#{solar_system_id}" |> String.to_integer()
}
|> Map.put_new(key_atom, value)
])
apply(WandererApp.Map.Server, method_atom, [
map_id,
%{
solar_system_id: "#{solar_system_id}" |> String.to_integer()
}
|> Map.put_new(key_atom, value)
])
{:noreply, socket}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to update system."
)}
end
end
@impl true
@@ -648,57 +707,65 @@ defmodule WandererAppWeb.MapLive do
"target" => solar_system_target_id,
"value" => value
} = _event,
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids}} =
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids, has_tracked_characters?: has_tracked_characters?}} =
socket
) do
case _check_user_permissions(socket, :update_system) do
true ->
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
_ -> nil
end
case has_tracked_characters? do
true ->
case _check_user_permissions(socket, :update_system) do
true ->
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
_ -> nil
end
key_atom =
case param do
"time_status" -> :time_status
"mass_status" -> :mass_status
"ship_size_type" -> :ship_size_type
"locked" -> :locked
_ -> nil
end
key_atom =
case param do
"time_status" -> :time_status
"mass_status" -> :mass_status
"ship_size_type" -> :ship_size_type
"locked" -> :locked
_ -> nil
end
map_id =
socket
|> map_id()
map_id =
socket
|> map_id()
:telemetry.execute([:wanderer_app, :map, :connection, :update], %{count: 1}, %{
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
})
:telemetry.execute([:wanderer_app, :map, :connection, :update], %{count: 1}, %{
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)
])
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}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to update connection."
)}
end
end
@impl true
@@ -891,18 +958,26 @@ defmodule WandererAppWeb.MapLive do
def handle_event(
"update_system_position",
position,
socket
%{assigns: %{has_tracked_characters?: has_tracked_characters?}} = socket
) do
case _check_user_permissions(socket, :update_system) do
case has_tracked_characters? do
true ->
socket
|> map_id()
|> _update_system_position(position)
case _check_user_permissions(socket, :update_system) do
true ->
socket
|> map_id()
|> _update_system_position(position)
{:noreply, socket}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to update system."
)}
end
end
@@ -910,18 +985,26 @@ defmodule WandererAppWeb.MapLive do
def handle_event(
"update_system_positions",
positions,
socket
%{assigns: %{has_tracked_characters?: has_tracked_characters?}} = socket
) do
case _check_user_permissions(socket, :update_system) do
case has_tracked_characters? do
true ->
socket
|> map_id()
|> _update_system_positions(positions)
case _check_user_permissions(socket, :update_system) do
true ->
socket
|> map_id()
|> _update_system_positions(positions)
{:noreply, socket}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to update systems."
)}
end
end
@@ -929,58 +1012,76 @@ defmodule WandererAppWeb.MapLive do
def handle_event(
"delete_systems",
solar_system_ids,
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids}} =
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids, has_tracked_characters?: has_tracked_characters?}} =
socket
) do
case _check_user_permissions(socket, :delete_system) do
case has_tracked_characters? do
true ->
socket
|> map_id()
|> WandererApp.Map.Server.delete_systems(
solar_system_ids |> Enum.map(&String.to_integer/1),
current_user.id,
tracked_character_ids |> List.first()
)
case _check_user_permissions(socket, :delete_system) do
true ->
socket
|> 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}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to delete systems."
)}
end
end
@impl true
def handle_event(
"manual_delete_connection",
%{"source" => solar_system_source_id, "target" => solar_system_target_id} = _event,
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids}} =
%{assigns: %{current_user: current_user, tracked_character_ids: tracked_character_ids, has_tracked_characters?: has_tracked_characters?}} =
socket
) do
case _check_user_permissions(socket, :delete_connection) do
case has_tracked_characters? do
true ->
map_id =
socket
|> map_id()
case _check_user_permissions(socket, :delete_connection) do
true ->
map_id =
socket
|> map_id()
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()
})
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()
})
:telemetry.execute([:wanderer_app, :map, :connection, :remove], %{count: 1}, %{
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()
})
:telemetry.execute([:wanderer_app, :map, :connection, :remove], %{count: 1}, %{
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}
{:noreply, socket}
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
{:noreply, socket |> put_flash(
:error,
"You should enable tracking for at least one character to delete connection."
)}
end
end
@impl true
@@ -1069,6 +1170,7 @@ defmodule WandererAppWeb.MapLive do
def handle_event("toggle_track", %{"character-id" => character_id}, socket) do
map = socket.assigns.map
character_settings = socket.assigns.character_settings
current_user = socket.assigns.current_user
socket =
case character_settings |> Enum.find(&(&1.character_id == character_id)) do
@@ -1147,6 +1249,8 @@ defmodule WandererAppWeb.MapLive do
{: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}}
@@ -1283,6 +1387,15 @@ defmodule WandererAppWeb.MapLive do
[]
end
events =
case map_characters |> Enum.empty?() do
true ->
events ++ [:empty_tracked_characters]
_ ->
events
end
{:ok, characters_limit} = map_id |> WandererApp.Map.get_characters_limit()
{:ok, present_character_ids} =
@@ -1488,6 +1601,7 @@ defmodule WandererAppWeb.MapLive do
:character_eve_id,
:name,
:description,
:custom_info,
:kind,
:group,
:updated_at
@@ -1517,6 +1631,9 @@ defmodule WandererAppWeb.MapLive do
{:ok, %{maps: maps |> Enum.sort_by(& &1.name, :asc) |> Enum.map(&map_map/1)}}
end
defp _has_tracked_characters?([]), do: false
defp _has_tracked_characters?(_user_characters), do: true
defp _update_system_positions(_map_id, []), do: :ok
defp _update_system_positions(map_id, [position | rest]) do
@@ -1692,6 +1809,7 @@ defmodule WandererAppWeb.MapLive do
eve_id: eve_id,
name: name,
description: Map.get(signature, "description"),
custom_info: Map.get(signature, "custom_info"),
kind: kind,
group: group,
character_eve_id: character_eve_id

View File

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