From f0029fbbc8446971abfb9a6514a85a6a138e2f9e Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sat, 30 Mar 2024 21:04:34 +0000
Subject: [PATCH 01/64] Refactored client update functions
---
CHANGELOG.md | 4 ++
lib/teiserver/api.ex | 4 --
lib/teiserver/connections/client_server.ex | 35 ++++-----
lib/teiserver/connections/libs/client_lib.ex | 36 ++++------
lib/teiserver/contexts/connections.ex | 8 +--
lib/teiserver/game/libs/lobby_lib.ex | 12 ++--
lib/teiserver/game/servers/lobby_server.ex | 31 +++++---
test/connections/client_in_lobby_test.exs | 28 ++++++++
test/connections/client_lib_test.exs | 76 ++------------------
test/game/libs/match_lib_test.exs | 8 +--
10 files changed, 98 insertions(+), 144 deletions(-)
create mode 100644 test/connections/client_in_lobby_test.exs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3378aabe7..d46fa99cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## v0.0.5
+- Swapped `team_colour` for `player_colour`
+- Refactored the client update process
+
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
- Added pubsub events for clients connecting, disconnecting and process destruction
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index 176bbe803..5e87faeb1 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -122,10 +122,6 @@ defmodule Teiserver.Api do
@spec update_client_in_lobby(Teiserver.user_id(), map, String.t()) :: Client.t() | nil
defdelegate update_client_in_lobby(user_id, updates, reason), to: ClientLib
- @doc section: :client
- @spec update_client_full(Teiserver.user_id(), map, String.t()) :: Client.t() | nil
- defdelegate update_client_full(user_id, updates, reason), to: ClientLib
-
### Game
# Lobby
@doc section: :lobby
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index 8ef297e37..d3725fb13 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -23,9 +23,6 @@ defmodule Teiserver.Connections.ClientServer do
defstruct [:client, :user_id, :connections, :client_topic, :lobby_topic]
end
- @standard_data_keys ~w(connected? last_disconnected in_game? afk? party_id)a
- @lobby_data_keys ~w(ready? player? player_number team_number player_colour sync lobby_host?)a
-
@impl true
def handle_call(:get_client_state, _from, state) do
{:reply, state.client, state}
@@ -56,35 +53,31 @@ defmodule Teiserver.Connections.ClientServer do
end
def handle_cast({:update_client, partial_client, reason}, state) do
- partial_client = Map.take(partial_client, @standard_data_keys)
-
- if partial_client != %{} do
+ if Enum.empty?(partial_client) do
+ {:noreply, state}
+ else
new_client = struct(state.client, partial_client)
new_state = update_client(state, new_client, reason)
{:noreply, new_state}
- else
- {:noreply, state}
end
end
def handle_cast({:update_client_in_lobby, partial_client, reason}, state) do
- partial_client =
- partial_client
- |> Map.take(@lobby_data_keys)
- |> Map.put(:id, state.user_id)
- |> LobbyLib.client_update_request(state.client.lobby_id)
-
- if partial_client != %{} do
- new_client = struct(state.client, partial_client)
- new_state = update_client(state, new_client, reason)
- {:noreply, new_state}
+ if Enum.empty?(partial_client) or state.client.lobby_id == nil do
+ {:noreply, state}
else
+ new_client = struct(state.client, partial_client)
+ diffs = MapHelper.map_diffs(state.client, new_client)
+
+ if not Enum.empty?(diffs) do
+ LobbyLib.client_update_request(state.client.lobby_id, new_client, diffs, reason)
+ end
+
{:noreply, state}
end
end
- def handle_cast({:update_client_full, partial_client, reason}, state) do
- new_client = struct(state.client, partial_client)
+ def handle_cast({:do_update_client_in_lobby, new_client, reason}, state) do
new_state = update_client(state, new_client, reason)
{:noreply, new_state}
end
@@ -143,7 +136,7 @@ defmodule Teiserver.Connections.ClientServer do
defp update_client(%State{} = state, %Client{} = new_client, reason) do
diffs = MapHelper.map_diffs(state.client, new_client)
- if diffs == %{} do
+ if Enum.empty?(diffs) do
# Nothing changed, we don't do anything
state
else
diff --git a/lib/teiserver/connections/libs/client_lib.ex b/lib/teiserver/connections/libs/client_lib.ex
index dcde32209..9c270fe51 100644
--- a/lib/teiserver/connections/libs/client_lib.ex
+++ b/lib/teiserver/connections/libs/client_lib.ex
@@ -94,16 +94,16 @@ defmodule Teiserver.Connections.ClientLib do
end
@doc """
- Updates a client with the new data (excluding lobby related details). If changes are made then it will also generate a `Teiserver.Connections.Client:{user_id}` pubsub message.
+ Updates a client with the new data (excluding lobby related details). If changes are made then it will also generate a `Teiserver.Connections.Client:{user_id}` pubsub message; if they are present in a lobby it will generate a similar message to `Teiserver.Game.Lobby:{lobby_id}`.
Returns nil if the Client does not exist, :ok if the client does.
## Examples
- iex> update_client(123, %{afk?: false})
+ iex> update_client(123, %{afk?: false}, "some reason")
:ok
- iex> update_client(456, %{afk?: false})
+ iex> update_client(456, %{afk?: false}, "some reason")
nil
"""
@@ -113,16 +113,18 @@ defmodule Teiserver.Connections.ClientLib do
end
@doc """
- Updates a client with the new data for their lobby presence. If changes are made then it will also generate a `Teiserver.Connections.Client:{user_id}` pubsub message and a `Teiserver.Game.Lobby:{lobby_id}` pubsub message.
+ Similar to `update_client/3`, in the ClientServer it will first validate the update is acceptable and then send it off to the LobbyServer allowing it to change the update as it sees fit. Depending on other factors the LobbyServer may call out to the lobby host for further input.
+
+ If the LobbyServer accepts any changes it will contact the ClientServer accordingly.
Returns nil if the Client does not exist, :ok if the client does.
## Examples
- iex> update_client_in_lobby(123, %{player_number: 123})
+ iex> update_client_in_lobby(123, %{player_number: 123}, "some reason")
:ok
- iex> update_client_in_lobby(456, %{player_number: 123})
+ iex> update_client_in_lobby(456, %{player_number: 123}, "some reason")
nil
"""
@@ -131,23 +133,11 @@ defmodule Teiserver.Connections.ClientLib do
cast_client(user_id, {:update_client_in_lobby, data, reason})
end
- @doc """
- Updates a client with the new data for any and all keys (so be careful not to break things like lobby memberships).
-
- Returns nil if the Client does not exist, :ok if the client does.
-
- ## Examples
-
- iex> update_client_full(123, %{player_number: 123})
- :ok
-
- iex> update_client_full(456, %{player_number: 123})
- nil
-
- """
- @spec update_client_full(Teiserver.user_id(), map, String.t()) :: :ok | nil
- def update_client_full(user_id, data, reason) do
- cast_client(user_id, {:update_client_full, data, reason})
+ # Used by the LobbyServer to update the ClientServer if `update_client_in_lobby/4` is successful
+ @doc false
+ @spec do_update_client_in_lobby(Teiserver.user_id(), map, String.t()) :: :ok | nil
+ def do_update_client_in_lobby(user_id, data, reason) do
+ cast_client(user_id, {:do_update_client_in_lobby, data, reason})
end
@doc """
diff --git a/lib/teiserver/contexts/connections.ex b/lib/teiserver/contexts/connections.ex
index b71c97158..870994160 100644
--- a/lib/teiserver/contexts/connections.ex
+++ b/lib/teiserver/contexts/connections.ex
@@ -44,17 +44,13 @@ defmodule Teiserver.Connections do
defdelegate get_client_list(user_ids), to: ClientLib
@doc section: :client
- @spec update_client(Teiserver.user_id(), map, String.t()) :: Client.t() | nil
+ @spec update_client(Teiserver.user_id(), map, String.t()) :: :ok | nil
defdelegate update_client(user_id, updates, reason), to: ClientLib
@doc section: :client
- @spec update_client_in_lobby(Teiserver.user_id(), map, String.t()) :: Client.t() | nil
+ @spec update_client_in_lobby(Teiserver.user_id(), map, String.t()) :: :ok | nil
defdelegate update_client_in_lobby(user_id, updates, reason), to: ClientLib
- @doc section: :client
- @spec update_client_full(Teiserver.user_id(), map, String.t()) :: Client.t() | nil
- defdelegate update_client_full(user_id, updates, reason), to: ClientLib
-
@doc section: :client
@spec connect_user(Teiserver.user_id()) :: Client.t()
defdelegate connect_user(user_id), to: ClientLib
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index 481c9e35f..4db16f528 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -218,7 +218,7 @@ defmodule Teiserver.Game.LobbyLib do
true ->
with {:ok, lobby} <- start_lobby_server(host_id, name),
:ok <- cycle_lobby(lobby.id),
- _ <- ClientLib.update_client_full(host_id, %{lobby_id: lobby.id, lobby_host?: true}, "opened lobby") do
+ _ <- ClientLib.update_client(host_id, %{lobby_id: lobby.id, lobby_host?: true}, "opened lobby") do
{:ok, lobby.id}
else
:failure1 -> :fail_result1
@@ -282,9 +282,9 @@ defmodule Teiserver.Game.LobbyLib do
iex> client_update_request(%{team_number: 1, id: 456}, 456)
nil
"""
- @spec client_update_request(map(), Lobby.id()) :: map()
- def client_update_request(changes, lobby_id) when is_binary(lobby_id) do
- call_lobby(lobby_id, {:client_update_request, changes})
+ @spec client_update_request(Lobby.id(), Client.t(), map(), String.t()) :: map()
+ def client_update_request(lobby_id, new_client, diffs, reason) when is_binary(lobby_id) do
+ cast_lobby(lobby_id, {:client_update_request, new_client, diffs, reason})
end
@doc """
@@ -303,10 +303,10 @@ defmodule Teiserver.Game.LobbyLib do
if lobby do
lobby.members
|> Enum.each(fn user_id ->
- ClientLib.update_client_full(user_id, %{lobby_id: nil, lobby_host?: false}, "lobby closed")
+ ClientLib.update_client(user_id, %{lobby_id: nil, lobby_host?: false}, "lobby closed")
end)
- ClientLib.update_client_full(lobby.host_id, %{lobby_id: nil, lobby_host?: false}, "closed lobby")
+ ClientLib.update_client(lobby.host_id, %{lobby_id: nil, lobby_host?: false}, "closed lobby")
end
stop_lobby_server(lobby_id)
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index 35f7af10c..b6991a979 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -7,7 +7,7 @@ defmodule Teiserver.Game.LobbyServer do
require Logger
alias Teiserver.{Connections, Account}
alias Teiserver.Game.{Lobby, LobbyLib, LobbySummary}
- alias Teiserver.Connections.ClientLib
+ alias Teiserver.Connections.{Client, ClientLib}
alias Teiserver.Helpers.MapHelper
@heartbeat_frequency_ms 5_000
@@ -34,10 +34,6 @@ defmodule Teiserver.Game.LobbyServer do
{:reply, can_add_client({user_id, password}, state), state}
end
- def handle_call({:client_update_request, %{id: _user_id} = changes}, _from, state) do
- {:reply, changes, state}
- end
-
# Attempts to add a client to the lobby
def handle_call({:add_client, user_id}, _from, state) do
case can_add_client({user_id, state.lobby.password}, state) do
@@ -61,6 +57,12 @@ defmodule Teiserver.Game.LobbyServer do
{:noreply, new_state}
end
+ def handle_cast({:client_update_request, new_client, diffs, reason}, state) do
+ state = client_update_request(state, new_client, diffs, reason)
+ {:noreply, state}
+ end
+
+
def handle_cast({:remove_client, user_id}, state) do
if Enum.member?(state.lobby.members, user_id) do
new_state = do_remove_client(user_id, state)
@@ -146,7 +148,7 @@ defmodule Teiserver.Game.LobbyServer do
%{}
end
- if changes == %{} do
+ if Enum.empty?(changes) do
{:noreply, state}
else
new_state = update_lobby(state, changes)
@@ -204,6 +206,17 @@ defmodule Teiserver.Game.LobbyServer do
end
end
+ @spec client_update_request(State.t(), Client.t(), map(), State.t()) :: State.t()
+ defp client_update_request(state, new_client, _diffs, reason) do
+ # Currently we just say yes so we pass-through the client
+ resulting_client = new_client
+
+ # Assuming there are still some changes, send them over to be implemented!
+ ClientLib.do_update_client_in_lobby(new_client.id, resulting_client, reason)
+
+ state
+ end
+
@spec update_lobby(State.t(), map()) :: State.t()
def update_lobby(state, changes) do
new_lobby = state.lobby
@@ -217,7 +230,7 @@ defmodule Teiserver.Game.LobbyServer do
defp do_update_lobby(%State{} = state, %Lobby{} = new_lobby) do
diffs = MapHelper.map_diffs(state.lobby, new_lobby)
- if diffs == %{} do
+ if Enum.empty?(diffs) do
# Nothing changed, we don't do anything
state
else
@@ -253,7 +266,7 @@ defmodule Teiserver.Game.LobbyServer do
defp do_add_client(user_id, state) do
shared_secret = Teiserver.Account.generate_password()
- ClientLib.update_client_full(user_id, %{
+ ClientLib.update_client(user_id, %{
lobby_id: state.lobby_id,
ready?: false,
player?: false,
@@ -288,7 +301,7 @@ defmodule Teiserver.Game.LobbyServer do
defp do_remove_client(user_id, state) do
Connections.unsubscribe_from_client(user_id)
- ClientLib.update_client_full(user_id, %{
+ ClientLib.update_client(user_id, %{
lobby_id: nil,
ready?: false,
player?: false,
diff --git a/test/connections/client_in_lobby_test.exs b/test/connections/client_in_lobby_test.exs
new file mode 100644
index 000000000..70fcf1974
--- /dev/null
+++ b/test/connections/client_in_lobby_test.exs
@@ -0,0 +1,28 @@
+defmodule Connections.ClientInLobbyLibTest do
+ @moduledoc false
+ use Teiserver.Case, async: false
+
+ alias Teiserver.{Connections, Game}
+ alias Teiserver.{ConnectionFixtures, GameFixtures}
+
+ describe "ClientLib" do
+ test "update_client_in_lobby" do
+ {_host_conn, _host_user, lobby_id} = GameFixtures.lobby_fixture_with_process()
+ {_conn, user} = ConnectionFixtures.client_fixture()
+
+ Game.add_client_to_lobby(user.id, lobby_id)
+
+ client = Connections.get_client(user.id)
+ assert client.lobby_id == lobby_id
+ assert client.player? == false
+
+ Connections.update_client_in_lobby(user.id, %{player?: true}, "reason here")
+
+ # Need to give the LobbyServer time to update us
+ :timer.sleep(50)
+
+ client = Connections.get_client(user.id)
+ assert client.player? == true
+ end
+ end
+end
diff --git a/test/connections/client_lib_test.exs b/test/connections/client_lib_test.exs
index 51a094d48..859150c32 100644
--- a/test/connections/client_lib_test.exs
+++ b/test/connections/client_lib_test.exs
@@ -3,8 +3,7 @@ defmodule Connections.ClientLibTest do
use Teiserver.Case, async: true
alias Teiserver.Connections
- alias Teiserver.Connections.ClientLib
- alias Teiserver.{ConnectionFixtures}
+ alias Teiserver.ConnectionFixtures
describe "ClientLib" do
test "server lifecycle" do
@@ -31,8 +30,8 @@ defmodule Connections.ClientLibTest do
client = Connections.get_client(user.id)
refute client.afk?
- # Now update it
- Connections.update_client(user.id, %{afk?: true, team_number: 123}, uuid)
+ # Now update it, the `total_number` key isn't a valid key
+ Connections.update_client(user.id, %{afk?: true, total_number: 123}, uuid)
# Check the client has updated
client = Connections.get_client(user.id)
@@ -56,7 +55,7 @@ defmodule Connections.ClientLibTest do
]
# Now try to update with the same details, should result in no change
- Connections.update_client(user.id, %{afk?: true, team_number: 123}, "test")
+ Connections.update_client(user.id, %{afk?: true}, "test")
client = Connections.get_client(user.id)
assert client.afk?
@@ -66,7 +65,7 @@ defmodule Connections.ClientLibTest do
assert msgs == []
# Now swap the value around to ensure we get a new update
- Connections.update_client(user.id, %{afk?: false, team_number: 123}, "test2")
+ Connections.update_client(user.id, %{afk?: false}, "test2")
client = Connections.get_client(user.id)
refute client.afk?
@@ -80,71 +79,6 @@ defmodule Connections.ClientLibTest do
assert client.team_number == nil
assert update_msg.reason == "test2"
end
-
- test "update_client_full" do
- uuid = Teiserver.uuid()
- {conn, user} = ConnectionFixtures.client_fixture()
- TestConn.subscribe(conn, Connections.client_topic(user.id))
-
- msgs = TestConn.get(conn)
- assert msgs == []
-
- # Check the client is as we expect
- client = Connections.get_client(user.id)
- refute client.afk?
- assert client.team_number == nil
-
- # Now update it
- ClientLib.update_client_full(user.id, %{afk?: true, team_number: 123}, uuid)
-
- # Check the client has updated
- client = Connections.get_client(user.id)
- assert client.afk?
- assert client.team_number == 123
-
- # Should have gotten a new message too
- msgs = TestConn.get(conn)
-
- assert msgs == [
- %{
- topic: Connections.client_topic(user.id),
- event: :client_updated,
- changes: %{
- afk?: true,
- update_id: 1,
- team_number: 123
- },
- reason: uuid,
- user_id: user.id
- }
- ]
-
- # Now try to update with the same details, should result in no change
- ClientLib.update_client_full(user.id, %{afk?: true, team_number: 123}, "test")
-
- client = Connections.get_client(user.id)
- assert client.afk?
- assert client.team_number == 123
-
- msgs = TestConn.get(conn)
- assert msgs == []
-
- # Now swap the value around to ensure we get a new update
- ClientLib.update_client_full(user.id, %{afk?: false, team_number: 456}, "test2")
-
- client = Connections.get_client(user.id)
- refute client.afk?
- assert client.team_number == 456
-
- msgs = TestConn.get(conn)
- assert Enum.count(msgs) == 1
- [update_msg] = msgs
-
- refute update_msg.changes.afk?
- assert client.team_number == 456
- assert update_msg.reason == "test2"
- end
-
test "get_client_list" do
{_conn1, user1} = ConnectionFixtures.client_fixture()
{_conn1, user2} = ConnectionFixtures.client_fixture()
diff --git a/test/game/libs/match_lib_test.exs b/test/game/libs/match_lib_test.exs
index 439091296..c8e641e2d 100644
--- a/test/game/libs/match_lib_test.exs
+++ b/test/game/libs/match_lib_test.exs
@@ -136,13 +136,13 @@ defmodule Teiserver.MatchLibAsyncTest do
assert lobby.players == []
# Update the clients by making them players and putting them on teams
- Connections.update_client_in_lobby(u1.id, %{player_number: 1, team_number: 1, player?: true}, "test")
+ Connections.update_client(u1.id, %{player_number: 1, team_number: 1, player?: true}, "test")
- Connections.update_client_in_lobby(u2.id, %{player_number: 2, team_number: 1, player?: true}, "test")
+ Connections.update_client(u2.id, %{player_number: 2, team_number: 1, player?: true}, "test")
- Connections.update_client_in_lobby(u3.id, %{player_number: 3, team_number: 2, player?: true}, "test")
+ Connections.update_client(u3.id, %{player_number: 3, team_number: 2, player?: true}, "test")
- Connections.update_client_in_lobby(u4.id, %{player_number: 4, team_number: 2, player?: true}, "test")
+ Connections.update_client(u4.id, %{player_number: 4, team_number: 2, player?: true}, "test")
# Give the lobby time to read and update
:timer.sleep(100)
From 13b25ece17b9546b5b987a944f775a4cac6f7438 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 1 Apr 2024 13:26:51 +0100
Subject: [PATCH 02/64] Added ability to disconnect client processes
---
lib/teiserver/connections/client_server.ex | 12 ++++++++++++
lib/teiserver/connections/libs/client_lib.ex | 13 ++++++++++++-
lib/teiserver/contexts/connections.ex | 4 ++++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index d3725fb13..de97d0272 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -82,6 +82,18 @@ defmodule Teiserver.Connections.ClientServer do
{:noreply, new_state}
end
+ # Unlike with a normal :DOWN message, this is one where the person purposefully disconnects
+ # and thus we don't want to keep the client alive
+ def handle_cast({:purposeful_disconnect, pid}, state) do
+ new_state = lose_connection(pid, state)
+ if new_state.client.connected? do
+ {:noreply, new_state}
+ else
+ ClientLib.stop_client_server(state.user_id)
+ {:noreply, new_state}
+ end
+ end
+
@impl true
def handle_info(:heartbeat, %State{client: %{connected?: false}} = state) do
seconds_since_disconnect = Timex.diff(Timex.now(), state.client.last_disconnected, :second)
diff --git a/lib/teiserver/connections/libs/client_lib.ex b/lib/teiserver/connections/libs/client_lib.ex
index 9c270fe51..84b20eddb 100644
--- a/lib/teiserver/connections/libs/client_lib.ex
+++ b/lib/teiserver/connections/libs/client_lib.ex
@@ -162,7 +162,7 @@ defmodule Teiserver.Connections.ClientLib do
end
@doc """
-
+ Sends a `:disconnect` message to every connection for the client and then stops the ClientServer
"""
@spec disconnect_user(Teiserver.user_id()) :: :ok
def disconnect_user(user_id) do
@@ -175,6 +175,17 @@ defmodule Teiserver.Connections.ClientLib do
stop_client_server(user_id)
end
+ @doc """
+ Sends the calling process a `:disconnect` message and informs the ClientServer it is
+ an intentional disconnect. This means if it is the last connection for the client the ClientServer
+ will stop itself rather than going into a disconnected state.
+ """
+ @spec disconnect_single_connection(Teiserver.user_id()) :: :ok
+ def disconnect_single_connection(user_id) do
+ cast_client(user_id, {:purposeful_disconnect, self()})
+ send(self(), :disconnect)
+ end
+
# Process stuff
@doc false
@spec start_client_server(Client.t()) :: pid()
diff --git a/lib/teiserver/contexts/connections.ex b/lib/teiserver/contexts/connections.ex
index 870994160..73b5f390e 100644
--- a/lib/teiserver/contexts/connections.ex
+++ b/lib/teiserver/contexts/connections.ex
@@ -59,6 +59,10 @@ defmodule Teiserver.Connections do
@spec disconnect_user(Teiserver.user_id()) :: :ok
defdelegate disconnect_user(user_id), to: ClientLib
+ @doc section: :client
+ @spec disconnect_single_connection(Teiserver.user_id()) :: :ok
+ defdelegate disconnect_single_connection(user_id), to: ClientLib
+
@doc false
@spec client_exists?(Teiserver.user_id()) :: pid() | boolean
defdelegate client_exists?(user_id), to: ClientLib
From 3e49abac7baac9bfd114198a571dab8382e58b18 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 1 Apr 2024 14:58:25 +0100
Subject: [PATCH 03/64] Added caches
---
lib/teiserver/account/libs/user_lib.ex | 22 ++++++++++++-
lib/teiserver/application.ex | 31 ++++++++++++++++++-
.../system/servers/cluster_member_server.ex | 1 -
mix.exs | 1 +
mix.lock | 5 +++
5 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index 459849f8c..4d9c116d5 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -73,6 +73,8 @@ defmodule Teiserver.Account.UserLib do
@doc """
Gets a single user by their user_id. If no user is found, returns `nil`.
+ Makes use of a Cache
+
## Examples
iex> get_user_by_id(123)
@@ -83,8 +85,26 @@ defmodule Teiserver.Account.UserLib do
"""
@spec get_user_by_id(Teiserver.user_id()) :: User.t() | nil
def get_user_by_id(user_id) do
+ case Cachex.get(:ts_user_by_user_id_cache, user_id) do
+ {:ok, nil} ->
+ user = do_get_user_by_id(user_id)
+ Cachex.put(:ts_user_by_user_id_cache, user_id, user)
+ user
+ {:ok, value} ->
+ value
+ end
+
+ # Cachex.fetch(:ts_user_by_user_id_cache, user_id, fn ->
+ # user = do_get_user_by_id(user_id)
+
+ # {:commit, user, ttl: :timer.minutes(15)}
+ # end)
+ end
+
+ @spec do_get_user_by_id(Teiserver.user_id()) :: User.t() | nil
+ defp do_get_user_by_id(user_id) do
UserQueries.user_query(id: user_id, limit: 1)
- |> Teiserver.Repo.one()
+ |> Teiserver.Repo.one()
end
@doc """
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index 92ccdbf62..be702a9db 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -27,7 +27,7 @@ defmodule Teiserver.Application do
# Lobbies
{DynamicSupervisor, strategy: :one_for_one, name: Teiserver.LobbySupervisor},
{Horde.Registry, [keys: :unique, members: :auto, name: Teiserver.LobbyRegistry]},
- {Registry, [keys: :unique, members: :auto, name: Teiserver.LocalLobbyRegistry]}
+ {Registry, [keys: :unique, members: :auto, name: Teiserver.LocalLobbyRegistry]},
# Matchmaking
# {DynamicSupervisor, strategy: :one_for_one, name: Teiserver.MMSupervisor},
@@ -35,6 +35,21 @@ defmodule Teiserver.Application do
# {Horde.Registry, [keys: :unique, members: :auto, name: Teiserver.MMMatchRegistry]},
# {Registry, [keys: :unique, members: :auto, name: Teiserver.LocalMMQueueRegistry]},
# {Registry, [keys: :unique, members: :auto, name: Teiserver.LocalMMMatchRegistry]}
+
+ # DB Lookup caches
+ add_cache(:ts_user_by_user_id_cache, [ttl: :timer.seconds(1)]),
+
+ # Telemetry caches
+ add_cache(:ts_property_types_cache),
+ add_cache(:ts_simple_client_event_types_cache),
+ add_cache(:ts_complex_client_event_types_cache),
+ add_cache(:ts_simple_lobby_event_types_cache),
+ add_cache(:ts_complex_lobby_event_types_cache),
+ add_cache(:ts_simple_match_event_types_cache),
+ add_cache(:ts_complex_match_event_types_cache),
+ add_cache(:ts_simple_server_event_types_cache),
+ add_cache(:ts_complex_server_event_types_cache),
+ add_cache(:ts_account_smurf_key_types),
]
opts = [strategy: :one_for_one, name: __MODULE__]
@@ -46,4 +61,18 @@ defmodule Teiserver.Application do
start_result
end
+
+ @spec add_cache(atom) :: map()
+ @spec add_cache(atom, list) :: map()
+ defp add_cache(name, opts \\ []) when is_atom(name) do
+ %{
+ id: name,
+ start:
+ {Cachex, :start_link,
+ [
+ name,
+ opts
+ ]}
+ }
+ end
end
diff --git a/lib/teiserver/system/servers/cluster_member_server.ex b/lib/teiserver/system/servers/cluster_member_server.ex
index c9d216dd5..e2273d32c 100644
--- a/lib/teiserver/system/servers/cluster_member_server.ex
+++ b/lib/teiserver/system/servers/cluster_member_server.ex
@@ -70,7 +70,6 @@ defmodule Teiserver.System.ClusterManager do
{:noreply, :running}
else
- Logger.warning("")
Process.send_after(self(), {:startup, start_count + 1}, @startup_delay * start_count)
{:noreply, :pending}
end
diff --git a/mix.exs b/mix.exs
index 179d08267..81392b4c6 100644
--- a/mix.exs
+++ b/mix.exs
@@ -233,6 +233,7 @@ defmodule Teiserver.MixProject do
{:typedstruct, "~> 0.5.2", runtime: false},
{:horde, "~> 0.9"},
{:uuid, "~> 1.1"},
+ {:cachex, "~> 3.6"},
# Dev and Test stuff
{:ex_doc, "~> 0.31", only: :dev, runtime: false},
diff --git a/mix.lock b/mix.lock
index e56e59cf5..4e9d1d9e3 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,6 +1,7 @@
%{
"argon2_elixir": {:hex, :argon2_elixir, "3.2.1", "f47740bf9f2a39ffef79ba48eb25dea2ee37bcc7eadf91d49615591d1a6fce1a", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "a813b78217394530b5fcf4c8070feee43df03ffef938d044019169c766315690"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
+ "cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
@@ -14,6 +15,7 @@
"ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
"elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
+ "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
"ex_doc": {:hex, :ex_doc, "0.31.0", "06eb1dfd787445d9cab9a45088405593dd3bb7fe99e097eaa71f37ba80c7a676", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5350cafa6b7f77bdd107aa2199fe277acf29d739aba5aee7e865fc680c62a110"},
"excoveralls": {:hex, :excoveralls, "0.15.3", "54bb54043e1cf5fe431eb3db36b25e8fd62cf3976666bafe491e3fa5e29eba47", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8eb5d8134d84c327685f7bb8f1db4147f1363c3c9533928234e496e3070114e"},
"expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"},
@@ -24,6 +26,7 @@
"horde": {:hex, :horde, "0.9.0", "522342bd7149aeed453c97692a8bca9cf7c9368c5a489afd802e575dc8df54a6", [:mix], [{:delta_crdt, "~> 0.6.2", [hex: :delta_crdt, repo: "hexpm", optional: false]}, {:libring, "~> 1.4", [hex: :libring, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 0.5.0 or ~> 1.0", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "fae11e5bc9c980038607d0c3338cdf7f97124a5d5382fd4b6fb6beaab8e214fe"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
+ "jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
"libring": {:hex, :libring, "1.6.0", "d5dca4bcb1765f862ab59f175b403e356dec493f565670e0bacc4b35e109ce0d", [:mix], [], "hexpm", "5e91ece396af4bce99953d49ee0b02f698cd38326d93cd068361038167484319"},
"makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
@@ -35,6 +38,7 @@
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"},
+ "sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
@@ -44,5 +48,6 @@
"typedstruct": {:hex, :typedstruct, "0.5.2", "a317be3ddfd020da09e1af8418b2653449541836eb5ff23bfdc642a5a4adcc59", [:make, :mix], [], "hexpm", "f9343bc65be73a550194e509c3110be966cb005bb7cba41614f29052e5aa408d"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
+ "unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
"uuid": {:hex, :uuid, "1.1.8", "e22fc04499de0de3ed1116b770c7737779f226ceefa0badb3592e64d5cfb4eb9", [:mix], [], "hexpm", "c790593b4c3b601f5dc2378baae7efaf5b3d73c4c6456ba85759905be792f2ac"},
}
From e80033c597aaac874c3175336f5a3ff02dea09fc Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 2 Apr 2024 20:02:11 +0100
Subject: [PATCH 04/64] Added cluster cache invalidation function
---
lib/teiserver.ex | 5 ++
lib/teiserver/application.ex | 6 ++-
.../system/servers/cache_cluster_server.ex | 47 +++++++++++++++++++
3 files changed, 57 insertions(+), 1 deletion(-)
create mode 100644 lib/teiserver/system/servers/cache_cluster_server.ex
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 3d873ed18..47639c741 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -89,4 +89,9 @@ defmodule Teiserver do
@doc false
@spec unsubscribe(String.t()) :: :ok
defdelegate unsubscribe(topic), to: PubSubHelper
+
+ # Cluster cache delegation
+ @spec invalidate_cache(atom, any) :: :ok
+ defdelegate invalidate_cache(table, key_or_keys), to: Teiserver.System.CacheClusterServer
+
end
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index be702a9db..23b9ace00 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -8,6 +8,7 @@ defmodule Teiserver.Application do
children = [
{Phoenix.PubSub, name: Teiserver.PubSub},
Teiserver.System.ClusterManagerSupervisor,
+ Teiserver.System.CacheClusterServer,
# Servers not part of the general slew of things
{Registry, [keys: :unique, members: :auto, name: Teiserver.ServerRegistry]},
@@ -37,7 +38,10 @@ defmodule Teiserver.Application do
# {Registry, [keys: :unique, members: :auto, name: Teiserver.LocalMMMatchRegistry]}
# DB Lookup caches
- add_cache(:ts_user_by_user_id_cache, [ttl: :timer.seconds(1)]),
+ add_cache(:ts_server_setting_cache, [ttl: :timer.minutes(1)]),
+ add_cache(:ts_user_setting_cache, [ttl: :timer.minutes(1)]),
+
+ add_cache(:ts_user_by_user_id_cache, [ttl: :timer.minutes(5)]),
# Telemetry caches
add_cache(:ts_property_types_cache),
diff --git a/lib/teiserver/system/servers/cache_cluster_server.ex b/lib/teiserver/system/servers/cache_cluster_server.ex
new file mode 100644
index 000000000..78a1830c9
--- /dev/null
+++ b/lib/teiserver/system/servers/cache_cluster_server.ex
@@ -0,0 +1,47 @@
+defmodule Teiserver.System.CacheClusterServer do
+ @moduledoc """
+ Allows us to track cache invalidation across a cluster.
+ """
+ use GenServer
+ alias Phoenix.PubSub
+
+ @spec start_link(list) :: :ignore | {:error, any} | {:ok, pid}
+ def start_link(opts \\ []) do
+ GenServer.start_link(__MODULE__, nil, opts)
+ end
+
+ @spec invalidate_cache(atom, any) :: :ok
+ def invalidate_cache(table, key_or_keys) do
+ key_or_keys
+ |> List.wrap()
+ |> Enum.each(fn key ->
+ Cachex.del(table, key)
+ end)
+
+ Phoenix.PubSub.broadcast(
+ Teiserver.PubSub,
+ "cache_cluster",
+ {:cache_cluster, :delete, Node.self(), table, key_or_keys}
+ )
+ end
+
+ @impl true
+ def handle_info({:cache_cluster, :delete, from_node, table, key_or_keys}, state) do
+ if from_node != Node.self() do
+ key_or_keys
+ |> List.wrap
+ |> Enum.each(fn key ->
+ Cachex.del(table, key)
+ end)
+ end
+
+ {:noreply, state}
+ end
+
+ @impl true
+ @spec init(any) :: {:ok, %{}}
+ def init(_) do
+ :ok = PubSub.subscribe(Teiserver.PubSub, "cache_cluster")
+ {:ok, %{}}
+ end
+end
From 71cc719a712e6c2054fdadf79587dfbe3118704b Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 2 Apr 2024 20:47:05 +0100
Subject: [PATCH 05/64] Added cache clearing when users are updated
---
lib/teiserver/account/libs/user_lib.ex | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index 4d9c116d5..40e74c2e7 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -194,8 +194,18 @@ defmodule Teiserver.Account.UserLib do
def update_user(%User{} = user, attrs) do
User.changeset(user, attrs, :full)
|> Teiserver.Repo.update()
+ |> maybe_decache_user()
end
+ # Clears the cache for a user after a successful database option
+ @spec maybe_decache_user(any()) :: any()
+ defp maybe_decache_user({:ok, user}) do
+ Teiserver.invalidate_cache(:ts_user_by_user_id_cache, user.id)
+ {:ok, user}
+ end
+
+ defp maybe_decache_user(v), do: v
+
@doc """
Updates a user's password.
@@ -212,6 +222,7 @@ defmodule Teiserver.Account.UserLib do
def update_password(%User{} = user, attrs) do
User.changeset(user, attrs, :change_password)
|> Teiserver.Repo.update()
+ |> maybe_decache_user()
end
@doc """
@@ -230,6 +241,7 @@ defmodule Teiserver.Account.UserLib do
def update_limited_user(%User{} = user, attrs) do
User.changeset(user, attrs, :user_form)
|> Teiserver.Repo.update()
+ |> maybe_decache_user()
end
@doc """
@@ -247,6 +259,7 @@ defmodule Teiserver.Account.UserLib do
@spec delete_user(User.t()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def delete_user(%User{} = user) do
Teiserver.Repo.delete(user)
+ |> maybe_decache_user()
end
@doc """
From 0a8ed43e97e729657341038c9d68e66be86096f9 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 3 Apr 2024 18:00:20 +0100
Subject: [PATCH 06/64] Added user and server settings
---
CHANGELOG.md | 1 +
lib/teiserver/account/libs/user_lib.ex | 6 -
lib/teiserver/api.ex | 19 ++
lib/teiserver/application.ex | 2 +
lib/teiserver/contexts/settings.ex | 114 ++++++++----
.../settings/libs/server_setting_lib.ex | 119 ++++++++++---
.../settings/libs/server_setting_type_lib.ex | 58 +++++++
.../settings/libs/user_setting_lib.ex | 136 +++++++++++----
.../settings/libs/user_setting_type_lib.ex | 58 +++++++
.../queries/server_setting_queries.ex | 63 +++----
.../settings/queries/user_setting_queries.ex | 44 +++--
.../settings/schemas/server_setting.ex | 6 +-
.../settings/schemas/server_setting_type.ex | 43 +++++
.../settings/schemas/user_setting.ex | 2 +
.../settings/schemas/user_setting_type.ex | 45 +++++
test/settings/server_setting_queries_test.exs | 53 ++++++
test/settings/server_setting_test.exs | 157 +++++++++++++++++
test/settings/server_setting_type_test.exs | 69 ++++++++
test/settings/user_setting_queries_test.exs | 55 ++++++
test/settings/user_setting_test.exs | 164 ++++++++++++++++++
test/settings/user_setting_type_test.exs | 69 ++++++++
test/support/fixtures/settings_fixtures.ex | 90 ++++++++++
22 files changed, 1224 insertions(+), 149 deletions(-)
create mode 100644 lib/teiserver/settings/libs/server_setting_type_lib.ex
create mode 100644 lib/teiserver/settings/libs/user_setting_type_lib.ex
create mode 100644 lib/teiserver/settings/schemas/server_setting_type.ex
create mode 100644 lib/teiserver/settings/schemas/user_setting_type.ex
create mode 100644 test/settings/server_setting_queries_test.exs
create mode 100644 test/settings/server_setting_test.exs
create mode 100644 test/settings/server_setting_type_test.exs
create mode 100644 test/settings/user_setting_queries_test.exs
create mode 100644 test/settings/user_setting_test.exs
create mode 100644 test/settings/user_setting_type_test.exs
create mode 100644 test/support/fixtures/settings_fixtures.ex
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d46fa99cf..ebc554b98 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
## v0.0.5
- Swapped `team_colour` for `player_colour`
- Refactored the client update process
+- Added User and Server runtime settings
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index 40e74c2e7..fa04f3331 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -93,12 +93,6 @@ defmodule Teiserver.Account.UserLib do
{:ok, value} ->
value
end
-
- # Cachex.fetch(:ts_user_by_user_id_cache, user_id, fn ->
- # user = do_get_user_by_id(user_id)
-
- # {:commit, user, ttl: :timer.minutes(15)}
- # end)
end
@spec do_get_user_by_id(Teiserver.user_id()) :: User.t() | nil
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index 5e87faeb1..48a123e4f 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -253,4 +253,23 @@ defmodule Teiserver.Api do
@doc section: :direct_message
@spec unsubscribe_from_user_messaging(User.id() | User.t()) :: :ok
defdelegate unsubscribe_from_user_messaging(user_or_user_id), to: DirectMessageLib
+
+ # Settings
+ alias Teiserver.Settings.{ServerSettingLib, UserSettingLib}
+
+ @doc section: :server_setting
+ @spec get_server_setting_value(String.t()) :: String.t() | integer() | boolean() | nil
+ defdelegate get_server_setting_value(key), to: ServerSettingLib
+
+ @doc section: :server_setting
+ @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ defdelegate set_server_setting_value(key, value), to: ServerSettingLib
+
+ @doc section: :user_setting
+ @spec get_user_setting_value(Teiserver.user_id(), String.t()) :: String.t() | integer() | boolean() | nil
+ defdelegate get_user_setting_value(user_id, key), to: UserSettingLib
+
+ @doc section: :user_setting
+ @spec set_user_setting_value(Teiserver.user_id(), String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ defdelegate set_user_setting_value(user_id, key, value), to: UserSettingLib
end
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index 23b9ace00..6afb65d77 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -38,7 +38,9 @@ defmodule Teiserver.Application do
# {Registry, [keys: :unique, members: :auto, name: Teiserver.LocalMMMatchRegistry]}
# DB Lookup caches
+ add_cache(:ts_server_setting_type_store),
add_cache(:ts_server_setting_cache, [ttl: :timer.minutes(1)]),
+ add_cache(:ts_user_setting_type_store),
add_cache(:ts_user_setting_cache, [ttl: :timer.minutes(1)]),
add_cache(:ts_user_by_user_id_cache, [ttl: :timer.minutes(5)]),
diff --git a/lib/teiserver/contexts/settings.ex b/lib/teiserver/contexts/settings.ex
index e402b679a..4b1718bc9 100644
--- a/lib/teiserver/contexts/settings.ex
+++ b/lib/teiserver/contexts/settings.ex
@@ -5,85 +5,133 @@ defmodule Teiserver.Settings do
- `Teiserver.Settings.UserSetting`
"""
+ # ServerSettingType
+ alias Teiserver.Settings.{ServerSettingType, ServerSettingTypeLib}
+
+ @doc section: :server_setting_type
+ @spec list_server_setting_types([String.t()]) :: [ServerSettingType.t()]
+ defdelegate list_server_setting_types(keys), to: ServerSettingTypeLib
+
+ @doc section: :server_setting_type
+ @spec list_server_setting_type_keys() :: [String.t()]
+ defdelegate list_server_setting_type_keys(), to: ServerSettingTypeLib
+
+ @doc section: :server_setting_type
+ @spec get_server_setting_type(String.t()) :: ServerSettingType.t() | nil
+ defdelegate get_server_setting_type(key), to: ServerSettingTypeLib
+
+ @doc section: :server_setting_type
+ @spec add_server_setting_type(map()) :: {:ok, ServerSettingType.t()} | {:error, String.t()}
+ defdelegate add_server_setting_type(args), to: ServerSettingTypeLib
+
# ServerSettings
alias Teiserver.Settings.{ServerSetting, ServerSettingLib, ServerSettingQueries}
@doc false
- @spec server_setting_query(list) :: Ecto.Query.t()
+ @spec server_setting_query(Teiserver.query_args()) :: Ecto.Query.t()
defdelegate server_setting_query(args), to: ServerSettingQueries
@doc section: :server_setting
- @spec list_server_settings() :: [ServerSetting.t()]
- defdelegate list_server_settings(), to: ServerSettingLib
-
- @doc section: :server_setting
- @spec list_server_settings(list) :: [ServerSetting.t()]
+ @spec list_server_settings(Teiserver.query_args()) :: [ServerSetting.t]
defdelegate list_server_settings(args), to: ServerSettingLib
@doc section: :server_setting
- @spec get_server_setting!(non_neg_integer(), list) :: ServerSetting.t()
+ @spec get_server_setting!(ServerSetting.key()) :: ServerSetting.t
+ @spec get_server_setting!(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t
defdelegate get_server_setting!(server_setting_id, query_args \\ []), to: ServerSettingLib
@doc section: :server_setting
- @spec get_server_setting(String.t(), list) :: ServerSetting.t() | nil
- defdelegate get_server_setting(key, query_args \\ []), to: ServerSettingLib
+ @spec get_server_setting(ServerSetting.key()) :: ServerSetting.t | nil
+ @spec get_server_setting(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t | nil
+ defdelegate get_server_setting(server_setting_id, query_args \\ []), to: ServerSettingLib
@doc section: :server_setting
- @spec create_server_setting(map) :: {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_server_setting(attrs \\ %{}), to: ServerSettingLib
+ @spec create_server_setting(map) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_server_setting(attrs), to: ServerSettingLib
@doc section: :server_setting
- @spec update_server_setting(ServerSetting, map) ::
- {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
+ @spec update_server_setting(ServerSetting, map) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t()}
defdelegate update_server_setting(server_setting, attrs), to: ServerSettingLib
@doc section: :server_setting
- @spec delete_server_setting(ServerSetting.t()) ::
- {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_setting(ServerSetting.t) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t()}
defdelegate delete_server_setting(server_setting), to: ServerSettingLib
@doc section: :server_setting
- @spec change_server_setting(ServerSetting.t(), map) :: Ecto.Changeset.t()
+ @spec change_server_setting(ServerSetting.t) :: Ecto.Changeset.t()
+ @spec change_server_setting(ServerSetting.t, map) :: Ecto.Changeset.t()
defdelegate change_server_setting(server_setting, attrs \\ %{}), to: ServerSettingLib
+ @doc section: :server_setting
+ @spec get_server_setting_value(String.t()) :: String.t() | integer() | boolean() | nil
+ defdelegate get_server_setting_value(key), to: ServerSettingLib
+
+ @doc section: :server_setting
+ @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ defdelegate set_server_setting_value(key, value), to: ServerSettingLib
+
+ # UserSettingType
+ alias Teiserver.Settings.{UserSettingType, UserSettingTypeLib}
+
+ @doc section: :user_setting_type
+ @spec list_user_setting_types([String.t()]) :: [UserSettingType.t()]
+ defdelegate list_user_setting_types(keys), to: UserSettingTypeLib
+
+ @doc section: :user_setting_type
+ @spec list_user_setting_type_keys() :: [String.t()]
+ defdelegate list_user_setting_type_keys(), to: UserSettingTypeLib
+
+ @doc section: :user_setting_type
+ @spec get_user_setting_type(String.t()) :: UserSettingType.t() | nil
+ defdelegate get_user_setting_type(key), to: UserSettingTypeLib
+
+ @doc section: :user_setting_type
+ @spec add_user_setting_type(map()) :: {:ok, UserSettingType.t()} | {:error, String.t()}
+ defdelegate add_user_setting_type(args), to: UserSettingTypeLib
+
+
+
# UserSettings
alias Teiserver.Settings.{UserSetting, UserSettingLib, UserSettingQueries}
@doc false
- @spec user_setting_query(list) :: Ecto.Query.t()
+ @spec user_setting_query(Teiserver.query_args()) :: Ecto.Query.t()
defdelegate user_setting_query(args), to: UserSettingQueries
@doc section: :user_setting
- @spec list_user_settings() :: [UserSetting.t()]
- defdelegate list_user_settings(), to: UserSettingLib
-
- @doc section: :user_setting
- @spec list_user_settings(list) :: [UserSetting.t()]
+ @spec list_user_settings(Teiserver.query_args()) :: [UserSetting.t]
defdelegate list_user_settings(args), to: UserSettingLib
@doc section: :user_setting
- @spec get_user_setting!(non_neg_integer(), list) :: UserSetting.t()
- defdelegate get_user_setting!(user_setting_id, query_args \\ []), to: UserSettingLib
+ @spec get_user_setting!(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t
+ defdelegate get_user_setting!(user_id, key), to: UserSettingLib
@doc section: :user_setting
- @spec get_user_setting(non_neg_integer(), list) :: UserSetting.t() | nil
- defdelegate get_user_setting(user_setting_id, query_args \\ []), to: UserSettingLib
+ @spec get_user_setting(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t | nil
+ defdelegate get_user_setting(user_id, key), to: UserSettingLib
@doc section: :user_setting
- @spec create_user_setting(map) :: {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_user_setting(attrs \\ %{}), to: UserSettingLib
+ @spec create_user_setting(map) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_user_setting(attrs), to: UserSettingLib
@doc section: :user_setting
- @spec update_user_setting(UserSetting, map) ::
- {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
+ @spec update_user_setting(UserSetting.t, map) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t()}
defdelegate update_user_setting(user_setting, attrs), to: UserSettingLib
@doc section: :user_setting
- @spec delete_user_setting(UserSetting.t()) ::
- {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
+ @spec delete_user_setting(UserSetting.t) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t()}
defdelegate delete_user_setting(user_setting), to: UserSettingLib
@doc section: :user_setting
- @spec change_user_setting(UserSetting.t(), map) :: Ecto.Changeset.t()
+ @spec change_user_setting(UserSetting.t) :: Ecto.Changeset.t()
+ @spec change_user_setting(UserSetting.t, map) :: Ecto.Changeset.t()
defdelegate change_user_setting(user_setting, attrs \\ %{}), to: UserSettingLib
+
+ @doc section: :user_setting
+ @spec get_user_setting_value(Teiserver.user_id(), String.t()) :: String.t() | integer() | boolean() | nil
+ defdelegate get_user_setting_value(user_id, key), to: UserSettingLib
+
+ @doc section: :user_setting
+ @spec set_user_setting_value(Teiserver.user_id(), String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ defdelegate set_user_setting_value(user_id, key, value), to: UserSettingLib
end
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index 2b1ae2817..cd727bd02 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -1,9 +1,9 @@
defmodule Teiserver.Settings.ServerSettingLib do
@moduledoc """
- Library of server_setting related functions.
+ TODO: Library of server_setting related functions.
"""
use TeiserverMacros, :library
- alias Teiserver.Settings.{ServerSetting, ServerSettingQueries}
+ alias Teiserver.Settings.{ServerSetting, ServerSettingQueries, ServerSettingTypeLib}
@doc """
Returns the list of server_settings.
@@ -14,11 +14,11 @@ defmodule Teiserver.Settings.ServerSettingLib do
[%ServerSetting{}, ...]
"""
- @spec list_server_settings(list) :: list
- def list_server_settings(query_args \\ []) do
+ @spec list_server_settings(Teiserver.query_args()) :: [ServerSetting.t()]
+ def list_server_settings(query_args) do
query_args
|> ServerSettingQueries.server_setting_query()
- |> Teiserver.Repo.all()
+ |> Repo.all()
end
@doc """
@@ -28,18 +28,19 @@ defmodule Teiserver.Settings.ServerSettingLib do
## Examples
- iex> get_server_setting!(123)
+ iex> get_server_setting!("key123")
%ServerSetting{}
- iex> get_server_setting!(456)
+ iex> get_server_setting!("key456")
** (Ecto.NoResultsError)
"""
- @spec get_server_setting!(String.t()) :: ServerSetting.t()
+ @spec get_server_setting!(ServerSetting.key()) :: ServerSetting.t()
+ @spec get_server_setting!(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t()
def get_server_setting!(key, query_args \\ []) do
(query_args ++ [key: key])
|> ServerSettingQueries.server_setting_query()
- |> Teiserver.Repo.one!()
+ |> Repo.one!()
end
@doc """
@@ -49,20 +50,94 @@ defmodule Teiserver.Settings.ServerSettingLib do
## Examples
- iex> get_server_setting(123)
+ iex> get_server_setting("key123")
%ServerSetting{}
- iex> get_server_setting(456)
+ iex> get_server_setting("key456")
nil
"""
- @spec get_server_setting(non_neg_integer(), list) :: ServerSetting.t() | nil
+ @spec get_server_setting(ServerSetting.key()) :: ServerSetting.t() | nil
+ @spec get_server_setting(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t() | nil
def get_server_setting(key, query_args \\ []) do
(query_args ++ [key: key])
|> ServerSettingQueries.server_setting_query()
- |> Teiserver.Repo.one()
+ |> Repo.one
end
+ @doc """
+ Gets the value of a server_setting.
+
+ Returns nil if the ServerSetting does not exist.
+
+ ## Examples
+
+ iex> get_server_setting_value("key123")
+ "value"
+
+ iex> get_server_setting_value("key456")
+ nil
+
+ """
+ @spec get_server_setting_value(ServerSetting.key()) :: String.t() | non_neg_integer() | boolean() | nil
+ def get_server_setting_value(key) do
+ case Cachex.get(:ts_server_setting_cache, key) do
+ {:ok, nil} ->
+ setting = get_server_setting(key, [limit: 1])
+ type = ServerSettingTypeLib.get_server_setting_type(key)
+
+ value = case setting do
+ nil ->
+ type.default
+
+ %{value: nil} ->
+ type.default
+
+ %{value: v} ->
+ v
+ end
+
+ value = convert_from_raw_value(value, type.type)
+
+ Cachex.put(:ts_server_setting_cache, key, value)
+ value
+ {:ok, value} ->
+ value
+ end
+ end
+
+ @spec convert_from_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
+ defp convert_from_raw_value(raw_value, "string"), do: raw_value
+ defp convert_from_raw_value(raw_value, "integer"), do: String.to_integer(raw_value)
+ defp convert_from_raw_value(raw_value, "boolean"), do: raw_value == "t"
+ defp convert_from_raw_value(_, _), do: nil
+
+ @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ def set_server_setting_value(key, value) do
+ type = ServerSettingTypeLib.get_server_setting_type(key)
+ raw_value = convert_to_raw_value(value, type.type)
+
+ case get_server_setting(key) do
+ nil ->
+ {:ok, _} = create_server_setting(%{
+ key: key,
+ value: raw_value
+ })
+ :ok
+
+ server_setting ->
+ {:ok, _} = update_server_setting(server_setting, %{"value" => raw_value})
+ Teiserver.invalidate_cache(:ts_server_setting_cache, key)
+ :ok
+ end
+ end
+
+ @spec convert_to_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
+ defp convert_to_raw_value(value, "string"), do: value
+ defp convert_to_raw_value(value, "integer"), do: to_string(value)
+ defp convert_to_raw_value(value, "boolean"), do: (if value, do: "t", else: "f")
+ defp convert_to_raw_value(_, _), do: nil
+
@doc """
Creates a server_setting.
@@ -75,11 +150,11 @@ defmodule Teiserver.Settings.ServerSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_server_setting(map) :: {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
- def create_server_setting(attrs \\ %{}) do
+ @spec create_server_setting(map) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t}
+ def create_server_setting(attrs) do
%ServerSetting{}
|> ServerSetting.changeset(attrs)
- |> Teiserver.Repo.insert()
+ |> Repo.insert()
end
@doc """
@@ -94,12 +169,11 @@ defmodule Teiserver.Settings.ServerSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_server_setting(ServerSetting.t(), map) ::
- {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
+ @spec update_server_setting(ServerSetting.t, map) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t}
def update_server_setting(%ServerSetting{} = server_setting, attrs) do
server_setting
|> ServerSetting.changeset(attrs)
- |> Teiserver.Repo.update()
+ |> Repo.update()
end
@doc """
@@ -114,10 +188,9 @@ defmodule Teiserver.Settings.ServerSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_server_setting(ServerSetting.t()) ::
- {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_setting(ServerSetting.t) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t}
def delete_server_setting(%ServerSetting{} = server_setting) do
- Teiserver.Repo.delete(server_setting)
+ Repo.delete(server_setting)
end
@doc """
@@ -129,7 +202,7 @@ defmodule Teiserver.Settings.ServerSettingLib do
%Ecto.Changeset{data: %ServerSetting{}}
"""
- @spec change_server_setting(ServerSetting.t(), map) :: Ecto.Changeset.t()
+ @spec change_server_setting(ServerSetting.t, map) :: Ecto.Changeset.t
def change_server_setting(%ServerSetting{} = server_setting, attrs \\ %{}) do
ServerSetting.changeset(server_setting, attrs)
end
diff --git a/lib/teiserver/settings/libs/server_setting_type_lib.ex b/lib/teiserver/settings/libs/server_setting_type_lib.ex
new file mode 100644
index 000000000..1dd2c9685
--- /dev/null
+++ b/lib/teiserver/settings/libs/server_setting_type_lib.ex
@@ -0,0 +1,58 @@
+defmodule Teiserver.Settings.ServerSettingTypeLib do
+ @moduledoc """
+ A set of functions for working with `ServerSettingType` objects.
+ """
+
+ @cache_table :ts_server_setting_type_store
+
+ alias Teiserver.Settings.ServerSettingType
+
+ @spec list_server_setting_types([String.t()]) :: [ServerSettingType.t()]
+ def list_server_setting_types(keys) do
+ keys
+ |> Enum.map(&get_server_setting_type/1)
+ end
+
+ @spec list_server_setting_type_keys() :: [String.t()]
+ def list_server_setting_type_keys() do
+ {:ok, v} = Cachex.get(@cache_table, "_all")
+ (v || [])
+ end
+
+ @spec get_server_setting_type(String.t()) :: ServerSettingType.t() | nil
+ def get_server_setting_type(key) do
+ {:ok, v} = Cachex.get(@cache_table, key)
+ v
+ end
+
+ @spec add_server_setting_type(map()) :: {:ok, ServerSettingType.t()} | {:error, String.t()}
+ def add_server_setting_type(args) do
+ if not Enum.member?(~w(string integer boolean), args.type) do
+ raise "Invalid type, must be one of `string`, `integer` or `boolean`"
+ end
+
+ existing_keys = list_server_setting_type_keys()
+ if Enum.member?(existing_keys, args.key) do
+ raise "Key #{args.key} already exists"
+ end
+
+ type = %ServerSettingType{
+ key: args.key,
+ label: args.label,
+ section: args.section,
+ type: args.type,
+
+ permissions: Map.get(args, :permissions),
+ choices: Map.get(args, :choices),
+ default: Map.get(args, :default),
+ description: Map.get(args, :description)
+ }
+
+ # Update our list of all keys
+ new_all = [type.key | existing_keys]
+ Cachex.put(@cache_table, "_all", new_all)
+
+ Cachex.put(@cache_table, type.key, type)
+ {:ok, type}
+ end
+end
diff --git a/lib/teiserver/settings/libs/user_setting_lib.ex b/lib/teiserver/settings/libs/user_setting_lib.ex
index 871011d4e..c40120480 100644
--- a/lib/teiserver/settings/libs/user_setting_lib.ex
+++ b/lib/teiserver/settings/libs/user_setting_lib.ex
@@ -1,9 +1,9 @@
defmodule Teiserver.Settings.UserSettingLib do
@moduledoc """
- Library of user_setting related functions.
+ TODO: Library of user_setting related functions.
"""
use TeiserverMacros, :library
- alias Teiserver.Settings.{UserSetting, UserSettingQueries}
+ alias Teiserver.Settings.{UserSetting, UserSettingQueries, UserSettingTypeLib}
@doc """
Returns the list of user_settings.
@@ -14,11 +14,11 @@ defmodule Teiserver.Settings.UserSettingLib do
[%UserSetting{}, ...]
"""
- @spec list_user_settings(Teiserver.query_args()) :: list
- def list_user_settings(query_args \\ []) do
+ @spec list_user_settings(Teiserver.query_args()) :: [UserSetting.t()]
+ def list_user_settings(query_args) do
query_args
|> UserSettingQueries.user_setting_query()
- |> Teiserver.Repo.all()
+ |> Repo.all()
end
@doc """
@@ -28,18 +28,17 @@ defmodule Teiserver.Settings.UserSettingLib do
## Examples
- iex> get_user_setting!(123)
+ iex> get_user_setting!("userid", "key123")
%UserSetting{}
- iex> get_user_setting!(456)
+ iex> get_user_setting!("userid", "key456")
** (Ecto.NoResultsError)
"""
- @spec get_user_setting!(non_neg_integer()) :: UserSetting.t()
- def get_user_setting!(user_setting_id, query_args \\ []) do
- (query_args ++ [id: user_setting_id])
- |> UserSettingQueries.user_setting_query()
- |> Teiserver.Repo.one!()
+ @spec get_user_setting!(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t
+ def get_user_setting!(user_id, key) do
+ UserSettingQueries.user_setting_query(where: [key: key, user_id: user_id], limit: 1)
+ |> Repo.one!()
end
@doc """
@@ -49,20 +48,97 @@ defmodule Teiserver.Settings.UserSettingLib do
## Examples
- iex> get_user_setting(123)
+ iex> get_user_setting("userid", "key123")
%UserSetting{}
- iex> get_user_setting(456)
+ iex> get_user_setting("userid", "key456")
nil
"""
- @spec get_user_setting(non_neg_integer(), list) :: UserSetting.t() | nil
- def get_user_setting(user_setting_id, query_args \\ []) do
- (query_args ++ [id: user_setting_id])
- |> UserSettingQueries.user_setting_query()
- |> Teiserver.Repo.one()
+ @spec get_user_setting(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t | nil
+ def get_user_setting(user_id, key) do
+ UserSettingQueries.user_setting_query(where: [key: key, user_id: user_id], limit: 1)
+ |> Repo.one
end
+ @doc """
+ Gets the value of a user_setting.
+
+ Returns nil if the UserSetting does not exist.
+
+ ## Examples
+
+ iex> get_user_setting_value("key123")
+ "value"
+
+ iex> get_user_setting_value("key456")
+ nil
+
+ """
+ @spec get_user_setting_value(Teiserver.user_id(), String.t()) :: String.t() | integer() | boolean() | nil
+ def get_user_setting_value(user_id, key) do
+ lookup = cache_key(user_id, key)
+
+ case Cachex.get(:ts_user_setting_cache, lookup) do
+ {:ok, nil} ->
+ setting = get_user_setting(user_id, key)
+ type = UserSettingTypeLib.get_user_setting_type(key)
+
+ value = case setting do
+ nil ->
+ type.default
+
+ %{value: nil} ->
+ type.default
+
+ %{value: v} ->
+ v
+ end
+
+ value = convert_from_raw_value(value, type.type)
+
+ Cachex.put(:ts_user_setting_cache, lookup, value)
+ value
+ {:ok, value} ->
+ value
+ end
+ end
+
+ @spec convert_from_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
+ defp convert_from_raw_value(raw_value, "string"), do: raw_value
+ defp convert_from_raw_value(raw_value, "integer"), do: String.to_integer(raw_value)
+ defp convert_from_raw_value(raw_value, "boolean"), do: raw_value == "t"
+ defp convert_from_raw_value(_, _), do: nil
+
+ @spec set_user_setting_value(Teiserver.user_id(), String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ def set_user_setting_value(user_id, key, value) do
+ lookup = cache_key(user_id, key)
+
+ type = UserSettingTypeLib.get_user_setting_type(key)
+ raw_value = convert_to_raw_value(value, type.type)
+
+ case get_user_setting(user_id, key) do
+ nil ->
+ {:ok, _} = create_user_setting(%{
+ user_id: user_id,
+ key: key,
+ value: raw_value
+ })
+ :ok
+
+ user_setting ->
+ {:ok, _} = update_user_setting(user_setting, %{"value" => raw_value})
+ Teiserver.invalidate_cache(:ts_user_setting_cache, lookup)
+ :ok
+ end
+ end
+
+ @spec convert_to_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
+ defp convert_to_raw_value(value, "string"), do: value
+ defp convert_to_raw_value(value, "integer"), do: to_string(value)
+ defp convert_to_raw_value(value, "boolean"), do: (if value, do: "t", else: "f")
+ defp convert_to_raw_value(_, _), do: nil
+
@doc """
Creates a user_setting.
@@ -75,11 +151,11 @@ defmodule Teiserver.Settings.UserSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_user_setting(map) :: {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
- def create_user_setting(attrs \\ %{}) do
+ @spec create_user_setting(map) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t}
+ def create_user_setting(attrs) do
%UserSetting{}
|> UserSetting.changeset(attrs)
- |> Teiserver.Repo.insert()
+ |> Repo.insert()
end
@doc """
@@ -94,12 +170,11 @@ defmodule Teiserver.Settings.UserSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_user_setting(UserSetting.t(), map) ::
- {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
+ @spec update_user_setting(UserSetting.t, map) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t}
def update_user_setting(%UserSetting{} = user_setting, attrs) do
user_setting
|> UserSetting.changeset(attrs)
- |> Teiserver.Repo.update()
+ |> Repo.update()
end
@doc """
@@ -114,10 +189,9 @@ defmodule Teiserver.Settings.UserSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_user_setting(UserSetting.t()) ::
- {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
+ @spec delete_user_setting(UserSetting.t) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t}
def delete_user_setting(%UserSetting{} = user_setting) do
- Teiserver.Repo.delete(user_setting)
+ Repo.delete(user_setting)
end
@doc """
@@ -129,8 +203,12 @@ defmodule Teiserver.Settings.UserSettingLib do
%Ecto.Changeset{data: %UserSetting{}}
"""
- @spec change_user_setting(UserSetting.t(), map) :: Ecto.Changeset.t()
+ @spec change_user_setting(UserSetting.t, map) :: Ecto.Changeset.t
def change_user_setting(%UserSetting{} = user_setting, attrs \\ %{}) do
UserSetting.changeset(user_setting, attrs)
end
+
+ defp cache_key(user_id, key) do
+ "#{user_id}$#{key}"
+ end
end
diff --git a/lib/teiserver/settings/libs/user_setting_type_lib.ex b/lib/teiserver/settings/libs/user_setting_type_lib.ex
new file mode 100644
index 000000000..4acb71ef1
--- /dev/null
+++ b/lib/teiserver/settings/libs/user_setting_type_lib.ex
@@ -0,0 +1,58 @@
+defmodule Teiserver.Settings.UserSettingTypeLib do
+ @moduledoc """
+ A set of functions for working with `UserSettingType` objects.
+ """
+
+ @cache_table :ts_user_setting_type_store
+
+ alias Teiserver.Settings.UserSettingType
+
+ @spec list_user_setting_types([String.t()]) :: [UserSettingType.t()]
+ def list_user_setting_types(keys) do
+ keys
+ |> Enum.map(&get_user_setting_type/1)
+ end
+
+ @spec list_user_setting_type_keys() :: [String.t()]
+ def list_user_setting_type_keys() do
+ {:ok, v} = Cachex.get(@cache_table, "_all")
+ (v || [])
+ end
+
+ @spec get_user_setting_type(String.t()) :: UserSettingType.t() | nil
+ def get_user_setting_type(key) do
+ {:ok, v} = Cachex.get(@cache_table, key)
+ v
+ end
+
+ @spec add_user_setting_type(map()) :: {:ok, UserSettingType.t()} | {:error, String.t()}
+ def add_user_setting_type(args) do
+ if not Enum.member?(~w(string integer boolean), args.type) do
+ raise "Invalid type, must be one of `string`, `integer` or `boolean`"
+ end
+
+ existing_keys = list_user_setting_type_keys()
+ if Enum.member?(existing_keys, args.key) do
+ raise "Key #{args.key} already exists"
+ end
+
+ type = %UserSettingType{
+ key: args.key,
+ label: args.label,
+ section: args.section,
+ type: args.type,
+
+ permissions: Map.get(args, :permissions),
+ choices: Map.get(args, :choices),
+ default: Map.get(args, :default),
+ description: Map.get(args, :description)
+ }
+
+ # Update our list of all keys
+ new_all = [type.key | existing_keys]
+ Cachex.put(@cache_table, "_all", new_all)
+
+ Cachex.put(@cache_table, type.key, type)
+ {:ok, type}
+ end
+end
diff --git a/lib/teiserver/settings/queries/server_setting_queries.ex b/lib/teiserver/settings/queries/server_setting_queries.ex
index c65486a34..365c213fe 100644
--- a/lib/teiserver/settings/queries/server_setting_queries.ex
+++ b/lib/teiserver/settings/queries/server_setting_queries.ex
@@ -9,9 +9,8 @@ defmodule Teiserver.Settings.ServerSettingQueries do
query = from(server_settings in ServerSetting)
query
- |> do_where(id: args[:id])
+ |> do_where(key: args[:key])
|> do_where(args[:where])
- |> do_preload(args[:preload])
|> do_order_by(args[:order_by])
|> QueryHelper.query_select(args[:select])
|> QueryHelper.limit_query(args[:limit] || 50)
@@ -31,21 +30,27 @@ defmodule Teiserver.Settings.ServerSettingQueries do
def _where(query, _, ""), do: query
def _where(query, _, nil), do: query
- def _where(query, :id, id) do
+ def _where(query, :key, key_list) when is_list(key_list) do
from(server_settings in query,
- where: server_settings.id == ^id
+ where: server_settings.key in ^key_list
)
end
- def _where(query, :id_in, id_list) do
+ def _where(query, :key, key) do
from(server_settings in query,
- where: server_settings.id in ^id_list
+ where: server_settings.key == ^key
)
end
- def _where(query, :name, name) do
+ def _where(query, :value, value_list) when is_list(value_list) do
from(server_settings in query,
- where: server_settings.name == ^name
+ where: server_settings.value in ^value_list
+ )
+ end
+
+ def _where(query, :value, value) do
+ from(server_settings in query,
+ where: server_settings.value == ^value
)
end
@@ -61,6 +66,18 @@ defmodule Teiserver.Settings.ServerSettingQueries do
)
end
+ def _where(query, :updated_after, timestamp) do
+ from(server_settings in query,
+ where: server_settings.updated_at >= ^timestamp
+ )
+ end
+
+ def _where(query, :updated_before, timestamp) do
+ from(server_settings in query,
+ where: server_settings.updated_at < ^timestamp
+ )
+ end
+
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
@@ -73,18 +90,6 @@ defmodule Teiserver.Settings.ServerSettingQueries do
end
@spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Name (A-Z)") do
- from(server_settings in query,
- order_by: [asc: server_settings.name]
- )
- end
-
- def _order_by(query, "Name (Z-A)") do
- from(server_settings in query,
- order_by: [desc: server_settings.name]
- )
- end
-
def _order_by(query, "Newest first") do
from(server_settings in query,
order_by: [desc: server_settings.inserted_at]
@@ -96,22 +101,4 @@ defmodule Teiserver.Settings.ServerSettingQueries do
order_by: [asc: server_settings.inserted_at]
)
end
-
- @spec do_preload(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_preload(query, nil), do: query
-
- defp do_preload(query, _), do: query
- # defp do_preload(query, preloads) do
- # preloads
- # |> List.wrap
- # |> Enum.reduce(query, fn key, query_acc ->
- # _preload(query_acc, key)
- # end)
- # end
-
- # def _preload(query, :relation) do
- # from server_setting in query,
- # left_join: relations in assoc(server_setting, :relation),
- # preload: [relation: relations]
- # end
end
diff --git a/lib/teiserver/settings/queries/user_setting_queries.ex b/lib/teiserver/settings/queries/user_setting_queries.ex
index 18611c88e..949e8ad24 100644
--- a/lib/teiserver/settings/queries/user_setting_queries.ex
+++ b/lib/teiserver/settings/queries/user_setting_queries.ex
@@ -9,7 +9,7 @@ defmodule Teiserver.Settings.UserSettingQueries do
query = from(user_settings in UserSetting)
query
- |> do_where(id: args[:id])
+ |> do_where(key: args[:key])
|> do_where(args[:where])
|> do_preload(args[:preload])
|> do_order_by(args[:order_by])
@@ -31,21 +31,39 @@ defmodule Teiserver.Settings.UserSettingQueries do
def _where(query, _, ""), do: query
def _where(query, _, nil), do: query
- def _where(query, :id, id) do
+ def _where(query, :key, key_list) when is_list(key_list) do
from(user_settings in query,
- where: user_settings.id == ^id
+ where: user_settings.key in ^key_list
)
end
- def _where(query, :id_in, id_list) do
+ def _where(query, :key, key) do
from(user_settings in query,
- where: user_settings.id in ^id_list
+ where: user_settings.key == ^key
)
end
- def _where(query, :name, name) do
+ def _where(query, :user_id, user_id_list) when is_list(user_id_list) do
from(user_settings in query,
- where: user_settings.name == ^name
+ where: user_settings.user_id in ^user_id_list
+ )
+ end
+
+ def _where(query, :user_id, user_id) do
+ from(user_settings in query,
+ where: user_settings.user_id == ^user_id
+ )
+ end
+
+ def _where(query, :value, value_list) when is_list(value_list) do
+ from(user_settings in query,
+ where: user_settings.value in ^value_list
+ )
+ end
+
+ def _where(query, :value, value) do
+ from(user_settings in query,
+ where: user_settings.value == ^value
)
end
@@ -73,18 +91,6 @@ defmodule Teiserver.Settings.UserSettingQueries do
end
@spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Name (A-Z)") do
- from(user_settings in query,
- order_by: [asc: user_settings.name]
- )
- end
-
- def _order_by(query, "Name (Z-A)") do
- from(user_settings in query,
- order_by: [desc: user_settings.name]
- )
- end
-
def _order_by(query, "Newest first") do
from(user_settings in query,
order_by: [desc: user_settings.inserted_at]
diff --git a/lib/teiserver/settings/schemas/server_setting.ex b/lib/teiserver/settings/schemas/server_setting.ex
index a31a09d08..6b994012e 100644
--- a/lib/teiserver/settings/schemas/server_setting.ex
+++ b/lib/teiserver/settings/schemas/server_setting.ex
@@ -18,6 +18,8 @@ defmodule Teiserver.Settings.ServerSetting do
timestamps()
end
+ @type key :: String.t()
+
@type t :: %__MODULE__{
key: String.t(),
value: String.t(),
@@ -26,9 +28,11 @@ defmodule Teiserver.Settings.ServerSetting do
}
@doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
def changeset(server_setting, attrs \\ %{}) do
server_setting
|> cast(attrs, ~w(key value)a)
- |> validate_required(~w(key value)a)
+ |> validate_required(~w(key)a)
end
end
diff --git a/lib/teiserver/settings/schemas/server_setting_type.ex b/lib/teiserver/settings/schemas/server_setting_type.ex
new file mode 100644
index 000000000..bd7a8425c
--- /dev/null
+++ b/lib/teiserver/settings/schemas/server_setting_type.ex
@@ -0,0 +1,43 @@
+defmodule Teiserver.Settings.ServerSettingType do
+ @moduledoc """
+ # ServerSettingType
+ A server setting type is a structure for server settings to reference. The setting types are created at node startup.
+
+ ### Attributes
+
+ * `:key` - The string key of the setting, this is the internal name used for the setting
+ * `:label` - The user-facing label used for the setting
+ * `:section` - A string referencing how the setting should be grouped
+ * `:type` - The type of value which should be parsed out, can be one of: `string`, `boolean`, `integer`
+
+ ### Optional attributes
+ * `:permissions` - A permission set (string or list of strings) used to check if a given user can edit this setting
+ * `:choices` - A list of acceptable choices for `string` based types
+ * `:default` - The default value for a setting if one is not set, defaults to `nil`
+ * `:description` - A longer description which can be used to provide more information to users
+ """
+
+ use TypedStruct
+
+ @derive Jason.Encoder
+ typedstruct do
+ @typedoc "A server setting type"
+
+ field(:key, Teiserver.Settings.ServerSetting.key())
+ field(:label, String.t())
+ field(:section, String.t())
+ field(:type, String.t())
+
+ field(:permissions, String.t() | [String.t()] | nil, default: nil)
+ field(:choices, [String.t()] | nil, default: nil)
+ field(:default, String.t() | Integer.t() | boolean | nil, default: nil)
+ field(:description, String.t() | nil, default: nil)
+ end
+
+ # @spec new(opts) :: __MODULE__.t()
+ # def new(opts) do
+ # %__MODULE__{
+ # key: opts[:key],
+ # }
+ # end
+end
diff --git a/lib/teiserver/settings/schemas/user_setting.ex b/lib/teiserver/settings/schemas/user_setting.ex
index fa2826039..4e5f5ecb1 100644
--- a/lib/teiserver/settings/schemas/user_setting.ex
+++ b/lib/teiserver/settings/schemas/user_setting.ex
@@ -29,6 +29,8 @@ defmodule Teiserver.Settings.UserSetting do
}
@doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
def changeset(server_setting, attrs \\ %{}) do
server_setting
|> cast(attrs, ~w(user_id key value)a)
diff --git a/lib/teiserver/settings/schemas/user_setting_type.ex b/lib/teiserver/settings/schemas/user_setting_type.ex
new file mode 100644
index 000000000..a9b64adb8
--- /dev/null
+++ b/lib/teiserver/settings/schemas/user_setting_type.ex
@@ -0,0 +1,45 @@
+defmodule Teiserver.Settings.UserSettingType do
+ @moduledoc """
+ # UserSettingType
+ A user setting type is a structure for user settings to reference. The setting types are created at node startup.
+
+ ### Attributes
+
+ * `:key` - The string key of the setting, this is the internal name used for the setting
+ * `:label` - The user-facing label used for the setting
+ * `:section` - A string referencing how the setting should be grouped
+ * `:type` - The type of value which should be parsed out, can be one of: `string`, `boolean`, `integer`
+
+ ### Optional attributes
+ * `:permissions` - A permission set (string or list of strings) used to check if a given user can edit this setting
+ * `:choices` - A list of acceptable choices for `string` based types
+ * `:default` - The default value for a setting if one is not set, defaults to `nil`
+ * `:description` - A longer description which can be used to provide more information to users
+ """
+
+ use TypedStruct
+
+ @type key :: String.t()
+
+ @derive Jason.Encoder
+ typedstruct do
+ @typedoc "A user setting type"
+
+ field(:key, key())
+ field(:label, String.t())
+ field(:section, String.t())
+ field(:type, String.t())
+
+ field(:permissions, String.t() | [String.t()] | nil, default: nil)
+ field(:choices, [String.t()] | nil, default: nil)
+ field(:default, String.t() | Integer.t() | boolean | nil, default: nil)
+ field(:description, String.t() | nil, default: nil)
+ end
+
+ # @spec new(opts) :: __MODULE__.t()
+ # def new(opts) do
+ # %__MODULE__{
+ # key: opts[:key],
+ # }
+ # end
+end
diff --git a/test/settings/server_setting_queries_test.exs b/test/settings/server_setting_queries_test.exs
new file mode 100644
index 000000000..174998830
--- /dev/null
+++ b/test/settings/server_setting_queries_test.exs
@@ -0,0 +1,53 @@
+defmodule Teiserver.ServerSettingQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Settings.ServerSettingQueries
+
+ describe "queries" do
+ @empty_query ServerSettingQueries.server_setting_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ ServerSettingQueries.server_setting_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ ServerSettingQueries.server_setting_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ ServerSettingQueries.server_setting_query(
+ where: [
+ key: ["key1", "key2"],
+ key: "key1",
+ value: ["value1", "value2"],
+ value: "value1",
+ inserted_after: Timex.now(),
+ inserted_before: Timex.now(),
+ updated_after: Timex.now(),
+ updated_before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ limit: nil,
+ select: [:key]
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/settings/server_setting_test.exs b/test/settings/server_setting_test.exs
new file mode 100644
index 000000000..458b3e03b
--- /dev/null
+++ b/test/settings/server_setting_test.exs
@@ -0,0 +1,157 @@
+defmodule Teiserver.ServerSettingTest do
+ @moduledoc false
+ alias Teiserver.Settings.ServerSetting
+ use Teiserver.Case, async: false
+
+ alias Teiserver.Settings
+ alias Teiserver.{SettingsFixtures}
+
+ defp valid_attrs do
+ %{
+ key: "some key",
+ value: "true"
+ }
+ end
+
+ defp update_attrs do
+ %{
+ key: "some updated key",
+ value: "false"
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ key: nil,
+ value: nil
+ }
+ end
+
+ describe "server_setting" do
+ alias Teiserver.Settings.ServerSetting
+
+ test "server_setting_query/0 returns a query" do
+ q = Settings.server_setting_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_server_setting/0 returns server_setting" do
+ # No server_setting yet
+ assert Settings.list_server_settings([]) == []
+
+ # Add a server_setting
+ SettingsFixtures.server_setting_fixture()
+ assert Settings.list_server_settings([]) != []
+ end
+
+ test "get_server_setting!/1 and get_server_setting/1 returns the server_setting with given id" do
+ server_setting = SettingsFixtures.server_setting_fixture()
+ assert Settings.get_server_setting!(server_setting.key) == server_setting
+ assert Settings.get_server_setting(server_setting.key) == server_setting
+ end
+
+ test "create_server_setting/1 with valid data creates a server_setting" do
+ assert {:ok, %ServerSetting{} = server_setting} =
+ Settings.create_server_setting(valid_attrs())
+
+ assert server_setting.key == "some key"
+ end
+
+ test "create_server_setting/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Settings.create_server_setting(invalid_attrs())
+ end
+
+ test "update_server_setting/2 with valid data updates the server_setting" do
+ server_setting = SettingsFixtures.server_setting_fixture()
+
+ assert {:ok, %ServerSetting{} = server_setting} =
+ Settings.update_server_setting(server_setting, update_attrs())
+
+ assert server_setting.key == "some updated key"
+ end
+
+ test "update_server_setting/2 with invalid data returns error changeset" do
+ server_setting = SettingsFixtures.server_setting_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Settings.update_server_setting(server_setting, invalid_attrs())
+
+ assert server_setting == Settings.get_server_setting!(server_setting.key)
+ end
+
+ test "delete_server_setting/1 deletes the server_setting" do
+ server_setting = SettingsFixtures.server_setting_fixture()
+ assert {:ok, %ServerSetting{}} = Settings.delete_server_setting(server_setting)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Settings.get_server_setting!(server_setting.key)
+ end
+
+ assert Settings.get_server_setting(server_setting.key) == nil
+ end
+
+ test "change_server_setting/1 returns a server_setting changeset" do
+ server_setting = SettingsFixtures.server_setting_fixture()
+ assert %Ecto.Changeset{} = Settings.change_server_setting(server_setting)
+ end
+ end
+
+ describe "values" do
+ test "first insert" do
+ type = SettingsFixtures.server_setting_type_fixture()
+
+ Settings.set_server_setting_value(type.key, "abcdef")
+ value = Settings.get_server_setting_value(type.key)
+ assert value == "abcdef"
+
+ Settings.set_server_setting_value(type.key, "123456")
+ value = Settings.get_server_setting_value(type.key)
+ assert value == "123456"
+ end
+
+ test "strings" do
+ type = SettingsFixtures.server_setting_type_fixture(%{"type" => "string"})
+ _setting = SettingsFixtures.server_setting_fixture(%{"type" => type, "value" => "123456789"})
+
+ value = Settings.get_server_setting_value(type.key)
+ assert value == "123456789"
+
+ Settings.set_server_setting_value(type.key, "abcdef")
+
+ value = Settings.get_server_setting_value(type.key)
+ assert value == "abcdef"
+ end
+
+ test "integers" do
+ type = SettingsFixtures.server_setting_type_fixture(%{"type" => "integer"})
+ _setting = SettingsFixtures.server_setting_fixture(%{"type" => type, "value" => "123456789"})
+
+ value = Settings.get_server_setting_value(type.key)
+ assert value == 123456789
+
+ Settings.set_server_setting_value(type.key, 123)
+
+ value = Settings.get_server_setting_value(type.key)
+ assert value == 123
+ end
+
+ test "booleans" do
+ type = SettingsFixtures.server_setting_type_fixture(%{"type" => "boolean"})
+ _setting = SettingsFixtures.server_setting_fixture(%{"type" => type, "value" => "t"})
+
+ value = Settings.get_server_setting_value(type.key)
+ assert value == true
+
+ Settings.set_server_setting_value(type.key, false)
+
+ value = Settings.get_server_setting_value(type.key)
+ assert value == false
+
+ # Set it back again as there are only two values
+ Settings.set_server_setting_value(type.key, true)
+
+ value = Settings.get_server_setting_value(type.key)
+ assert value == true
+ end
+ end
+end
diff --git a/test/settings/server_setting_type_test.exs b/test/settings/server_setting_type_test.exs
new file mode 100644
index 000000000..1325e9d07
--- /dev/null
+++ b/test/settings/server_setting_type_test.exs
@@ -0,0 +1,69 @@
+defmodule Teiserver.ServerSettingTypeTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Settings
+
+ describe "server setting types" do
+ test "create - errors" do
+ assert_raise(KeyError, fn ->
+ Settings.add_server_setting_type(%{
+ key: "#{__MODULE__} create errors"
+ })
+ end)
+
+ assert_raise(KeyError, fn ->
+ Settings.add_server_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here"
+ })
+ end)
+
+ # We should get a different error (Runtime) if we
+ # use the wrong type
+ assert_raise(RuntimeError, fn ->
+ Settings.add_server_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here",
+ section: "test",
+ type: "not a type"
+ })
+ end)
+
+ # Do it correctly so we can test for duplicate key error
+ {:ok, _} = Settings.add_server_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
+
+ assert_raise(RuntimeError, fn ->
+ Settings.add_server_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
+ end)
+ end
+
+ test "create - correctly" do
+ key = "#{__MODULE__} create"
+
+ assert Settings.get_server_setting_type(key) == nil
+
+ {result, type} = Settings.add_server_setting_type(%{
+ key: key,
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
+
+ assert result == :ok
+ assert type.key == key
+
+ assert Settings.get_server_setting_type(key) == type
+ end
+ end
+end
diff --git a/test/settings/user_setting_queries_test.exs b/test/settings/user_setting_queries_test.exs
new file mode 100644
index 000000000..a5b45d84d
--- /dev/null
+++ b/test/settings/user_setting_queries_test.exs
@@ -0,0 +1,55 @@
+defmodule Teiserver.UserSettingQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Settings.UserSettingQueries
+
+ describe "queries" do
+ @empty_query UserSettingQueries.user_setting_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ UserSettingQueries.user_setting_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ UserSettingQueries.user_setting_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ UserSettingQueries.user_setting_query(
+ where: [
+ user_id: [Teiserver.uuid(), Teiserver.uuid()],
+ user_id: Teiserver.uuid(),
+ key: ["key1", "key2"],
+ key: "key1",
+ value: ["value1", "value2"],
+ value: "value1",
+ inserted_after: Timex.now(),
+ inserted_before: Timex.now(),
+ updated_after: Timex.now(),
+ updated_before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ limit: nil,
+ select: [:key]
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/settings/user_setting_test.exs b/test/settings/user_setting_test.exs
new file mode 100644
index 000000000..d3703f4dc
--- /dev/null
+++ b/test/settings/user_setting_test.exs
@@ -0,0 +1,164 @@
+defmodule Teiserver.UserSettingTest do
+ @moduledoc false
+ alias Teiserver.Settings.UserSetting
+ use Teiserver.Case, async: false
+
+ alias Teiserver.Settings
+ alias Teiserver.{AccountFixtures, SettingsFixtures}
+
+ defp valid_attrs do
+ %{
+ user_id: AccountFixtures.user_fixture().id,
+ key: "some key",
+ value: "true"
+ }
+ end
+
+ defp update_attrs do
+ %{
+ user_id: AccountFixtures.user_fixture().id,
+ key: "some updated key",
+ value: "false"
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ user_id: nil,
+ key: nil,
+ value: nil
+ }
+ end
+
+ describe "user_setting" do
+ alias Teiserver.Settings.UserSetting
+
+ test "user_setting_query/0 returns a query" do
+ q = Settings.user_setting_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_user_setting/0 returns user_setting" do
+ # No user_setting yet
+ assert Settings.list_user_settings([]) == []
+
+ # Add a user_setting
+ SettingsFixtures.user_setting_fixture()
+ assert Settings.list_user_settings([]) != []
+ end
+
+ test "get_user_setting!/1 and get_user_setting/1 returns the user_setting with given id" do
+ user_setting = SettingsFixtures.user_setting_fixture()
+ assert Settings.get_user_setting!(user_setting.user_id, user_setting.key) == user_setting
+ assert Settings.get_user_setting(user_setting.user_id, user_setting.key) == user_setting
+ end
+
+ test "create_user_setting/1 with valid data creates a user_setting" do
+ assert {:ok, %UserSetting{} = user_setting} =
+ Settings.create_user_setting(valid_attrs())
+
+ assert user_setting.key == "some key"
+ end
+
+ test "create_user_setting/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Settings.create_user_setting(invalid_attrs())
+ end
+
+ test "update_user_setting/2 with valid data updates the user_setting" do
+ user_setting = SettingsFixtures.user_setting_fixture()
+
+ assert {:ok, %UserSetting{} = user_setting} =
+ Settings.update_user_setting(user_setting, update_attrs())
+
+ assert user_setting.key == "some updated key"
+ end
+
+ test "update_user_setting/2 with invalid data returns error changeset" do
+ user_setting = SettingsFixtures.user_setting_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Settings.update_user_setting(user_setting, invalid_attrs())
+
+ assert user_setting == Settings.get_user_setting!(user_setting.user_id, user_setting.key)
+ end
+
+ test "delete_user_setting/1 deletes the user_setting" do
+ user_setting = SettingsFixtures.user_setting_fixture()
+ assert {:ok, %UserSetting{}} = Settings.delete_user_setting(user_setting)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Settings.get_user_setting!(user_setting.user_id, user_setting.key)
+ end
+
+ assert Settings.get_user_setting(user_setting.user_id, user_setting.key) == nil
+ end
+
+ test "change_user_setting/1 returns a user_setting changeset" do
+ user_setting = SettingsFixtures.user_setting_fixture()
+ assert %Ecto.Changeset{} = Settings.change_user_setting(user_setting)
+ end
+ end
+
+ describe "values" do
+ test "first insert" do
+ user_id = AccountFixtures.user_fixture().id
+ type = SettingsFixtures.user_setting_type_fixture()
+
+ Settings.set_user_setting_value(user_id, type.key, "abcdef")
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == "abcdef"
+
+ Settings.set_user_setting_value(user_id, type.key, "123456")
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == "123456"
+ end
+
+ test "strings" do
+ user_id = AccountFixtures.user_fixture().id
+ type = SettingsFixtures.user_setting_type_fixture(%{"type" => "string"})
+ _setting = SettingsFixtures.user_setting_fixture(%{"user_id" => user_id, "type" => type, "value" => "123456789"})
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == "123456789"
+
+ Settings.set_user_setting_value(user_id, type.key, "abcdef")
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == "abcdef"
+ end
+
+ test "integers" do
+ user_id = AccountFixtures.user_fixture().id
+ type = SettingsFixtures.user_setting_type_fixture(%{"type" => "integer"})
+ _setting = SettingsFixtures.user_setting_fixture(%{"user_id" => user_id, "type" => type, "value" => "123456789"})
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == 123456789
+
+ Settings.set_user_setting_value(user_id, type.key, 123)
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == 123
+ end
+
+ test "booleans" do
+ user_id = AccountFixtures.user_fixture().id
+ type = SettingsFixtures.user_setting_type_fixture(%{"type" => "boolean"})
+ _setting = SettingsFixtures.user_setting_fixture(%{"user_id" => user_id, "type" => type, "value" => "t"})
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == true
+
+ Settings.set_user_setting_value(user_id, type.key, false)
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == false
+
+ # Set it back again as there are only two values
+ Settings.set_user_setting_value(user_id, type.key, true)
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == true
+ end
+ end
+end
diff --git a/test/settings/user_setting_type_test.exs b/test/settings/user_setting_type_test.exs
new file mode 100644
index 000000000..cce48b2da
--- /dev/null
+++ b/test/settings/user_setting_type_test.exs
@@ -0,0 +1,69 @@
+defmodule Teiserver.UserSettingTypeTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Settings
+
+ describe "user setting types" do
+ test "create - errors" do
+ assert_raise(KeyError, fn ->
+ Settings.add_user_setting_type(%{
+ key: "#{__MODULE__} create errors"
+ })
+ end)
+
+ assert_raise(KeyError, fn ->
+ Settings.add_user_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here"
+ })
+ end)
+
+ # We should get a different error (Runtime) if we
+ # use the wrong type
+ assert_raise(RuntimeError, fn ->
+ Settings.add_user_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here",
+ section: "test",
+ type: "not a type"
+ })
+ end)
+
+ # Do it correctly so we can test for duplicate key error
+ {:ok, _} = Settings.add_user_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
+
+ assert_raise(RuntimeError, fn ->
+ Settings.add_user_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
+ end)
+ end
+
+ test "create - correctly" do
+ key = "#{__MODULE__} create"
+
+ assert Settings.get_user_setting_type(key) == nil
+
+ {result, type} = Settings.add_user_setting_type(%{
+ key: key,
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
+
+ assert result == :ok
+ assert type.key == key
+
+ assert Settings.get_user_setting_type(key) == type
+ end
+ end
+end
diff --git a/test/support/fixtures/settings_fixtures.ex b/test/support/fixtures/settings_fixtures.ex
new file mode 100644
index 000000000..8611b2596
--- /dev/null
+++ b/test/support/fixtures/settings_fixtures.ex
@@ -0,0 +1,90 @@
+defmodule Teiserver.SettingsFixtures do
+ @moduledoc false
+ alias Teiserver.Settings
+ alias Teiserver.Settings.{ServerSettingType, ServerSetting, UserSetting}
+ import Teiserver.AccountFixtures, only: [user_fixture: 0]
+
+ @spec server_setting_type_fixture() :: ServerSettingType.t()
+ @spec server_setting_type_fixture(map) :: ServerSettingType.t()
+ def server_setting_type_fixture(data \\ %{}) do
+ r = :rand.uniform(999_999_999)
+
+ {:ok, type} = Settings.add_server_setting_type(%{
+ key: data["key"] || "key_#{r}",
+ label: data["label"] || "label_#{r}",
+ section: data["section"] || "section_#{r}",
+ type: data["type"] || "string",
+
+ permissions: data["permissions"] || nil,
+ choices: data["choices"] || nil,
+ default: data["default"] || nil,
+ description: data["description"] || nil
+ })
+ type
+ end
+
+ @spec server_setting_fixture() :: ServerSetting.t()
+ @spec server_setting_fixture(map) :: ServerSetting.t()
+ def server_setting_fixture(data \\ %{}) do
+ type = data["type"] || server_setting_type_fixture()
+
+ r = :rand.uniform(999_999_999)
+ value = case type.type do
+ "string" -> data["value"] || "#{r}"
+ "integer" -> to_string(data["value"]) || "#{r}"
+ "boolean" -> data["value"] || (if Integer.mod(r, 2) == 1, do: "t", else: "f")
+ end
+
+ ServerSetting.changeset(
+ %ServerSetting{},
+ %{
+ key: type.key,
+ value: value
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+
+ @spec user_setting_type_fixture() :: UserSettingType.t()
+ @spec user_setting_type_fixture(map) :: UserSettingType.t()
+ def user_setting_type_fixture(data \\ %{}) do
+ r = :rand.uniform(999_999_999)
+
+ {:ok, type} = Settings.add_user_setting_type(%{
+ key: data["key"] || "key_#{r}",
+ label: data["label"] || "label_#{r}",
+ section: data["section"] || "section_#{r}",
+ type: data["type"] || "string",
+
+ permissions: data["permissions"] || nil,
+ choices: data["choices"] || nil,
+ default: data["default"] || nil,
+ description: data["description"] || nil
+ })
+ type
+ end
+
+ @spec user_setting_fixture() :: UserSetting.t()
+ @spec user_setting_fixture(map) :: UserSetting.t()
+ def user_setting_fixture(data \\ %{}) do
+ type = data["type"] || user_setting_type_fixture()
+
+ r = :rand.uniform(999_999_999)
+ value = case type.type do
+ "string" -> data["value"] || "#{r}"
+ "integer" -> to_string(data["value"]) || "#{r}"
+ "boolean" -> data["value"] || (if Integer.mod(r, 2) == 1, do: "t", else: "f")
+ end
+
+ UserSetting.changeset(
+ %UserSetting{},
+ %{
+ user_id: data["user_id"] || user_fixture().id,
+ key: type.key,
+ value: value
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+end
From f64cf8226c1b1aff6c86d2db99ef40b5bf72a8b2 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 3 Apr 2024 18:17:34 +0100
Subject: [PATCH 07/64] Doc fixes for settings
---
lib/teiserver/contexts/settings.ex | 2 ++
lib/teiserver/settings/libs/server_setting_lib.ex | 2 +-
lib/teiserver/settings/libs/server_setting_type_lib.ex | 2 +-
lib/teiserver/settings/libs/user_setting_lib.ex | 2 +-
lib/teiserver/settings/libs/user_setting_type_lib.ex | 2 +-
lib/teiserver/settings/schemas/server_setting.ex | 8 +++++---
lib/teiserver/settings/schemas/server_setting_type.ex | 9 +--------
lib/teiserver/settings/schemas/user_setting.ex | 8 +++++---
lib/teiserver/settings/schemas/user_setting_type.ex | 9 +--------
9 files changed, 18 insertions(+), 26 deletions(-)
diff --git a/lib/teiserver/contexts/settings.ex b/lib/teiserver/contexts/settings.ex
index 4b1718bc9..94267f941 100644
--- a/lib/teiserver/contexts/settings.ex
+++ b/lib/teiserver/contexts/settings.ex
@@ -1,7 +1,9 @@
defmodule Teiserver.Settings do
@moduledoc """
The contextual module for:
+ - `Teiserver.Settings.ServerSettingType`
- `Teiserver.Settings.ServerSetting`
+ - `Teiserver.Settings.UserSettingType`
- `Teiserver.Settings.UserSetting`
"""
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index cd727bd02..0ac4caa41 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -1,6 +1,6 @@
defmodule Teiserver.Settings.ServerSettingLib do
@moduledoc """
- TODO: Library of server_setting related functions.
+ A library of functions for working with `Teiserver.Settings.ServerSetting`
"""
use TeiserverMacros, :library
alias Teiserver.Settings.{ServerSetting, ServerSettingQueries, ServerSettingTypeLib}
diff --git a/lib/teiserver/settings/libs/server_setting_type_lib.ex b/lib/teiserver/settings/libs/server_setting_type_lib.ex
index 1dd2c9685..666949d55 100644
--- a/lib/teiserver/settings/libs/server_setting_type_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_type_lib.ex
@@ -1,6 +1,6 @@
defmodule Teiserver.Settings.ServerSettingTypeLib do
@moduledoc """
- A set of functions for working with `ServerSettingType` objects.
+ A library of functions for working with `Teiserver.Settings.ServerSettingType`
"""
@cache_table :ts_server_setting_type_store
diff --git a/lib/teiserver/settings/libs/user_setting_lib.ex b/lib/teiserver/settings/libs/user_setting_lib.ex
index c40120480..f39bd3b68 100644
--- a/lib/teiserver/settings/libs/user_setting_lib.ex
+++ b/lib/teiserver/settings/libs/user_setting_lib.ex
@@ -1,6 +1,6 @@
defmodule Teiserver.Settings.UserSettingLib do
@moduledoc """
- TODO: Library of user_setting related functions.
+ A library of functions for working with `Teiserver.Settings.UserSetting`
"""
use TeiserverMacros, :library
alias Teiserver.Settings.{UserSetting, UserSettingQueries, UserSettingTypeLib}
diff --git a/lib/teiserver/settings/libs/user_setting_type_lib.ex b/lib/teiserver/settings/libs/user_setting_type_lib.ex
index 4acb71ef1..b593d362b 100644
--- a/lib/teiserver/settings/libs/user_setting_type_lib.ex
+++ b/lib/teiserver/settings/libs/user_setting_type_lib.ex
@@ -1,6 +1,6 @@
defmodule Teiserver.Settings.UserSettingTypeLib do
@moduledoc """
- A set of functions for working with `UserSettingType` objects.
+ A library of functions for working with `Teiserver.Settings.UserSettingType`
"""
@cache_table :ts_user_setting_type_store
diff --git a/lib/teiserver/settings/schemas/server_setting.ex b/lib/teiserver/settings/schemas/server_setting.ex
index 6b994012e..b6f032750 100644
--- a/lib/teiserver/settings/schemas/server_setting.ex
+++ b/lib/teiserver/settings/schemas/server_setting.ex
@@ -1,12 +1,14 @@
defmodule Teiserver.Settings.ServerSetting do
@moduledoc """
# Site setting
- A key/value storage of settings used as part of the server.
+ A key/value storage of settings used as part of the server. While backed by the database they are cached and thus should be quick to access. ServerSettings can be changed at any stage.
+
+ Each setting key exists only once and affects the entire Teiserver cluster.
### Attributes
- * `:key` - The key of the setting
- * `:email` - The value of the setting
+ * `:key` - The key of the setting, refers to a `Teiserver.Settings.UserSettingType`
+ * `:value` - The value of the setting, while stored as a string it will be converted based on the setting type
"""
use TeiserverMacros, :schema
diff --git a/lib/teiserver/settings/schemas/server_setting_type.ex b/lib/teiserver/settings/schemas/server_setting_type.ex
index bd7a8425c..4238bcffc 100644
--- a/lib/teiserver/settings/schemas/server_setting_type.ex
+++ b/lib/teiserver/settings/schemas/server_setting_type.ex
@@ -1,7 +1,7 @@
defmodule Teiserver.Settings.ServerSettingType do
@moduledoc """
# ServerSettingType
- A server setting type is a structure for server settings to reference. The setting types are created at node startup.
+ A server setting type is a structure for server settings to reference. The setting types are created at node startup and though the values can be changed at runtime the types are not intended to be changed at runtime.
### Attributes
@@ -33,11 +33,4 @@ defmodule Teiserver.Settings.ServerSettingType do
field(:default, String.t() | Integer.t() | boolean | nil, default: nil)
field(:description, String.t() | nil, default: nil)
end
-
- # @spec new(opts) :: __MODULE__.t()
- # def new(opts) do
- # %__MODULE__{
- # key: opts[:key],
- # }
- # end
end
diff --git a/lib/teiserver/settings/schemas/user_setting.ex b/lib/teiserver/settings/schemas/user_setting.ex
index 4e5f5ecb1..4cf89f929 100644
--- a/lib/teiserver/settings/schemas/user_setting.ex
+++ b/lib/teiserver/settings/schemas/user_setting.ex
@@ -1,13 +1,15 @@
defmodule Teiserver.Settings.UserSetting do
@moduledoc """
# User setting
- A key/value storage of settings tied to users
+ A key/value storage of settings tied to users. They are backed by the database but cached so can be accessed easily. Each user has their own settings with types defined by `Teiserver.Settings.UserSettingType`.
+
+ The intended use case for User settings is anything where you want to store a key-value store against the user.
### Attributes
* `:user_id` - A reference to the User in question
- * `:key` - The key of the setting
- * `:email` - The value of the setting
+ * `:key` - The key of the setting linking it to a `Teiserver.Settings.UserSettingType`
+ * `:value` - The value of the setting
"""
use TeiserverMacros, :schema
diff --git a/lib/teiserver/settings/schemas/user_setting_type.ex b/lib/teiserver/settings/schemas/user_setting_type.ex
index a9b64adb8..b48e0ac62 100644
--- a/lib/teiserver/settings/schemas/user_setting_type.ex
+++ b/lib/teiserver/settings/schemas/user_setting_type.ex
@@ -1,7 +1,7 @@
defmodule Teiserver.Settings.UserSettingType do
@moduledoc """
# UserSettingType
- A user setting type is a structure for user settings to reference. The setting types are created at node startup.
+ A user setting type is a structure for user settings to reference. The setting types are created at node startup and though the values can be changed at runtime the types are not intended to be changed at runtime.
### Attributes
@@ -35,11 +35,4 @@ defmodule Teiserver.Settings.UserSettingType do
field(:default, String.t() | Integer.t() | boolean | nil, default: nil)
field(:description, String.t() | nil, default: nil)
end
-
- # @spec new(opts) :: __MODULE__.t()
- # def new(opts) do
- # %__MODULE__{
- # key: opts[:key],
- # }
- # end
end
From 3e9508b5936329bfd0af753e9762c91f1928c75d Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 3 Apr 2024 22:01:19 +0100
Subject: [PATCH 08/64] Added audit logs
---
coveralls.json | 1 +
documentation/guides/telemetry_events.md | 20 +++
lib/teiserver.ex | 3 +-
lib/teiserver/account/libs/user_lib.ex | 3 +-
lib/teiserver/account/schemas/user.ex | 5 +-
lib/teiserver/api.ex | 22 ++-
lib/teiserver/application.ex | 17 +-
.../communication/libs/match_message_lib.ex | 3 +-
lib/teiserver/connections/client_server.ex | 18 +-
lib/teiserver/contexts/game.ex | 3 +-
lib/teiserver/contexts/logging.ex | 46 +++++
lib/teiserver/contexts/settings.ex | 54 +++---
lib/teiserver/contexts/telemetry.ex | 45 ++++-
lib/teiserver/game/libs/lobby_lib.ex | 17 +-
lib/teiserver/game/servers/lobby_server.ex | 69 +++++---
lib/teiserver/helpers/map_helper.ex | 22 +--
lib/teiserver/logging/libs/audit_log_lib.ex | 165 ++++++++++++++++++
.../logging/queries/audit_log_queries.ex | 137 +++++++++++++++
lib/teiserver/logging/schemas/audit_log.ex | 42 +++++
.../logging/schemas/match_activity_day_log.ex | 0
.../schemas/match_activity_month_log.ex | 0
.../schemas/match_activity_quarter_log.ex | 0
.../schemas/match_activity_week_log.ex | 0
.../schemas/match_activity_year_log.ex | 0
.../schemas/server_activity_day_log.ex | 0
.../schemas/server_activity_minute_log.ex | 0
.../schemas/server_activity_month_log.ex | 0
.../schemas/server_activity_quarter_log.ex | 0
.../schemas/server_activity_week_log.ex | 0
.../schemas/server_activity_year_log.ex | 0
lib/teiserver/migrations/postgres/v01.ex | 27 ++-
.../settings/libs/server_setting_lib.ex | 50 +++---
.../settings/libs/server_setting_type_lib.ex | 4 +-
.../settings/libs/user_setting_lib.ex | 57 +++---
.../settings/libs/user_setting_type_lib.ex | 4 +-
.../settings/schemas/server_setting_type.ex | 2 +-
.../system/servers/cache_cluster_server.ex | 2 +-
.../telemetry/libs/event_type_lib.ex | 137 +++++++++++++++
.../telemetry/queries/event_type_queries.ex | 75 ++++++++
.../telemetry/schemas/complex_anon_event.ex | 40 +++++
.../schemas/complex_clientapp_event.ex | 40 +++++
.../telemetry/schemas/complex_lobby_event.ex | 43 +++++
.../telemetry/schemas/complex_match_event.ex | 48 +++++
.../telemetry/schemas/complex_server_event.ex | 40 +++++
lib/teiserver/telemetry/schemas/event_type.ex | 33 ++++
.../telemetry/schemas/simple_anon_event.ex | 36 ++++
.../schemas/simple_clientapp_event.ex | 36 ++++
.../telemetry/schemas/simple_lobby_event.ex | 39 +++++
.../telemetry/schemas/simple_match_event.ex | 43 +++++
.../telemetry/schemas/simple_server_event.ex | 36 ++++
mix.exs | 1 +
test/connections/client_lib_test.exs | 1 +
test/game/libs/lobby_lib_test.exs | 4 +-
test/game/lobby_server_test.exs | 18 +-
test/logging/libs/audit_log_lib_test.exs | 127 ++++++++++++++
.../queries/audit_log_queries_test.exs | 56 ++++++
test/settings/server_setting_test.exs | 10 +-
test/settings/server_setting_type_test.exs | 26 +--
test/settings/user_setting_test.exs | 26 ++-
test/settings/user_setting_type_test.exs | 26 +--
test/support/fixtures/logging_fixtures.ex | 39 +++++
test/support/fixtures/settings_fixtures.ex | 67 +++----
62 files changed, 1662 insertions(+), 223 deletions(-)
create mode 100644 documentation/guides/telemetry_events.md
create mode 100644 lib/teiserver/logging/libs/audit_log_lib.ex
create mode 100644 lib/teiserver/logging/queries/audit_log_queries.ex
create mode 100644 lib/teiserver/logging/schemas/match_activity_day_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_activity_month_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_activity_quarter_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_activity_week_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_activity_year_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_activity_day_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_activity_minute_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_activity_month_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_activity_quarter_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_activity_week_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_activity_year_log.ex
create mode 100644 lib/teiserver/telemetry/libs/event_type_lib.ex
create mode 100644 lib/teiserver/telemetry/queries/event_type_queries.ex
create mode 100644 lib/teiserver/telemetry/schemas/complex_anon_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/complex_clientapp_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/complex_lobby_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/complex_match_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/complex_server_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/event_type.ex
create mode 100644 lib/teiserver/telemetry/schemas/simple_anon_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/simple_clientapp_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/simple_lobby_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/simple_match_event.ex
create mode 100644 lib/teiserver/telemetry/schemas/simple_server_event.ex
create mode 100644 test/logging/libs/audit_log_lib_test.exs
create mode 100644 test/logging/queries/audit_log_queries_test.exs
create mode 100644 test/support/fixtures/logging_fixtures.ex
diff --git a/coveralls.json b/coveralls.json
index 836f1438c..686f7f373 100644
--- a/coveralls.json
+++ b/coveralls.json
@@ -1,6 +1,7 @@
{
"skip_files": [
"^test/.*",
+ "lib/teiserver/migrations/*",
"lib/teiserver/helpers/file_macros.ex",
"lib/teiserver/game/servers/lobby_id_server.ex"
],
diff --git a/documentation/guides/telemetry_events.md b/documentation/guides/telemetry_events.md
new file mode 100644
index 000000000..2d8e94b3e
--- /dev/null
+++ b/documentation/guides/telemetry_events.md
@@ -0,0 +1,20 @@
+# Overview
+
+## Privacy warning
+- Understand what PII is
+- Know the laws of wherever you are providing a service
+- I am not a lawyer, if in doubt don't collect data
+
+## Event categories
+- Server
+- Lobby
+- ClientApp
+- Match
+
+## Limitations
+
+## Extension
+- How to extend it to add new data
+
+## Third party services
+I want to add the ability to forward all telemetry data straight to third parties making it easier to scales games in future but I've not had a chance to do this yet. If this is something you want please create a [github issue](https://github.com/Teifion/teiserver/issues) or [Pull Request](https://github.com/Teifion/teiserver/pulls) for it.
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 47639c741..327b0c37e 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -74,7 +74,7 @@ defmodule Teiserver do
@spec deterministic_uuid(String.t()) :: String.t()
def deterministic_uuid(base) do
- UUID.uuid5(:nil, base)
+ UUID.uuid5(nil, base)
end
# PubSub delegation
@@ -93,5 +93,4 @@ defmodule Teiserver do
# Cluster cache delegation
@spec invalidate_cache(atom, any) :: :ok
defdelegate invalidate_cache(table, key_or_keys), to: Teiserver.System.CacheClusterServer
-
end
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index fa04f3331..d4dd88750 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -90,6 +90,7 @@ defmodule Teiserver.Account.UserLib do
user = do_get_user_by_id(user_id)
Cachex.put(:ts_user_by_user_id_cache, user_id, user)
user
+
{:ok, value} ->
value
end
@@ -98,7 +99,7 @@ defmodule Teiserver.Account.UserLib do
@spec do_get_user_by_id(Teiserver.user_id()) :: User.t() | nil
defp do_get_user_by_id(user_id) do
UserQueries.user_query(id: user_id, limit: 1)
- |> Teiserver.Repo.one()
+ |> Teiserver.Repo.one()
end
@doc """
diff --git a/lib/teiserver/account/schemas/user.ex b/lib/teiserver/account/schemas/user.ex
index e97c7a897..dcfc48367 100644
--- a/lib/teiserver/account/schemas/user.ex
+++ b/lib/teiserver/account/schemas/user.ex
@@ -257,7 +257,10 @@ defmodule Teiserver.Account.User do
min_length = Application.get_env(:teiserver, :default_min_user_password_length, 6)
changeset
- |> validate_length(:password, min: min_length, message: "Passwords must be at least #{min_length} characters long")
+ |> validate_length(:password,
+ min: min_length,
+ message: "Passwords must be at least #{min_length} characters long"
+ )
end
@doc """
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index 48a123e4f..e3ef7908b 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -177,10 +177,10 @@ defmodule Teiserver.Api do
defdelegate can_add_client_to_lobby(user_id, lobby_id), to: LobbyLib
@doc section: :lobby
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) :: {boolean(), String.t() | nil}
+ @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) ::
+ {boolean(), String.t() | nil}
defdelegate can_add_client_to_lobby(user_id, lobby_id, password), to: LobbyLib
-
@doc section: :lobby
@spec add_client_to_lobby(Teiserver.user_id(), Lobby.id()) :: :ok | {:error, String.t()}
defdelegate add_client_to_lobby(user_id, lobby_id), to: LobbyLib
@@ -262,14 +262,26 @@ defmodule Teiserver.Api do
defdelegate get_server_setting_value(key), to: ServerSettingLib
@doc section: :server_setting
- @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) ::
+ :ok
defdelegate set_server_setting_value(key, value), to: ServerSettingLib
@doc section: :user_setting
- @spec get_user_setting_value(Teiserver.user_id(), String.t()) :: String.t() | integer() | boolean() | nil
+ @spec get_user_setting_value(Teiserver.user_id(), String.t()) ::
+ String.t() | integer() | boolean() | nil
defdelegate get_user_setting_value(user_id, key), to: UserSettingLib
@doc section: :user_setting
- @spec set_user_setting_value(Teiserver.user_id(), String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ @spec set_user_setting_value(
+ Teiserver.user_id(),
+ String.t(),
+ String.t() | non_neg_integer() | boolean() | nil
+ ) :: :ok
defdelegate set_user_setting_value(user_id, key, value), to: UserSettingLib
+
+ # Logging
+ alias Teiserver.Logging.AuditLogLib
+
+ @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ defdelegate create_audit_log(user_id, ip, action, details), to: AuditLogLib
end
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index 6afb65d77..aba8be08d 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -39,11 +39,10 @@ defmodule Teiserver.Application do
# DB Lookup caches
add_cache(:ts_server_setting_type_store),
- add_cache(:ts_server_setting_cache, [ttl: :timer.minutes(1)]),
+ add_cache(:ts_server_setting_cache, ttl: :timer.minutes(1)),
add_cache(:ts_user_setting_type_store),
- add_cache(:ts_user_setting_cache, [ttl: :timer.minutes(1)]),
-
- add_cache(:ts_user_by_user_id_cache, [ttl: :timer.minutes(5)]),
+ add_cache(:ts_user_setting_cache, ttl: :timer.minutes(1)),
+ add_cache(:ts_user_by_user_id_cache, ttl: :timer.minutes(5)),
# Telemetry caches
add_cache(:ts_property_types_cache),
@@ -55,7 +54,7 @@ defmodule Teiserver.Application do
add_cache(:ts_complex_match_event_types_cache),
add_cache(:ts_simple_server_event_types_cache),
add_cache(:ts_complex_server_event_types_cache),
- add_cache(:ts_account_smurf_key_types),
+ add_cache(:ts_account_smurf_key_types)
]
opts = [strategy: :one_for_one, name: __MODULE__]
@@ -75,10 +74,10 @@ defmodule Teiserver.Application do
id: name,
start:
{Cachex, :start_link,
- [
- name,
- opts
- ]}
+ [
+ name,
+ opts
+ ]}
}
end
end
diff --git a/lib/teiserver/communication/libs/match_message_lib.ex b/lib/teiserver/communication/libs/match_message_lib.ex
index 48dce7ae7..62b960ac1 100644
--- a/lib/teiserver/communication/libs/match_message_lib.ex
+++ b/lib/teiserver/communication/libs/match_message_lib.ex
@@ -50,7 +50,6 @@ defmodule Teiserver.Communication.MatchMessageLib do
list_match_messages(where: [match_id: match_id], limit: limit, order_by: ["Newest first"])
end
-
@doc """
Wraps `send_match_message/3` to send a message when in the lobby instead of the match
@@ -82,11 +81,11 @@ defmodule Teiserver.Communication.MatchMessageLib do
match_message: match_message
}
)
+
{:ok, match_message}
err ->
err
-
end
end
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index de97d0272..3e4cfb1c5 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -86,6 +86,7 @@ defmodule Teiserver.Connections.ClientServer do
# and thus we don't want to keep the client alive
def handle_cast({:purposeful_disconnect, pid}, state) do
new_state = lose_connection(pid, state)
+
if new_state.client.connected? do
{:noreply, new_state}
else
@@ -180,16 +181,17 @@ defmodule Teiserver.Connections.ClientServer do
)
end
- new_state = cond do
- state.client.lobby_id == nil && new_client.lobby_id != nil ->
- added_to_lobby(new_client.lobby_id, state)
+ new_state =
+ cond do
+ state.client.lobby_id == nil && new_client.lobby_id != nil ->
+ added_to_lobby(new_client.lobby_id, state)
- state.client.lobby_id != nil && new_client.lobby_id == nil ->
- removed_from_lobby(state.client.lobby_id, state)
+ state.client.lobby_id != nil && new_client.lobby_id == nil ->
+ removed_from_lobby(state.client.lobby_id, state)
- true ->
- state
- end
+ true ->
+ state
+ end
%{new_state | client: new_client}
end
diff --git a/lib/teiserver/contexts/game.ex b/lib/teiserver/contexts/game.ex
index cd89074e5..b0031e51b 100644
--- a/lib/teiserver/contexts/game.ex
+++ b/lib/teiserver/contexts/game.ex
@@ -78,7 +78,8 @@ defmodule Teiserver.Game do
defdelegate can_add_client_to_lobby(user_id, lobby_id), to: LobbyLib
@doc section: :lobby
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) :: {boolean(), String.t() | nil}
+ @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) ::
+ {boolean(), String.t() | nil}
defdelegate can_add_client_to_lobby(user_id, lobby_id, password), to: LobbyLib
@doc section: :lobby
diff --git a/lib/teiserver/contexts/logging.ex b/lib/teiserver/contexts/logging.ex
index ba83f036b..cb130519a 100644
--- a/lib/teiserver/contexts/logging.ex
+++ b/lib/teiserver/contexts/logging.ex
@@ -11,6 +11,52 @@ defmodule Teiserver.Logging do
"""
# AuditLogs
+ alias Teiserver.Logging.{AuditLog, AuditLogLib, AuditLogQueries}
+
+ @doc false
+ @spec audit_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate audit_log_query(args), to: AuditLogQueries
+
+ @doc section: :audit_log
+ @spec list_audit_logs(Teiserver.query_args()) :: [AuditLog.t]
+ defdelegate list_audit_logs(args), to: AuditLogLib
+
+ @doc section: :audit_log
+ @spec get_audit_log!(AuditLog.id()) :: AuditLog.t
+ @spec get_audit_log!(AuditLog.id(), Teiserver.query_args()) :: AuditLog.t
+ defdelegate get_audit_log!(audit_log_id, query_args \\ []), to: AuditLogLib
+
+ @doc section: :audit_log
+ @spec get_audit_log(AuditLog.id()) :: AuditLog.t | nil
+ @spec get_audit_log(AuditLog.id(), Teiserver.query_args()) :: AuditLog.t | nil
+ defdelegate get_audit_log(audit_log_id, query_args \\ []), to: AuditLogLib
+
+ @doc section: :audit_log
+ @spec create_audit_log(map) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_audit_log(attrs), to: AuditLogLib
+
+ @doc section: :audit_log
+ @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ defdelegate create_audit_log(user_id, ip, action, details), to: AuditLogLib
+
+ @doc section: :audit_log
+ @spec create_anonymous_audit_log(String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ defdelegate create_anonymous_audit_log(ip, action, details), to: AuditLogLib
+
+ @doc section: :audit_log
+ @spec update_audit_log(AuditLog, map) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_audit_log(audit_log, attrs), to: AuditLogLib
+
+ @doc section: :audit_log
+ @spec delete_audit_log(AuditLog.t) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_audit_log(audit_log), to: AuditLogLib
+
+ @doc section: :audit_log
+ @spec change_audit_log(AuditLog.t) :: Ecto.Changeset.t()
+ @spec change_audit_log(AuditLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_audit_log(audit_log, attrs \\ %{}), to: AuditLogLib
+
+
# Crash logs
# UserLogs (UserActivity logs in Barserver)
diff --git a/lib/teiserver/contexts/settings.ex b/lib/teiserver/contexts/settings.ex
index 94267f941..64e2642e2 100644
--- a/lib/teiserver/contexts/settings.ex
+++ b/lib/teiserver/contexts/settings.ex
@@ -34,34 +34,36 @@ defmodule Teiserver.Settings do
defdelegate server_setting_query(args), to: ServerSettingQueries
@doc section: :server_setting
- @spec list_server_settings(Teiserver.query_args()) :: [ServerSetting.t]
+ @spec list_server_settings(Teiserver.query_args()) :: [ServerSetting.t()]
defdelegate list_server_settings(args), to: ServerSettingLib
@doc section: :server_setting
- @spec get_server_setting!(ServerSetting.key()) :: ServerSetting.t
- @spec get_server_setting!(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t
+ @spec get_server_setting!(ServerSetting.key()) :: ServerSetting.t()
+ @spec get_server_setting!(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t()
defdelegate get_server_setting!(server_setting_id, query_args \\ []), to: ServerSettingLib
@doc section: :server_setting
- @spec get_server_setting(ServerSetting.key()) :: ServerSetting.t | nil
- @spec get_server_setting(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t | nil
+ @spec get_server_setting(ServerSetting.key()) :: ServerSetting.t() | nil
+ @spec get_server_setting(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t() | nil
defdelegate get_server_setting(server_setting_id, query_args \\ []), to: ServerSettingLib
@doc section: :server_setting
- @spec create_server_setting(map) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t()}
+ @spec create_server_setting(map) :: {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_server_setting(attrs), to: ServerSettingLib
@doc section: :server_setting
- @spec update_server_setting(ServerSetting, map) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t()}
+ @spec update_server_setting(ServerSetting, map) ::
+ {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_server_setting(server_setting, attrs), to: ServerSettingLib
@doc section: :server_setting
- @spec delete_server_setting(ServerSetting.t) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_setting(ServerSetting.t()) ::
+ {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_server_setting(server_setting), to: ServerSettingLib
@doc section: :server_setting
- @spec change_server_setting(ServerSetting.t) :: Ecto.Changeset.t()
- @spec change_server_setting(ServerSetting.t, map) :: Ecto.Changeset.t()
+ @spec change_server_setting(ServerSetting.t()) :: Ecto.Changeset.t()
+ @spec change_server_setting(ServerSetting.t(), map) :: Ecto.Changeset.t()
defdelegate change_server_setting(server_setting, attrs \\ %{}), to: ServerSettingLib
@doc section: :server_setting
@@ -69,7 +71,8 @@ defmodule Teiserver.Settings do
defdelegate get_server_setting_value(key), to: ServerSettingLib
@doc section: :server_setting
- @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) ::
+ :ok
defdelegate set_server_setting_value(key, value), to: ServerSettingLib
# UserSettingType
@@ -91,8 +94,6 @@ defmodule Teiserver.Settings do
@spec add_user_setting_type(map()) :: {:ok, UserSettingType.t()} | {:error, String.t()}
defdelegate add_user_setting_type(args), to: UserSettingTypeLib
-
-
# UserSettings
alias Teiserver.Settings.{UserSetting, UserSettingLib, UserSettingQueries}
@@ -101,39 +102,46 @@ defmodule Teiserver.Settings do
defdelegate user_setting_query(args), to: UserSettingQueries
@doc section: :user_setting
- @spec list_user_settings(Teiserver.query_args()) :: [UserSetting.t]
+ @spec list_user_settings(Teiserver.query_args()) :: [UserSetting.t()]
defdelegate list_user_settings(args), to: UserSettingLib
@doc section: :user_setting
- @spec get_user_setting!(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t
+ @spec get_user_setting!(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t()
defdelegate get_user_setting!(user_id, key), to: UserSettingLib
@doc section: :user_setting
- @spec get_user_setting(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t | nil
+ @spec get_user_setting(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t() | nil
defdelegate get_user_setting(user_id, key), to: UserSettingLib
@doc section: :user_setting
- @spec create_user_setting(map) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t()}
+ @spec create_user_setting(map) :: {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_user_setting(attrs), to: UserSettingLib
@doc section: :user_setting
- @spec update_user_setting(UserSetting.t, map) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t()}
+ @spec update_user_setting(UserSetting.t(), map) ::
+ {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_user_setting(user_setting, attrs), to: UserSettingLib
@doc section: :user_setting
- @spec delete_user_setting(UserSetting.t) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_user_setting(UserSetting.t()) ::
+ {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_user_setting(user_setting), to: UserSettingLib
@doc section: :user_setting
- @spec change_user_setting(UserSetting.t) :: Ecto.Changeset.t()
- @spec change_user_setting(UserSetting.t, map) :: Ecto.Changeset.t()
+ @spec change_user_setting(UserSetting.t()) :: Ecto.Changeset.t()
+ @spec change_user_setting(UserSetting.t(), map) :: Ecto.Changeset.t()
defdelegate change_user_setting(user_setting, attrs \\ %{}), to: UserSettingLib
@doc section: :user_setting
- @spec get_user_setting_value(Teiserver.user_id(), String.t()) :: String.t() | integer() | boolean() | nil
+ @spec get_user_setting_value(Teiserver.user_id(), String.t()) ::
+ String.t() | integer() | boolean() | nil
defdelegate get_user_setting_value(user_id, key), to: UserSettingLib
@doc section: :user_setting
- @spec set_user_setting_value(Teiserver.user_id(), String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ @spec set_user_setting_value(
+ Teiserver.user_id(),
+ String.t(),
+ String.t() | non_neg_integer() | boolean() | nil
+ ) :: :ok
defdelegate set_user_setting_value(user_id, key, value), to: UserSettingLib
end
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
index 0fee87421..3840da4cc 100644
--- a/lib/teiserver/contexts/telemetry.ex
+++ b/lib/teiserver/contexts/telemetry.ex
@@ -1,6 +1,10 @@
defmodule Teiserver.Telemetry do
@moduledoc """
+ This page is a reference for the Telemetry data functions. For a guide on how to use the Telemetry features please refer to the [telemetry guide](guides/telemetry_events.md).
+
The contextual module for:
+ - `Teiserver.Telemetry.EventType`
+
- `Teiserver.Telemetry.SimpleGameEvent`
- `Teiserver.Telemetry.SimpleServerEvent`
- `Teiserver.Telemetry.SimpleLobbyEvent`
@@ -16,8 +20,41 @@ defmodule Teiserver.Telemetry do
- `Teiserver.Telemetry.ComplexAnonEvent`
"""
- # MatchEvents
- # ServerEvents
- # LobbyEvents
- # Client or User Events
+ # EventTypes
+ alias Teiserver.Telemetry.{EventType, EventTypeLib, EventTypeQueries}
+
+ @doc false
+ @spec event_type_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate event_type_query(args), to: EventTypeQueries
+
+ @doc section: :event_type
+ @spec list_event_types(Teiserver.query_args()) :: [EventType.t()]
+ defdelegate list_event_types(args), to: EventTypeLib
+
+ @doc section: :event_type
+ @spec get_event_type!(EventType.id()) :: EventType.t()
+ @spec get_event_type!(EventType.id(), Teiserver.query_args()) :: EventType.t()
+ defdelegate get_event_type!(event_type_id, query_args \\ []), to: EventTypeLib
+
+ @doc section: :event_type
+ @spec get_event_type(EventType.id()) :: EventType.t() | nil
+ @spec get_event_type(EventType.id(), Teiserver.query_args()) :: EventType.t() | nil
+ defdelegate get_event_type(event_type_id, query_args \\ []), to: EventTypeLib
+
+ @doc section: :event_type
+ @spec create_event_type(map) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate create_event_type(attrs), to: EventTypeLib
+
+ @doc section: :event_type
+ @spec update_event_type(EventType, map) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate update_event_type(event_type, attrs), to: EventTypeLib
+
+ @doc section: :event_type
+ @spec delete_event_type(EventType.t()) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_event_type(event_type), to: EventTypeLib
+
+ @doc section: :event_type
+ @spec change_event_type(EventType.t()) :: Ecto.Changeset.t()
+ @spec change_event_type(EventType.t(), map) :: Ecto.Changeset.t()
+ defdelegate change_event_type(event_type, attrs \\ %{}), to: EventTypeLib
end
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index 4db16f528..e556b5772 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -103,6 +103,7 @@ defmodule Teiserver.Game.LobbyLib do
@spec include_lobby?(LobbySummary.t(), map()) :: boolean
defp include_lobby?(nil, _), do: false
+
defp include_lobby?(lobby, filters) do
[
test_match_ongoing?(filters["match_ongoing?"], lobby),
@@ -119,7 +120,7 @@ defmodule Teiserver.Game.LobbyLib do
test_min_player_count(filters["min_player_count"], lobby),
test_max_player_count(filters["max_player_count"], lobby)
]
- |> Enum.all?
+ |> Enum.all?()
end
@spec test_match_ongoing?(nil | boolean, LobbySummary.t()) :: boolean
@@ -127,6 +128,7 @@ defmodule Teiserver.Game.LobbyLib do
defp test_match_ongoing?(value, lobby), do: lobby.match_ongoing? == value
defp test_require_any_tags(nil, _), do: true
+
defp test_require_any_tags(tags, lobby) do
tags
|> Enum.any?(fn tag ->
@@ -135,6 +137,7 @@ defmodule Teiserver.Game.LobbyLib do
end
defp test_require_all_tags(nil, _), do: true
+
defp test_require_all_tags(tags, lobby) do
tags
|> Enum.all?(fn tag ->
@@ -143,6 +146,7 @@ defmodule Teiserver.Game.LobbyLib do
end
defp test_exclude_tags(nil, _), do: true
+
defp test_exclude_tags(tags, lobby) do
tags
|> Enum.all?(fn tag ->
@@ -179,7 +183,6 @@ defmodule Teiserver.Game.LobbyLib do
defp test_max_player_count(nil, _), do: true
defp test_max_player_count(value, lobby), do: lobby.player_count <= value
-
@doc """
Given a user_id of the host and the initial lobby name, starts a process
for tracking the lobby.
@@ -218,7 +221,12 @@ defmodule Teiserver.Game.LobbyLib do
true ->
with {:ok, lobby} <- start_lobby_server(host_id, name),
:ok <- cycle_lobby(lobby.id),
- _ <- ClientLib.update_client(host_id, %{lobby_id: lobby.id, lobby_host?: true}, "opened lobby") do
+ _ <-
+ ClientLib.update_client(
+ host_id,
+ %{lobby_id: lobby.id, lobby_host?: true},
+ "opened lobby"
+ ) do
{:ok, lobby.id}
else
:failure1 -> :fail_result1
@@ -316,7 +324,8 @@ defmodule Teiserver.Game.LobbyLib do
Adds a client to the lobby
"""
@spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id()) :: {boolean(), String.t() | nil}
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) :: {boolean(), String.t() | nil}
+ @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) ::
+ {boolean(), String.t() | nil}
def can_add_client_to_lobby(user_id, lobby_id, password \\ nil) do
case call_lobby(lobby_id, {:can_add_client, user_id, password}) do
nil ->
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index b6991a979..fa4f68fbc 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -62,7 +62,6 @@ defmodule Teiserver.Game.LobbyServer do
{:noreply, state}
end
-
def handle_cast({:remove_client, user_id}, state) do
if Enum.member?(state.lobby.members, user_id) do
new_state = do_remove_client(user_id, state)
@@ -121,7 +120,8 @@ defmodule Teiserver.Game.LobbyServer do
end
def handle_info(
- %{topic: "Teiserver.Connections.Client" <> _, event: :client_updated, user_id: user_id} = msg,
+ %{topic: "Teiserver.Connections.Client" <> _, event: :client_updated, user_id: user_id} =
+ msg,
state
) do
lobby = state.lobby
@@ -167,7 +167,8 @@ defmodule Teiserver.Game.LobbyServer do
GenServer.start_link(__MODULE__, opts[:data], [])
end
- @spec can_add_client({Teiserver.user_id(), String.t()}, State.t()) :: {boolean(), String.t() | nil}
+ @spec can_add_client({Teiserver.user_id(), String.t()}, State.t()) ::
+ {boolean(), String.t() | nil}
defp can_add_client({user_id, password}, %{lobby: lobby} = _state) do
cond do
Enum.member?(lobby.members, user_id) ->
@@ -219,7 +220,8 @@ defmodule Teiserver.Game.LobbyServer do
@spec update_lobby(State.t(), map()) :: State.t()
def update_lobby(state, changes) do
- new_lobby = state.lobby
+ new_lobby =
+ state.lobby
|> struct(changes)
|> apply_calculated_changes
@@ -256,7 +258,7 @@ defmodule Teiserver.Game.LobbyServer do
@spec apply_calculated_changes(Lobby.t()) :: Lobby.t()
defp apply_calculated_changes(lobby_state) do
changes = %{
- passworded?: (lobby_state.password != nil && lobby_state.password != "")
+ passworded?: lobby_state.password != nil && lobby_state.password != ""
}
struct(lobby_state, changes)
@@ -266,16 +268,20 @@ defmodule Teiserver.Game.LobbyServer do
defp do_add_client(user_id, state) do
shared_secret = Teiserver.Account.generate_password()
- ClientLib.update_client(user_id, %{
- lobby_id: state.lobby_id,
- ready?: false,
- player?: false,
- player_number: nil,
- team_number: nil,
- player_colour: nil,
- sync: nil,
- lobby_host?: false
- }, "joined_lobby")
+ ClientLib.update_client(
+ user_id,
+ %{
+ lobby_id: state.lobby_id,
+ ready?: false,
+ player?: false,
+ player_number: nil,
+ team_number: nil,
+ player_colour: nil,
+ sync: nil,
+ lobby_host?: false
+ },
+ "joined_lobby"
+ )
client = ClientLib.get_client(user_id)
@@ -291,26 +297,31 @@ defmodule Teiserver.Game.LobbyServer do
Connections.subscribe_to_client(user_id)
- {shared_secret, update_lobby(state, %{
- members: [user_id | state.lobby.members],
- spectators: [user_id | state.lobby.spectators]
- })}
+ {shared_secret,
+ update_lobby(state, %{
+ members: [user_id | state.lobby.members],
+ spectators: [user_id | state.lobby.spectators]
+ })}
end
@spec do_remove_client(Teiserver.user_id(), State.t()) :: State.t()
defp do_remove_client(user_id, state) do
Connections.unsubscribe_from_client(user_id)
- ClientLib.update_client(user_id, %{
- lobby_id: nil,
- ready?: false,
- player?: false,
- player_number: nil,
- team_number: nil,
- player_colour: nil,
- sync: nil,
- lobby_host?: false
- }, "left_lobby")
+ ClientLib.update_client(
+ user_id,
+ %{
+ lobby_id: nil,
+ ready?: false,
+ player?: false,
+ player_number: nil,
+ team_number: nil,
+ player_colour: nil,
+ sync: nil,
+ lobby_host?: false
+ },
+ "left_lobby"
+ )
Teiserver.broadcast(
state.lobby_topic,
diff --git a/lib/teiserver/helpers/map_helper.ex b/lib/teiserver/helpers/map_helper.ex
index 0ceb573b7..e8fb9cf12 100644
--- a/lib/teiserver/helpers/map_helper.ex
+++ b/lib/teiserver/helpers/map_helper.ex
@@ -9,17 +9,17 @@ defmodule Teiserver.Helpers.MapHelper do
@spec map_diffs(map(), map()) :: map()
def map_diffs(m1, m2) do
Enum.uniq(Map.keys(m1) ++ Map.keys(m2))
- |> Enum.map(fn key ->
- v1 = Map.get(m1, key, nil)
- v2 = Map.get(m2, key, nil)
+ |> Enum.map(fn key ->
+ v1 = Map.get(m1, key, nil)
+ v2 = Map.get(m2, key, nil)
- if v1 != v2 do
- {key, v2}
- else
- nil
- end
- end)
- |> Enum.reject(&(&1 == nil))
- |> Map.new
+ if v1 != v2 do
+ {key, v2}
+ else
+ nil
+ end
+ end)
+ |> Enum.reject(&(&1 == nil))
+ |> Map.new()
end
end
diff --git a/lib/teiserver/logging/libs/audit_log_lib.ex b/lib/teiserver/logging/libs/audit_log_lib.ex
new file mode 100644
index 000000000..adc54f029
--- /dev/null
+++ b/lib/teiserver/logging/libs/audit_log_lib.ex
@@ -0,0 +1,165 @@
+defmodule Teiserver.Logging.AuditLogLib do
+ @moduledoc """
+ Library of AuditLog related functions
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{AuditLog, AuditLogQueries}
+
+ @doc """
+ Returns the list of audit_logs.
+
+ ## Examples
+
+ iex> list_audit_logs()
+ [%AuditLog{}, ...]
+
+ """
+ @spec list_audit_logs(Teiserver.query_args()) :: [AuditLog.t()]
+ def list_audit_logs(query_args) do
+ query_args
+ |> AuditLogQueries.audit_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single audit_log.
+
+ Raises `Ecto.NoResultsError` if the AuditLog does not exist.
+
+ ## Examples
+
+ iex> get_audit_log!(123)
+ %AuditLog{}
+
+ iex> get_audit_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_audit_log!(AuditLog.id()) :: AuditLog.t()
+ @spec get_audit_log!(AuditLog.id(), Teiserver.query_args()) :: AuditLog.t()
+ def get_audit_log!(audit_log_id, query_args \\ []) do
+ (query_args ++ [id: audit_log_id])
+ |> AuditLogQueries.audit_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single audit_log.
+
+ Returns nil if the AuditLog does not exist.
+
+ ## Examples
+
+ iex> get_audit_log(123)
+ %AuditLog{}
+
+ iex> get_audit_log(456)
+ nil
+
+ """
+ @spec get_audit_log(AuditLog.id()) :: AuditLog.t() | nil
+ @spec get_audit_log(AuditLog.id(), Teiserver.query_args()) :: AuditLog.t() | nil
+ def get_audit_log(audit_log_id, query_args \\ []) do
+ (query_args ++ [id: audit_log_id])
+ |> AuditLogQueries.audit_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a audit_log.
+
+ ## Examples
+
+ iex> create_audit_log(%{field: value})
+ {:ok, %AuditLog{}}
+
+ iex> create_audit_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ iex> create_audit_log("user_id", "127.0.0.1", "Action", %{key: "value"})
+ {:ok, %AuditLog{}}
+
+ """
+ @spec create_audit_log(map) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ def create_audit_log(attrs) do
+ %AuditLog{}
+ |> AuditLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ def create_audit_log(user_id, ip, action, details) do
+ %AuditLog{}
+ |> AuditLog.changeset(%{
+ user_id: user_id,
+ ip: ip,
+ action: action,
+ details: details
+ })
+ |> Repo.insert()
+ end
+
+ @doc """
+ See `create_audit_log/4`, this is the same but without a user.
+ """
+ @spec create_anonymous_audit_log(String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ def create_anonymous_audit_log(ip, action, details) do
+ %AuditLog{}
+ |> AuditLog.changeset(%{
+ ip: ip,
+ action: action,
+ details: details
+ })
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a audit_log.
+
+ ## Examples
+
+ iex> update_audit_log(audit_log, %{field: new_value})
+ {:ok, %AuditLog{}}
+
+ iex> update_audit_log(audit_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_audit_log(AuditLog.t, map) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ def update_audit_log(%AuditLog{} = audit_log, attrs) do
+ audit_log
+ |> AuditLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a audit_log.
+
+ ## Examples
+
+ iex> delete_audit_log(audit_log)
+ {:ok, %AuditLog{}}
+
+ iex> delete_audit_log(audit_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_audit_log(AuditLog.t) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ def delete_audit_log(%AuditLog{} = audit_log) do
+ Repo.delete(audit_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking audit_log changes.
+
+ ## Examples
+
+ iex> change_audit_log(audit_log)
+ %Ecto.Changeset{data: %AuditLog{}}
+
+ """
+ @spec change_audit_log(AuditLog.t, map) :: Ecto.Changeset.t
+ def change_audit_log(%AuditLog{} = audit_log, attrs \\ %{}) do
+ AuditLog.changeset(audit_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/queries/audit_log_queries.ex b/lib/teiserver/logging/queries/audit_log_queries.ex
new file mode 100644
index 000000000..ba09a0fc2
--- /dev/null
+++ b/lib/teiserver/logging/queries/audit_log_queries.ex
@@ -0,0 +1,137 @@
+defmodule Teiserver.Logging.AuditLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.AuditLog
+ require Logger
+
+ @spec audit_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def audit_log_query(args) do
+ query = from(audit_logs in AuditLog)
+
+ query
+ |> do_where(id: args[:id])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_preload(args[:preload])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :id, id_list) when is_list(id_list) do
+ from audit_logs in query,
+ where: audit_logs.id in ^id_list
+ end
+
+ def _where(query, :id, id) do
+ from audit_logs in query,
+ where: audit_logs.id == ^id
+ end
+
+ def _where(query, :action, action_list) when is_list(action_list) do
+ from audit_logs in query,
+ where: audit_logs.action in ^action_list
+ end
+
+ def _where(query, :action, action) do
+ from audit_logs in query,
+ where: audit_logs.action == ^action
+ end
+
+ def _where(query, :detail_equal, {field, value}) do
+ from audit_logs in query,
+ where: fragment("? ->> ? = ?", audit_logs.details, ^field, ^value)
+ end
+
+ def _where(query, :detail_greater_than, {field, value}) do
+ from audit_logs in query,
+ where: fragment("? ->> ? > ?", audit_logs.details, ^field, ^value)
+ end
+
+ def _where(query, :detail_less_than, {field, value}) do
+ from audit_logs in query,
+ where: fragment("? ->> ? < ?", audit_logs.details, ^field, ^value)
+ end
+
+ def _where(query, :detail_not, {field, value}) do
+ from audit_logs in query,
+ where: fragment("? ->> ? != ?", audit_logs.details, ^field, ^value)
+ end
+
+
+ def _where(query, :inserted_after, timestamp) do
+ from audit_logs in query,
+ where: audit_logs.inserted_at >= ^timestamp
+ end
+
+ def _where(query, :inserted_before, timestamp) do
+ from audit_logs in query,
+ where: audit_logs.inserted_at < ^timestamp
+ end
+
+ def _where(query, :updated_after, timestamp) do
+ from audit_logs in query,
+ where: audit_logs.updated_at >= ^timestamp
+ end
+
+ def _where(query, :updated_before, timestamp) do
+ from audit_logs in query,
+ where: audit_logs.updated_at < ^timestamp
+ end
+
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from audit_logs in query,
+ order_by: [desc: audit_logs.inserted_at]
+ end
+
+ def _order_by(query, "Oldest first") do
+ from audit_logs in query,
+ order_by: [asc: audit_logs.inserted_at]
+ end
+
+
+ @spec do_preload(Ecto.Query.t(), List.t() | nil) :: Ecto.Query.t()
+ defp do_preload(query, nil), do: query
+
+ defp do_preload(query, preloads) do
+ preloads
+ |> List.wrap
+ |> Enum.reduce(query, fn key, query_acc ->
+ _preload(query_acc, key)
+ end)
+ end
+
+ @spec _preload(Ecto.Query.t(), any) :: Ecto.Query.t()
+ def _preload(query, :user) do
+ from audit_log in query,
+ left_join: users in assoc(audit_log, :user),
+ preload: [user: users]
+ end
+end
diff --git a/lib/teiserver/logging/schemas/audit_log.ex b/lib/teiserver/logging/schemas/audit_log.ex
index e69de29bb..e463f822b 100644
--- a/lib/teiserver/logging/schemas/audit_log.ex
+++ b/lib/teiserver/logging/schemas/audit_log.ex
@@ -0,0 +1,42 @@
+defmodule Teiserver.Logging.AuditLog do
+ @moduledoc """
+ # AuditLog
+ Description here
+
+ ### Attributes
+
+ * `:action` - The action performed which generated the audit log
+ * `:details` - A key-value store of extra details related to the action
+ * `:ip` - The IP address of the sender of the command (if available)
+ * `:user` - The user who performed the action
+ """
+ use TeiserverMacros, :schema
+
+ schema "audit_logs" do
+ field(:action, :string)
+ field(:details, :map)
+ field(:ip, :string)
+ belongs_to(:user, Teiserver.Account.User, type: Ecto.UUID)
+
+ timestamps()
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ id: id(),
+ action: String.t(),
+ details: map(),
+ ip: String.t(),
+ user_id: Teiserver.user_id()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(action details ip user_id)a)
+ |> validate_required(~w(action details)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/match_activity_day_log.ex b/lib/teiserver/logging/schemas/match_activity_day_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/match_activity_month_log.ex b/lib/teiserver/logging/schemas/match_activity_month_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/match_activity_quarter_log.ex b/lib/teiserver/logging/schemas/match_activity_quarter_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/match_activity_week_log.ex b/lib/teiserver/logging/schemas/match_activity_week_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/match_activity_year_log.ex b/lib/teiserver/logging/schemas/match_activity_year_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/server_activity_day_log.ex b/lib/teiserver/logging/schemas/server_activity_day_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/server_activity_minute_log.ex b/lib/teiserver/logging/schemas/server_activity_minute_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/server_activity_month_log.ex b/lib/teiserver/logging/schemas/server_activity_month_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/server_activity_quarter_log.ex b/lib/teiserver/logging/schemas/server_activity_quarter_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/server_activity_week_log.ex b/lib/teiserver/logging/schemas/server_activity_week_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/logging/schemas/server_activity_year_log.ex b/lib/teiserver/logging/schemas/server_activity_year_log.ex
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index 567951e26..7261d1d7f 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -183,10 +183,35 @@ defmodule Teiserver.Migrations.Postgres.V01 do
timestamps()
end
- create(index(:settings_user_settings, [:user_id], prefix: prefix))
+ create_if_not_exists(index(:settings_user_settings, [:user_id], prefix: prefix))
+
+ # Logging
+ create_if_not_exists table(:audit_logs, prefix: prefix) do
+ add(:action, :string)
+ add(:details, :jsonb)
+ add(:ip, :string)
+ add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
+
+ timestamps()
+ end
+
+ # Telemetry tables
+ create_if_not_exists table(:telemetry_event_types, prefix: prefix) do
+ add(:category, :string)
+ add(:name, :string)
+ end
+
+ create_if_not_exists(unique_index(:telemetry_event_types, [:category, :name], prefix: prefix))
end
+ @spec down(map) :: any
def down(%{prefix: prefix, quoted_prefix: _quoted}) do
+ # Telemetry
+ drop_if_exists(table(:telemetry_event_types, prefix: prefix))
+
+ # Logging
+ drop_if_exists(table(:audit_logs, prefix: prefix))
+
# Comms
drop_if_exists(table(:communication_room_messages, prefix: prefix))
drop_if_exists(table(:communication_rooms, prefix: prefix))
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index 0ac4caa41..d7f43ba39 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Settings.ServerSettingLib do
def get_server_setting(key, query_args \\ []) do
(query_args ++ [key: key])
|> ServerSettingQueries.server_setting_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -79,28 +79,31 @@ defmodule Teiserver.Settings.ServerSettingLib do
nil
"""
- @spec get_server_setting_value(ServerSetting.key()) :: String.t() | non_neg_integer() | boolean() | nil
+ @spec get_server_setting_value(ServerSetting.key()) ::
+ String.t() | non_neg_integer() | boolean() | nil
def get_server_setting_value(key) do
case Cachex.get(:ts_server_setting_cache, key) do
{:ok, nil} ->
- setting = get_server_setting(key, [limit: 1])
+ setting = get_server_setting(key, limit: 1)
type = ServerSettingTypeLib.get_server_setting_type(key)
- value = case setting do
- nil ->
- type.default
+ value =
+ case setting do
+ nil ->
+ type.default
- %{value: nil} ->
- type.default
+ %{value: nil} ->
+ type.default
- %{value: v} ->
- v
- end
+ %{value: v} ->
+ v
+ end
value = convert_from_raw_value(value, type.type)
Cachex.put(:ts_server_setting_cache, key, value)
value
+
{:ok, value} ->
value
end
@@ -112,17 +115,20 @@ defmodule Teiserver.Settings.ServerSettingLib do
defp convert_from_raw_value(raw_value, "boolean"), do: raw_value == "t"
defp convert_from_raw_value(_, _), do: nil
- @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) ::
+ :ok
def set_server_setting_value(key, value) do
type = ServerSettingTypeLib.get_server_setting_type(key)
raw_value = convert_to_raw_value(value, type.type)
case get_server_setting(key) do
nil ->
- {:ok, _} = create_server_setting(%{
- key: key,
- value: raw_value
- })
+ {:ok, _} =
+ create_server_setting(%{
+ key: key,
+ value: raw_value
+ })
+
:ok
server_setting ->
@@ -135,7 +141,7 @@ defmodule Teiserver.Settings.ServerSettingLib do
@spec convert_to_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
defp convert_to_raw_value(value, "string"), do: value
defp convert_to_raw_value(value, "integer"), do: to_string(value)
- defp convert_to_raw_value(value, "boolean"), do: (if value, do: "t", else: "f")
+ defp convert_to_raw_value(value, "boolean"), do: if(value, do: "t", else: "f")
defp convert_to_raw_value(_, _), do: nil
@doc """
@@ -150,7 +156,7 @@ defmodule Teiserver.Settings.ServerSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_server_setting(map) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t}
+ @spec create_server_setting(map) :: {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
def create_server_setting(attrs) do
%ServerSetting{}
|> ServerSetting.changeset(attrs)
@@ -169,7 +175,8 @@ defmodule Teiserver.Settings.ServerSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_server_setting(ServerSetting.t, map) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t}
+ @spec update_server_setting(ServerSetting.t(), map) ::
+ {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
def update_server_setting(%ServerSetting{} = server_setting, attrs) do
server_setting
|> ServerSetting.changeset(attrs)
@@ -188,7 +195,8 @@ defmodule Teiserver.Settings.ServerSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_server_setting(ServerSetting.t) :: {:ok, ServerSetting.t} | {:error, Ecto.Changeset.t}
+ @spec delete_server_setting(ServerSetting.t()) ::
+ {:ok, ServerSetting.t()} | {:error, Ecto.Changeset.t()}
def delete_server_setting(%ServerSetting{} = server_setting) do
Repo.delete(server_setting)
end
@@ -202,7 +210,7 @@ defmodule Teiserver.Settings.ServerSettingLib do
%Ecto.Changeset{data: %ServerSetting{}}
"""
- @spec change_server_setting(ServerSetting.t, map) :: Ecto.Changeset.t
+ @spec change_server_setting(ServerSetting.t(), map) :: Ecto.Changeset.t()
def change_server_setting(%ServerSetting{} = server_setting, attrs \\ %{}) do
ServerSetting.changeset(server_setting, attrs)
end
diff --git a/lib/teiserver/settings/libs/server_setting_type_lib.ex b/lib/teiserver/settings/libs/server_setting_type_lib.ex
index 666949d55..ffeb97cd5 100644
--- a/lib/teiserver/settings/libs/server_setting_type_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_type_lib.ex
@@ -16,7 +16,7 @@ defmodule Teiserver.Settings.ServerSettingTypeLib do
@spec list_server_setting_type_keys() :: [String.t()]
def list_server_setting_type_keys() do
{:ok, v} = Cachex.get(@cache_table, "_all")
- (v || [])
+ v || []
end
@spec get_server_setting_type(String.t()) :: ServerSettingType.t() | nil
@@ -32,6 +32,7 @@ defmodule Teiserver.Settings.ServerSettingTypeLib do
end
existing_keys = list_server_setting_type_keys()
+
if Enum.member?(existing_keys, args.key) do
raise "Key #{args.key} already exists"
end
@@ -41,7 +42,6 @@ defmodule Teiserver.Settings.ServerSettingTypeLib do
label: args.label,
section: args.section,
type: args.type,
-
permissions: Map.get(args, :permissions),
choices: Map.get(args, :choices),
default: Map.get(args, :default),
diff --git a/lib/teiserver/settings/libs/user_setting_lib.ex b/lib/teiserver/settings/libs/user_setting_lib.ex
index f39bd3b68..dff91bf12 100644
--- a/lib/teiserver/settings/libs/user_setting_lib.ex
+++ b/lib/teiserver/settings/libs/user_setting_lib.ex
@@ -35,7 +35,7 @@ defmodule Teiserver.Settings.UserSettingLib do
** (Ecto.NoResultsError)
"""
- @spec get_user_setting!(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t
+ @spec get_user_setting!(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t()
def get_user_setting!(user_id, key) do
UserSettingQueries.user_setting_query(where: [key: key, user_id: user_id], limit: 1)
|> Repo.one!()
@@ -55,10 +55,10 @@ defmodule Teiserver.Settings.UserSettingLib do
nil
"""
- @spec get_user_setting(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t | nil
+ @spec get_user_setting(Teiserver.user_id(), UserSetting.key()) :: UserSetting.t() | nil
def get_user_setting(user_id, key) do
UserSettingQueries.user_setting_query(where: [key: key, user_id: user_id], limit: 1)
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -75,7 +75,8 @@ defmodule Teiserver.Settings.UserSettingLib do
nil
"""
- @spec get_user_setting_value(Teiserver.user_id(), String.t()) :: String.t() | integer() | boolean() | nil
+ @spec get_user_setting_value(Teiserver.user_id(), String.t()) ::
+ String.t() | integer() | boolean() | nil
def get_user_setting_value(user_id, key) do
lookup = cache_key(user_id, key)
@@ -84,21 +85,23 @@ defmodule Teiserver.Settings.UserSettingLib do
setting = get_user_setting(user_id, key)
type = UserSettingTypeLib.get_user_setting_type(key)
- value = case setting do
- nil ->
- type.default
+ value =
+ case setting do
+ nil ->
+ type.default
- %{value: nil} ->
- type.default
+ %{value: nil} ->
+ type.default
- %{value: v} ->
- v
- end
+ %{value: v} ->
+ v
+ end
value = convert_from_raw_value(value, type.type)
Cachex.put(:ts_user_setting_cache, lookup, value)
value
+
{:ok, value} ->
value
end
@@ -110,7 +113,11 @@ defmodule Teiserver.Settings.UserSettingLib do
defp convert_from_raw_value(raw_value, "boolean"), do: raw_value == "t"
defp convert_from_raw_value(_, _), do: nil
- @spec set_user_setting_value(Teiserver.user_id(), String.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok
+ @spec set_user_setting_value(
+ Teiserver.user_id(),
+ String.t(),
+ String.t() | non_neg_integer() | boolean() | nil
+ ) :: :ok
def set_user_setting_value(user_id, key, value) do
lookup = cache_key(user_id, key)
@@ -119,11 +126,13 @@ defmodule Teiserver.Settings.UserSettingLib do
case get_user_setting(user_id, key) do
nil ->
- {:ok, _} = create_user_setting(%{
- user_id: user_id,
- key: key,
- value: raw_value
- })
+ {:ok, _} =
+ create_user_setting(%{
+ user_id: user_id,
+ key: key,
+ value: raw_value
+ })
+
:ok
user_setting ->
@@ -136,7 +145,7 @@ defmodule Teiserver.Settings.UserSettingLib do
@spec convert_to_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
defp convert_to_raw_value(value, "string"), do: value
defp convert_to_raw_value(value, "integer"), do: to_string(value)
- defp convert_to_raw_value(value, "boolean"), do: (if value, do: "t", else: "f")
+ defp convert_to_raw_value(value, "boolean"), do: if(value, do: "t", else: "f")
defp convert_to_raw_value(_, _), do: nil
@doc """
@@ -151,7 +160,7 @@ defmodule Teiserver.Settings.UserSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_user_setting(map) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t}
+ @spec create_user_setting(map) :: {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
def create_user_setting(attrs) do
%UserSetting{}
|> UserSetting.changeset(attrs)
@@ -170,7 +179,8 @@ defmodule Teiserver.Settings.UserSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_user_setting(UserSetting.t, map) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t}
+ @spec update_user_setting(UserSetting.t(), map) ::
+ {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
def update_user_setting(%UserSetting{} = user_setting, attrs) do
user_setting
|> UserSetting.changeset(attrs)
@@ -189,7 +199,8 @@ defmodule Teiserver.Settings.UserSettingLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_user_setting(UserSetting.t) :: {:ok, UserSetting.t} | {:error, Ecto.Changeset.t}
+ @spec delete_user_setting(UserSetting.t()) ::
+ {:ok, UserSetting.t()} | {:error, Ecto.Changeset.t()}
def delete_user_setting(%UserSetting{} = user_setting) do
Repo.delete(user_setting)
end
@@ -203,7 +214,7 @@ defmodule Teiserver.Settings.UserSettingLib do
%Ecto.Changeset{data: %UserSetting{}}
"""
- @spec change_user_setting(UserSetting.t, map) :: Ecto.Changeset.t
+ @spec change_user_setting(UserSetting.t(), map) :: Ecto.Changeset.t()
def change_user_setting(%UserSetting{} = user_setting, attrs \\ %{}) do
UserSetting.changeset(user_setting, attrs)
end
diff --git a/lib/teiserver/settings/libs/user_setting_type_lib.ex b/lib/teiserver/settings/libs/user_setting_type_lib.ex
index b593d362b..f36ab1a1d 100644
--- a/lib/teiserver/settings/libs/user_setting_type_lib.ex
+++ b/lib/teiserver/settings/libs/user_setting_type_lib.ex
@@ -16,7 +16,7 @@ defmodule Teiserver.Settings.UserSettingTypeLib do
@spec list_user_setting_type_keys() :: [String.t()]
def list_user_setting_type_keys() do
{:ok, v} = Cachex.get(@cache_table, "_all")
- (v || [])
+ v || []
end
@spec get_user_setting_type(String.t()) :: UserSettingType.t() | nil
@@ -32,6 +32,7 @@ defmodule Teiserver.Settings.UserSettingTypeLib do
end
existing_keys = list_user_setting_type_keys()
+
if Enum.member?(existing_keys, args.key) do
raise "Key #{args.key} already exists"
end
@@ -41,7 +42,6 @@ defmodule Teiserver.Settings.UserSettingTypeLib do
label: args.label,
section: args.section,
type: args.type,
-
permissions: Map.get(args, :permissions),
choices: Map.get(args, :choices),
default: Map.get(args, :default),
diff --git a/lib/teiserver/settings/schemas/server_setting_type.ex b/lib/teiserver/settings/schemas/server_setting_type.ex
index 4238bcffc..50627921f 100644
--- a/lib/teiserver/settings/schemas/server_setting_type.ex
+++ b/lib/teiserver/settings/schemas/server_setting_type.ex
@@ -28,7 +28,7 @@ defmodule Teiserver.Settings.ServerSettingType do
field(:section, String.t())
field(:type, String.t())
- field(:permissions, String.t() | [String.t()] | nil, default: nil)
+ field(:permissions, String.t() | [String.t()] | nil, default: nil)
field(:choices, [String.t()] | nil, default: nil)
field(:default, String.t() | Integer.t() | boolean | nil, default: nil)
field(:description, String.t() | nil, default: nil)
diff --git a/lib/teiserver/system/servers/cache_cluster_server.ex b/lib/teiserver/system/servers/cache_cluster_server.ex
index 78a1830c9..e3ed50980 100644
--- a/lib/teiserver/system/servers/cache_cluster_server.ex
+++ b/lib/teiserver/system/servers/cache_cluster_server.ex
@@ -29,7 +29,7 @@ defmodule Teiserver.System.CacheClusterServer do
def handle_info({:cache_cluster, :delete, from_node, table, key_or_keys}, state) do
if from_node != Node.self() do
key_or_keys
- |> List.wrap
+ |> List.wrap()
|> Enum.each(fn key ->
Cachex.del(table, key)
end)
diff --git a/lib/teiserver/telemetry/libs/event_type_lib.ex b/lib/teiserver/telemetry/libs/event_type_lib.ex
new file mode 100644
index 000000000..749d9b482
--- /dev/null
+++ b/lib/teiserver/telemetry/libs/event_type_lib.ex
@@ -0,0 +1,137 @@
+defmodule Teiserver.Telemetry.EventTypeLib do
+ @moduledoc """
+ Library of event_type related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Telemetry.{EventType, EventTypeQueries}
+
+ @doc """
+ Returns the list of event_types.
+
+ ## Examples
+
+ iex> list_event_types()
+ [%EventType{}, ...]
+
+ """
+ @spec list_event_types(Teiserver.query_args()) :: [EventType.t()]
+ def list_event_types(query_args) do
+ query_args
+ |> EventTypeQueries.event_type_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single event_type.
+
+ Raises `Ecto.NoResultsError` if the EventType does not exist.
+
+ ## Examples
+
+ iex> get_event_type!(123)
+ %EventType{}
+
+ iex> get_event_type!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_event_type!(EventType.id()) :: EventType.t()
+ @spec get_event_type!(EventType.id(), Teiserver.query_args()) :: EventType.t()
+ def get_event_type!(event_type_id, query_args \\ []) do
+ (query_args ++ [id: event_type_id])
+ |> EventTypeQueries.event_type_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single event_type.
+
+ Returns nil if the EventType does not exist.
+
+ ## Examples
+
+ iex> get_event_type(123)
+ %EventType{}
+
+ iex> get_event_type(456)
+ nil
+
+ """
+ @spec get_event_type(EventType.id()) :: EventType.t() | nil
+ @spec get_event_type(EventType.id(), Teiserver.query_args()) :: EventType.t() | nil
+ def get_event_type(event_type_id, query_args \\ []) do
+ (query_args ++ [id: event_type_id])
+ |> EventTypeQueries.event_type_query()
+ |> Repo.one()
+ end
+
+ @doc """
+ Creates a event_type.
+
+ ## Examples
+
+ iex> create_event_type(%{field: value})
+ {:ok, %EventType{}}
+
+ iex> create_event_type(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_event_type(map) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
+ def create_event_type(attrs) do
+ %EventType{}
+ |> EventType.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a event_type.
+
+ ## Examples
+
+ iex> update_event_type(event_type, %{field: new_value})
+ {:ok, %EventType{}}
+
+ iex> update_event_type(event_type, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_event_type(EventType.t(), map) ::
+ {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
+ def update_event_type(%EventType{} = event_type, attrs) do
+ event_type
+ |> EventType.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a event_type.
+
+ ## Examples
+
+ iex> delete_event_type(event_type)
+ {:ok, %EventType{}}
+
+ iex> delete_event_type(event_type)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_event_type(EventType.t()) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
+ def delete_event_type(%EventType{} = event_type) do
+ Repo.delete(event_type)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking event_type changes.
+
+ ## Examples
+
+ iex> change_event_type(event_type)
+ %Ecto.Changeset{data: %EventType{}}
+
+ """
+ @spec change_event_type(EventType.t(), map) :: Ecto.Changeset.t()
+ def change_event_type(%EventType{} = event_type, attrs \\ %{}) do
+ EventType.changeset(event_type, attrs)
+ end
+end
diff --git a/lib/teiserver/telemetry/queries/event_type_queries.ex b/lib/teiserver/telemetry/queries/event_type_queries.ex
new file mode 100644
index 000000000..191eb1231
--- /dev/null
+++ b/lib/teiserver/telemetry/queries/event_type_queries.ex
@@ -0,0 +1,75 @@
+defmodule Teiserver.Telemetry.EventTypeQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Telemetry.EventType
+ require Logger
+
+ @spec event_type_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def event_type_query(args) do
+ query = from(event_types in EventType)
+
+ query
+ |> do_where(id: args[:id])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :id, id_list) when is_list(id_list) do
+ from(event_types in query,
+ where: event_types.id in ^id_list
+ )
+ end
+
+ def _where(query, :id, id) do
+ from(event_types in query,
+ where: event_types.id == ^id
+ )
+ end
+
+ def _where(query, :name, name) do
+ from(event_types in query,
+ where: event_types.name == ^name
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Name (A-Z)") do
+ from(event_types in query,
+ order_by: [asc: event_types.name]
+ )
+ end
+
+ def _order_by(query, "Name (Z-A)") do
+ from(event_types in query,
+ order_by: [desc: event_types.name]
+ )
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/complex_anon_event.ex b/lib/teiserver/telemetry/schemas/complex_anon_event.ex
new file mode 100644
index 000000000..60411f65f
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/complex_anon_event.ex
@@ -0,0 +1,40 @@
+defmodule Teiserver.Telemetry.ComplexAnonEvent do
+ @moduledoc """
+ # ComplexAnonEvent
+ A complex event taking place on a Client application but without a user_id to link it to.
+
+ ### Attributes
+
+ * `:hash_id` - A hash value representing the anonymous user allowing events from the same person to be grouped without linking them to a specific user profile
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ * `:details` - A key-value map of the details of the event
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_complex_anon_events" do
+ field(:hash_id, Ecto.UUID)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+
+ field(:details, :map)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ hash_id: Ecto.UUID.t(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t(),
+ details: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(hash_id event_type_id inserted_at details)a)
+ |> validate_required(~w(hash_id event_type_id inserted_at details)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/complex_clientapp_event.ex b/lib/teiserver/telemetry/schemas/complex_clientapp_event.ex
new file mode 100644
index 000000000..b4f8ebc43
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/complex_clientapp_event.ex
@@ -0,0 +1,40 @@
+defmodule Teiserver.Telemetry.ComplexClientappEvent do
+ @moduledoc """
+ # ComplexClientappEvent
+ A complex event taking place on a Client application with a user attached
+
+ ### Attributes
+
+ * `:user_id` - The user this event took place for
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ * `:details` - A key-value map of the details of the event
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_complex_anon_events" do
+ belongs_to(:user_id, Teiserver.Account.User)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+
+ field(:details, :map)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ user_id: Teiserver.user_id(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t(),
+ details: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(user_id event_type_id inserted_at details)a)
+ |> validate_required(~w(user_id event_type_id inserted_at details)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/complex_lobby_event.ex b/lib/teiserver/telemetry/schemas/complex_lobby_event.ex
new file mode 100644
index 000000000..122aeccdf
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/complex_lobby_event.ex
@@ -0,0 +1,43 @@
+defmodule Teiserver.Telemetry.ComplexLobbyEvent do
+ @moduledoc """
+ # ComplexLobbyEvent
+ A complex event taking place inside a lobby
+
+ ### Attributes
+
+ * `:user_id` - The `Teiserver.Account.User` this event took place for
+ * `:match_id` - The match_id of the lobby this took place in
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ * `:details` - A key-value map of the details of the event
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_complex_lobby_events" do
+ belongs_to(:user_id, Teiserver.Account.User)
+ belongs_to(:match_id, Teiserver.Game.Match)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+
+ field(:details, :map)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ user_id: Teiserver.user_id(),
+ match_id: Teiserver.match_id(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t(),
+ details: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(user_id match_id event_type_id inserted_at details)a)
+ |> validate_required(~w(user_id match_id event_type_id inserted_at details)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/complex_match_event.ex b/lib/teiserver/telemetry/schemas/complex_match_event.ex
new file mode 100644
index 000000000..1b89b19ec
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/complex_match_event.ex
@@ -0,0 +1,48 @@
+defmodule Teiserver.Telemetry.ComplexMatchEvent do
+ @moduledoc """
+ # ComplexMatchEvent
+ A complex event taking place inside of a match
+
+ ### Attributes
+
+ * `:user_id` - The `Teiserver.Account.User` this event took place for
+ * `:match_id` - The `Teiserver.Game.Match` this took place in
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ * `:game_time_seconds` - The number of seconds elapsed in the game before the event took place
+ * `:details` - A key-value map of the details of the event
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_complex_anon_events" do
+ belongs_to(:user_id, Teiserver.Account.User)
+ belongs_to(:match_id, Teiserver.Game.Match)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+
+ field(:game_time_seconds, :integer)
+ field(:details, :map)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ user_id: Teiserver.user_id(),
+ match_id: Teiserver.match_id(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t(),
+ game_time_seconds: non_neg_integer(),
+ details: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(user_id match_id event_type_id inserted_at game_time_seconds details)a)
+ |> validate_required(
+ ~w(user_id match_id event_type_id inserted_at game_time_seconds details)a
+ )
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/complex_server_event.ex b/lib/teiserver/telemetry/schemas/complex_server_event.ex
new file mode 100644
index 000000000..ffbc24274
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/complex_server_event.ex
@@ -0,0 +1,40 @@
+defmodule Teiserver.Telemetry.ComplexServerEvent do
+ @moduledoc """
+ # ComplexServerEvent
+ A complex event taking place on a Client application with a user attached
+
+ ### Attributes
+
+ * `:user_id` - The user this event took place for
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ * `:details` - A key-value map of the details of the event
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_complex_anon_events" do
+ belongs_to(:user_id, Teiserver.Account.User)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+
+ field(:details, :map)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ user_id: Teiserver.user_id(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t(),
+ details: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(user_id event_type_id inserted_at details)a)
+ |> validate_required(~w(user_id event_type_id inserted_at details)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/event_type.ex b/lib/teiserver/telemetry/schemas/event_type.ex
new file mode 100644
index 000000000..d2dfa8227
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/event_type.ex
@@ -0,0 +1,33 @@
+defmodule Teiserver.Telemetry.EventType do
+ @moduledoc """
+ # EventType
+ A name lookup for events to prevent us having to store a string for every single row.
+
+ ### Attributes
+
+ * `:category` - The category
+ * `:name` - The name of the event
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_event_types" do
+ field(:category, :string)
+ field(:name, :string)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ id: id(),
+ name: String.t()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(category name)a)
+ |> validate_required(~w(category name)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/simple_anon_event.ex b/lib/teiserver/telemetry/schemas/simple_anon_event.ex
new file mode 100644
index 000000000..10ac81777
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/simple_anon_event.ex
@@ -0,0 +1,36 @@
+defmodule Teiserver.Telemetry.SimpleAnonEvent do
+ @moduledoc """
+ # SimpleAnonEvent
+ A simple event taking place on a Client application but without a user_id to link it to.
+
+ ### Attributes
+
+ * `:hash_id` - A hash value representing the anonymous user allowing events from the same person to be grouped without linking them to a specific user profile
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_simple_anon_events" do
+ field(:hash_id, Ecto.UUID)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ hash_id: Ecto.UUID.t(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(hash_id event_type_id inserted_at)a)
+ |> validate_required(~w(hash_id event_type_id inserted_at)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/simple_clientapp_event.ex b/lib/teiserver/telemetry/schemas/simple_clientapp_event.ex
new file mode 100644
index 000000000..517768d48
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/simple_clientapp_event.ex
@@ -0,0 +1,36 @@
+defmodule Teiserver.Telemetry.SimpleClientappEvent do
+ @moduledoc """
+ # SimpleClientappEvent
+ A complex event taking place on a Client application with a user attached
+
+ ### Attributes
+
+ * `:user_id` - The user this event took place for
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_complex_anon_events" do
+ belongs_to(:user_id, Teiserver.Account.User)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ user_id: Teiserver.user_id(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(user_id event_type_id inserted_at)a)
+ |> validate_required(~w(user_id event_type_id inserted_at)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/simple_lobby_event.ex b/lib/teiserver/telemetry/schemas/simple_lobby_event.ex
new file mode 100644
index 000000000..ca4211308
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/simple_lobby_event.ex
@@ -0,0 +1,39 @@
+defmodule Teiserver.Telemetry.SimpleLobbyEvent do
+ @moduledoc """
+ # SimpleLobbyEvent
+ A simple event taking place inside a lobby
+
+ ### Attributes
+
+ * `:user_id` - The `Teiserver.Account.User` this event took place for
+ * `:match_id` - The match_id of the lobby this took place in
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_simple_lobby_events" do
+ belongs_to(:user_id, Teiserver.Account.User)
+ belongs_to(:match_id, Teiserver.Game.Match)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ user_id: Teiserver.user_id(),
+ match_id: Teiserver.match_id(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(user_id match_id event_type_id inserted_at)a)
+ |> validate_required(~w(user_id match_id event_type_id inserted_at)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/simple_match_event.ex b/lib/teiserver/telemetry/schemas/simple_match_event.ex
new file mode 100644
index 000000000..de5a2fa46
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/simple_match_event.ex
@@ -0,0 +1,43 @@
+defmodule Teiserver.Telemetry.SimpleMatchEvent do
+ @moduledoc """
+ # SimpleMatchEvent
+ A simple event taking place inside of a match
+
+ ### Attributes
+
+ * `:user_id` - The `Teiserver.Account.User` this event took place for
+ * `:match_id` - The `Teiserver.Game.Match` this took place in
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ * `:game_time_seconds` - The number of seconds elapsed in the game before the event took place
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_simple_anon_events" do
+ belongs_to(:user_id, Teiserver.Account.User)
+ belongs_to(:match_id, Teiserver.Game.Match)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+
+ field(:game_time_seconds, :integer)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ user_id: Teiserver.user_id(),
+ match_id: Teiserver.match_id(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t(),
+ game_time_seconds: non_neg_integer()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(user_id match_id event_type_id inserted_at game_time_seconds)a)
+ |> validate_required(~w(user_id match_id event_type_id inserted_at game_time_seconds)a)
+ end
+end
diff --git a/lib/teiserver/telemetry/schemas/simple_server_event.ex b/lib/teiserver/telemetry/schemas/simple_server_event.ex
new file mode 100644
index 000000000..cbf10a34f
--- /dev/null
+++ b/lib/teiserver/telemetry/schemas/simple_server_event.ex
@@ -0,0 +1,36 @@
+defmodule Teiserver.Telemetry.SimpleServerEvent do
+ @moduledoc """
+ # SimpleServerEvent
+ A simple event taking place on a Client application with a user attached
+
+ ### Attributes
+
+ * `:user_id` - The user this event took place for
+ * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
+ * `:inserted_at` - The timestamp the event took place
+ """
+ use TeiserverMacros, :schema
+
+ schema "telemetry_simple_anon_events" do
+ belongs_to(:user_id, Teiserver.Account.User)
+ belongs_to(:event_type, Teiserver.Telemetry.EventType)
+ field(:inserted_at, :utc_datetime)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ user_id: Teiserver.user_id(),
+ event_type_id: Teiserver.Telemetry.EventType.id(),
+ inserted_at: DateTime.t()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(user_id event_type_id inserted_at)a)
+ |> validate_required(~w(user_id event_type_id inserted_at)a)
+ end
+end
diff --git a/mix.exs b/mix.exs
index 81392b4c6..c46c0f0b3 100644
--- a/mix.exs
+++ b/mix.exs
@@ -59,6 +59,7 @@ defmodule Teiserver.MixProject do
"documentation/guides/program_structure.md",
"documentation/guides/snippets.md",
"documentation/guides/match_lifecycle.md",
+ "documentation/guides/telemetry_events.md",
# Development
"documentation/development/features.md",
diff --git a/test/connections/client_lib_test.exs b/test/connections/client_lib_test.exs
index 859150c32..717b2f774 100644
--- a/test/connections/client_lib_test.exs
+++ b/test/connections/client_lib_test.exs
@@ -79,6 +79,7 @@ defmodule Connections.ClientLibTest do
assert client.team_number == nil
assert update_msg.reason == "test2"
end
+
test "get_client_list" do
{_conn1, user1} = ConnectionFixtures.client_fixture()
{_conn1, user2} = ConnectionFixtures.client_fixture()
diff --git a/test/game/libs/lobby_lib_test.exs b/test/game/libs/lobby_lib_test.exs
index 808d9a34f..71e2da36b 100644
--- a/test/game/libs/lobby_lib_test.exs
+++ b/test/game/libs/lobby_lib_test.exs
@@ -56,7 +56,9 @@ defmodule Teiserver.Game.LobbyLibTest do
assert Enum.member?(lobby_list_ids, lobby3_id)
# Now just two of them
- lobby_list = Game.stream_lobby_summaries(%{"ids" => [lobby1_id, lobby2_id]}) |> Enum.to_list()
+ lobby_list =
+ Game.stream_lobby_summaries(%{"ids" => [lobby1_id, lobby2_id]}) |> Enum.to_list()
+
assert Enum.count(lobby_list) == 2
lobby_list_ids = Enum.map(lobby_list, fn l -> l.id end)
diff --git a/test/game/lobby_server_test.exs b/test/game/lobby_server_test.exs
index 0bffb7f8c..0f2281985 100644
--- a/test/game/lobby_server_test.exs
+++ b/test/game/lobby_server_test.exs
@@ -26,15 +26,15 @@ defmodule Teiserver.Game.LobbyServerTest do
[m] = TestConn.get(listener)
assert m == %{
- topic: topic,
- update_id: 1,
- event: :lobby_updated,
- changes: %{
- host_data: nil,
- update_id: 1
- },
- lobby_id: lobby_id
- }
+ topic: topic,
+ update_id: 1,
+ event: :lobby_updated,
+ changes: %{
+ host_data: nil,
+ update_id: 1
+ },
+ lobby_id: lobby_id
+ }
# Now destroy the client process
Connections.stop_client_server(user.id)
diff --git a/test/logging/libs/audit_log_lib_test.exs b/test/logging/libs/audit_log_lib_test.exs
new file mode 100644
index 000000000..81febb0dd
--- /dev/null
+++ b/test/logging/libs/audit_log_lib_test.exs
@@ -0,0 +1,127 @@
+defmodule Teiserver.AuditLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.AuditLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.{LoggingFixtures, AccountFixtures}
+
+ defp valid_attrs do
+ %{
+ action: "some action",
+ ip: "127.0.0.1",
+ details: %{key: 1},
+ user_id: AccountFixtures.user_fixture().id
+ }
+ end
+
+ defp update_attrs do
+ %{
+ action: "some updated action",
+ ip: "127.0.0.127",
+ details: %{key: "updated"},
+ user_id: AccountFixtures.user_fixture().id
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ action: nil,
+ ip: nil,
+ details: nil,
+ user_id: nil
+ }
+ end
+
+ describe "audit_log" do
+ alias Teiserver.Logging.AuditLog
+
+ test "audit_log_query/0 returns a query" do
+ q = Logging.audit_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_audit_log/0 returns audit_log" do
+ # No audit_log yet
+ assert Logging.list_audit_logs([]) == []
+
+ # Add a audit_log
+ LoggingFixtures.audit_log_fixture()
+ assert Logging.list_audit_logs([]) != []
+ end
+
+ test "get_audit_log!/1 and get_audit_log/1 returns the audit_log with given id" do
+ audit_log = LoggingFixtures.audit_log_fixture()
+ assert Logging.get_audit_log!(audit_log.id) == audit_log
+ assert Logging.get_audit_log(audit_log.id) == audit_log
+ end
+
+ test "create_audit_log/1 with valid data creates a audit_log" do
+ assert {:ok, %AuditLog{} = audit_log} =
+ Logging.create_audit_log(valid_attrs())
+
+ assert audit_log.action == "some action"
+ end
+
+ test "create_audit_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_audit_log(invalid_attrs())
+ end
+
+ test "create_audit_log/4 with valid data creates a audit_log" do
+ user_id = AccountFixtures.user_fixture().id
+ assert {:ok, %AuditLog{} = audit_log} =
+ Logging.create_audit_log(user_id, "ip", "some action", %{})
+
+ assert audit_log.action == "some action"
+ end
+
+ test "create_audit_log/4 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_audit_log(nil, nil, nil, nil)
+ end
+
+ test "create_anonymous_audit_log/3 with valid data creates a audit_log" do
+ assert {:ok, %AuditLog{} = audit_log} =
+ Logging.create_anonymous_audit_log("ip", "some action", %{})
+
+ assert audit_log.action == "some action"
+ end
+
+ test "create_anonymous_audit_log/3 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_anonymous_audit_log(nil, nil, nil)
+ end
+
+ test "update_audit_log/2 with valid data updates the audit_log" do
+ audit_log = LoggingFixtures.audit_log_fixture()
+
+ assert {:ok, %AuditLog{} = audit_log} =
+ Logging.update_audit_log(audit_log, update_attrs())
+
+ assert audit_log.action == "some updated action"
+ end
+
+ test "update_audit_log/2 with invalid data returns error changeset" do
+ audit_log = LoggingFixtures.audit_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_audit_log(audit_log, invalid_attrs())
+
+ assert audit_log == Logging.get_audit_log!(audit_log.id)
+ end
+
+ test "delete_audit_log/1 deletes the audit_log" do
+ audit_log = LoggingFixtures.audit_log_fixture()
+ assert {:ok, %AuditLog{}} = Logging.delete_audit_log(audit_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_audit_log!(audit_log.id)
+ end
+
+ assert Logging.get_audit_log(audit_log.id) == nil
+ end
+
+ test "change_audit_log/1 returns a audit_log changeset" do
+ audit_log = LoggingFixtures.audit_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_audit_log(audit_log)
+ end
+ end
+end
diff --git a/test/logging/queries/audit_log_queries_test.exs b/test/logging/queries/audit_log_queries_test.exs
new file mode 100644
index 000000000..6cd00594e
--- /dev/null
+++ b/test/logging/queries/audit_log_queries_test.exs
@@ -0,0 +1,56 @@
+defmodule Teiserver.AuditLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.AuditLogQueries
+
+ describe "queries" do
+ @empty_query AuditLogQueries.audit_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ AuditLogQueries.audit_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ AuditLogQueries.audit_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ AuditLogQueries.audit_log_query(
+ where: [
+ id: [1, 2],
+ id: 1,
+ action: ["action1", "action2"],
+ action: "action",
+ detail_equal: {"key", "value"},
+ detail_greater_than: {"key", "value"},
+ detail_less_than: {"key", "value"},
+ detail_not: {"key", "value"},
+ inserted_after: Timex.now(),
+ inserted_before: Timex.now(),
+ updated_after: Timex.now(),
+ updated_before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: [:user]
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/settings/server_setting_test.exs b/test/settings/server_setting_test.exs
index 458b3e03b..b2b5b8d89 100644
--- a/test/settings/server_setting_test.exs
+++ b/test/settings/server_setting_test.exs
@@ -111,7 +111,9 @@ defmodule Teiserver.ServerSettingTest do
test "strings" do
type = SettingsFixtures.server_setting_type_fixture(%{"type" => "string"})
- _setting = SettingsFixtures.server_setting_fixture(%{"type" => type, "value" => "123456789"})
+
+ _setting =
+ SettingsFixtures.server_setting_fixture(%{"type" => type, "value" => "123456789"})
value = Settings.get_server_setting_value(type.key)
assert value == "123456789"
@@ -124,10 +126,12 @@ defmodule Teiserver.ServerSettingTest do
test "integers" do
type = SettingsFixtures.server_setting_type_fixture(%{"type" => "integer"})
- _setting = SettingsFixtures.server_setting_fixture(%{"type" => type, "value" => "123456789"})
+
+ _setting =
+ SettingsFixtures.server_setting_fixture(%{"type" => type, "value" => "123456789"})
value = Settings.get_server_setting_value(type.key)
- assert value == 123456789
+ assert value == 123_456_789
Settings.set_server_setting_value(type.key, 123)
diff --git a/test/settings/server_setting_type_test.exs b/test/settings/server_setting_type_test.exs
index 1325e9d07..db153385a 100644
--- a/test/settings/server_setting_type_test.exs
+++ b/test/settings/server_setting_type_test.exs
@@ -31,12 +31,13 @@ defmodule Teiserver.ServerSettingTypeTest do
end)
# Do it correctly so we can test for duplicate key error
- {:ok, _} = Settings.add_server_setting_type(%{
- key: "#{__MODULE__} create errors",
- label: "label here",
- section: "test",
- type: "string"
- })
+ {:ok, _} =
+ Settings.add_server_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
assert_raise(RuntimeError, fn ->
Settings.add_server_setting_type(%{
@@ -53,12 +54,13 @@ defmodule Teiserver.ServerSettingTypeTest do
assert Settings.get_server_setting_type(key) == nil
- {result, type} = Settings.add_server_setting_type(%{
- key: key,
- label: "label here",
- section: "test",
- type: "string"
- })
+ {result, type} =
+ Settings.add_server_setting_type(%{
+ key: key,
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
assert result == :ok
assert type.key == key
diff --git a/test/settings/user_setting_test.exs b/test/settings/user_setting_test.exs
index d3703f4dc..73ad6ee82 100644
--- a/test/settings/user_setting_test.exs
+++ b/test/settings/user_setting_test.exs
@@ -116,7 +116,13 @@ defmodule Teiserver.UserSettingTest do
test "strings" do
user_id = AccountFixtures.user_fixture().id
type = SettingsFixtures.user_setting_type_fixture(%{"type" => "string"})
- _setting = SettingsFixtures.user_setting_fixture(%{"user_id" => user_id, "type" => type, "value" => "123456789"})
+
+ _setting =
+ SettingsFixtures.user_setting_fixture(%{
+ "user_id" => user_id,
+ "type" => type,
+ "value" => "123456789"
+ })
value = Settings.get_user_setting_value(user_id, type.key)
assert value == "123456789"
@@ -130,10 +136,16 @@ defmodule Teiserver.UserSettingTest do
test "integers" do
user_id = AccountFixtures.user_fixture().id
type = SettingsFixtures.user_setting_type_fixture(%{"type" => "integer"})
- _setting = SettingsFixtures.user_setting_fixture(%{"user_id" => user_id, "type" => type, "value" => "123456789"})
+
+ _setting =
+ SettingsFixtures.user_setting_fixture(%{
+ "user_id" => user_id,
+ "type" => type,
+ "value" => "123456789"
+ })
value = Settings.get_user_setting_value(user_id, type.key)
- assert value == 123456789
+ assert value == 123_456_789
Settings.set_user_setting_value(user_id, type.key, 123)
@@ -144,7 +156,13 @@ defmodule Teiserver.UserSettingTest do
test "booleans" do
user_id = AccountFixtures.user_fixture().id
type = SettingsFixtures.user_setting_type_fixture(%{"type" => "boolean"})
- _setting = SettingsFixtures.user_setting_fixture(%{"user_id" => user_id, "type" => type, "value" => "t"})
+
+ _setting =
+ SettingsFixtures.user_setting_fixture(%{
+ "user_id" => user_id,
+ "type" => type,
+ "value" => "t"
+ })
value = Settings.get_user_setting_value(user_id, type.key)
assert value == true
diff --git a/test/settings/user_setting_type_test.exs b/test/settings/user_setting_type_test.exs
index cce48b2da..fd8480759 100644
--- a/test/settings/user_setting_type_test.exs
+++ b/test/settings/user_setting_type_test.exs
@@ -31,12 +31,13 @@ defmodule Teiserver.UserSettingTypeTest do
end)
# Do it correctly so we can test for duplicate key error
- {:ok, _} = Settings.add_user_setting_type(%{
- key: "#{__MODULE__} create errors",
- label: "label here",
- section: "test",
- type: "string"
- })
+ {:ok, _} =
+ Settings.add_user_setting_type(%{
+ key: "#{__MODULE__} create errors",
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
assert_raise(RuntimeError, fn ->
Settings.add_user_setting_type(%{
@@ -53,12 +54,13 @@ defmodule Teiserver.UserSettingTypeTest do
assert Settings.get_user_setting_type(key) == nil
- {result, type} = Settings.add_user_setting_type(%{
- key: key,
- label: "label here",
- section: "test",
- type: "string"
- })
+ {result, type} =
+ Settings.add_user_setting_type(%{
+ key: key,
+ label: "label here",
+ section: "test",
+ type: "string"
+ })
assert result == :ok
assert type.key == key
diff --git a/test/support/fixtures/logging_fixtures.ex b/test/support/fixtures/logging_fixtures.ex
new file mode 100644
index 000000000..0a66ee821
--- /dev/null
+++ b/test/support/fixtures/logging_fixtures.ex
@@ -0,0 +1,39 @@
+defmodule Teiserver.LoggingFixtures do
+ @moduledoc false
+ import Teiserver.AccountFixtures, only: [user_fixture: 0]
+ alias Teiserver.Logging.{AuditLog}
+
+ @spec audit_log_fixture() :: AuditLog.t()
+ @spec audit_log_fixture(map) :: AuditLog.t()
+ def audit_log_fixture(data \\ %{}) do
+ r = :rand.uniform(999_999_999)
+
+ AuditLog.changeset(
+ %AuditLog{},
+ %{
+ action: data[:action] || "action_#{r}",
+ details: data[:details] || %{},
+ ip: data[:ip] || "ip_#{r}",
+ user_id: data[:user_id] || user_fixture().id
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec anonymous_audit_log_fixture() :: AuditLog.t()
+ @spec anonymous_audit_log_fixture(map) :: AuditLog.t()
+ def anonymous_audit_log_fixture(data \\ %{}) do
+ r = :rand.uniform(999_999_999)
+
+ AuditLog.changeset(
+ %AuditLog{},
+ %{
+ action: data[:action] || "action_#{r}",
+ details: data[:details] || %{},
+ ip: data[:ip] || "ip_#{r}",
+ user_id: nil
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+end
diff --git a/test/support/fixtures/settings_fixtures.ex b/test/support/fixtures/settings_fixtures.ex
index 8611b2596..51d9ac59a 100644
--- a/test/support/fixtures/settings_fixtures.ex
+++ b/test/support/fixtures/settings_fixtures.ex
@@ -9,17 +9,18 @@ defmodule Teiserver.SettingsFixtures do
def server_setting_type_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
- {:ok, type} = Settings.add_server_setting_type(%{
- key: data["key"] || "key_#{r}",
- label: data["label"] || "label_#{r}",
- section: data["section"] || "section_#{r}",
- type: data["type"] || "string",
+ {:ok, type} =
+ Settings.add_server_setting_type(%{
+ key: data["key"] || "key_#{r}",
+ label: data["label"] || "label_#{r}",
+ section: data["section"] || "section_#{r}",
+ type: data["type"] || "string",
+ permissions: data["permissions"] || nil,
+ choices: data["choices"] || nil,
+ default: data["default"] || nil,
+ description: data["description"] || nil
+ })
- permissions: data["permissions"] || nil,
- choices: data["choices"] || nil,
- default: data["default"] || nil,
- description: data["description"] || nil
- })
type
end
@@ -29,11 +30,13 @@ defmodule Teiserver.SettingsFixtures do
type = data["type"] || server_setting_type_fixture()
r = :rand.uniform(999_999_999)
- value = case type.type do
- "string" -> data["value"] || "#{r}"
- "integer" -> to_string(data["value"]) || "#{r}"
- "boolean" -> data["value"] || (if Integer.mod(r, 2) == 1, do: "t", else: "f")
- end
+
+ value =
+ case type.type do
+ "string" -> data["value"] || "#{r}"
+ "integer" -> to_string(data["value"]) || "#{r}"
+ "boolean" -> data["value"] || if Integer.mod(r, 2) == 1, do: "t", else: "f"
+ end
ServerSetting.changeset(
%ServerSetting{},
@@ -45,23 +48,23 @@ defmodule Teiserver.SettingsFixtures do
|> Teiserver.Repo.insert!()
end
-
@spec user_setting_type_fixture() :: UserSettingType.t()
@spec user_setting_type_fixture(map) :: UserSettingType.t()
def user_setting_type_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
- {:ok, type} = Settings.add_user_setting_type(%{
- key: data["key"] || "key_#{r}",
- label: data["label"] || "label_#{r}",
- section: data["section"] || "section_#{r}",
- type: data["type"] || "string",
+ {:ok, type} =
+ Settings.add_user_setting_type(%{
+ key: data["key"] || "key_#{r}",
+ label: data["label"] || "label_#{r}",
+ section: data["section"] || "section_#{r}",
+ type: data["type"] || "string",
+ permissions: data["permissions"] || nil,
+ choices: data["choices"] || nil,
+ default: data["default"] || nil,
+ description: data["description"] || nil
+ })
- permissions: data["permissions"] || nil,
- choices: data["choices"] || nil,
- default: data["default"] || nil,
- description: data["description"] || nil
- })
type
end
@@ -71,11 +74,13 @@ defmodule Teiserver.SettingsFixtures do
type = data["type"] || user_setting_type_fixture()
r = :rand.uniform(999_999_999)
- value = case type.type do
- "string" -> data["value"] || "#{r}"
- "integer" -> to_string(data["value"]) || "#{r}"
- "boolean" -> data["value"] || (if Integer.mod(r, 2) == 1, do: "t", else: "f")
- end
+
+ value =
+ case type.type do
+ "string" -> data["value"] || "#{r}"
+ "integer" -> to_string(data["value"]) || "#{r}"
+ "boolean" -> data["value"] || if Integer.mod(r, 2) == 1, do: "t", else: "f"
+ end
UserSetting.changeset(
%UserSetting{},
From 5d1f5daad0ddb794ff349821defad05214d6a70a Mon Sep 17 00:00:00 2001
From: Teifion
Date: Thu, 4 Apr 2024 13:05:15 +0100
Subject: [PATCH 09/64] Added create_anonymous_audit_log to Api
---
lib/teiserver/api.ex | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index e3ef7908b..c6d2d4d3b 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -284,4 +284,7 @@ defmodule Teiserver.Api do
@spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
defdelegate create_audit_log(user_id, ip, action, details), to: AuditLogLib
+
+ @spec create_anonymous_audit_log(String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ defdelegate create_anonymous_audit_log(ip, action, details), to: AuditLogLib
end
From bc508b5ccc83172884de4de00730155352de9b22 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 7 Apr 2024 12:55:22 +0100
Subject: [PATCH 10/64] Added logging tables
---
CHANGELOG.md | 3 +
lib/teiserver/api.ex | 6 +-
lib/teiserver/contexts/logging.ex | 511 +++++++++++++++++-
lib/teiserver/logging/libs/audit_log_lib.ex | 16 +-
.../logging/libs/match_day_log_lib.ex | 136 +++++
.../logging/libs/match_minute_log_lib.ex | 136 +++++
.../logging/libs/match_month_log_lib.ex | 136 +++++
.../logging/libs/match_quarter_log_lib.ex | 136 +++++
.../logging/libs/match_week_log_lib.ex | 136 +++++
.../logging/libs/match_year_log_lib.ex | 136 +++++
.../logging/libs/server_day_log_lib.ex | 136 +++++
.../logging/libs/server_minute_log_lib.ex | 136 +++++
.../logging/libs/server_month_log_lib.ex | 136 +++++
.../logging/libs/server_quarter_log_lib.ex | 136 +++++
.../logging/libs/server_week_log_lib.ex | 136 +++++
.../logging/libs/server_year_log_lib.ex | 136 +++++
.../logging/queries/audit_log_queries.ex | 52 +-
.../logging/queries/match_day_log_queries.ex | 75 +++
.../queries/match_minute_log_queries.ex | 69 +++
.../queries/match_month_log_queries.ex | 87 +++
.../queries/match_quarter_log_queries.ex | 87 +++
.../logging/queries/match_week_log_queries.ex | 87 +++
.../logging/queries/match_year_log_queries.ex | 81 +++
.../logging/queries/server_day_log_queries.ex | 75 +++
.../queries/server_minute_log_queries.ex | 69 +++
.../queries/server_month_log_queries.ex | 87 +++
.../queries/server_quarter_log_queries.ex | 87 +++
.../queries/server_week_log_queries.ex | 87 +++
.../queries/server_year_log_queries.ex | 81 +++
.../logging/schemas/match_activity_day_log.ex | 0
.../schemas/match_activity_month_log.ex | 0
.../schemas/match_activity_quarter_log.ex | 0
.../schemas/match_activity_week_log.ex | 0
.../schemas/match_activity_year_log.ex | 0
.../logging/schemas/match_day_log.ex | 32 ++
.../logging/schemas/match_minute_log.ex | 32 ++
.../logging/schemas/match_month_log.ex | 38 ++
.../logging/schemas/match_quarter_log.ex | 38 ++
.../logging/schemas/match_week_log.ex | 38 ++
.../logging/schemas/match_year_log.ex | 35 ++
.../schemas/server_activity_day_log.ex | 0
.../schemas/server_activity_minute_log.ex | 0
.../schemas/server_activity_month_log.ex | 0
.../schemas/server_activity_quarter_log.ex | 0
.../schemas/server_activity_week_log.ex | 0
.../schemas/server_activity_year_log.ex | 0
.../logging/schemas/server_day_log.ex | 32 ++
.../logging/schemas/server_minute_log.ex | 32 ++
.../logging/schemas/server_month_log.ex | 38 ++
.../logging/schemas/server_quarter_log.ex | 38 ++
.../logging/schemas/server_week_log.ex | 38 ++
.../logging/schemas/server_year_log.ex | 35 ++
lib/{ => teiserver/migrations}/migration.ex | 0
lib/teiserver/migrations/postgres.ex | 2 +-
lib/teiserver/migrations/postgres/v01.ex | 24 -
lib/teiserver/migrations/postgres/v02.ex | 112 ++++
.../settings/queries/user_setting_queries.ex | 12 +
test/logging/libs/audit_log_lib_test.exs | 1 +
test/logging/libs/match_day_log_lib_test.exs | 98 ++++
.../libs/match_minute_log_lib_test.exs | 98 ++++
.../logging/libs/match_month_log_lib_test.exs | 102 ++++
.../libs/match_quarter_log_lib_test.exs | 102 ++++
test/logging/libs/match_week_log_lib_test.exs | 102 ++++
test/logging/libs/match_year_log_lib_test.exs | 100 ++++
test/logging/libs/server_day_log_lib_test.exs | 98 ++++
.../libs/server_minute_log_lib_test.exs | 98 ++++
.../libs/server_month_log_lib_test.exs | 102 ++++
.../libs/server_quarter_log_lib_test.exs | 104 ++++
.../logging/libs/server_week_log_lib_test.exs | 102 ++++
.../logging/libs/server_year_log_lib_test.exs | 100 ++++
.../queries/match_day_log_queries_test.exs | 47 ++
.../queries/match_minute_log_queries_test.exs | 46 ++
.../queries/match_month_log_queries_test.exs | 49 ++
.../match_quarter_log_queries_test.exs | 49 ++
.../queries/match_week_log_queries_test.exs | 49 ++
.../queries/match_year_log_queries_test.exs | 48 ++
.../queries/server_day_log_queries_test.exs | 47 ++
.../server_minute_log_queries_test.exs | 46 ++
.../queries/server_month_log_queries_test.exs | 49 ++
.../server_quarter_log_queries_test.exs | 49 ++
.../queries/server_week_log_queries_test.exs | 49 ++
.../queries/server_year_log_queries_test.exs | 48 ++
test/support/fixtures/logging_fixtures.ex | 173 ++++++
83 files changed, 5646 insertions(+), 78 deletions(-)
create mode 100644 lib/teiserver/logging/libs/match_day_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/match_minute_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/match_month_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/match_quarter_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/match_week_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/match_year_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/server_day_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/server_minute_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/server_month_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/server_quarter_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/server_week_log_lib.ex
create mode 100644 lib/teiserver/logging/libs/server_year_log_lib.ex
create mode 100644 lib/teiserver/logging/queries/match_day_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/match_minute_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/match_month_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/match_quarter_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/match_week_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/match_year_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/server_day_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/server_minute_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/server_month_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/server_quarter_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/server_week_log_queries.ex
create mode 100644 lib/teiserver/logging/queries/server_year_log_queries.ex
delete mode 100644 lib/teiserver/logging/schemas/match_activity_day_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_activity_month_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_activity_quarter_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_activity_week_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_activity_year_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_day_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_minute_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_month_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_quarter_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_week_log.ex
create mode 100644 lib/teiserver/logging/schemas/match_year_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_activity_day_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_activity_minute_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_activity_month_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_activity_quarter_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_activity_week_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_activity_year_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_day_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_minute_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_month_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_quarter_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_week_log.ex
create mode 100644 lib/teiserver/logging/schemas/server_year_log.ex
rename lib/{ => teiserver/migrations}/migration.ex (100%)
create mode 100644 lib/teiserver/migrations/postgres/v02.ex
create mode 100644 test/logging/libs/match_day_log_lib_test.exs
create mode 100644 test/logging/libs/match_minute_log_lib_test.exs
create mode 100644 test/logging/libs/match_month_log_lib_test.exs
create mode 100644 test/logging/libs/match_quarter_log_lib_test.exs
create mode 100644 test/logging/libs/match_week_log_lib_test.exs
create mode 100644 test/logging/libs/match_year_log_lib_test.exs
create mode 100644 test/logging/libs/server_day_log_lib_test.exs
create mode 100644 test/logging/libs/server_minute_log_lib_test.exs
create mode 100644 test/logging/libs/server_month_log_lib_test.exs
create mode 100644 test/logging/libs/server_quarter_log_lib_test.exs
create mode 100644 test/logging/libs/server_week_log_lib_test.exs
create mode 100644 test/logging/libs/server_year_log_lib_test.exs
create mode 100644 test/logging/queries/match_day_log_queries_test.exs
create mode 100644 test/logging/queries/match_minute_log_queries_test.exs
create mode 100644 test/logging/queries/match_month_log_queries_test.exs
create mode 100644 test/logging/queries/match_quarter_log_queries_test.exs
create mode 100644 test/logging/queries/match_week_log_queries_test.exs
create mode 100644 test/logging/queries/match_year_log_queries_test.exs
create mode 100644 test/logging/queries/server_day_log_queries_test.exs
create mode 100644 test/logging/queries/server_minute_log_queries_test.exs
create mode 100644 test/logging/queries/server_month_log_queries_test.exs
create mode 100644 test/logging/queries/server_quarter_log_queries_test.exs
create mode 100644 test/logging/queries/server_week_log_queries_test.exs
create mode 100644 test/logging/queries/server_year_log_queries_test.exs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ebc554b98..785cd70f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,9 @@
- Swapped `team_colour` for `player_colour`
- Refactored the client update process
- Added User and Server runtime settings
+- Added logging for server and match usage
+- Added Telemetry events
+
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index c6d2d4d3b..7df142654 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -282,9 +282,11 @@ defmodule Teiserver.Api do
# Logging
alias Teiserver.Logging.AuditLogLib
- @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) ::
+ {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_audit_log(user_id, ip, action, details), to: AuditLogLib
- @spec create_anonymous_audit_log(String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_anonymous_audit_log(String.t(), String.t(), map()) ::
+ {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_anonymous_audit_log(ip, action, details), to: AuditLogLib
end
diff --git a/lib/teiserver/contexts/logging.ex b/lib/teiserver/contexts/logging.ex
index cb130519a..20a952632 100644
--- a/lib/teiserver/contexts/logging.ex
+++ b/lib/teiserver/contexts/logging.ex
@@ -3,11 +3,21 @@ defmodule Teiserver.Logging do
The contextual module for:
- `Teiserver.Logging.AuditLog`
- `Teiserver.Logging.CrashLog`
- - `Teiserver.Logging.UserLog`
- - `Teiserver.Logging.UsageLog`
- - `Teiserver.Logging.LobbyLog`
- - `Teiserver.Logging.MatchLog`
- - `Teiserver.Logging.EventLog`
+ - `Teiserver.Logging.MatchMinuteLog`
+ - `Teiserver.Logging.MatchDayLog`
+ - `Teiserver.Logging.MatchWeekLog`
+ - `Teiserver.Logging.MatchQuarterLog`
+ - `Teiserver.Logging.MatchYearLog`
+ - `Teiserver.Logging.ServerMinuteLog`
+ - `Teiserver.Logging.ServerDayLog`
+ - `Teiserver.Logging.ServerWeekLog`
+ - `Teiserver.Logging.ServerQuarterLog`
+ - `Teiserver.Logging.ServerYearLog`
+
+ ## Minutes through to years
+ The system is designed to take a snapshot of activity every minute and roll these up into day logs at the end of each day. The system then later creates week, month, quarter and year snapshots from the day logs. While we could just roll up the day logs each time we need to make a query the space taken by the extra snapshots is very small and makes querying so much easier I decided to add the extra files/tables.
+
+ Minute to minute logs are deleted periodically to save space but Day logs and beyond are designed to be kept.
"""
# AuditLogs
@@ -18,51 +28,504 @@ defmodule Teiserver.Logging do
defdelegate audit_log_query(args), to: AuditLogQueries
@doc section: :audit_log
- @spec list_audit_logs(Teiserver.query_args()) :: [AuditLog.t]
+ @spec list_audit_logs(Teiserver.query_args()) :: [AuditLog.t()]
defdelegate list_audit_logs(args), to: AuditLogLib
@doc section: :audit_log
- @spec get_audit_log!(AuditLog.id()) :: AuditLog.t
- @spec get_audit_log!(AuditLog.id(), Teiserver.query_args()) :: AuditLog.t
+ @spec get_audit_log!(AuditLog.id()) :: AuditLog.t()
+ @spec get_audit_log!(AuditLog.id(), Teiserver.query_args()) :: AuditLog.t()
defdelegate get_audit_log!(audit_log_id, query_args \\ []), to: AuditLogLib
@doc section: :audit_log
- @spec get_audit_log(AuditLog.id()) :: AuditLog.t | nil
- @spec get_audit_log(AuditLog.id(), Teiserver.query_args()) :: AuditLog.t | nil
+ @spec get_audit_log(AuditLog.id()) :: AuditLog.t() | nil
+ @spec get_audit_log(AuditLog.id(), Teiserver.query_args()) :: AuditLog.t() | nil
defdelegate get_audit_log(audit_log_id, query_args \\ []), to: AuditLogLib
@doc section: :audit_log
- @spec create_audit_log(map) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_audit_log(map) :: {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_audit_log(attrs), to: AuditLogLib
@doc section: :audit_log
- @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) ::
+ {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_audit_log(user_id, ip, action, details), to: AuditLogLib
@doc section: :audit_log
- @spec create_anonymous_audit_log(String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_anonymous_audit_log(String.t(), String.t(), map()) ::
+ {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_anonymous_audit_log(ip, action, details), to: AuditLogLib
@doc section: :audit_log
- @spec update_audit_log(AuditLog, map) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_audit_log(AuditLog, map) :: {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_audit_log(audit_log, attrs), to: AuditLogLib
@doc section: :audit_log
- @spec delete_audit_log(AuditLog.t) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_audit_log(AuditLog.t()) :: {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_audit_log(audit_log), to: AuditLogLib
@doc section: :audit_log
- @spec change_audit_log(AuditLog.t) :: Ecto.Changeset.t()
- @spec change_audit_log(AuditLog.t, map) :: Ecto.Changeset.t()
+ @spec change_audit_log(AuditLog.t()) :: Ecto.Changeset.t()
+ @spec change_audit_log(AuditLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_audit_log(audit_log, attrs \\ %{}), to: AuditLogLib
-
# Crash logs
- # UserLogs (UserActivity logs in Barserver)
- # UsageLogs (ServerActivity logs in Barserver, add stats of things like messages sent etc)
- # LobbyLogs
- # MatchLogs
- # EventLogs (Telemetry events)
- # + Aggregates
+
+
+ # MatchMinuteLogs
+ alias Teiserver.Logging.{MatchMinuteLog, MatchMinuteLogLib, MatchMinuteLogQueries}
+
+ @doc false
+ @spec match_minute_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate match_minute_log_query(args), to: MatchMinuteLogQueries
+
+ @doc section: :match_minute_log
+ @spec list_match_minute_logs(Teiserver.query_args()) :: [MatchMinuteLog.t]
+ defdelegate list_match_minute_logs(args), to: MatchMinuteLogLib
+
+ @doc section: :match_minute_log
+ @spec get_match_minute_log!(DateTime.t()) :: MatchMinuteLog.t
+ @spec get_match_minute_log!(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t
+ defdelegate get_match_minute_log!(timestamp, query_args \\ []), to: MatchMinuteLogLib
+
+ @doc section: :match_minute_log
+ @spec get_match_minute_log(DateTime.t()) :: MatchMinuteLog.t | nil
+ @spec get_match_minute_log(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t | nil
+ defdelegate get_match_minute_log(timestamp, query_args \\ []), to: MatchMinuteLogLib
+
+ @doc section: :match_minute_log
+ @spec create_match_minute_log(map) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_match_minute_log(attrs), to: MatchMinuteLogLib
+
+ @doc section: :match_minute_log
+ @spec update_match_minute_log(MatchMinuteLog, map) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_match_minute_log(match_minute_log, attrs), to: MatchMinuteLogLib
+
+ @doc section: :match_minute_log
+ @spec delete_match_minute_log(MatchMinuteLog.t) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_match_minute_log(match_minute_log), to: MatchMinuteLogLib
+
+ @doc section: :match_minute_log
+ @spec change_match_minute_log(MatchMinuteLog.t) :: Ecto.Changeset.t()
+ @spec change_match_minute_log(MatchMinuteLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_match_minute_log(match_minute_log, attrs \\ %{}), to: MatchMinuteLogLib
+
+ # MatchDayLogs
+ alias Teiserver.Logging.{MatchDayLog, MatchDayLogLib, MatchDayLogQueries}
+
+ @doc false
+ @spec match_day_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate match_day_log_query(args), to: MatchDayLogQueries
+
+ @doc section: :match_day_log
+ @spec list_match_day_logs(Teiserver.query_args()) :: [MatchDayLog.t]
+ defdelegate list_match_day_logs(args), to: MatchDayLogLib
+
+ @doc section: :match_day_log
+ @spec get_match_day_log!(Date.t()) :: MatchDayLog.t
+ @spec get_match_day_log!(Date.t(), Teiserver.query_args()) :: MatchDayLog.t
+ defdelegate get_match_day_log!(date, query_args \\ []), to: MatchDayLogLib
+
+ @doc section: :match_day_log
+ @spec get_match_day_log(Date.t()) :: MatchDayLog.t | nil
+ @spec get_match_day_log(Date.t(), Teiserver.query_args()) :: MatchDayLog.t | nil
+ defdelegate get_match_day_log(date, query_args \\ []), to: MatchDayLogLib
+
+ @doc section: :match_day_log
+ @spec create_match_day_log(map) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_match_day_log(attrs), to: MatchDayLogLib
+
+ @doc section: :match_day_log
+ @spec update_match_day_log(MatchDayLog, map) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_match_day_log(match_day_log, attrs), to: MatchDayLogLib
+
+ @doc section: :match_day_log
+ @spec delete_match_day_log(MatchDayLog.t) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_match_day_log(match_day_log), to: MatchDayLogLib
+
+ @doc section: :match_day_log
+ @spec change_match_day_log(MatchDayLog.t) :: Ecto.Changeset.t()
+ @spec change_match_day_log(MatchDayLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_match_day_log(match_day_log, attrs \\ %{}), to: MatchDayLogLib
+
+ # MatchWeekLogs
+ alias Teiserver.Logging.{MatchWeekLog, MatchWeekLogLib, MatchWeekLogQueries}
+
+ @doc false
+ @spec match_week_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate match_week_log_query(args), to: MatchWeekLogQueries
+
+ @doc section: :match_week_log
+ @spec list_match_week_logs(Teiserver.query_args()) :: [MatchWeekLog.t]
+ defdelegate list_match_week_logs(args), to: MatchWeekLogLib
+
+ @doc section: :match_week_log
+ @spec get_match_week_log!(Date.t()) :: MatchWeekLog.t
+ @spec get_match_week_log!(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t
+ defdelegate get_match_week_log!(date, query_args \\ []), to: MatchWeekLogLib
+
+ @doc section: :match_week_log
+ @spec get_match_week_log(Date.t()) :: MatchWeekLog.t | nil
+ @spec get_match_week_log(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t | nil
+ defdelegate get_match_week_log(date, query_args \\ []), to: MatchWeekLogLib
+
+ @doc section: :match_week_log
+ @spec create_match_week_log(map) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_match_week_log(attrs), to: MatchWeekLogLib
+
+ @doc section: :match_week_log
+ @spec update_match_week_log(MatchWeekLog, map) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_match_week_log(match_week_log, attrs), to: MatchWeekLogLib
+
+ @doc section: :match_week_log
+ @spec delete_match_week_log(MatchWeekLog.t) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_match_week_log(match_week_log), to: MatchWeekLogLib
+
+ @doc section: :match_week_log
+ @spec change_match_week_log(MatchWeekLog.t) :: Ecto.Changeset.t()
+ @spec change_match_week_log(MatchWeekLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_match_week_log(match_week_log, attrs \\ %{}), to: MatchWeekLogLib
+
+ # MatchMonthLogs
+ alias Teiserver.Logging.{MatchMonthLog, MatchMonthLogLib, MatchMonthLogQueries}
+
+ @doc false
+ @spec match_month_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate match_month_log_query(args), to: MatchMonthLogQueries
+
+ @doc section: :match_month_log
+ @spec list_match_month_logs(Teiserver.query_args()) :: [MatchMonthLog.t]
+ defdelegate list_match_month_logs(args), to: MatchMonthLogLib
+
+ @doc section: :match_month_log
+ @spec get_match_month_log!(Date.t()) :: MatchMonthLog.t
+ @spec get_match_month_log!(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t
+ defdelegate get_match_month_log!(date, query_args \\ []), to: MatchMonthLogLib
+
+ @doc section: :match_month_log
+ @spec get_match_month_log(Date.t()) :: MatchMonthLog.t | nil
+ @spec get_match_month_log(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t | nil
+ defdelegate get_match_month_log(date, query_args \\ []), to: MatchMonthLogLib
+
+ @doc section: :match_month_log
+ @spec create_match_month_log(map) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_match_month_log(attrs), to: MatchMonthLogLib
+
+ @doc section: :match_month_log
+ @spec update_match_month_log(MatchMonthLog, map) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_match_month_log(match_month_log, attrs), to: MatchMonthLogLib
+
+ @doc section: :match_month_log
+ @spec delete_match_month_log(MatchMonthLog.t) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_match_month_log(match_month_log), to: MatchMonthLogLib
+
+ @doc section: :match_month_log
+ @spec change_match_month_log(MatchMonthLog.t) :: Ecto.Changeset.t()
+ @spec change_match_month_log(MatchMonthLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_match_month_log(match_month_log, attrs \\ %{}), to: MatchMonthLogLib
+
+ # MatchQuarterLogs
+ alias Teiserver.Logging.{MatchQuarterLog, MatchQuarterLogLib, MatchQuarterLogQueries}
+
+ @doc false
+ @spec match_quarter_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate match_quarter_log_query(args), to: MatchQuarterLogQueries
+
+ @doc section: :match_quarter_log
+ @spec list_match_quarter_logs(Teiserver.query_args()) :: [MatchQuarterLog.t]
+ defdelegate list_match_quarter_logs(args), to: MatchQuarterLogLib
+
+ @doc section: :match_quarter_log
+ @spec get_match_quarter_log!(Date.t()) :: MatchQuarterLog.t
+ @spec get_match_quarter_log!(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t
+ defdelegate get_match_quarter_log!(date, query_args \\ []), to: MatchQuarterLogLib
+
+ @doc section: :match_quarter_log
+ @spec get_match_quarter_log(Date.t()) :: MatchQuarterLog.t | nil
+ @spec get_match_quarter_log(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t | nil
+ defdelegate get_match_quarter_log(date, query_args \\ []), to: MatchQuarterLogLib
+
+ @doc section: :match_quarter_log
+ @spec create_match_quarter_log(map) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_match_quarter_log(attrs), to: MatchQuarterLogLib
+
+ @doc section: :match_quarter_log
+ @spec update_match_quarter_log(MatchQuarterLog, map) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_match_quarter_log(match_quarter_log, attrs), to: MatchQuarterLogLib
+
+ @doc section: :match_quarter_log
+ @spec delete_match_quarter_log(MatchQuarterLog.t) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_match_quarter_log(match_quarter_log), to: MatchQuarterLogLib
+
+ @doc section: :match_quarter_log
+ @spec change_match_quarter_log(MatchQuarterLog.t) :: Ecto.Changeset.t()
+ @spec change_match_quarter_log(MatchQuarterLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_match_quarter_log(match_quarter_log, attrs \\ %{}), to: MatchQuarterLogLib
+
+ # MatchYearLogs
+ alias Teiserver.Logging.{MatchYearLog, MatchYearLogLib, MatchYearLogQueries}
+
+ @doc false
+ @spec match_year_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate match_year_log_query(args), to: MatchYearLogQueries
+
+ @doc section: :match_year_log
+ @spec list_match_year_logs(Teiserver.query_args()) :: [MatchYearLog.t]
+ defdelegate list_match_year_logs(args), to: MatchYearLogLib
+
+ @doc section: :match_year_log
+ @spec get_match_year_log!(Date.t()) :: MatchYearLog.t
+ @spec get_match_year_log!(Date.t(), Teiserver.query_args()) :: MatchYearLog.t
+ defdelegate get_match_year_log!(date, query_args \\ []), to: MatchYearLogLib
+
+ @doc section: :match_year_log
+ @spec get_match_year_log(Date.t()) :: MatchYearLog.t | nil
+ @spec get_match_year_log(Date.t(), Teiserver.query_args()) :: MatchYearLog.t | nil
+ defdelegate get_match_year_log(date, query_args \\ []), to: MatchYearLogLib
+
+ @doc section: :match_year_log
+ @spec create_match_year_log(map) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_match_year_log(attrs), to: MatchYearLogLib
+
+ @doc section: :match_year_log
+ @spec update_match_year_log(MatchYearLog, map) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_match_year_log(match_year_log, attrs), to: MatchYearLogLib
+
+ @doc section: :match_year_log
+ @spec delete_match_year_log(MatchYearLog.t) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_match_year_log(match_year_log), to: MatchYearLogLib
+
+ @doc section: :match_year_log
+ @spec change_match_year_log(MatchYearLog.t) :: Ecto.Changeset.t()
+ @spec change_match_year_log(MatchYearLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_match_year_log(match_year_log, attrs \\ %{}), to: MatchYearLogLib
+
+
+ # ServerMinuteLogs
+ alias Teiserver.Logging.{ServerMinuteLog, ServerMinuteLogLib, ServerMinuteLogQueries}
+
+ @doc false
+ @spec server_minute_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate server_minute_log_query(args), to: ServerMinuteLogQueries
+
+ @doc section: :server_minute_log
+ @spec list_server_minute_logs(Teiserver.query_args()) :: [ServerMinuteLog.t]
+ defdelegate list_server_minute_logs(args), to: ServerMinuteLogLib
+
+ @doc section: :server_minute_log
+ @spec get_server_minute_log!(DateTime.t()) :: ServerMinuteLog.t
+ @spec get_server_minute_log!(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t
+ defdelegate get_server_minute_log!(timestamp, query_args \\ []), to: ServerMinuteLogLib
+
+ @doc section: :server_minute_log
+ @spec get_server_minute_log(DateTime.t()) :: ServerMinuteLog.t | nil
+ @spec get_server_minute_log(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t | nil
+ defdelegate get_server_minute_log(timestamp, query_args \\ []), to: ServerMinuteLogLib
+
+ @doc section: :server_minute_log
+ @spec create_server_minute_log(map) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_server_minute_log(attrs), to: ServerMinuteLogLib
+
+ @doc section: :server_minute_log
+ @spec update_server_minute_log(ServerMinuteLog, map) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_server_minute_log(server_minute_log, attrs), to: ServerMinuteLogLib
+
+ @doc section: :server_minute_log
+ @spec delete_server_minute_log(ServerMinuteLog.t) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_server_minute_log(server_minute_log), to: ServerMinuteLogLib
+
+ @doc section: :server_minute_log
+ @spec change_server_minute_log(ServerMinuteLog.t) :: Ecto.Changeset.t()
+ @spec change_server_minute_log(ServerMinuteLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_server_minute_log(server_minute_log, attrs \\ %{}), to: ServerMinuteLogLib
+
+ # ServerDayLogs
+ alias Teiserver.Logging.{ServerDayLog, ServerDayLogLib, ServerDayLogQueries}
+
+ @doc false
+ @spec server_day_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate server_day_log_query(args), to: ServerDayLogQueries
+
+ @doc section: :server_day_log
+ @spec list_server_day_logs(Teiserver.query_args()) :: [ServerDayLog.t]
+ defdelegate list_server_day_logs(args), to: ServerDayLogLib
+
+ @doc section: :server_day_log
+ @spec get_server_day_log!(Date.t()) :: ServerDayLog.t
+ @spec get_server_day_log!(Date.t(), Teiserver.query_args()) :: ServerDayLog.t
+ defdelegate get_server_day_log!(date, query_args \\ []), to: ServerDayLogLib
+
+ @doc section: :server_day_log
+ @spec get_server_day_log(Date.t()) :: ServerDayLog.t | nil
+ @spec get_server_day_log(Date.t(), Teiserver.query_args()) :: ServerDayLog.t | nil
+ defdelegate get_server_day_log(date, query_args \\ []), to: ServerDayLogLib
+
+ @doc section: :server_day_log
+ @spec create_server_day_log(map) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_server_day_log(attrs), to: ServerDayLogLib
+
+ @doc section: :server_day_log
+ @spec update_server_day_log(ServerDayLog, map) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_server_day_log(server_day_log, attrs), to: ServerDayLogLib
+
+ @doc section: :server_day_log
+ @spec delete_server_day_log(ServerDayLog.t) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_server_day_log(server_day_log), to: ServerDayLogLib
+
+ @doc section: :server_day_log
+ @spec change_server_day_log(ServerDayLog.t) :: Ecto.Changeset.t()
+ @spec change_server_day_log(ServerDayLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_server_day_log(server_day_log, attrs \\ %{}), to: ServerDayLogLib
+
+ # ServerWeekLogs
+ alias Teiserver.Logging.{ServerWeekLog, ServerWeekLogLib, ServerWeekLogQueries}
+
+ @doc false
+ @spec server_week_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate server_week_log_query(args), to: ServerWeekLogQueries
+
+ @doc section: :server_week_log
+ @spec list_server_week_logs(Teiserver.query_args()) :: [ServerWeekLog.t]
+ defdelegate list_server_week_logs(args), to: ServerWeekLogLib
+
+ @doc section: :server_week_log
+ @spec get_server_week_log!(Date.t()) :: ServerWeekLog.t
+ @spec get_server_week_log!(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t
+ defdelegate get_server_week_log!(date, query_args \\ []), to: ServerWeekLogLib
+
+ @doc section: :server_week_log
+ @spec get_server_week_log(Date.t()) :: ServerWeekLog.t | nil
+ @spec get_server_week_log(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t | nil
+ defdelegate get_server_week_log(date, query_args \\ []), to: ServerWeekLogLib
+
+ @doc section: :server_week_log
+ @spec create_server_week_log(map) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_server_week_log(attrs), to: ServerWeekLogLib
+
+ @doc section: :server_week_log
+ @spec update_server_week_log(ServerWeekLog, map) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_server_week_log(server_week_log, attrs), to: ServerWeekLogLib
+
+ @doc section: :server_week_log
+ @spec delete_server_week_log(ServerWeekLog.t) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_server_week_log(server_week_log), to: ServerWeekLogLib
+
+ @doc section: :server_week_log
+ @spec change_server_week_log(ServerWeekLog.t) :: Ecto.Changeset.t()
+ @spec change_server_week_log(ServerWeekLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_server_week_log(server_week_log, attrs \\ %{}), to: ServerWeekLogLib
+
+ # ServerMonthLogs
+ alias Teiserver.Logging.{ServerMonthLog, ServerMonthLogLib, ServerMonthLogQueries}
+
+ @doc false
+ @spec server_month_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate server_month_log_query(args), to: ServerMonthLogQueries
+
+ @doc section: :server_month_log
+ @spec list_server_month_logs(Teiserver.query_args()) :: [ServerMonthLog.t]
+ defdelegate list_server_month_logs(args), to: ServerMonthLogLib
+
+ @doc section: :server_month_log
+ @spec get_server_month_log!(Date.t()) :: ServerMonthLog.t
+ @spec get_server_month_log!(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t
+ defdelegate get_server_month_log!(date, query_args \\ []), to: ServerMonthLogLib
+
+ @doc section: :server_month_log
+ @spec get_server_month_log(Date.t()) :: ServerMonthLog.t | nil
+ @spec get_server_month_log(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t | nil
+ defdelegate get_server_month_log(date, query_args \\ []), to: ServerMonthLogLib
+
+ @doc section: :server_month_log
+ @spec create_server_month_log(map) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_server_month_log(attrs), to: ServerMonthLogLib
+
+ @doc section: :server_month_log
+ @spec update_server_month_log(ServerMonthLog, map) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_server_month_log(server_month_log, attrs), to: ServerMonthLogLib
+
+ @doc section: :server_month_log
+ @spec delete_server_month_log(ServerMonthLog.t) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_server_month_log(server_month_log), to: ServerMonthLogLib
+
+ @doc section: :server_month_log
+ @spec change_server_month_log(ServerMonthLog.t) :: Ecto.Changeset.t()
+ @spec change_server_month_log(ServerMonthLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_server_month_log(server_month_log, attrs \\ %{}), to: ServerMonthLogLib
+
+ # ServerQuarterLogs
+ alias Teiserver.Logging.{ServerQuarterLog, ServerQuarterLogLib, ServerQuarterLogQueries}
+
+ @doc false
+ @spec server_quarter_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate server_quarter_log_query(args), to: ServerQuarterLogQueries
+
+ @doc section: :server_quarter_log
+ @spec list_server_quarter_logs(Teiserver.query_args()) :: [ServerQuarterLog.t]
+ defdelegate list_server_quarter_logs(args), to: ServerQuarterLogLib
+
+ @doc section: :server_quarter_log
+ @spec get_server_quarter_log!(Date.t()) :: ServerQuarterLog.t
+ @spec get_server_quarter_log!(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t
+ defdelegate get_server_quarter_log!(date, query_args \\ []), to: ServerQuarterLogLib
+
+ @doc section: :server_quarter_log
+ @spec get_server_quarter_log(Date.t()) :: ServerQuarterLog.t | nil
+ @spec get_server_quarter_log(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t | nil
+ defdelegate get_server_quarter_log(date, query_args \\ []), to: ServerQuarterLogLib
+
+ @doc section: :server_quarter_log
+ @spec create_server_quarter_log(map) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_server_quarter_log(attrs), to: ServerQuarterLogLib
+
+ @doc section: :server_quarter_log
+ @spec update_server_quarter_log(ServerQuarterLog, map) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_server_quarter_log(server_quarter_log, attrs), to: ServerQuarterLogLib
+
+ @doc section: :server_quarter_log
+ @spec delete_server_quarter_log(ServerQuarterLog.t) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_server_quarter_log(server_quarter_log), to: ServerQuarterLogLib
+
+ @doc section: :server_quarter_log
+ @spec change_server_quarter_log(ServerQuarterLog.t) :: Ecto.Changeset.t()
+ @spec change_server_quarter_log(ServerQuarterLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_server_quarter_log(server_quarter_log, attrs \\ %{}), to: ServerQuarterLogLib
+
+ # ServerYearLogs
+ alias Teiserver.Logging.{ServerYearLog, ServerYearLogLib, ServerYearLogQueries}
+
+ @doc false
+ @spec server_year_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate server_year_log_query(args), to: ServerYearLogQueries
+
+ @doc section: :server_year_log
+ @spec list_server_year_logs(Teiserver.query_args()) :: [ServerYearLog.t]
+ defdelegate list_server_year_logs(args), to: ServerYearLogLib
+
+ @doc section: :server_year_log
+ @spec get_server_year_log!(Date.t()) :: ServerYearLog.t
+ @spec get_server_year_log!(Date.t(), Teiserver.query_args()) :: ServerYearLog.t
+ defdelegate get_server_year_log!(date, query_args \\ []), to: ServerYearLogLib
+
+ @doc section: :server_year_log
+ @spec get_server_year_log(Date.t()) :: ServerYearLog.t | nil
+ @spec get_server_year_log(Date.t(), Teiserver.query_args()) :: ServerYearLog.t | nil
+ defdelegate get_server_year_log(date, query_args \\ []), to: ServerYearLogLib
+
+ @doc section: :server_year_log
+ @spec create_server_year_log(map) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate create_server_year_log(attrs), to: ServerYearLogLib
+
+ @doc section: :server_year_log
+ @spec update_server_year_log(ServerYearLog, map) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate update_server_year_log(server_year_log, attrs), to: ServerYearLogLib
+
+ @doc section: :server_year_log
+ @spec delete_server_year_log(ServerYearLog.t) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_server_year_log(server_year_log), to: ServerYearLogLib
+
+ @doc section: :server_year_log
+ @spec change_server_year_log(ServerYearLog.t) :: Ecto.Changeset.t()
+ @spec change_server_year_log(ServerYearLog.t, map) :: Ecto.Changeset.t()
+ defdelegate change_server_year_log(server_year_log, attrs \\ %{}), to: ServerYearLogLib
end
diff --git a/lib/teiserver/logging/libs/audit_log_lib.ex b/lib/teiserver/logging/libs/audit_log_lib.ex
index adc54f029..523a6149f 100644
--- a/lib/teiserver/logging/libs/audit_log_lib.ex
+++ b/lib/teiserver/logging/libs/audit_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.AuditLogLib do
def get_audit_log(audit_log_id, query_args \\ []) do
(query_args ++ [id: audit_log_id])
|> AuditLogQueries.audit_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -80,14 +80,15 @@ defmodule Teiserver.Logging.AuditLogLib do
{:ok, %AuditLog{}}
"""
- @spec create_audit_log(map) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_audit_log(map) :: {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
def create_audit_log(attrs) do
%AuditLog{}
|> AuditLog.changeset(attrs)
|> Repo.insert()
end
- @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) ::
+ {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
def create_audit_log(user_id, ip, action, details) do
%AuditLog{}
|> AuditLog.changeset(%{
@@ -102,7 +103,8 @@ defmodule Teiserver.Logging.AuditLogLib do
@doc """
See `create_audit_log/4`, this is the same but without a user.
"""
- @spec create_anonymous_audit_log(String.t(), String.t(), map()) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_anonymous_audit_log(String.t(), String.t(), map()) ::
+ {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
def create_anonymous_audit_log(ip, action, details) do
%AuditLog{}
|> AuditLog.changeset(%{
@@ -125,7 +127,7 @@ defmodule Teiserver.Logging.AuditLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_audit_log(AuditLog.t, map) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_audit_log(AuditLog.t(), map) :: {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
def update_audit_log(%AuditLog{} = audit_log, attrs) do
audit_log
|> AuditLog.changeset(attrs)
@@ -144,7 +146,7 @@ defmodule Teiserver.Logging.AuditLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_audit_log(AuditLog.t) :: {:ok, AuditLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_audit_log(AuditLog.t()) :: {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
def delete_audit_log(%AuditLog{} = audit_log) do
Repo.delete(audit_log)
end
@@ -158,7 +160,7 @@ defmodule Teiserver.Logging.AuditLogLib do
%Ecto.Changeset{data: %AuditLog{}}
"""
- @spec change_audit_log(AuditLog.t, map) :: Ecto.Changeset.t
+ @spec change_audit_log(AuditLog.t(), map) :: Ecto.Changeset.t()
def change_audit_log(%AuditLog{} = audit_log, attrs \\ %{}) do
AuditLog.changeset(audit_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/match_day_log_lib.ex b/lib/teiserver/logging/libs/match_day_log_lib.ex
new file mode 100644
index 000000000..ece9a1acb
--- /dev/null
+++ b/lib/teiserver/logging/libs/match_day_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.MatchDayLogLib do
+ @moduledoc """
+ Library of match_day_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{MatchDayLog, MatchDayLogQueries}
+
+ @doc """
+ Returns the list of match_day_logs.
+
+ ## Examples
+
+ iex> list_match_day_logs()
+ [%MatchDayLog{}, ...]
+
+ """
+ @spec list_match_day_logs(Teiserver.query_args()) :: [MatchDayLog.t()]
+ def list_match_day_logs(query_args) do
+ query_args
+ |> MatchDayLogQueries.match_day_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single match_day_log.
+
+ Raises `Ecto.NoResultsError` if the MatchDayLog does not exist.
+
+ ## Examples
+
+ iex> get_match_day_log!(123)
+ %MatchDayLog{}
+
+ iex> get_match_day_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_match_day_log!(Date.t()) :: MatchDayLog.t()
+ @spec get_match_day_log!(Date.t(), Teiserver.query_args()) :: MatchDayLog.t()
+ def get_match_day_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchDayLogQueries.match_day_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single match_day_log.
+
+ Returns nil if the MatchDayLog does not exist.
+
+ ## Examples
+
+ iex> get_match_day_log(123)
+ %MatchDayLog{}
+
+ iex> get_match_day_log(456)
+ nil
+
+ """
+ @spec get_match_day_log(Date.t()) :: MatchDayLog.t() | nil
+ @spec get_match_day_log(Date.t(), Teiserver.query_args()) :: MatchDayLog.t() | nil
+ def get_match_day_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchDayLogQueries.match_day_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a match_day_log.
+
+ ## Examples
+
+ iex> create_match_day_log(%{field: value})
+ {:ok, %MatchDayLog{}}
+
+ iex> create_match_day_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_match_day_log(map) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t}
+ def create_match_day_log(attrs) do
+ %MatchDayLog{}
+ |> MatchDayLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a match_day_log.
+
+ ## Examples
+
+ iex> update_match_day_log(match_day_log, %{field: new_value})
+ {:ok, %MatchDayLog{}}
+
+ iex> update_match_day_log(match_day_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_match_day_log(MatchDayLog.t, map) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t}
+ def update_match_day_log(%MatchDayLog{} = match_day_log, attrs) do
+ match_day_log
+ |> MatchDayLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a match_day_log.
+
+ ## Examples
+
+ iex> delete_match_day_log(match_day_log)
+ {:ok, %MatchDayLog{}}
+
+ iex> delete_match_day_log(match_day_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_match_day_log(MatchDayLog.t) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t}
+ def delete_match_day_log(%MatchDayLog{} = match_day_log) do
+ Repo.delete(match_day_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking match_day_log changes.
+
+ ## Examples
+
+ iex> change_match_day_log(match_day_log)
+ %Ecto.Changeset{data: %MatchDayLog{}}
+
+ """
+ @spec change_match_day_log(MatchDayLog.t, map) :: Ecto.Changeset.t
+ def change_match_day_log(%MatchDayLog{} = match_day_log, attrs \\ %{}) do
+ MatchDayLog.changeset(match_day_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/match_minute_log_lib.ex b/lib/teiserver/logging/libs/match_minute_log_lib.ex
new file mode 100644
index 000000000..75d58e27f
--- /dev/null
+++ b/lib/teiserver/logging/libs/match_minute_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.MatchMinuteLogLib do
+ @moduledoc """
+ Library of match_minute_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{MatchMinuteLog, MatchMinuteLogQueries}
+
+ @doc """
+ Returns the list of match_minute_logs.
+
+ ## Examples
+
+ iex> list_match_minute_logs()
+ [%MatchMinuteLog{}, ...]
+
+ """
+ @spec list_match_minute_logs(Teiserver.query_args()) :: [MatchMinuteLog.t()]
+ def list_match_minute_logs(query_args) do
+ query_args
+ |> MatchMinuteLogQueries.match_minute_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single match_minute_log.
+
+ Raises `Ecto.NoResultsError` if the MatchMinuteLog does not exist.
+
+ ## Examples
+
+ iex> get_match_minute_log!(123)
+ %MatchMinuteLog{}
+
+ iex> get_match_minute_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_match_minute_log!(DateTime.t()) :: MatchMinuteLog.t()
+ @spec get_match_minute_log!(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t()
+ def get_match_minute_log!(timestamp, query_args \\ []) do
+ (query_args ++ [timestamp: timestamp])
+ |> MatchMinuteLogQueries.match_minute_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single match_minute_log.
+
+ Returns nil if the MatchMinuteLog does not exist.
+
+ ## Examples
+
+ iex> get_match_minute_log(123)
+ %MatchMinuteLog{}
+
+ iex> get_match_minute_log(456)
+ nil
+
+ """
+ @spec get_match_minute_log(DateTime.t()) :: MatchMinuteLog.t() | nil
+ @spec get_match_minute_log(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t() | nil
+ def get_match_minute_log(timestamp, query_args \\ []) do
+ (query_args ++ [timestamp: timestamp])
+ |> MatchMinuteLogQueries.match_minute_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a match_minute_log.
+
+ ## Examples
+
+ iex> create_match_minute_log(%{field: value})
+ {:ok, %MatchMinuteLog{}}
+
+ iex> create_match_minute_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_match_minute_log(map) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t}
+ def create_match_minute_log(attrs) do
+ %MatchMinuteLog{}
+ |> MatchMinuteLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a match_minute_log.
+
+ ## Examples
+
+ iex> update_match_minute_log(match_minute_log, %{field: new_value})
+ {:ok, %MatchMinuteLog{}}
+
+ iex> update_match_minute_log(match_minute_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_match_minute_log(MatchMinuteLog.t, map) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t}
+ def update_match_minute_log(%MatchMinuteLog{} = match_minute_log, attrs) do
+ match_minute_log
+ |> MatchMinuteLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a match_minute_log.
+
+ ## Examples
+
+ iex> delete_match_minute_log(match_minute_log)
+ {:ok, %MatchMinuteLog{}}
+
+ iex> delete_match_minute_log(match_minute_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_match_minute_log(MatchMinuteLog.t) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t}
+ def delete_match_minute_log(%MatchMinuteLog{} = match_minute_log) do
+ Repo.delete(match_minute_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking match_minute_log changes.
+
+ ## Examples
+
+ iex> change_match_minute_log(match_minute_log)
+ %Ecto.Changeset{data: %MatchMinuteLog{}}
+
+ """
+ @spec change_match_minute_log(MatchMinuteLog.t, map) :: Ecto.Changeset.t
+ def change_match_minute_log(%MatchMinuteLog{} = match_minute_log, attrs \\ %{}) do
+ MatchMinuteLog.changeset(match_minute_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/match_month_log_lib.ex b/lib/teiserver/logging/libs/match_month_log_lib.ex
new file mode 100644
index 000000000..8c53a8ce6
--- /dev/null
+++ b/lib/teiserver/logging/libs/match_month_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.MatchMonthLogLib do
+ @moduledoc """
+ Library of match_month_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{MatchMonthLog, MatchMonthLogQueries}
+
+ @doc """
+ Returns the list of match_month_logs.
+
+ ## Examples
+
+ iex> list_match_month_logs()
+ [%MatchMonthLog{}, ...]
+
+ """
+ @spec list_match_month_logs(Teiserver.query_args()) :: [MatchMonthLog.t()]
+ def list_match_month_logs(query_args) do
+ query_args
+ |> MatchMonthLogQueries.match_month_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single match_month_log.
+
+ Raises `Ecto.NoResultsError` if the MatchMonthLog does not exist.
+
+ ## Examples
+
+ iex> get_match_month_log!(123)
+ %MatchMonthLog{}
+
+ iex> get_match_month_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_match_month_log!(Date.t()) :: MatchMonthLog.t()
+ @spec get_match_month_log!(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t()
+ def get_match_month_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchMonthLogQueries.match_month_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single match_month_log.
+
+ Returns nil if the MatchMonthLog does not exist.
+
+ ## Examples
+
+ iex> get_match_month_log(123)
+ %MatchMonthLog{}
+
+ iex> get_match_month_log(456)
+ nil
+
+ """
+ @spec get_match_month_log(Date.t()) :: MatchMonthLog.t() | nil
+ @spec get_match_month_log(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t() | nil
+ def get_match_month_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchMonthLogQueries.match_month_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a match_month_log.
+
+ ## Examples
+
+ iex> create_match_month_log(%{field: value})
+ {:ok, %MatchMonthLog{}}
+
+ iex> create_match_month_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_match_month_log(map) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t}
+ def create_match_month_log(attrs) do
+ %MatchMonthLog{}
+ |> MatchMonthLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a match_month_log.
+
+ ## Examples
+
+ iex> update_match_month_log(match_month_log, %{field: new_value})
+ {:ok, %MatchMonthLog{}}
+
+ iex> update_match_month_log(match_month_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_match_month_log(MatchMonthLog.t, map) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t}
+ def update_match_month_log(%MatchMonthLog{} = match_month_log, attrs) do
+ match_month_log
+ |> MatchMonthLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a match_month_log.
+
+ ## Examples
+
+ iex> delete_match_month_log(match_month_log)
+ {:ok, %MatchMonthLog{}}
+
+ iex> delete_match_month_log(match_month_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_match_month_log(MatchMonthLog.t) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t}
+ def delete_match_month_log(%MatchMonthLog{} = match_month_log) do
+ Repo.delete(match_month_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking match_month_log changes.
+
+ ## Examples
+
+ iex> change_match_month_log(match_month_log)
+ %Ecto.Changeset{data: %MatchMonthLog{}}
+
+ """
+ @spec change_match_month_log(MatchMonthLog.t, map) :: Ecto.Changeset.t
+ def change_match_month_log(%MatchMonthLog{} = match_month_log, attrs \\ %{}) do
+ MatchMonthLog.changeset(match_month_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/match_quarter_log_lib.ex b/lib/teiserver/logging/libs/match_quarter_log_lib.ex
new file mode 100644
index 000000000..7bbbf8dcc
--- /dev/null
+++ b/lib/teiserver/logging/libs/match_quarter_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.MatchQuarterLogLib do
+ @moduledoc """
+ Library of match_quarter_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{MatchQuarterLog, MatchQuarterLogQueries}
+
+ @doc """
+ Returns the list of match_quarter_logs.
+
+ ## Examples
+
+ iex> list_match_quarter_logs()
+ [%MatchQuarterLog{}, ...]
+
+ """
+ @spec list_match_quarter_logs(Teiserver.query_args()) :: [MatchQuarterLog.t()]
+ def list_match_quarter_logs(query_args) do
+ query_args
+ |> MatchQuarterLogQueries.match_quarter_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single match_quarter_log.
+
+ Raises `Ecto.NoResultsError` if the MatchQuarterLog does not exist.
+
+ ## Examples
+
+ iex> get_match_quarter_log!(123)
+ %MatchQuarterLog{}
+
+ iex> get_match_quarter_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_match_quarter_log!(Date.t()) :: MatchQuarterLog.t()
+ @spec get_match_quarter_log!(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t()
+ def get_match_quarter_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchQuarterLogQueries.match_quarter_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single match_quarter_log.
+
+ Returns nil if the MatchQuarterLog does not exist.
+
+ ## Examples
+
+ iex> get_match_quarter_log(123)
+ %MatchQuarterLog{}
+
+ iex> get_match_quarter_log(456)
+ nil
+
+ """
+ @spec get_match_quarter_log(Date.t()) :: MatchQuarterLog.t() | nil
+ @spec get_match_quarter_log(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t() | nil
+ def get_match_quarter_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchQuarterLogQueries.match_quarter_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a match_quarter_log.
+
+ ## Examples
+
+ iex> create_match_quarter_log(%{field: value})
+ {:ok, %MatchQuarterLog{}}
+
+ iex> create_match_quarter_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_match_quarter_log(map) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t}
+ def create_match_quarter_log(attrs) do
+ %MatchQuarterLog{}
+ |> MatchQuarterLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a match_quarter_log.
+
+ ## Examples
+
+ iex> update_match_quarter_log(match_quarter_log, %{field: new_value})
+ {:ok, %MatchQuarterLog{}}
+
+ iex> update_match_quarter_log(match_quarter_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_match_quarter_log(MatchQuarterLog.t, map) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t}
+ def update_match_quarter_log(%MatchQuarterLog{} = match_quarter_log, attrs) do
+ match_quarter_log
+ |> MatchQuarterLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a match_quarter_log.
+
+ ## Examples
+
+ iex> delete_match_quarter_log(match_quarter_log)
+ {:ok, %MatchQuarterLog{}}
+
+ iex> delete_match_quarter_log(match_quarter_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_match_quarter_log(MatchQuarterLog.t) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t}
+ def delete_match_quarter_log(%MatchQuarterLog{} = match_quarter_log) do
+ Repo.delete(match_quarter_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking match_quarter_log changes.
+
+ ## Examples
+
+ iex> change_match_quarter_log(match_quarter_log)
+ %Ecto.Changeset{data: %MatchQuarterLog{}}
+
+ """
+ @spec change_match_quarter_log(MatchQuarterLog.t, map) :: Ecto.Changeset.t
+ def change_match_quarter_log(%MatchQuarterLog{} = match_quarter_log, attrs \\ %{}) do
+ MatchQuarterLog.changeset(match_quarter_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/match_week_log_lib.ex b/lib/teiserver/logging/libs/match_week_log_lib.ex
new file mode 100644
index 000000000..b9d1257cc
--- /dev/null
+++ b/lib/teiserver/logging/libs/match_week_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.MatchWeekLogLib do
+ @moduledoc """
+ Library of match_week_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{MatchWeekLog, MatchWeekLogQueries}
+
+ @doc """
+ Returns the list of match_week_logs.
+
+ ## Examples
+
+ iex> list_match_week_logs()
+ [%MatchWeekLog{}, ...]
+
+ """
+ @spec list_match_week_logs(Teiserver.query_args()) :: [MatchWeekLog.t()]
+ def list_match_week_logs(query_args) do
+ query_args
+ |> MatchWeekLogQueries.match_week_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single match_week_log.
+
+ Raises `Ecto.NoResultsError` if the MatchWeekLog does not exist.
+
+ ## Examples
+
+ iex> get_match_week_log!(123)
+ %MatchWeekLog{}
+
+ iex> get_match_week_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_match_week_log!(Date.t()) :: MatchWeekLog.t()
+ @spec get_match_week_log!(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t()
+ def get_match_week_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchWeekLogQueries.match_week_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single match_week_log.
+
+ Returns nil if the MatchWeekLog does not exist.
+
+ ## Examples
+
+ iex> get_match_week_log(123)
+ %MatchWeekLog{}
+
+ iex> get_match_week_log(456)
+ nil
+
+ """
+ @spec get_match_week_log(Date.t()) :: MatchWeekLog.t() | nil
+ @spec get_match_week_log(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t() | nil
+ def get_match_week_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchWeekLogQueries.match_week_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a match_week_log.
+
+ ## Examples
+
+ iex> create_match_week_log(%{field: value})
+ {:ok, %MatchWeekLog{}}
+
+ iex> create_match_week_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_match_week_log(map) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t}
+ def create_match_week_log(attrs) do
+ %MatchWeekLog{}
+ |> MatchWeekLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a match_week_log.
+
+ ## Examples
+
+ iex> update_match_week_log(match_week_log, %{field: new_value})
+ {:ok, %MatchWeekLog{}}
+
+ iex> update_match_week_log(match_week_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_match_week_log(MatchWeekLog.t, map) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t}
+ def update_match_week_log(%MatchWeekLog{} = match_week_log, attrs) do
+ match_week_log
+ |> MatchWeekLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a match_week_log.
+
+ ## Examples
+
+ iex> delete_match_week_log(match_week_log)
+ {:ok, %MatchWeekLog{}}
+
+ iex> delete_match_week_log(match_week_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_match_week_log(MatchWeekLog.t) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t}
+ def delete_match_week_log(%MatchWeekLog{} = match_week_log) do
+ Repo.delete(match_week_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking match_week_log changes.
+
+ ## Examples
+
+ iex> change_match_week_log(match_week_log)
+ %Ecto.Changeset{data: %MatchWeekLog{}}
+
+ """
+ @spec change_match_week_log(MatchWeekLog.t, map) :: Ecto.Changeset.t
+ def change_match_week_log(%MatchWeekLog{} = match_week_log, attrs \\ %{}) do
+ MatchWeekLog.changeset(match_week_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/match_year_log_lib.ex b/lib/teiserver/logging/libs/match_year_log_lib.ex
new file mode 100644
index 000000000..bf752f453
--- /dev/null
+++ b/lib/teiserver/logging/libs/match_year_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.MatchYearLogLib do
+ @moduledoc """
+ Library of match_year_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{MatchYearLog, MatchYearLogQueries}
+
+ @doc """
+ Returns the list of match_year_logs.
+
+ ## Examples
+
+ iex> list_match_year_logs()
+ [%MatchYearLog{}, ...]
+
+ """
+ @spec list_match_year_logs(Teiserver.query_args()) :: [MatchYearLog.t()]
+ def list_match_year_logs(query_args) do
+ query_args
+ |> MatchYearLogQueries.match_year_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single match_year_log.
+
+ Raises `Ecto.NoResultsError` if the MatchYearLog does not exist.
+
+ ## Examples
+
+ iex> get_match_year_log!(123)
+ %MatchYearLog{}
+
+ iex> get_match_year_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_match_year_log!(Date.t()) :: MatchYearLog.t()
+ @spec get_match_year_log!(Date.t(), Teiserver.query_args()) :: MatchYearLog.t()
+ def get_match_year_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchYearLogQueries.match_year_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single match_year_log.
+
+ Returns nil if the MatchYearLog does not exist.
+
+ ## Examples
+
+ iex> get_match_year_log(123)
+ %MatchYearLog{}
+
+ iex> get_match_year_log(456)
+ nil
+
+ """
+ @spec get_match_year_log(Date.t()) :: MatchYearLog.t() | nil
+ @spec get_match_year_log(Date.t(), Teiserver.query_args()) :: MatchYearLog.t() | nil
+ def get_match_year_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> MatchYearLogQueries.match_year_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a match_year_log.
+
+ ## Examples
+
+ iex> create_match_year_log(%{field: value})
+ {:ok, %MatchYearLog{}}
+
+ iex> create_match_year_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_match_year_log(map) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t}
+ def create_match_year_log(attrs) do
+ %MatchYearLog{}
+ |> MatchYearLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a match_year_log.
+
+ ## Examples
+
+ iex> update_match_year_log(match_year_log, %{field: new_value})
+ {:ok, %MatchYearLog{}}
+
+ iex> update_match_year_log(match_year_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_match_year_log(MatchYearLog.t, map) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t}
+ def update_match_year_log(%MatchYearLog{} = match_year_log, attrs) do
+ match_year_log
+ |> MatchYearLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a match_year_log.
+
+ ## Examples
+
+ iex> delete_match_year_log(match_year_log)
+ {:ok, %MatchYearLog{}}
+
+ iex> delete_match_year_log(match_year_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_match_year_log(MatchYearLog.t) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t}
+ def delete_match_year_log(%MatchYearLog{} = match_year_log) do
+ Repo.delete(match_year_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking match_year_log changes.
+
+ ## Examples
+
+ iex> change_match_year_log(match_year_log)
+ %Ecto.Changeset{data: %MatchYearLog{}}
+
+ """
+ @spec change_match_year_log(MatchYearLog.t, map) :: Ecto.Changeset.t
+ def change_match_year_log(%MatchYearLog{} = match_year_log, attrs \\ %{}) do
+ MatchYearLog.changeset(match_year_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/server_day_log_lib.ex b/lib/teiserver/logging/libs/server_day_log_lib.ex
new file mode 100644
index 000000000..f57e22db7
--- /dev/null
+++ b/lib/teiserver/logging/libs/server_day_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.ServerDayLogLib do
+ @moduledoc """
+ Library of server_day_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{ServerDayLog, ServerDayLogQueries}
+
+ @doc """
+ Returns the list of server_day_logs.
+
+ ## Examples
+
+ iex> list_server_day_logs()
+ [%ServerDayLog{}, ...]
+
+ """
+ @spec list_server_day_logs(Teiserver.query_args()) :: [ServerDayLog.t()]
+ def list_server_day_logs(query_args) do
+ query_args
+ |> ServerDayLogQueries.server_day_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single server_day_log.
+
+ Raises `Ecto.NoResultsError` if the ServerDayLog does not exist.
+
+ ## Examples
+
+ iex> get_server_day_log!(123)
+ %ServerDayLog{}
+
+ iex> get_server_day_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_server_day_log!(Date.t()) :: ServerDayLog.t()
+ @spec get_server_day_log!(Date.t(), Teiserver.query_args()) :: ServerDayLog.t()
+ def get_server_day_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerDayLogQueries.server_day_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single server_day_log.
+
+ Returns nil if the ServerDayLog does not exist.
+
+ ## Examples
+
+ iex> get_server_day_log(123)
+ %ServerDayLog{}
+
+ iex> get_server_day_log(456)
+ nil
+
+ """
+ @spec get_server_day_log(Date.t()) :: ServerDayLog.t() | nil
+ @spec get_server_day_log(Date.t(), Teiserver.query_args()) :: ServerDayLog.t() | nil
+ def get_server_day_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerDayLogQueries.server_day_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a server_day_log.
+
+ ## Examples
+
+ iex> create_server_day_log(%{field: value})
+ {:ok, %ServerDayLog{}}
+
+ iex> create_server_day_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_server_day_log(map) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t}
+ def create_server_day_log(attrs) do
+ %ServerDayLog{}
+ |> ServerDayLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a server_day_log.
+
+ ## Examples
+
+ iex> update_server_day_log(server_day_log, %{field: new_value})
+ {:ok, %ServerDayLog{}}
+
+ iex> update_server_day_log(server_day_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_server_day_log(ServerDayLog.t, map) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t}
+ def update_server_day_log(%ServerDayLog{} = server_day_log, attrs) do
+ server_day_log
+ |> ServerDayLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a server_day_log.
+
+ ## Examples
+
+ iex> delete_server_day_log(server_day_log)
+ {:ok, %ServerDayLog{}}
+
+ iex> delete_server_day_log(server_day_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_server_day_log(ServerDayLog.t) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t}
+ def delete_server_day_log(%ServerDayLog{} = server_day_log) do
+ Repo.delete(server_day_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking server_day_log changes.
+
+ ## Examples
+
+ iex> change_server_day_log(server_day_log)
+ %Ecto.Changeset{data: %ServerDayLog{}}
+
+ """
+ @spec change_server_day_log(ServerDayLog.t, map) :: Ecto.Changeset.t
+ def change_server_day_log(%ServerDayLog{} = server_day_log, attrs \\ %{}) do
+ ServerDayLog.changeset(server_day_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/server_minute_log_lib.ex b/lib/teiserver/logging/libs/server_minute_log_lib.ex
new file mode 100644
index 000000000..2e40c8ecd
--- /dev/null
+++ b/lib/teiserver/logging/libs/server_minute_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.ServerMinuteLogLib do
+ @moduledoc """
+ Library of server_minute_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{ServerMinuteLog, ServerMinuteLogQueries}
+
+ @doc """
+ Returns the list of server_minute_logs.
+
+ ## Examples
+
+ iex> list_server_minute_logs()
+ [%ServerMinuteLog{}, ...]
+
+ """
+ @spec list_server_minute_logs(Teiserver.query_args()) :: [ServerMinuteLog.t()]
+ def list_server_minute_logs(query_args) do
+ query_args
+ |> ServerMinuteLogQueries.server_minute_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single server_minute_log.
+
+ Raises `Ecto.NoResultsError` if the ServerMinuteLog does not exist.
+
+ ## Examples
+
+ iex> get_server_minute_log!(123)
+ %ServerMinuteLog{}
+
+ iex> get_server_minute_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_server_minute_log!(DateTime.t()) :: ServerMinuteLog.t()
+ @spec get_server_minute_log!(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t()
+ def get_server_minute_log!(timestamp, query_args \\ []) do
+ (query_args ++ [timestamp: timestamp])
+ |> ServerMinuteLogQueries.server_minute_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single server_minute_log.
+
+ Returns nil if the ServerMinuteLog does not exist.
+
+ ## Examples
+
+ iex> get_server_minute_log(123)
+ %ServerMinuteLog{}
+
+ iex> get_server_minute_log(456)
+ nil
+
+ """
+ @spec get_server_minute_log(DateTime.t()) :: ServerMinuteLog.t() | nil
+ @spec get_server_minute_log(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t() | nil
+ def get_server_minute_log(timestamp, query_args \\ []) do
+ (query_args ++ [timestamp: timestamp])
+ |> ServerMinuteLogQueries.server_minute_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a server_minute_log.
+
+ ## Examples
+
+ iex> create_server_minute_log(%{field: value})
+ {:ok, %ServerMinuteLog{}}
+
+ iex> create_server_minute_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_server_minute_log(map) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t}
+ def create_server_minute_log(attrs) do
+ %ServerMinuteLog{}
+ |> ServerMinuteLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a server_minute_log.
+
+ ## Examples
+
+ iex> update_server_minute_log(server_minute_log, %{field: new_value})
+ {:ok, %ServerMinuteLog{}}
+
+ iex> update_server_minute_log(server_minute_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_server_minute_log(ServerMinuteLog.t, map) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t}
+ def update_server_minute_log(%ServerMinuteLog{} = server_minute_log, attrs) do
+ server_minute_log
+ |> ServerMinuteLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a server_minute_log.
+
+ ## Examples
+
+ iex> delete_server_minute_log(server_minute_log)
+ {:ok, %ServerMinuteLog{}}
+
+ iex> delete_server_minute_log(server_minute_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_server_minute_log(ServerMinuteLog.t) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t}
+ def delete_server_minute_log(%ServerMinuteLog{} = server_minute_log) do
+ Repo.delete(server_minute_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking server_minute_log changes.
+
+ ## Examples
+
+ iex> change_server_minute_log(server_minute_log)
+ %Ecto.Changeset{data: %ServerMinuteLog{}}
+
+ """
+ @spec change_server_minute_log(ServerMinuteLog.t, map) :: Ecto.Changeset.t
+ def change_server_minute_log(%ServerMinuteLog{} = server_minute_log, attrs \\ %{}) do
+ ServerMinuteLog.changeset(server_minute_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/server_month_log_lib.ex b/lib/teiserver/logging/libs/server_month_log_lib.ex
new file mode 100644
index 000000000..15e471c4d
--- /dev/null
+++ b/lib/teiserver/logging/libs/server_month_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.ServerMonthLogLib do
+ @moduledoc """
+ Library of server_month_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{ServerMonthLog, ServerMonthLogQueries}
+
+ @doc """
+ Returns the list of server_month_logs.
+
+ ## Examples
+
+ iex> list_server_month_logs()
+ [%ServerMonthLog{}, ...]
+
+ """
+ @spec list_server_month_logs(Teiserver.query_args()) :: [ServerMonthLog.t()]
+ def list_server_month_logs(query_args) do
+ query_args
+ |> ServerMonthLogQueries.server_month_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single server_month_log.
+
+ Raises `Ecto.NoResultsError` if the ServerMonthLog does not exist.
+
+ ## Examples
+
+ iex> get_server_month_log!(123)
+ %ServerMonthLog{}
+
+ iex> get_server_month_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_server_month_log!(Date.t()) :: ServerMonthLog.t()
+ @spec get_server_month_log!(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t()
+ def get_server_month_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerMonthLogQueries.server_month_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single server_month_log.
+
+ Returns nil if the ServerMonthLog does not exist.
+
+ ## Examples
+
+ iex> get_server_month_log(123)
+ %ServerMonthLog{}
+
+ iex> get_server_month_log(456)
+ nil
+
+ """
+ @spec get_server_month_log(Date.t()) :: ServerMonthLog.t() | nil
+ @spec get_server_month_log(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t() | nil
+ def get_server_month_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerMonthLogQueries.server_month_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a server_month_log.
+
+ ## Examples
+
+ iex> create_server_month_log(%{field: value})
+ {:ok, %ServerMonthLog{}}
+
+ iex> create_server_month_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_server_month_log(map) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t}
+ def create_server_month_log(attrs) do
+ %ServerMonthLog{}
+ |> ServerMonthLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a server_month_log.
+
+ ## Examples
+
+ iex> update_server_month_log(server_month_log, %{field: new_value})
+ {:ok, %ServerMonthLog{}}
+
+ iex> update_server_month_log(server_month_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_server_month_log(ServerMonthLog.t, map) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t}
+ def update_server_month_log(%ServerMonthLog{} = server_month_log, attrs) do
+ server_month_log
+ |> ServerMonthLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a server_month_log.
+
+ ## Examples
+
+ iex> delete_server_month_log(server_month_log)
+ {:ok, %ServerMonthLog{}}
+
+ iex> delete_server_month_log(server_month_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_server_month_log(ServerMonthLog.t) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t}
+ def delete_server_month_log(%ServerMonthLog{} = server_month_log) do
+ Repo.delete(server_month_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking server_month_log changes.
+
+ ## Examples
+
+ iex> change_server_month_log(server_month_log)
+ %Ecto.Changeset{data: %ServerMonthLog{}}
+
+ """
+ @spec change_server_month_log(ServerMonthLog.t, map) :: Ecto.Changeset.t
+ def change_server_month_log(%ServerMonthLog{} = server_month_log, attrs \\ %{}) do
+ ServerMonthLog.changeset(server_month_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/server_quarter_log_lib.ex b/lib/teiserver/logging/libs/server_quarter_log_lib.ex
new file mode 100644
index 000000000..2483dde97
--- /dev/null
+++ b/lib/teiserver/logging/libs/server_quarter_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.ServerQuarterLogLib do
+ @moduledoc """
+ Library of server_quarter_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{ServerQuarterLog, ServerQuarterLogQueries}
+
+ @doc """
+ Returns the list of server_quarter_logs.
+
+ ## Examples
+
+ iex> list_server_quarter_logs()
+ [%ServerQuarterLog{}, ...]
+
+ """
+ @spec list_server_quarter_logs(Teiserver.query_args()) :: [ServerQuarterLog.t()]
+ def list_server_quarter_logs(query_args) do
+ query_args
+ |> ServerQuarterLogQueries.server_quarter_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single server_quarter_log.
+
+ Raises `Ecto.NoResultsError` if the ServerQuarterLog does not exist.
+
+ ## Examples
+
+ iex> get_server_quarter_log!(123)
+ %ServerQuarterLog{}
+
+ iex> get_server_quarter_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_server_quarter_log!(Date.t()) :: ServerQuarterLog.t()
+ @spec get_server_quarter_log!(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t()
+ def get_server_quarter_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerQuarterLogQueries.server_quarter_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single server_quarter_log.
+
+ Returns nil if the ServerQuarterLog does not exist.
+
+ ## Examples
+
+ iex> get_server_quarter_log(123)
+ %ServerQuarterLog{}
+
+ iex> get_server_quarter_log(456)
+ nil
+
+ """
+ @spec get_server_quarter_log(Date.t()) :: ServerQuarterLog.t() | nil
+ @spec get_server_quarter_log(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t() | nil
+ def get_server_quarter_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerQuarterLogQueries.server_quarter_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a server_quarter_log.
+
+ ## Examples
+
+ iex> create_server_quarter_log(%{field: value})
+ {:ok, %ServerQuarterLog{}}
+
+ iex> create_server_quarter_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_server_quarter_log(map) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t}
+ def create_server_quarter_log(attrs) do
+ %ServerQuarterLog{}
+ |> ServerQuarterLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a server_quarter_log.
+
+ ## Examples
+
+ iex> update_server_quarter_log(server_quarter_log, %{field: new_value})
+ {:ok, %ServerQuarterLog{}}
+
+ iex> update_server_quarter_log(server_quarter_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_server_quarter_log(ServerQuarterLog.t, map) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t}
+ def update_server_quarter_log(%ServerQuarterLog{} = server_quarter_log, attrs) do
+ server_quarter_log
+ |> ServerQuarterLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a server_quarter_log.
+
+ ## Examples
+
+ iex> delete_server_quarter_log(server_quarter_log)
+ {:ok, %ServerQuarterLog{}}
+
+ iex> delete_server_quarter_log(server_quarter_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_server_quarter_log(ServerQuarterLog.t) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t}
+ def delete_server_quarter_log(%ServerQuarterLog{} = server_quarter_log) do
+ Repo.delete(server_quarter_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking server_quarter_log changes.
+
+ ## Examples
+
+ iex> change_server_quarter_log(server_quarter_log)
+ %Ecto.Changeset{data: %ServerQuarterLog{}}
+
+ """
+ @spec change_server_quarter_log(ServerQuarterLog.t, map) :: Ecto.Changeset.t
+ def change_server_quarter_log(%ServerQuarterLog{} = server_quarter_log, attrs \\ %{}) do
+ ServerQuarterLog.changeset(server_quarter_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/server_week_log_lib.ex b/lib/teiserver/logging/libs/server_week_log_lib.ex
new file mode 100644
index 000000000..fce346d2a
--- /dev/null
+++ b/lib/teiserver/logging/libs/server_week_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.ServerWeekLogLib do
+ @moduledoc """
+ Library of server_week_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{ServerWeekLog, ServerWeekLogQueries}
+
+ @doc """
+ Returns the list of server_week_logs.
+
+ ## Examples
+
+ iex> list_server_week_logs()
+ [%ServerWeekLog{}, ...]
+
+ """
+ @spec list_server_week_logs(Teiserver.query_args()) :: [ServerWeekLog.t()]
+ def list_server_week_logs(query_args) do
+ query_args
+ |> ServerWeekLogQueries.server_week_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single server_week_log.
+
+ Raises `Ecto.NoResultsError` if the ServerWeekLog does not exist.
+
+ ## Examples
+
+ iex> get_server_week_log!(123)
+ %ServerWeekLog{}
+
+ iex> get_server_week_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_server_week_log!(Date.t()) :: ServerWeekLog.t()
+ @spec get_server_week_log!(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t()
+ def get_server_week_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerWeekLogQueries.server_week_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single server_week_log.
+
+ Returns nil if the ServerWeekLog does not exist.
+
+ ## Examples
+
+ iex> get_server_week_log(123)
+ %ServerWeekLog{}
+
+ iex> get_server_week_log(456)
+ nil
+
+ """
+ @spec get_server_week_log(Date.t()) :: ServerWeekLog.t() | nil
+ @spec get_server_week_log(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t() | nil
+ def get_server_week_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerWeekLogQueries.server_week_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a server_week_log.
+
+ ## Examples
+
+ iex> create_server_week_log(%{field: value})
+ {:ok, %ServerWeekLog{}}
+
+ iex> create_server_week_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_server_week_log(map) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t}
+ def create_server_week_log(attrs) do
+ %ServerWeekLog{}
+ |> ServerWeekLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a server_week_log.
+
+ ## Examples
+
+ iex> update_server_week_log(server_week_log, %{field: new_value})
+ {:ok, %ServerWeekLog{}}
+
+ iex> update_server_week_log(server_week_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_server_week_log(ServerWeekLog.t, map) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t}
+ def update_server_week_log(%ServerWeekLog{} = server_week_log, attrs) do
+ server_week_log
+ |> ServerWeekLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a server_week_log.
+
+ ## Examples
+
+ iex> delete_server_week_log(server_week_log)
+ {:ok, %ServerWeekLog{}}
+
+ iex> delete_server_week_log(server_week_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_server_week_log(ServerWeekLog.t) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t}
+ def delete_server_week_log(%ServerWeekLog{} = server_week_log) do
+ Repo.delete(server_week_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking server_week_log changes.
+
+ ## Examples
+
+ iex> change_server_week_log(server_week_log)
+ %Ecto.Changeset{data: %ServerWeekLog{}}
+
+ """
+ @spec change_server_week_log(ServerWeekLog.t, map) :: Ecto.Changeset.t
+ def change_server_week_log(%ServerWeekLog{} = server_week_log, attrs \\ %{}) do
+ ServerWeekLog.changeset(server_week_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/libs/server_year_log_lib.ex b/lib/teiserver/logging/libs/server_year_log_lib.ex
new file mode 100644
index 000000000..32f9189c1
--- /dev/null
+++ b/lib/teiserver/logging/libs/server_year_log_lib.ex
@@ -0,0 +1,136 @@
+defmodule Teiserver.Logging.ServerYearLogLib do
+ @moduledoc """
+ Library of server_year_log related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Logging.{ServerYearLog, ServerYearLogQueries}
+
+ @doc """
+ Returns the list of server_year_logs.
+
+ ## Examples
+
+ iex> list_server_year_logs()
+ [%ServerYearLog{}, ...]
+
+ """
+ @spec list_server_year_logs(Teiserver.query_args()) :: [ServerYearLog.t()]
+ def list_server_year_logs(query_args) do
+ query_args
+ |> ServerYearLogQueries.server_year_log_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single server_year_log.
+
+ Raises `Ecto.NoResultsError` if the ServerYearLog does not exist.
+
+ ## Examples
+
+ iex> get_server_year_log!(123)
+ %ServerYearLog{}
+
+ iex> get_server_year_log!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_server_year_log!(Date.t()) :: ServerYearLog.t()
+ @spec get_server_year_log!(Date.t(), Teiserver.query_args()) :: ServerYearLog.t()
+ def get_server_year_log!(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerYearLogQueries.server_year_log_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single server_year_log.
+
+ Returns nil if the ServerYearLog does not exist.
+
+ ## Examples
+
+ iex> get_server_year_log(123)
+ %ServerYearLog{}
+
+ iex> get_server_year_log(456)
+ nil
+
+ """
+ @spec get_server_year_log(Date.t()) :: ServerYearLog.t() | nil
+ @spec get_server_year_log(Date.t(), Teiserver.query_args()) :: ServerYearLog.t() | nil
+ def get_server_year_log(date, query_args \\ []) do
+ (query_args ++ [date: date])
+ |> ServerYearLogQueries.server_year_log_query()
+ |> Repo.one
+ end
+
+ @doc """
+ Creates a server_year_log.
+
+ ## Examples
+
+ iex> create_server_year_log(%{field: value})
+ {:ok, %ServerYearLog{}}
+
+ iex> create_server_year_log(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_server_year_log(map) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t}
+ def create_server_year_log(attrs) do
+ %ServerYearLog{}
+ |> ServerYearLog.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a server_year_log.
+
+ ## Examples
+
+ iex> update_server_year_log(server_year_log, %{field: new_value})
+ {:ok, %ServerYearLog{}}
+
+ iex> update_server_year_log(server_year_log, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_server_year_log(ServerYearLog.t, map) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t}
+ def update_server_year_log(%ServerYearLog{} = server_year_log, attrs) do
+ server_year_log
+ |> ServerYearLog.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a server_year_log.
+
+ ## Examples
+
+ iex> delete_server_year_log(server_year_log)
+ {:ok, %ServerYearLog{}}
+
+ iex> delete_server_year_log(server_year_log)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_server_year_log(ServerYearLog.t) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t}
+ def delete_server_year_log(%ServerYearLog{} = server_year_log) do
+ Repo.delete(server_year_log)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking server_year_log changes.
+
+ ## Examples
+
+ iex> change_server_year_log(server_year_log)
+ %Ecto.Changeset{data: %ServerYearLog{}}
+
+ """
+ @spec change_server_year_log(ServerYearLog.t, map) :: Ecto.Changeset.t
+ def change_server_year_log(%ServerYearLog{} = server_year_log, attrs \\ %{}) do
+ ServerYearLog.changeset(server_year_log, attrs)
+ end
+end
diff --git a/lib/teiserver/logging/queries/audit_log_queries.ex b/lib/teiserver/logging/queries/audit_log_queries.ex
index ba09a0fc2..616182986 100644
--- a/lib/teiserver/logging/queries/audit_log_queries.ex
+++ b/lib/teiserver/logging/queries/audit_log_queries.ex
@@ -33,73 +33,83 @@ defmodule Teiserver.Logging.AuditLogQueries do
def _where(query, _, nil), do: query
def _where(query, :id, id_list) when is_list(id_list) do
- from audit_logs in query,
+ from(audit_logs in query,
where: audit_logs.id in ^id_list
+ )
end
def _where(query, :id, id) do
- from audit_logs in query,
+ from(audit_logs in query,
where: audit_logs.id == ^id
+ )
end
def _where(query, :action, action_list) when is_list(action_list) do
- from audit_logs in query,
+ from(audit_logs in query,
where: audit_logs.action in ^action_list
+ )
end
def _where(query, :action, action) do
- from audit_logs in query,
+ from(audit_logs in query,
where: audit_logs.action == ^action
+ )
end
def _where(query, :detail_equal, {field, value}) do
- from audit_logs in query,
+ from(audit_logs in query,
where: fragment("? ->> ? = ?", audit_logs.details, ^field, ^value)
+ )
end
def _where(query, :detail_greater_than, {field, value}) do
- from audit_logs in query,
+ from(audit_logs in query,
where: fragment("? ->> ? > ?", audit_logs.details, ^field, ^value)
+ )
end
def _where(query, :detail_less_than, {field, value}) do
- from audit_logs in query,
+ from(audit_logs in query,
where: fragment("? ->> ? < ?", audit_logs.details, ^field, ^value)
+ )
end
def _where(query, :detail_not, {field, value}) do
- from audit_logs in query,
+ from(audit_logs in query,
where: fragment("? ->> ? != ?", audit_logs.details, ^field, ^value)
+ )
end
-
def _where(query, :inserted_after, timestamp) do
- from audit_logs in query,
+ from(audit_logs in query,
where: audit_logs.inserted_at >= ^timestamp
+ )
end
def _where(query, :inserted_before, timestamp) do
- from audit_logs in query,
+ from(audit_logs in query,
where: audit_logs.inserted_at < ^timestamp
+ )
end
def _where(query, :updated_after, timestamp) do
- from audit_logs in query,
+ from(audit_logs in query,
where: audit_logs.updated_at >= ^timestamp
+ )
end
def _where(query, :updated_before, timestamp) do
- from audit_logs in query,
+ from(audit_logs in query,
where: audit_logs.updated_at < ^timestamp
+ )
end
-
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
defp do_order_by(query, params) when is_list(params) do
params
- |> List.wrap
+ |> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
_order_by(query_acc, key)
end)
@@ -107,22 +117,23 @@ defmodule Teiserver.Logging.AuditLogQueries do
@spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
def _order_by(query, "Newest first") do
- from audit_logs in query,
+ from(audit_logs in query,
order_by: [desc: audit_logs.inserted_at]
+ )
end
def _order_by(query, "Oldest first") do
- from audit_logs in query,
+ from(audit_logs in query,
order_by: [asc: audit_logs.inserted_at]
+ )
end
-
@spec do_preload(Ecto.Query.t(), List.t() | nil) :: Ecto.Query.t()
defp do_preload(query, nil), do: query
defp do_preload(query, preloads) do
preloads
- |> List.wrap
+ |> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
_preload(query_acc, key)
end)
@@ -130,8 +141,9 @@ defmodule Teiserver.Logging.AuditLogQueries do
@spec _preload(Ecto.Query.t(), any) :: Ecto.Query.t()
def _preload(query, :user) do
- from audit_log in query,
+ from(audit_log in query,
left_join: users in assoc(audit_log, :user),
preload: [user: users]
+ )
end
end
diff --git a/lib/teiserver/logging/queries/match_day_log_queries.ex b/lib/teiserver/logging/queries/match_day_log_queries.ex
new file mode 100644
index 000000000..38c1e78e0
--- /dev/null
+++ b/lib/teiserver/logging/queries/match_day_log_queries.ex
@@ -0,0 +1,75 @@
+defmodule Teiserver.Logging.MatchDayLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.MatchDayLog
+ require Logger
+
+ @spec match_day_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def match_day_log_query(args) do
+ query = from(match_day_logs in MatchDayLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(match_day_logs in query,
+ where: match_day_logs.date == ^date
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(match_day_logs in query,
+ where: match_day_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(match_day_logs in query,
+ where: match_day_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(match_day_logs in query,
+ order_by: [desc: match_day_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(match_day_logs in query,
+ order_by: [asc: match_day_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/match_minute_log_queries.ex b/lib/teiserver/logging/queries/match_minute_log_queries.ex
new file mode 100644
index 000000000..5d949b5ab
--- /dev/null
+++ b/lib/teiserver/logging/queries/match_minute_log_queries.ex
@@ -0,0 +1,69 @@
+defmodule Teiserver.Logging.MatchMinuteLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.MatchMinuteLog
+ require Logger
+
+ @spec match_minute_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def match_minute_log_query(args) do
+ query = from(match_minute_logs in MatchMinuteLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :after, timestamp) do
+ from(match_minute_logs in query,
+ where: match_minute_logs.timestamp >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(match_minute_logs in query,
+ where: match_minute_logs.timestamp < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(match_minute_logs in query,
+ order_by: [desc: match_minute_logs.timestamp]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(match_minute_logs in query,
+ order_by: [asc: match_minute_logs.timestamp]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/match_month_log_queries.ex b/lib/teiserver/logging/queries/match_month_log_queries.ex
new file mode 100644
index 000000000..6bb39faf4
--- /dev/null
+++ b/lib/teiserver/logging/queries/match_month_log_queries.ex
@@ -0,0 +1,87 @@
+defmodule Teiserver.Logging.MatchMonthLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.MatchMonthLog
+ require Logger
+
+ @spec match_month_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def match_month_log_query(args) do
+ query = from(match_month_logs in MatchMonthLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(match_month_logs in query,
+ where: match_month_logs.date == ^date
+ )
+ end
+
+ def _where(query, :year, year) do
+ from(match_month_logs in query,
+ where: match_month_logs.year == ^year
+ )
+ end
+
+ def _where(query, :month, month) do
+ from(match_month_logs in query,
+ where: match_month_logs.month == ^month
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(match_month_logs in query,
+ where: match_month_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(match_month_logs in query,
+ where: match_month_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(match_month_logs in query,
+ order_by: [desc: match_month_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(match_month_logs in query,
+ order_by: [asc: match_month_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/match_quarter_log_queries.ex b/lib/teiserver/logging/queries/match_quarter_log_queries.ex
new file mode 100644
index 000000000..34bd4b1b8
--- /dev/null
+++ b/lib/teiserver/logging/queries/match_quarter_log_queries.ex
@@ -0,0 +1,87 @@
+defmodule Teiserver.Logging.MatchQuarterLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.MatchQuarterLog
+ require Logger
+
+ @spec match_quarter_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def match_quarter_log_query(args) do
+ query = from(match_quarter_logs in MatchQuarterLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(match_quarter_logs in query,
+ where: match_quarter_logs.date == ^date
+ )
+ end
+
+ def _where(query, :year, year) do
+ from(match_quarter_logs in query,
+ where: match_quarter_logs.year == ^year
+ )
+ end
+
+ def _where(query, :quarter, quarter) do
+ from(match_quarter_logs in query,
+ where: match_quarter_logs.quarter == ^quarter
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(match_quarter_logs in query,
+ where: match_quarter_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(match_quarter_logs in query,
+ where: match_quarter_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(match_quarter_logs in query,
+ order_by: [desc: match_quarter_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(match_quarter_logs in query,
+ order_by: [asc: match_quarter_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/match_week_log_queries.ex b/lib/teiserver/logging/queries/match_week_log_queries.ex
new file mode 100644
index 000000000..12dc7a3a9
--- /dev/null
+++ b/lib/teiserver/logging/queries/match_week_log_queries.ex
@@ -0,0 +1,87 @@
+defmodule Teiserver.Logging.MatchWeekLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.MatchWeekLog
+ require Logger
+
+ @spec match_week_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def match_week_log_query(args) do
+ query = from(match_week_logs in MatchWeekLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(match_week_logs in query,
+ where: match_week_logs.date == ^date
+ )
+ end
+
+ def _where(query, :year, year) do
+ from(match_week_logs in query,
+ where: match_week_logs.year == ^year
+ )
+ end
+
+ def _where(query, :week, week) do
+ from(match_week_logs in query,
+ where: match_week_logs.week == ^week
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(match_week_logs in query,
+ where: match_week_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(match_week_logs in query,
+ where: match_week_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(match_week_logs in query,
+ order_by: [desc: match_week_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(match_week_logs in query,
+ order_by: [asc: match_week_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/match_year_log_queries.ex b/lib/teiserver/logging/queries/match_year_log_queries.ex
new file mode 100644
index 000000000..0698bbbe1
--- /dev/null
+++ b/lib/teiserver/logging/queries/match_year_log_queries.ex
@@ -0,0 +1,81 @@
+defmodule Teiserver.Logging.MatchYearLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.MatchYearLog
+ require Logger
+
+ @spec match_year_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def match_year_log_query(args) do
+ query = from(match_year_logs in MatchYearLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(match_year_logs in query,
+ where: match_year_logs.date == ^date
+ )
+ end
+
+ def _where(query, :year, year) do
+ from(match_year_logs in query,
+ where: match_year_logs.year == ^year
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(match_year_logs in query,
+ where: match_year_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(match_year_logs in query,
+ where: match_year_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(match_year_logs in query,
+ order_by: [desc: match_year_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(match_year_logs in query,
+ order_by: [asc: match_year_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/server_day_log_queries.ex b/lib/teiserver/logging/queries/server_day_log_queries.ex
new file mode 100644
index 000000000..27bccbfb5
--- /dev/null
+++ b/lib/teiserver/logging/queries/server_day_log_queries.ex
@@ -0,0 +1,75 @@
+defmodule Teiserver.Logging.ServerDayLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.ServerDayLog
+ require Logger
+
+ @spec server_day_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def server_day_log_query(args) do
+ query = from(server_day_logs in ServerDayLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(server_day_logs in query,
+ where: server_day_logs.date == ^date
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(server_day_logs in query,
+ where: server_day_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(server_day_logs in query,
+ where: server_day_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(server_day_logs in query,
+ order_by: [desc: server_day_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(server_day_logs in query,
+ order_by: [asc: server_day_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/server_minute_log_queries.ex b/lib/teiserver/logging/queries/server_minute_log_queries.ex
new file mode 100644
index 000000000..c43f14a6b
--- /dev/null
+++ b/lib/teiserver/logging/queries/server_minute_log_queries.ex
@@ -0,0 +1,69 @@
+defmodule Teiserver.Logging.ServerMinuteLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.ServerMinuteLog
+ require Logger
+
+ @spec server_minute_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def server_minute_log_query(args) do
+ query = from(server_minute_logs in ServerMinuteLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :after, timestamp) do
+ from(server_minute_logs in query,
+ where: server_minute_logs.timestamp >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(server_minute_logs in query,
+ where: server_minute_logs.timestamp < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(server_minute_logs in query,
+ order_by: [desc: server_minute_logs.timestamp]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(server_minute_logs in query,
+ order_by: [asc: server_minute_logs.timestamp]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/server_month_log_queries.ex b/lib/teiserver/logging/queries/server_month_log_queries.ex
new file mode 100644
index 000000000..29f7c8a68
--- /dev/null
+++ b/lib/teiserver/logging/queries/server_month_log_queries.ex
@@ -0,0 +1,87 @@
+defmodule Teiserver.Logging.ServerMonthLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.ServerMonthLog
+ require Logger
+
+ @spec server_month_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def server_month_log_query(args) do
+ query = from(server_month_logs in ServerMonthLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(server_month_logs in query,
+ where: server_month_logs.date == ^date
+ )
+ end
+
+ def _where(query, :year, year) do
+ from(server_month_logs in query,
+ where: server_month_logs.year == ^year
+ )
+ end
+
+ def _where(query, :month, month) do
+ from(server_month_logs in query,
+ where: server_month_logs.month == ^month
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(server_month_logs in query,
+ where: server_month_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(server_month_logs in query,
+ where: server_month_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(server_month_logs in query,
+ order_by: [desc: server_month_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(server_month_logs in query,
+ order_by: [asc: server_month_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/server_quarter_log_queries.ex b/lib/teiserver/logging/queries/server_quarter_log_queries.ex
new file mode 100644
index 000000000..fffde04d5
--- /dev/null
+++ b/lib/teiserver/logging/queries/server_quarter_log_queries.ex
@@ -0,0 +1,87 @@
+defmodule Teiserver.Logging.ServerQuarterLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.ServerQuarterLog
+ require Logger
+
+ @spec server_quarter_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def server_quarter_log_query(args) do
+ query = from(server_quarter_logs in ServerQuarterLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(server_quarter_logs in query,
+ where: server_quarter_logs.date == ^date
+ )
+ end
+
+ def _where(query, :year, year) do
+ from(server_quarter_logs in query,
+ where: server_quarter_logs.year == ^year
+ )
+ end
+
+ def _where(query, :quarter, quarter) do
+ from(server_quarter_logs in query,
+ where: server_quarter_logs.quarter == ^quarter
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(server_quarter_logs in query,
+ where: server_quarter_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(server_quarter_logs in query,
+ where: server_quarter_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(server_quarter_logs in query,
+ order_by: [desc: server_quarter_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(server_quarter_logs in query,
+ order_by: [asc: server_quarter_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/server_week_log_queries.ex b/lib/teiserver/logging/queries/server_week_log_queries.ex
new file mode 100644
index 000000000..dad8bd48f
--- /dev/null
+++ b/lib/teiserver/logging/queries/server_week_log_queries.ex
@@ -0,0 +1,87 @@
+defmodule Teiserver.Logging.ServerWeekLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.ServerWeekLog
+ require Logger
+
+ @spec server_week_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def server_week_log_query(args) do
+ query = from(server_week_logs in ServerWeekLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(server_week_logs in query,
+ where: server_week_logs.date == ^date
+ )
+ end
+
+ def _where(query, :year, year) do
+ from(server_week_logs in query,
+ where: server_week_logs.year == ^year
+ )
+ end
+
+ def _where(query, :week, week) do
+ from(server_week_logs in query,
+ where: server_week_logs.week == ^week
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(server_week_logs in query,
+ where: server_week_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(server_week_logs in query,
+ where: server_week_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(server_week_logs in query,
+ order_by: [desc: server_week_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(server_week_logs in query,
+ order_by: [asc: server_week_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/queries/server_year_log_queries.ex b/lib/teiserver/logging/queries/server_year_log_queries.ex
new file mode 100644
index 000000000..ff7e7c51a
--- /dev/null
+++ b/lib/teiserver/logging/queries/server_year_log_queries.ex
@@ -0,0 +1,81 @@
+defmodule Teiserver.Logging.ServerYearLogQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Logging.ServerYearLog
+ require Logger
+
+ @spec server_year_log_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def server_year_log_query(args) do
+ query = from(server_year_logs in ServerYearLog)
+
+ query
+ |> do_where(date: args[:date])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :date, date) do
+ from(server_year_logs in query,
+ where: server_year_logs.date == ^date
+ )
+ end
+
+ def _where(query, :year, year) do
+ from(server_year_logs in query,
+ where: server_year_logs.year == ^year
+ )
+ end
+
+ def _where(query, :after, timestamp) do
+ from(server_year_logs in query,
+ where: server_year_logs.date >= ^timestamp
+ )
+ end
+
+ def _where(query, :before, timestamp) do
+ from(server_year_logs in query,
+ where: server_year_logs.date < ^timestamp
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) when is_list(params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Newest first") do
+ from(server_year_logs in query,
+ order_by: [desc: server_year_logs.date]
+ )
+ end
+
+ def _order_by(query, "Oldest first") do
+ from(server_year_logs in query,
+ order_by: [asc: server_year_logs.date]
+ )
+ end
+end
diff --git a/lib/teiserver/logging/schemas/match_activity_day_log.ex b/lib/teiserver/logging/schemas/match_activity_day_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/match_activity_month_log.ex b/lib/teiserver/logging/schemas/match_activity_month_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/match_activity_quarter_log.ex b/lib/teiserver/logging/schemas/match_activity_quarter_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/match_activity_week_log.ex b/lib/teiserver/logging/schemas/match_activity_week_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/match_activity_year_log.ex b/lib/teiserver/logging/schemas/match_activity_year_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/match_day_log.ex b/lib/teiserver/logging/schemas/match_day_log.ex
new file mode 100644
index 000000000..1788b1723
--- /dev/null
+++ b/lib/teiserver/logging/schemas/match_day_log.ex
@@ -0,0 +1,32 @@
+defmodule Teiserver.Logging.MatchDayLog do
+ @moduledoc """
+ # MatchDayLog
+ A log of the activity for that day on the match.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_match_day_logs" do
+ field(:date, :date, primary_key: true)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(date data)a)
+ |> validate_required(~w(date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/match_minute_log.ex b/lib/teiserver/logging/schemas/match_minute_log.ex
new file mode 100644
index 000000000..1afd7078b
--- /dev/null
+++ b/lib/teiserver/logging/schemas/match_minute_log.ex
@@ -0,0 +1,32 @@
+defmodule Teiserver.Logging.MatchMinuteLog do
+ @moduledoc """
+ # MatchMinuteLog
+ A log of the activity for that minute on the server.
+
+ ### Attributes
+
+ * `:timestamp` - The timestamp this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_match_minute_logs" do
+ field(:timestamp, :utc_datetime, primary_key: true)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ timestamp: DateTime.t(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(timestamp data)a)
+ |> validate_required(~w(timestamp data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/match_month_log.ex b/lib/teiserver/logging/schemas/match_month_log.ex
new file mode 100644
index 000000000..69493ced9
--- /dev/null
+++ b/lib/teiserver/logging/schemas/match_month_log.ex
@@ -0,0 +1,38 @@
+defmodule Teiserver.Logging.MatchMonthLog do
+ @moduledoc """
+ # MatchMonthLog
+ A log of the activity for that month on the match.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:year` - The year this log refers to
+ * `:month` - The month this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_match_month_logs" do
+ field(:year, :integer, primary_key: true)
+ field(:month, :integer, primary_key: true)
+ field(:date, :date)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ year: non_neg_integer(),
+ month: non_neg_integer(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(year month date data)a)
+ |> validate_required(~w(year month date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/match_quarter_log.ex b/lib/teiserver/logging/schemas/match_quarter_log.ex
new file mode 100644
index 000000000..d4a2beb45
--- /dev/null
+++ b/lib/teiserver/logging/schemas/match_quarter_log.ex
@@ -0,0 +1,38 @@
+defmodule Teiserver.Logging.MatchQuarterLog do
+ @moduledoc """
+ # MatchQuarterLog
+ A log of the activity for that quarter on the match.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:year` - The year this log refers to
+ * `:quarter` - The quarter this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_match_quarter_logs" do
+ field(:year, :integer, primary_key: true)
+ field(:quarter, :integer, primary_key: true)
+ field(:date, :date)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ year: non_neg_integer(),
+ quarter: non_neg_integer(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(year quarter date data)a)
+ |> validate_required(~w(year quarter date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/match_week_log.ex b/lib/teiserver/logging/schemas/match_week_log.ex
new file mode 100644
index 000000000..765db9eca
--- /dev/null
+++ b/lib/teiserver/logging/schemas/match_week_log.ex
@@ -0,0 +1,38 @@
+defmodule Teiserver.Logging.MatchWeekLog do
+ @moduledoc """
+ # MatchWeekLog
+ A log of the activity for that week on the match.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:year` - The year this log refers to
+ * `:week` - The week this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_match_week_logs" do
+ field(:year, :integer, primary_key: true)
+ field(:week, :integer, primary_key: true)
+ field(:date, :date)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ year: non_neg_integer(),
+ week: non_neg_integer(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(year week date data)a)
+ |> validate_required(~w(year week date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/match_year_log.ex b/lib/teiserver/logging/schemas/match_year_log.ex
new file mode 100644
index 000000000..d6ce30764
--- /dev/null
+++ b/lib/teiserver/logging/schemas/match_year_log.ex
@@ -0,0 +1,35 @@
+defmodule Teiserver.Logging.MatchYearLog do
+ @moduledoc """
+ # MatchYearLog
+ A log of the activity for that year on the match.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:year` - The year this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_match_year_logs" do
+ field(:year, :integer, primary_key: true)
+ field(:date, :date)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ year: non_neg_integer(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(year date data)a)
+ |> validate_required(~w(year date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/server_activity_day_log.ex b/lib/teiserver/logging/schemas/server_activity_day_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/server_activity_minute_log.ex b/lib/teiserver/logging/schemas/server_activity_minute_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/server_activity_month_log.ex b/lib/teiserver/logging/schemas/server_activity_month_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/server_activity_quarter_log.ex b/lib/teiserver/logging/schemas/server_activity_quarter_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/server_activity_week_log.ex b/lib/teiserver/logging/schemas/server_activity_week_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/server_activity_year_log.ex b/lib/teiserver/logging/schemas/server_activity_year_log.ex
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/teiserver/logging/schemas/server_day_log.ex b/lib/teiserver/logging/schemas/server_day_log.ex
new file mode 100644
index 000000000..3fbd8ab3e
--- /dev/null
+++ b/lib/teiserver/logging/schemas/server_day_log.ex
@@ -0,0 +1,32 @@
+defmodule Teiserver.Logging.ServerDayLog do
+ @moduledoc """
+ # ServerDayLog
+ A log of the activity for that day on the server.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_server_day_logs" do
+ field(:date, :date, primary_key: true)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(date data)a)
+ |> validate_required(~w(date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/server_minute_log.ex b/lib/teiserver/logging/schemas/server_minute_log.ex
new file mode 100644
index 000000000..daa57ab61
--- /dev/null
+++ b/lib/teiserver/logging/schemas/server_minute_log.ex
@@ -0,0 +1,32 @@
+defmodule Teiserver.Logging.ServerMinuteLog do
+ @moduledoc """
+ # ServerMinuteLog
+ A log of the activity for that minute on the server.
+
+ ### Attributes
+
+ * `:timestamp` - The timestamp this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_server_minute_logs" do
+ field(:timestamp, :utc_datetime, primary_key: true)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ timestamp: DateTime.t(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(timestamp data)a)
+ |> validate_required(~w(timestamp data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/server_month_log.ex b/lib/teiserver/logging/schemas/server_month_log.ex
new file mode 100644
index 000000000..06344b7c5
--- /dev/null
+++ b/lib/teiserver/logging/schemas/server_month_log.ex
@@ -0,0 +1,38 @@
+defmodule Teiserver.Logging.ServerMonthLog do
+ @moduledoc """
+ # ServerMonthLog
+ A log of the activity for that month on the server.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:year` - The year this log refers to
+ * `:month` - The month this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_server_month_logs" do
+ field(:year, :integer, primary_key: true)
+ field(:month, :integer, primary_key: true)
+ field(:date, :date)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ year: non_neg_integer(),
+ month: non_neg_integer(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(year month date data)a)
+ |> validate_required(~w(year month date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/server_quarter_log.ex b/lib/teiserver/logging/schemas/server_quarter_log.ex
new file mode 100644
index 000000000..3e55c8b6d
--- /dev/null
+++ b/lib/teiserver/logging/schemas/server_quarter_log.ex
@@ -0,0 +1,38 @@
+defmodule Teiserver.Logging.ServerQuarterLog do
+ @moduledoc """
+ # ServerQuarterLog
+ A log of the activity for that quarter on the server.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:year` - The year this log refers to
+ * `:quarter` - The quarter this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_server_quarter_logs" do
+ field(:year, :integer, primary_key: true)
+ field(:quarter, :integer, primary_key: true)
+ field(:date, :date)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ year: non_neg_integer(),
+ quarter: non_neg_integer(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(year quarter date data)a)
+ |> validate_required(~w(year quarter date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/server_week_log.ex b/lib/teiserver/logging/schemas/server_week_log.ex
new file mode 100644
index 000000000..fc4c61642
--- /dev/null
+++ b/lib/teiserver/logging/schemas/server_week_log.ex
@@ -0,0 +1,38 @@
+defmodule Teiserver.Logging.ServerWeekLog do
+ @moduledoc """
+ # ServerWeekLog
+ A log of the activity for that week on the server.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:year` - The year this log refers to
+ * `:week` - The week this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_server_week_logs" do
+ field(:year, :integer, primary_key: true)
+ field(:week, :integer, primary_key: true)
+ field(:date, :date)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ year: non_neg_integer(),
+ week: non_neg_integer(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(year week date data)a)
+ |> validate_required(~w(year week date data)a)
+ end
+end
diff --git a/lib/teiserver/logging/schemas/server_year_log.ex b/lib/teiserver/logging/schemas/server_year_log.ex
new file mode 100644
index 000000000..c796fa9f5
--- /dev/null
+++ b/lib/teiserver/logging/schemas/server_year_log.ex
@@ -0,0 +1,35 @@
+defmodule Teiserver.Logging.ServerYearLog do
+ @moduledoc """
+ # ServerYearLog
+ A log of the activity for that year on the server.
+
+ ### Attributes
+
+ * `:date` - The date this log refers to
+ * `:year` - The year this log refers to
+ * `:data` - The data included
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "logging_server_year_logs" do
+ field(:year, :integer, primary_key: true)
+ field(:date, :date)
+ field(:data, :map)
+ end
+
+ @type t :: %__MODULE__{
+ date: Date.t(),
+ year: non_neg_integer(),
+ data: map()
+ }
+
+ @doc false
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, attrs \\ %{}) do
+ struct
+ |> cast(attrs, ~w(year date data)a)
+ |> validate_required(~w(year date data)a)
+ end
+end
diff --git a/lib/migration.ex b/lib/teiserver/migrations/migration.ex
similarity index 100%
rename from lib/migration.ex
rename to lib/teiserver/migrations/migration.ex
diff --git a/lib/teiserver/migrations/postgres.ex b/lib/teiserver/migrations/postgres.ex
index 8c76f12cb..433b5acb6 100644
--- a/lib/teiserver/migrations/postgres.ex
+++ b/lib/teiserver/migrations/postgres.ex
@@ -7,7 +7,7 @@ defmodule Teiserver.Migrations.Postgres do
use Ecto.Migration
@initial_version 1
- @current_version 1
+ @current_version 2
@default_prefix "public"
@doc false
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index 7261d1d7f..181a369a4 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -184,34 +184,10 @@ defmodule Teiserver.Migrations.Postgres.V01 do
end
create_if_not_exists(index(:settings_user_settings, [:user_id], prefix: prefix))
-
- # Logging
- create_if_not_exists table(:audit_logs, prefix: prefix) do
- add(:action, :string)
- add(:details, :jsonb)
- add(:ip, :string)
- add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
-
- timestamps()
- end
-
- # Telemetry tables
- create_if_not_exists table(:telemetry_event_types, prefix: prefix) do
- add(:category, :string)
- add(:name, :string)
- end
-
- create_if_not_exists(unique_index(:telemetry_event_types, [:category, :name], prefix: prefix))
end
@spec down(map) :: any
def down(%{prefix: prefix, quoted_prefix: _quoted}) do
- # Telemetry
- drop_if_exists(table(:telemetry_event_types, prefix: prefix))
-
- # Logging
- drop_if_exists(table(:audit_logs, prefix: prefix))
-
# Comms
drop_if_exists(table(:communication_room_messages, prefix: prefix))
drop_if_exists(table(:communication_rooms, prefix: prefix))
diff --git a/lib/teiserver/migrations/postgres/v02.ex b/lib/teiserver/migrations/postgres/v02.ex
new file mode 100644
index 000000000..48c74037c
--- /dev/null
+++ b/lib/teiserver/migrations/postgres/v02.ex
@@ -0,0 +1,112 @@
+defmodule Teiserver.Migrations.Postgres.V02 do
+ @moduledoc false
+ # Copied and tweaked from Oban
+
+ use Ecto.Migration
+
+ @spec up(map) :: any
+ def up(%{prefix: prefix}) do
+ # Logging
+ create_if_not_exists table(:audit_logs, prefix: prefix) do
+ add(:action, :string)
+ add(:details, :jsonb)
+ add(:ip, :string)
+ add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
+
+ timestamps()
+ end
+
+ # Logging - Server activity
+ create_if_not_exists table(:logging_server_minute_logs, primary_key: false) do
+ add(:timestamp, :utc_datetime, primary_key: true)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_server_day_logs, primary_key: false) do
+ add(:date, :date, primary_key: true)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_server_week_logs, primary_key: false, prefix: prefix) do
+ add(:year, :integer, primary_key: true)
+ add(:week, :integer, primary_key: true)
+ add(:date, :date)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_server_month_logs, primary_key: false, prefix: prefix) do
+ add(:year, :integer, primary_key: true)
+ add(:month, :integer, primary_key: true)
+ add(:date, :date)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_server_quarter_logs, primary_key: false, prefix: prefix) do
+ add(:year, :integer, primary_key: true)
+ add(:quarter, :integer, primary_key: true)
+ add(:date, :date)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_server_year_logs, primary_key: false, prefix: prefix) do
+ add(:year, :integer, primary_key: true)
+ add(:date, :date)
+ add(:data, :jsonb)
+ end
+
+ # Logging - Match logs
+ create_if_not_exists table(:logging_match_minute_logs, primary_key: false) do
+ add(:timestamp, :utc_datetime, primary_key: true)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_match_day_logs, primary_key: false) do
+ add(:date, :date, primary_key: true)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_match_week_logs, primary_key: false, prefix: prefix) do
+ add(:year, :integer, primary_key: true)
+ add(:week, :integer, primary_key: true)
+ add(:date, :date)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_match_month_logs, primary_key: false, prefix: prefix) do
+ add(:year, :integer, primary_key: true)
+ add(:month, :integer, primary_key: true)
+ add(:date, :date)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_match_quarter_logs, primary_key: false, prefix: prefix) do
+ add(:year, :integer, primary_key: true)
+ add(:quarter, :integer, primary_key: true)
+ add(:date, :date)
+ add(:data, :jsonb)
+ end
+
+ create_if_not_exists table(:logging_match_year_logs, primary_key: false, prefix: prefix) do
+ add(:year, :integer, primary_key: true)
+ add(:date, :date)
+ add(:data, :jsonb)
+ end
+
+ # Telemetry tables
+ create_if_not_exists table(:telemetry_event_types, prefix: prefix) do
+ add(:category, :string)
+ add(:name, :string)
+ end
+
+ create_if_not_exists(unique_index(:telemetry_event_types, [:category, :name], prefix: prefix))
+ end
+
+ @spec down(map) :: any
+ def down(%{prefix: prefix, quoted_prefix: _quoted}) do
+ # Telemetry
+ drop_if_exists(table(:telemetry_event_types, prefix: prefix))
+
+ # Logging
+ drop_if_exists(table(:audit_logs, prefix: prefix))
+ end
+end
diff --git a/lib/teiserver/settings/queries/user_setting_queries.ex b/lib/teiserver/settings/queries/user_setting_queries.ex
index 949e8ad24..70bfb04f8 100644
--- a/lib/teiserver/settings/queries/user_setting_queries.ex
+++ b/lib/teiserver/settings/queries/user_setting_queries.ex
@@ -79,6 +79,18 @@ defmodule Teiserver.Settings.UserSettingQueries do
)
end
+ def _where(query, :updated_after, timestamp) do
+ from(user_settings in query,
+ where: user_settings.updated_at >= ^timestamp
+ )
+ end
+
+ def _where(query, :updated_before, timestamp) do
+ from(user_settings in query,
+ where: user_settings.updated_at < ^timestamp
+ )
+ end
+
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
diff --git a/test/logging/libs/audit_log_lib_test.exs b/test/logging/libs/audit_log_lib_test.exs
index 81febb0dd..2f5fbf52e 100644
--- a/test/logging/libs/audit_log_lib_test.exs
+++ b/test/logging/libs/audit_log_lib_test.exs
@@ -69,6 +69,7 @@ defmodule Teiserver.AuditLogLibTest do
test "create_audit_log/4 with valid data creates a audit_log" do
user_id = AccountFixtures.user_fixture().id
+
assert {:ok, %AuditLog{} = audit_log} =
Logging.create_audit_log(user_id, "ip", "some action", %{})
diff --git a/test/logging/libs/match_day_log_lib_test.exs b/test/logging/libs/match_day_log_lib_test.exs
new file mode 100644
index 000000000..8b41c6d65
--- /dev/null
+++ b/test/logging/libs/match_day_log_lib_test.exs
@@ -0,0 +1,98 @@
+defmodule Teiserver.MatchDayLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.MatchDayLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(days: 1),
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "match_day_log" do
+ alias Teiserver.Logging.MatchDayLog
+
+ test "match_day_log_query/0 returns a query" do
+ q = Logging.match_day_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_match_day_log/0 returns match_day_log" do
+ # No match_day_log yet
+ assert Logging.list_match_day_logs([]) == []
+
+ # Add a match_day_log
+ LoggingFixtures.match_day_log_fixture()
+ assert Logging.list_match_day_logs([]) != []
+ end
+
+ test "get_match_day_log!/1 and get_match_day_log/1 returns the match_day_log with given id" do
+ match_day_log = LoggingFixtures.match_day_log_fixture()
+ assert Logging.get_match_day_log!(match_day_log.date) == match_day_log
+ assert Logging.get_match_day_log(match_day_log.date) == match_day_log
+ end
+
+ test "create_match_day_log/1 with valid data creates a match_day_log" do
+ assert {:ok, %MatchDayLog{} = match_day_log} =
+ Logging.create_match_day_log(valid_attrs())
+
+ assert match_day_log.data == %{"key" => 1}
+ end
+
+ test "create_match_day_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_match_day_log(invalid_attrs())
+ end
+
+ test "update_match_day_log/2 with valid data updates the match_day_log" do
+ match_day_log = LoggingFixtures.match_day_log_fixture()
+
+ assert {:ok, %MatchDayLog{} = match_day_log} =
+ Logging.update_match_day_log(match_day_log, update_attrs())
+
+ assert match_day_log.data == %{"other-key" => 2}
+ end
+
+ test "update_match_day_log/2 with invalid data returns error changeset" do
+ match_day_log = LoggingFixtures.match_day_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_match_day_log(match_day_log, invalid_attrs())
+
+ assert match_day_log == Logging.get_match_day_log!(match_day_log.date)
+ end
+
+ test "delete_match_day_log/1 deletes the match_day_log" do
+ match_day_log = LoggingFixtures.match_day_log_fixture()
+ assert {:ok, %MatchDayLog{}} = Logging.delete_match_day_log(match_day_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_match_day_log!(match_day_log.date)
+ end
+
+ assert Logging.get_match_day_log(match_day_log.date) == nil
+ end
+
+ test "change_match_day_log/1 returns a match_day_log changeset" do
+ match_day_log = LoggingFixtures.match_day_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_match_day_log(match_day_log)
+ end
+ end
+end
diff --git a/test/logging/libs/match_minute_log_lib_test.exs b/test/logging/libs/match_minute_log_lib_test.exs
new file mode 100644
index 000000000..177239c71
--- /dev/null
+++ b/test/logging/libs/match_minute_log_lib_test.exs
@@ -0,0 +1,98 @@
+defmodule Teiserver.MatchMinuteLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.MatchMinuteLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ timestamp: Timex.now(),
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ timestamp: Timex.now() |> Timex.shift(minutes: 1),
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ timestamp: nil,
+ data: nil
+ }
+ end
+
+ describe "match_minute_log" do
+ alias Teiserver.Logging.MatchMinuteLog
+
+ test "match_minute_log_query/0 returns a query" do
+ q = Logging.match_minute_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_match_minute_log/0 returns match_minute_log" do
+ # No match_minute_log yet
+ assert Logging.list_match_minute_logs([]) == []
+
+ # Add a match_minute_log
+ LoggingFixtures.match_minute_log_fixture()
+ assert Logging.list_match_minute_logs([]) != []
+ end
+
+ test "get_match_minute_log!/1 and get_match_minute_log/1 returns the match_minute_log with given id" do
+ match_minute_log = LoggingFixtures.match_minute_log_fixture()
+ assert Logging.get_match_minute_log!(match_minute_log.timestamp) == match_minute_log
+ assert Logging.get_match_minute_log(match_minute_log.timestamp) == match_minute_log
+ end
+
+ test "create_match_minute_log/1 with valid data creates a match_minute_log" do
+ assert {:ok, %MatchMinuteLog{} = match_minute_log} =
+ Logging.create_match_minute_log(valid_attrs())
+
+ assert match_minute_log.data == %{"key" => 1}
+ end
+
+ test "create_match_minute_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_match_minute_log(invalid_attrs())
+ end
+
+ test "update_match_minute_log/2 with valid data updates the match_minute_log" do
+ match_minute_log = LoggingFixtures.match_minute_log_fixture()
+
+ assert {:ok, %MatchMinuteLog{} = match_minute_log} =
+ Logging.update_match_minute_log(match_minute_log, update_attrs())
+
+ assert match_minute_log.data == %{"other-key" => 2}
+ end
+
+ test "update_match_minute_log/2 with invalid data returns error changeset" do
+ match_minute_log = LoggingFixtures.match_minute_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_match_minute_log(match_minute_log, invalid_attrs())
+
+ assert match_minute_log == Logging.get_match_minute_log!(match_minute_log.timestamp)
+ end
+
+ test "delete_match_minute_log/1 deletes the match_minute_log" do
+ match_minute_log = LoggingFixtures.match_minute_log_fixture()
+ assert {:ok, %MatchMinuteLog{}} = Logging.delete_match_minute_log(match_minute_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_match_minute_log!(match_minute_log.timestamp)
+ end
+
+ assert Logging.get_match_minute_log(match_minute_log.timestamp) == nil
+ end
+
+ test "change_match_minute_log/1 returns a match_minute_log changeset" do
+ match_minute_log = LoggingFixtures.match_minute_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_match_minute_log(match_minute_log)
+ end
+ end
+end
diff --git a/test/logging/libs/match_month_log_lib_test.exs b/test/logging/libs/match_month_log_lib_test.exs
new file mode 100644
index 000000000..13050f00c
--- /dev/null
+++ b/test/logging/libs/match_month_log_lib_test.exs
@@ -0,0 +1,102 @@
+defmodule Teiserver.MatchMonthLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.MatchMonthLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ year: 1,
+ month: 1,
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(months: 1),
+ year: 2,
+ month: 2,
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "match_month_log" do
+ alias Teiserver.Logging.MatchMonthLog
+
+ test "match_month_log_query/0 returns a query" do
+ q = Logging.match_month_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_match_month_log/0 returns match_month_log" do
+ # No match_month_log yet
+ assert Logging.list_match_month_logs([]) == []
+
+ # Add a match_month_log
+ LoggingFixtures.match_month_log_fixture()
+ assert Logging.list_match_month_logs([]) != []
+ end
+
+ test "get_match_month_log!/1 and get_match_month_log/1 returns the match_month_log with given id" do
+ match_month_log = LoggingFixtures.match_month_log_fixture()
+ assert Logging.get_match_month_log!(match_month_log.date) == match_month_log
+ assert Logging.get_match_month_log(match_month_log.date) == match_month_log
+ end
+
+ test "create_match_month_log/1 with valid data creates a match_month_log" do
+ assert {:ok, %MatchMonthLog{} = match_month_log} =
+ Logging.create_match_month_log(valid_attrs())
+
+ assert match_month_log.data == %{"key" => 1}
+ end
+
+ test "create_match_month_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_match_month_log(invalid_attrs())
+ end
+
+ test "update_match_month_log/2 with valid data updates the match_month_log" do
+ match_month_log = LoggingFixtures.match_month_log_fixture()
+
+ assert {:ok, %MatchMonthLog{} = match_month_log} =
+ Logging.update_match_month_log(match_month_log, update_attrs())
+
+ assert match_month_log.data == %{"other-key" => 2}
+ end
+
+ test "update_match_month_log/2 with invalid data returns error changeset" do
+ match_month_log = LoggingFixtures.match_month_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_match_month_log(match_month_log, invalid_attrs())
+
+ assert match_month_log == Logging.get_match_month_log!(match_month_log.date)
+ end
+
+ test "delete_match_month_log/1 deletes the match_month_log" do
+ match_month_log = LoggingFixtures.match_month_log_fixture()
+ assert {:ok, %MatchMonthLog{}} = Logging.delete_match_month_log(match_month_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_match_month_log!(match_month_log.date)
+ end
+
+ assert Logging.get_match_month_log(match_month_log.date) == nil
+ end
+
+ test "change_match_month_log/1 returns a match_month_log changeset" do
+ match_month_log = LoggingFixtures.match_month_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_match_month_log(match_month_log)
+ end
+ end
+end
diff --git a/test/logging/libs/match_quarter_log_lib_test.exs b/test/logging/libs/match_quarter_log_lib_test.exs
new file mode 100644
index 000000000..93b19b8c2
--- /dev/null
+++ b/test/logging/libs/match_quarter_log_lib_test.exs
@@ -0,0 +1,102 @@
+defmodule Teiserver.MatchQuarterLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.MatchQuarterLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ year: 1,
+ quarter: 1,
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(months: 3),
+ year: 2,
+ quarter: 2,
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "match_quarter_log" do
+ alias Teiserver.Logging.MatchQuarterLog
+
+ test "match_quarter_log_query/0 returns a query" do
+ q = Logging.match_quarter_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_match_quarter_log/0 returns match_quarter_log" do
+ # No match_quarter_log yet
+ assert Logging.list_match_quarter_logs([]) == []
+
+ # Add a match_quarter_log
+ LoggingFixtures.match_quarter_log_fixture()
+ assert Logging.list_match_quarter_logs([]) != []
+ end
+
+ test "get_match_quarter_log!/1 and get_match_quarter_log/1 returns the match_quarter_log with given id" do
+ match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
+ assert Logging.get_match_quarter_log!(match_quarter_log.date) == match_quarter_log
+ assert Logging.get_match_quarter_log(match_quarter_log.date) == match_quarter_log
+ end
+
+ test "create_match_quarter_log/1 with valid data creates a match_quarter_log" do
+ assert {:ok, %MatchQuarterLog{} = match_quarter_log} =
+ Logging.create_match_quarter_log(valid_attrs())
+
+ assert match_quarter_log.data == %{"key" => 1}
+ end
+
+ test "create_match_quarter_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_match_quarter_log(invalid_attrs())
+ end
+
+ test "update_match_quarter_log/2 with valid data updates the match_quarter_log" do
+ match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
+
+ assert {:ok, %MatchQuarterLog{} = match_quarter_log} =
+ Logging.update_match_quarter_log(match_quarter_log, update_attrs())
+
+ assert match_quarter_log.data == %{"other-key" => 2}
+ end
+
+ test "update_match_quarter_log/2 with invalid data returns error changeset" do
+ match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_match_quarter_log(match_quarter_log, invalid_attrs())
+
+ assert match_quarter_log == Logging.get_match_quarter_log!(match_quarter_log.date)
+ end
+
+ test "delete_match_quarter_log/1 deletes the match_quarter_log" do
+ match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
+ assert {:ok, %MatchQuarterLog{}} = Logging.delete_match_quarter_log(match_quarter_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_match_quarter_log!(match_quarter_log.date)
+ end
+
+ assert Logging.get_match_quarter_log(match_quarter_log.date) == nil
+ end
+
+ test "change_match_quarter_log/1 returns a match_quarter_log changeset" do
+ match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_match_quarter_log(match_quarter_log)
+ end
+ end
+end
diff --git a/test/logging/libs/match_week_log_lib_test.exs b/test/logging/libs/match_week_log_lib_test.exs
new file mode 100644
index 000000000..cbc31504a
--- /dev/null
+++ b/test/logging/libs/match_week_log_lib_test.exs
@@ -0,0 +1,102 @@
+defmodule Teiserver.MatchWeekLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.MatchWeekLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ year: 1,
+ week: 1,
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(weeks: 1),
+ year: 2,
+ week: 2,
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "match_week_log" do
+ alias Teiserver.Logging.MatchWeekLog
+
+ test "match_week_log_query/0 returns a query" do
+ q = Logging.match_week_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_match_week_log/0 returns match_week_log" do
+ # No match_week_log yet
+ assert Logging.list_match_week_logs([]) == []
+
+ # Add a match_week_log
+ LoggingFixtures.match_week_log_fixture()
+ assert Logging.list_match_week_logs([]) != []
+ end
+
+ test "get_match_week_log!/1 and get_match_week_log/1 returns the match_week_log with given id" do
+ match_week_log = LoggingFixtures.match_week_log_fixture()
+ assert Logging.get_match_week_log!(match_week_log.date) == match_week_log
+ assert Logging.get_match_week_log(match_week_log.date) == match_week_log
+ end
+
+ test "create_match_week_log/1 with valid data creates a match_week_log" do
+ assert {:ok, %MatchWeekLog{} = match_week_log} =
+ Logging.create_match_week_log(valid_attrs())
+
+ assert match_week_log.data == %{"key" => 1}
+ end
+
+ test "create_match_week_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_match_week_log(invalid_attrs())
+ end
+
+ test "update_match_week_log/2 with valid data updates the match_week_log" do
+ match_week_log = LoggingFixtures.match_week_log_fixture()
+
+ assert {:ok, %MatchWeekLog{} = match_week_log} =
+ Logging.update_match_week_log(match_week_log, update_attrs())
+
+ assert match_week_log.data == %{"other-key" => 2}
+ end
+
+ test "update_match_week_log/2 with invalid data returns error changeset" do
+ match_week_log = LoggingFixtures.match_week_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_match_week_log(match_week_log, invalid_attrs())
+
+ assert match_week_log == Logging.get_match_week_log!(match_week_log.date)
+ end
+
+ test "delete_match_week_log/1 deletes the match_week_log" do
+ match_week_log = LoggingFixtures.match_week_log_fixture()
+ assert {:ok, %MatchWeekLog{}} = Logging.delete_match_week_log(match_week_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_match_week_log!(match_week_log.date)
+ end
+
+ assert Logging.get_match_week_log(match_week_log.date) == nil
+ end
+
+ test "change_match_week_log/1 returns a match_week_log changeset" do
+ match_week_log = LoggingFixtures.match_week_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_match_week_log(match_week_log)
+ end
+ end
+end
diff --git a/test/logging/libs/match_year_log_lib_test.exs b/test/logging/libs/match_year_log_lib_test.exs
new file mode 100644
index 000000000..7f1471c9c
--- /dev/null
+++ b/test/logging/libs/match_year_log_lib_test.exs
@@ -0,0 +1,100 @@
+defmodule Teiserver.MatchYearLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.MatchYearLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ year: 1,
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(years: 1),
+ year: 2,
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "match_year_log" do
+ alias Teiserver.Logging.MatchYearLog
+
+ test "match_year_log_query/0 returns a query" do
+ q = Logging.match_year_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_match_year_log/0 returns match_year_log" do
+ # No match_year_log yet
+ assert Logging.list_match_year_logs([]) == []
+
+ # Add a match_year_log
+ LoggingFixtures.match_year_log_fixture()
+ assert Logging.list_match_year_logs([]) != []
+ end
+
+ test "get_match_year_log!/1 and get_match_year_log/1 returns the match_year_log with given id" do
+ match_year_log = LoggingFixtures.match_year_log_fixture()
+ assert Logging.get_match_year_log!(match_year_log.date) == match_year_log
+ assert Logging.get_match_year_log(match_year_log.date) == match_year_log
+ end
+
+ test "create_match_year_log/1 with valid data creates a match_year_log" do
+ assert {:ok, %MatchYearLog{} = match_year_log} =
+ Logging.create_match_year_log(valid_attrs())
+
+ assert match_year_log.data == %{"key" => 1}
+ end
+
+ test "create_match_year_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_match_year_log(invalid_attrs())
+ end
+
+ test "update_match_year_log/2 with valid data updates the match_year_log" do
+ match_year_log = LoggingFixtures.match_year_log_fixture()
+
+ assert {:ok, %MatchYearLog{} = match_year_log} =
+ Logging.update_match_year_log(match_year_log, update_attrs())
+
+ assert match_year_log.data == %{"other-key" => 2}
+ end
+
+ test "update_match_year_log/2 with invalid data returns error changeset" do
+ match_year_log = LoggingFixtures.match_year_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_match_year_log(match_year_log, invalid_attrs())
+
+ assert match_year_log == Logging.get_match_year_log!(match_year_log.date)
+ end
+
+ test "delete_match_year_log/1 deletes the match_year_log" do
+ match_year_log = LoggingFixtures.match_year_log_fixture()
+ assert {:ok, %MatchYearLog{}} = Logging.delete_match_year_log(match_year_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_match_year_log!(match_year_log.date)
+ end
+
+ assert Logging.get_match_year_log(match_year_log.date) == nil
+ end
+
+ test "change_match_year_log/1 returns a match_year_log changeset" do
+ match_year_log = LoggingFixtures.match_year_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_match_year_log(match_year_log)
+ end
+ end
+end
diff --git a/test/logging/libs/server_day_log_lib_test.exs b/test/logging/libs/server_day_log_lib_test.exs
new file mode 100644
index 000000000..3068bdc12
--- /dev/null
+++ b/test/logging/libs/server_day_log_lib_test.exs
@@ -0,0 +1,98 @@
+defmodule Teiserver.ServerDayLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.ServerDayLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(days: 1),
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "server_day_log" do
+ alias Teiserver.Logging.ServerDayLog
+
+ test "server_day_log_query/0 returns a query" do
+ q = Logging.server_day_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_server_day_log/0 returns server_day_log" do
+ # No server_day_log yet
+ assert Logging.list_server_day_logs([]) == []
+
+ # Add a server_day_log
+ LoggingFixtures.server_day_log_fixture()
+ assert Logging.list_server_day_logs([]) != []
+ end
+
+ test "get_server_day_log!/1 and get_server_day_log/1 returns the server_day_log with given id" do
+ server_day_log = LoggingFixtures.server_day_log_fixture()
+ assert Logging.get_server_day_log!(server_day_log.date) == server_day_log
+ assert Logging.get_server_day_log(server_day_log.date) == server_day_log
+ end
+
+ test "create_server_day_log/1 with valid data creates a server_day_log" do
+ assert {:ok, %ServerDayLog{} = server_day_log} =
+ Logging.create_server_day_log(valid_attrs())
+
+ assert server_day_log.data == %{"key" => 1}
+ end
+
+ test "create_server_day_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_server_day_log(invalid_attrs())
+ end
+
+ test "update_server_day_log/2 with valid data updates the server_day_log" do
+ server_day_log = LoggingFixtures.server_day_log_fixture()
+
+ assert {:ok, %ServerDayLog{} = server_day_log} =
+ Logging.update_server_day_log(server_day_log, update_attrs())
+
+ assert server_day_log.data == %{"other-key" => 2}
+ end
+
+ test "update_server_day_log/2 with invalid data returns error changeset" do
+ server_day_log = LoggingFixtures.server_day_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_server_day_log(server_day_log, invalid_attrs())
+
+ assert server_day_log == Logging.get_server_day_log!(server_day_log.date)
+ end
+
+ test "delete_server_day_log/1 deletes the server_day_log" do
+ server_day_log = LoggingFixtures.server_day_log_fixture()
+ assert {:ok, %ServerDayLog{}} = Logging.delete_server_day_log(server_day_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_server_day_log!(server_day_log.date)
+ end
+
+ assert Logging.get_server_day_log(server_day_log.date) == nil
+ end
+
+ test "change_server_day_log/1 returns a server_day_log changeset" do
+ server_day_log = LoggingFixtures.server_day_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_server_day_log(server_day_log)
+ end
+ end
+end
diff --git a/test/logging/libs/server_minute_log_lib_test.exs b/test/logging/libs/server_minute_log_lib_test.exs
new file mode 100644
index 000000000..f3a25781b
--- /dev/null
+++ b/test/logging/libs/server_minute_log_lib_test.exs
@@ -0,0 +1,98 @@
+defmodule Teiserver.ServerMinuteLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.ServerMinuteLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ timestamp: Timex.now(),
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ timestamp: Timex.now() |> Timex.shift(minutes: 1),
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ timestamp: nil,
+ data: nil
+ }
+ end
+
+ describe "server_minute_log" do
+ alias Teiserver.Logging.ServerMinuteLog
+
+ test "server_minute_log_query/0 returns a query" do
+ q = Logging.server_minute_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_server_minute_log/0 returns server_minute_log" do
+ # No server_minute_log yet
+ assert Logging.list_server_minute_logs([]) == []
+
+ # Add a server_minute_log
+ LoggingFixtures.server_minute_log_fixture()
+ assert Logging.list_server_minute_logs([]) != []
+ end
+
+ test "get_server_minute_log!/1 and get_server_minute_log/1 returns the server_minute_log with given id" do
+ server_minute_log = LoggingFixtures.server_minute_log_fixture()
+ assert Logging.get_server_minute_log!(server_minute_log.timestamp) == server_minute_log
+ assert Logging.get_server_minute_log(server_minute_log.timestamp) == server_minute_log
+ end
+
+ test "create_server_minute_log/1 with valid data creates a server_minute_log" do
+ assert {:ok, %ServerMinuteLog{} = server_minute_log} =
+ Logging.create_server_minute_log(valid_attrs())
+
+ assert server_minute_log.data == %{"key" => 1}
+ end
+
+ test "create_server_minute_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_server_minute_log(invalid_attrs())
+ end
+
+ test "update_server_minute_log/2 with valid data updates the server_minute_log" do
+ server_minute_log = LoggingFixtures.server_minute_log_fixture()
+
+ assert {:ok, %ServerMinuteLog{} = server_minute_log} =
+ Logging.update_server_minute_log(server_minute_log, update_attrs())
+
+ assert server_minute_log.data == %{"other-key" => 2}
+ end
+
+ test "update_server_minute_log/2 with invalid data returns error changeset" do
+ server_minute_log = LoggingFixtures.server_minute_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_server_minute_log(server_minute_log, invalid_attrs())
+
+ assert server_minute_log == Logging.get_server_minute_log!(server_minute_log.timestamp)
+ end
+
+ test "delete_server_minute_log/1 deletes the server_minute_log" do
+ server_minute_log = LoggingFixtures.server_minute_log_fixture()
+ assert {:ok, %ServerMinuteLog{}} = Logging.delete_server_minute_log(server_minute_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_server_minute_log!(server_minute_log.timestamp)
+ end
+
+ assert Logging.get_server_minute_log(server_minute_log.timestamp) == nil
+ end
+
+ test "change_server_minute_log/1 returns a server_minute_log changeset" do
+ server_minute_log = LoggingFixtures.server_minute_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_server_minute_log(server_minute_log)
+ end
+ end
+end
diff --git a/test/logging/libs/server_month_log_lib_test.exs b/test/logging/libs/server_month_log_lib_test.exs
new file mode 100644
index 000000000..1a7cd566c
--- /dev/null
+++ b/test/logging/libs/server_month_log_lib_test.exs
@@ -0,0 +1,102 @@
+defmodule Teiserver.ServerMonthLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.ServerMonthLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ year: 1,
+ month: 1,
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(months: 1),
+ year: 2,
+ month: 2,
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "server_month_log" do
+ alias Teiserver.Logging.ServerMonthLog
+
+ test "server_month_log_query/0 returns a query" do
+ q = Logging.server_month_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_server_month_log/0 returns server_month_log" do
+ # No server_month_log yet
+ assert Logging.list_server_month_logs([]) == []
+
+ # Add a server_month_log
+ LoggingFixtures.server_month_log_fixture()
+ assert Logging.list_server_month_logs([]) != []
+ end
+
+ test "get_server_month_log!/1 and get_server_month_log/1 returns the server_month_log with given id" do
+ server_month_log = LoggingFixtures.server_month_log_fixture()
+ assert Logging.get_server_month_log!(server_month_log.date) == server_month_log
+ assert Logging.get_server_month_log(server_month_log.date) == server_month_log
+ end
+
+ test "create_server_month_log/1 with valid data creates a server_month_log" do
+ assert {:ok, %ServerMonthLog{} = server_month_log} =
+ Logging.create_server_month_log(valid_attrs())
+
+ assert server_month_log.data == %{"key" => 1}
+ end
+
+ test "create_server_month_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_server_month_log(invalid_attrs())
+ end
+
+ test "update_server_month_log/2 with valid data updates the server_month_log" do
+ server_month_log = LoggingFixtures.server_month_log_fixture()
+
+ assert {:ok, %ServerMonthLog{} = server_month_log} =
+ Logging.update_server_month_log(server_month_log, update_attrs())
+
+ assert server_month_log.data == %{"other-key" => 2}
+ end
+
+ test "update_server_month_log/2 with invalid data returns error changeset" do
+ server_month_log = LoggingFixtures.server_month_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_server_month_log(server_month_log, invalid_attrs())
+
+ assert server_month_log == Logging.get_server_month_log!(server_month_log.date)
+ end
+
+ test "delete_server_month_log/1 deletes the server_month_log" do
+ server_month_log = LoggingFixtures.server_month_log_fixture()
+ assert {:ok, %ServerMonthLog{}} = Logging.delete_server_month_log(server_month_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_server_month_log!(server_month_log.date)
+ end
+
+ assert Logging.get_server_month_log(server_month_log.date) == nil
+ end
+
+ test "change_server_month_log/1 returns a server_month_log changeset" do
+ server_month_log = LoggingFixtures.server_month_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_server_month_log(server_month_log)
+ end
+ end
+end
diff --git a/test/logging/libs/server_quarter_log_lib_test.exs b/test/logging/libs/server_quarter_log_lib_test.exs
new file mode 100644
index 000000000..f4c875347
--- /dev/null
+++ b/test/logging/libs/server_quarter_log_lib_test.exs
@@ -0,0 +1,104 @@
+defmodule Teiserver.ServerQuarterLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.ServerQuarterLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ year: 1,
+ quarter: 1,
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(months: 3),
+ year: 2,
+ quarter: 2,
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ year: nil,
+ quarter: nil,
+ data: nil
+ }
+ end
+
+ describe "server_quarter_log" do
+ alias Teiserver.Logging.ServerQuarterLog
+
+ test "server_quarter_log_query/0 returns a query" do
+ q = Logging.server_quarter_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_server_quarter_log/0 returns server_quarter_log" do
+ # No server_quarter_log yet
+ assert Logging.list_server_quarter_logs([]) == []
+
+ # Add a server_quarter_log
+ LoggingFixtures.server_quarter_log_fixture()
+ assert Logging.list_server_quarter_logs([]) != []
+ end
+
+ test "get_server_quarter_log!/1 and get_server_quarter_log/1 returns the server_quarter_log with given id" do
+ server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
+ assert Logging.get_server_quarter_log!(server_quarter_log.date) == server_quarter_log
+ assert Logging.get_server_quarter_log(server_quarter_log.date) == server_quarter_log
+ end
+
+ test "create_server_quarter_log/1 with valid data creates a server_quarter_log" do
+ assert {:ok, %ServerQuarterLog{} = server_quarter_log} =
+ Logging.create_server_quarter_log(valid_attrs())
+
+ assert server_quarter_log.data == %{"key" => 1}
+ end
+
+ test "create_server_quarter_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_server_quarter_log(invalid_attrs())
+ end
+
+ test "update_server_quarter_log/2 with valid data updates the server_quarter_log" do
+ server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
+
+ assert {:ok, %ServerQuarterLog{} = server_quarter_log} =
+ Logging.update_server_quarter_log(server_quarter_log, update_attrs())
+
+ assert server_quarter_log.data == %{"other-key" => 2}
+ end
+
+ test "update_server_quarter_log/2 with invalid data returns error changeset" do
+ server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_server_quarter_log(server_quarter_log, invalid_attrs())
+
+ assert server_quarter_log == Logging.get_server_quarter_log!(server_quarter_log.date)
+ end
+
+ test "delete_server_quarter_log/1 deletes the server_quarter_log" do
+ server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
+ assert {:ok, %ServerQuarterLog{}} = Logging.delete_server_quarter_log(server_quarter_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_server_quarter_log!(server_quarter_log.date)
+ end
+
+ assert Logging.get_server_quarter_log(server_quarter_log.date) == nil
+ end
+
+ test "change_server_quarter_log/1 returns a server_quarter_log changeset" do
+ server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_server_quarter_log(server_quarter_log)
+ end
+ end
+end
diff --git a/test/logging/libs/server_week_log_lib_test.exs b/test/logging/libs/server_week_log_lib_test.exs
new file mode 100644
index 000000000..5eb21efc5
--- /dev/null
+++ b/test/logging/libs/server_week_log_lib_test.exs
@@ -0,0 +1,102 @@
+defmodule Teiserver.ServerWeekLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.ServerWeekLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ year: 1,
+ week: 1,
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(weeks: 1),
+ year: 2,
+ week: 2,
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "server_week_log" do
+ alias Teiserver.Logging.ServerWeekLog
+
+ test "server_week_log_query/0 returns a query" do
+ q = Logging.server_week_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_server_week_log/0 returns server_week_log" do
+ # No server_week_log yet
+ assert Logging.list_server_week_logs([]) == []
+
+ # Add a server_week_log
+ LoggingFixtures.server_week_log_fixture()
+ assert Logging.list_server_week_logs([]) != []
+ end
+
+ test "get_server_week_log!/1 and get_server_week_log/1 returns the server_week_log with given id" do
+ server_week_log = LoggingFixtures.server_week_log_fixture()
+ assert Logging.get_server_week_log!(server_week_log.date) == server_week_log
+ assert Logging.get_server_week_log(server_week_log.date) == server_week_log
+ end
+
+ test "create_server_week_log/1 with valid data creates a server_week_log" do
+ assert {:ok, %ServerWeekLog{} = server_week_log} =
+ Logging.create_server_week_log(valid_attrs())
+
+ assert server_week_log.data == %{"key" => 1}
+ end
+
+ test "create_server_week_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_server_week_log(invalid_attrs())
+ end
+
+ test "update_server_week_log/2 with valid data updates the server_week_log" do
+ server_week_log = LoggingFixtures.server_week_log_fixture()
+
+ assert {:ok, %ServerWeekLog{} = server_week_log} =
+ Logging.update_server_week_log(server_week_log, update_attrs())
+
+ assert server_week_log.data == %{"other-key" => 2}
+ end
+
+ test "update_server_week_log/2 with invalid data returns error changeset" do
+ server_week_log = LoggingFixtures.server_week_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_server_week_log(server_week_log, invalid_attrs())
+
+ assert server_week_log == Logging.get_server_week_log!(server_week_log.date)
+ end
+
+ test "delete_server_week_log/1 deletes the server_week_log" do
+ server_week_log = LoggingFixtures.server_week_log_fixture()
+ assert {:ok, %ServerWeekLog{}} = Logging.delete_server_week_log(server_week_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_server_week_log!(server_week_log.date)
+ end
+
+ assert Logging.get_server_week_log(server_week_log.date) == nil
+ end
+
+ test "change_server_week_log/1 returns a server_week_log changeset" do
+ server_week_log = LoggingFixtures.server_week_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_server_week_log(server_week_log)
+ end
+ end
+end
diff --git a/test/logging/libs/server_year_log_lib_test.exs b/test/logging/libs/server_year_log_lib_test.exs
new file mode 100644
index 000000000..068d5661b
--- /dev/null
+++ b/test/logging/libs/server_year_log_lib_test.exs
@@ -0,0 +1,100 @@
+defmodule Teiserver.ServerYearLogLibTest do
+ @moduledoc false
+ alias Teiserver.Logging.ServerYearLog
+ alias Teiserver.Logging
+ use Teiserver.Case, async: true
+
+ alias Teiserver.LoggingFixtures
+
+ defp valid_attrs do
+ %{
+ date: Timex.today(),
+ year: 1,
+ data: %{"key" => 1}
+ }
+ end
+
+ defp update_attrs do
+ %{
+ date: Timex.today() |> Timex.shift(years: 1),
+ year: 2,
+ data: %{"other-key" => 2}
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ date: nil,
+ data: nil
+ }
+ end
+
+ describe "server_year_log" do
+ alias Teiserver.Logging.ServerYearLog
+
+ test "server_year_log_query/0 returns a query" do
+ q = Logging.server_year_log_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_server_year_log/0 returns server_year_log" do
+ # No server_year_log yet
+ assert Logging.list_server_year_logs([]) == []
+
+ # Add a server_year_log
+ LoggingFixtures.server_year_log_fixture()
+ assert Logging.list_server_year_logs([]) != []
+ end
+
+ test "get_server_year_log!/1 and get_server_year_log/1 returns the server_year_log with given id" do
+ server_year_log = LoggingFixtures.server_year_log_fixture()
+ assert Logging.get_server_year_log!(server_year_log.date) == server_year_log
+ assert Logging.get_server_year_log(server_year_log.date) == server_year_log
+ end
+
+ test "create_server_year_log/1 with valid data creates a server_year_log" do
+ assert {:ok, %ServerYearLog{} = server_year_log} =
+ Logging.create_server_year_log(valid_attrs())
+
+ assert server_year_log.data == %{"key" => 1}
+ end
+
+ test "create_server_year_log/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Logging.create_server_year_log(invalid_attrs())
+ end
+
+ test "update_server_year_log/2 with valid data updates the server_year_log" do
+ server_year_log = LoggingFixtures.server_year_log_fixture()
+
+ assert {:ok, %ServerYearLog{} = server_year_log} =
+ Logging.update_server_year_log(server_year_log, update_attrs())
+
+ assert server_year_log.data == %{"other-key" => 2}
+ end
+
+ test "update_server_year_log/2 with invalid data returns error changeset" do
+ server_year_log = LoggingFixtures.server_year_log_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Logging.update_server_year_log(server_year_log, invalid_attrs())
+
+ assert server_year_log == Logging.get_server_year_log!(server_year_log.date)
+ end
+
+ test "delete_server_year_log/1 deletes the server_year_log" do
+ server_year_log = LoggingFixtures.server_year_log_fixture()
+ assert {:ok, %ServerYearLog{}} = Logging.delete_server_year_log(server_year_log)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Logging.get_server_year_log!(server_year_log.date)
+ end
+
+ assert Logging.get_server_year_log(server_year_log.date) == nil
+ end
+
+ test "change_server_year_log/1 returns a server_year_log changeset" do
+ server_year_log = LoggingFixtures.server_year_log_fixture()
+ assert %Ecto.Changeset{} = Logging.change_server_year_log(server_year_log)
+ end
+ end
+end
diff --git a/test/logging/queries/match_day_log_queries_test.exs b/test/logging/queries/match_day_log_queries_test.exs
new file mode 100644
index 000000000..3bfef2061
--- /dev/null
+++ b/test/logging/queries/match_day_log_queries_test.exs
@@ -0,0 +1,47 @@
+defmodule Teiserver.MatchDayLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.MatchDayLogQueries
+
+ describe "queries" do
+ @empty_query MatchDayLogQueries.match_day_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ MatchDayLogQueries.match_day_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ MatchDayLogQueries.match_day_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ MatchDayLogQueries.match_day_log_query(
+ where: [
+ date: Timex.today(),
+ after: Timex.today(),
+ before: Timex.today()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/match_minute_log_queries_test.exs b/test/logging/queries/match_minute_log_queries_test.exs
new file mode 100644
index 000000000..2aa68dad5
--- /dev/null
+++ b/test/logging/queries/match_minute_log_queries_test.exs
@@ -0,0 +1,46 @@
+defmodule Teiserver.MatchMinuteLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.MatchMinuteLogQueries
+
+ describe "queries" do
+ @empty_query MatchMinuteLogQueries.match_minute_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ MatchMinuteLogQueries.match_minute_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ MatchMinuteLogQueries.match_minute_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ MatchMinuteLogQueries.match_minute_log_query(
+ where: [
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/match_month_log_queries_test.exs b/test/logging/queries/match_month_log_queries_test.exs
new file mode 100644
index 000000000..3ca31386e
--- /dev/null
+++ b/test/logging/queries/match_month_log_queries_test.exs
@@ -0,0 +1,49 @@
+defmodule Teiserver.MatchMonthLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.MatchMonthLogQueries
+
+ describe "queries" do
+ @empty_query MatchMonthLogQueries.match_month_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ MatchMonthLogQueries.match_month_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ MatchMonthLogQueries.match_month_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ MatchMonthLogQueries.match_month_log_query(
+ where: [
+ date: Timex.today(),
+ year: 123,
+ month: 123,
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/match_quarter_log_queries_test.exs b/test/logging/queries/match_quarter_log_queries_test.exs
new file mode 100644
index 000000000..aa787e14e
--- /dev/null
+++ b/test/logging/queries/match_quarter_log_queries_test.exs
@@ -0,0 +1,49 @@
+defmodule Teiserver.MatchQuarterLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.MatchQuarterLogQueries
+
+ describe "queries" do
+ @empty_query MatchQuarterLogQueries.match_quarter_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ MatchQuarterLogQueries.match_quarter_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ MatchQuarterLogQueries.match_quarter_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ MatchQuarterLogQueries.match_quarter_log_query(
+ where: [
+ date: Timex.today(),
+ year: 123,
+ quarter: 123,
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/match_week_log_queries_test.exs b/test/logging/queries/match_week_log_queries_test.exs
new file mode 100644
index 000000000..16fd6916e
--- /dev/null
+++ b/test/logging/queries/match_week_log_queries_test.exs
@@ -0,0 +1,49 @@
+defmodule Teiserver.MatchWeekLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.MatchWeekLogQueries
+
+ describe "queries" do
+ @empty_query MatchWeekLogQueries.match_week_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ MatchWeekLogQueries.match_week_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ MatchWeekLogQueries.match_week_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ MatchWeekLogQueries.match_week_log_query(
+ where: [
+ date: Timex.today(),
+ year: 123,
+ week: 123,
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/match_year_log_queries_test.exs b/test/logging/queries/match_year_log_queries_test.exs
new file mode 100644
index 000000000..32a67b0b6
--- /dev/null
+++ b/test/logging/queries/match_year_log_queries_test.exs
@@ -0,0 +1,48 @@
+defmodule Teiserver.MatchYearLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.MatchYearLogQueries
+
+ describe "queries" do
+ @empty_query MatchYearLogQueries.match_year_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ MatchYearLogQueries.match_year_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ MatchYearLogQueries.match_year_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ MatchYearLogQueries.match_year_log_query(
+ where: [
+ date: Timex.today(),
+ year: 123,
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/server_day_log_queries_test.exs b/test/logging/queries/server_day_log_queries_test.exs
new file mode 100644
index 000000000..6b7f7c25c
--- /dev/null
+++ b/test/logging/queries/server_day_log_queries_test.exs
@@ -0,0 +1,47 @@
+defmodule Teiserver.ServerDayLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.ServerDayLogQueries
+
+ describe "queries" do
+ @empty_query ServerDayLogQueries.server_day_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ ServerDayLogQueries.server_day_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ ServerDayLogQueries.server_day_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ ServerDayLogQueries.server_day_log_query(
+ where: [
+ date: Timex.today(),
+ after: Timex.today(),
+ before: Timex.today()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/server_minute_log_queries_test.exs b/test/logging/queries/server_minute_log_queries_test.exs
new file mode 100644
index 000000000..dfdc01afa
--- /dev/null
+++ b/test/logging/queries/server_minute_log_queries_test.exs
@@ -0,0 +1,46 @@
+defmodule Teiserver.ServerMinuteLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.ServerMinuteLogQueries
+
+ describe "queries" do
+ @empty_query ServerMinuteLogQueries.server_minute_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ ServerMinuteLogQueries.server_minute_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ ServerMinuteLogQueries.server_minute_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ ServerMinuteLogQueries.server_minute_log_query(
+ where: [
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/server_month_log_queries_test.exs b/test/logging/queries/server_month_log_queries_test.exs
new file mode 100644
index 000000000..346e932c0
--- /dev/null
+++ b/test/logging/queries/server_month_log_queries_test.exs
@@ -0,0 +1,49 @@
+defmodule Teiserver.ServerMonthLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.ServerMonthLogQueries
+
+ describe "queries" do
+ @empty_query ServerMonthLogQueries.server_month_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ ServerMonthLogQueries.server_month_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ ServerMonthLogQueries.server_month_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ ServerMonthLogQueries.server_month_log_query(
+ where: [
+ date: Timex.today(),
+ year: 123,
+ month: 123,
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/server_quarter_log_queries_test.exs b/test/logging/queries/server_quarter_log_queries_test.exs
new file mode 100644
index 000000000..7492c7402
--- /dev/null
+++ b/test/logging/queries/server_quarter_log_queries_test.exs
@@ -0,0 +1,49 @@
+defmodule Teiserver.ServerQuarterLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.ServerQuarterLogQueries
+
+ describe "queries" do
+ @empty_query ServerQuarterLogQueries.server_quarter_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ ServerQuarterLogQueries.server_quarter_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ ServerQuarterLogQueries.server_quarter_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ ServerQuarterLogQueries.server_quarter_log_query(
+ where: [
+ date: Timex.today(),
+ year: 123,
+ quarter: 123,
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/server_week_log_queries_test.exs b/test/logging/queries/server_week_log_queries_test.exs
new file mode 100644
index 000000000..8830bba80
--- /dev/null
+++ b/test/logging/queries/server_week_log_queries_test.exs
@@ -0,0 +1,49 @@
+defmodule Teiserver.ServerWeekLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.ServerWeekLogQueries
+
+ describe "queries" do
+ @empty_query ServerWeekLogQueries.server_week_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ ServerWeekLogQueries.server_week_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ ServerWeekLogQueries.server_week_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ ServerWeekLogQueries.server_week_log_query(
+ where: [
+ date: Timex.today(),
+ year: 123,
+ week: 123,
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/logging/queries/server_year_log_queries_test.exs b/test/logging/queries/server_year_log_queries_test.exs
new file mode 100644
index 000000000..8a70ebf64
--- /dev/null
+++ b/test/logging/queries/server_year_log_queries_test.exs
@@ -0,0 +1,48 @@
+defmodule Teiserver.ServerYearLogQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Logging.ServerYearLogQueries
+
+ describe "queries" do
+ @empty_query ServerYearLogQueries.server_year_log_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ ServerYearLogQueries.server_year_log_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ ServerYearLogQueries.server_year_log_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ ServerYearLogQueries.server_year_log_query(
+ where: [
+ date: Timex.today(),
+ year: 123,
+ after: Timex.now(),
+ before: Timex.now()
+ ],
+ order_by: [
+ "Newest first",
+ "Oldest first"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/support/fixtures/logging_fixtures.ex b/test/support/fixtures/logging_fixtures.ex
index 0a66ee821..e661c4b37 100644
--- a/test/support/fixtures/logging_fixtures.ex
+++ b/test/support/fixtures/logging_fixtures.ex
@@ -2,6 +2,7 @@ defmodule Teiserver.LoggingFixtures do
@moduledoc false
import Teiserver.AccountFixtures, only: [user_fixture: 0]
alias Teiserver.Logging.{AuditLog}
+ alias Teiserver.Logging
@spec audit_log_fixture() :: AuditLog.t()
@spec audit_log_fixture(map) :: AuditLog.t()
@@ -36,4 +37,176 @@ defmodule Teiserver.LoggingFixtures do
)
|> Teiserver.Repo.insert!()
end
+
+ # Match logs
+ @spec match_minute_log_fixture() :: Logging.MatchMinuteLog.t()
+ @spec match_minute_log_fixture(map) :: Logging.MatchMinuteLog.t()
+ def match_minute_log_fixture(data \\ %{}) do
+ Logging.MatchMinuteLog.changeset(
+ %Logging.MatchMinuteLog{},
+ %{
+ timestamp: data[:timestamp] || Timex.now(),
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec match_day_log_fixture() :: Logging.MatchDayLog.t()
+ @spec match_day_log_fixture(map) :: Logging.MatchDayLog.t()
+ def match_day_log_fixture(data \\ %{}) do
+ Logging.MatchDayLog.changeset(
+ %Logging.MatchDayLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec match_week_log_fixture() :: Logging.MatchWeekLog.t()
+ @spec match_week_log_fixture(map) :: Logging.MatchWeekLog.t()
+ def match_week_log_fixture(data \\ %{}) do
+ Logging.MatchWeekLog.changeset(
+ %Logging.MatchWeekLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ year: data[:year] || 1,
+ week: data[:week] || 1,
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec match_month_log_fixture() :: Logging.MatchMonthLog.t()
+ @spec match_month_log_fixture(map) :: Logging.MatchMonthLog.t()
+ def match_month_log_fixture(data \\ %{}) do
+ Logging.MatchMonthLog.changeset(
+ %Logging.MatchMonthLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ year: data[:year] || 1,
+ month: data[:month] || 1,
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec match_quarter_log_fixture() :: Logging.MatchQuarterLog.t()
+ @spec match_quarter_log_fixture(map) :: Logging.MatchQuarterLog.t()
+ def match_quarter_log_fixture(data \\ %{}) do
+ Logging.MatchQuarterLog.changeset(
+ %Logging.MatchQuarterLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ year: data[:year] || 1,
+ quarter: data[:quarter] || 1,
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec match_year_log_fixture() :: Logging.MatchYearLog.t()
+ @spec match_year_log_fixture(map) :: Logging.MatchYearLog.t()
+ def match_year_log_fixture(data \\ %{}) do
+ Logging.MatchYearLog.changeset(
+ %Logging.MatchYearLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ year: data[:year] || 1,
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ # Server logs
+ @spec server_minute_log_fixture() :: Logging.ServerMinuteLog.t()
+ @spec server_minute_log_fixture(map) :: Logging.ServerMinuteLog.t()
+ def server_minute_log_fixture(data \\ %{}) do
+ Logging.ServerMinuteLog.changeset(
+ %Logging.ServerMinuteLog{},
+ %{
+ timestamp: data[:timestamp] || Timex.now(),
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec server_day_log_fixture() :: Logging.ServerDayLog.t()
+ @spec server_day_log_fixture(map) :: Logging.ServerDayLog.t()
+ def server_day_log_fixture(data \\ %{}) do
+ Logging.ServerDayLog.changeset(
+ %Logging.ServerDayLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec server_week_log_fixture() :: Logging.ServerWeekLog.t()
+ @spec server_week_log_fixture(map) :: Logging.ServerWeekLog.t()
+ def server_week_log_fixture(data \\ %{}) do
+ Logging.ServerWeekLog.changeset(
+ %Logging.ServerWeekLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ year: data[:year] || 1,
+ week: data[:week] || 1,
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec server_month_log_fixture() :: Logging.ServerMonthLog.t()
+ @spec server_month_log_fixture(map) :: Logging.ServerMonthLog.t()
+ def server_month_log_fixture(data \\ %{}) do
+ Logging.ServerMonthLog.changeset(
+ %Logging.ServerMonthLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ year: data[:year] || 1,
+ month: data[:month] || 1,
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec server_quarter_log_fixture() :: Logging.ServerQuarterLog.t()
+ @spec server_quarter_log_fixture(map) :: Logging.ServerQuarterLog.t()
+ def server_quarter_log_fixture(data \\ %{}) do
+ Logging.ServerQuarterLog.changeset(
+ %Logging.ServerQuarterLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ year: data[:year] || 1,
+ quarter: data[:quarter] || 1,
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec server_year_log_fixture() :: Logging.ServerYearLog.t()
+ @spec server_year_log_fixture(map) :: Logging.ServerYearLog.t()
+ def server_year_log_fixture(data \\ %{}) do
+ Logging.ServerYearLog.changeset(
+ %Logging.ServerYearLog{},
+ %{
+ date: data[:date] || Timex.today(),
+ year: data[:year] || 1,
+ data: data[:data] || %{}
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
end
From 86b71b5450d09b249657fadd6c67cd3592072a12 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 7 Apr 2024 13:01:37 +0100
Subject: [PATCH 11/64] Formatting and documentation fixes
---
documentation/guides/config.md | 4 +-
documentation/guides/installation.md | 2 +-
documentation/guides/match_lifecycle.md | 2 +-
lib/teiserver/contexts/logging.ex | 268 ++++++++++--------
lib/teiserver/game/libs/lobby_lib.ex | 4 +-
lib/teiserver/helpers/query_helper.ex | 4 +-
.../logging/libs/match_day_log_lib.ex | 12 +-
.../logging/libs/match_minute_log_lib.ex | 12 +-
.../logging/libs/match_month_log_lib.ex | 12 +-
.../logging/libs/match_quarter_log_lib.ex | 12 +-
.../logging/libs/match_week_log_lib.ex | 12 +-
.../logging/libs/match_year_log_lib.ex | 12 +-
.../logging/libs/server_day_log_lib.ex | 12 +-
.../logging/libs/server_minute_log_lib.ex | 12 +-
.../logging/libs/server_month_log_lib.ex | 12 +-
.../logging/libs/server_quarter_log_lib.ex | 13 +-
.../logging/libs/server_week_log_lib.ex | 12 +-
.../logging/libs/server_year_log_lib.ex | 12 +-
.../settings/schemas/server_setting_type.ex | 2 +-
.../settings/schemas/user_setting.ex | 2 +
.../settings/schemas/user_setting_type.ex | 2 +-
mix.exs | 19 +-
22 files changed, 260 insertions(+), 194 deletions(-)
diff --git a/documentation/guides/config.md b/documentation/guides/config.md
index b79f34f76..b81f4b075 100644
--- a/documentation/guides/config.md
+++ b/documentation/guides/config.md
@@ -50,10 +50,10 @@ Allows you to overwrite `Teiserver.Game.MatchTypeLib.default_calculate_match_typ
Allows you to overwrite `Teiserver.Account.User.default_calculate_user_permissions/1`. This is used to generate the list of permissions held by a user. By default it mirrors their groups.
## `fn_lobby_name_acceptor`
-A function used to determine if a lobby name is acceptable. Defaults to `Teiserver.Game.LobbyLib.default_lobby_name_acceptable/1` which always returns true.
+A function used to determine if a lobby name is acceptable. Defaults to `Teiserver.Game.LobbyLib.default_lobby_name_acceptable?/1` which always returns true.
## `fn_user_name_acceptor`
-A function used to determine if a lobby name is acceptable. Defaults to `Teiserver.Account.UserLib.default_user_name_acceptable/1` which always returns true.
+A function used to determine if a lobby name is acceptable. Defaults to `Teiserver.Account.UserLib.default_user_name_acceptable?/1` which always returns true.
## `fn_uuid_generator`
The function used to generate UUIDs. Defaults to `&Ecto.UUID.generate/0`.
diff --git a/documentation/guides/installation.md b/documentation/guides/installation.md
index 5f13afc19..98cf10a25 100644
--- a/documentation/guides/installation.md
+++ b/documentation/guides/installation.md
@@ -6,7 +6,7 @@ First add to your dependencies in `mix.exs`.
```elixir
def deps do
[
- {:teiserver, "~> 0.0.4"}
+ {:teiserver, "~> 0.0.5"}
]
end
```
diff --git a/documentation/guides/match_lifecycle.md b/documentation/guides/match_lifecycle.md
index 6565afb37..40e28ce79 100644
--- a/documentation/guides/match_lifecycle.md
+++ b/documentation/guides/match_lifecycle.md
@@ -36,7 +36,7 @@ To remove a client from a lobby you will need to call `Teiserver.Game.remove_cli
- The lobby state will be updated to remove this user from the member, spectator and player lists as appropriate
### Client updates
-Typically a client will update via `Teiserver.Connections.update_client/2` but if you want to update the lobby details of a client you should use `Teiserver.Connections.update_client_in_lobby/2`.
+Typically a client will update via `Teiserver.Connections.update_client/3` but if you want to update the lobby details of a client you should use `Teiserver.Connections.update_client_in_lobby/3`.
The standard `update_client` only contacts the ClientServer to update values but with the `update_client_in_lobby` function the ClientServer will check with the LobbyServer before updating any details to ensure it is allowed to.
diff --git a/lib/teiserver/contexts/logging.ex b/lib/teiserver/contexts/logging.ex
index 20a952632..3962cf227 100644
--- a/lib/teiserver/contexts/logging.ex
+++ b/lib/teiserver/contexts/logging.ex
@@ -70,8 +70,6 @@ defmodule Teiserver.Logging do
# Crash logs
-
-
# MatchMinuteLogs
alias Teiserver.Logging.{MatchMinuteLog, MatchMinuteLogLib, MatchMinuteLogQueries}
@@ -80,34 +78,36 @@ defmodule Teiserver.Logging do
defdelegate match_minute_log_query(args), to: MatchMinuteLogQueries
@doc section: :match_minute_log
- @spec list_match_minute_logs(Teiserver.query_args()) :: [MatchMinuteLog.t]
+ @spec list_match_minute_logs(Teiserver.query_args()) :: [MatchMinuteLog.t()]
defdelegate list_match_minute_logs(args), to: MatchMinuteLogLib
@doc section: :match_minute_log
- @spec get_match_minute_log!(DateTime.t()) :: MatchMinuteLog.t
- @spec get_match_minute_log!(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t
+ @spec get_match_minute_log!(DateTime.t()) :: MatchMinuteLog.t()
+ @spec get_match_minute_log!(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t()
defdelegate get_match_minute_log!(timestamp, query_args \\ []), to: MatchMinuteLogLib
@doc section: :match_minute_log
- @spec get_match_minute_log(DateTime.t()) :: MatchMinuteLog.t | nil
- @spec get_match_minute_log(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t | nil
+ @spec get_match_minute_log(DateTime.t()) :: MatchMinuteLog.t() | nil
+ @spec get_match_minute_log(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t() | nil
defdelegate get_match_minute_log(timestamp, query_args \\ []), to: MatchMinuteLogLib
@doc section: :match_minute_log
- @spec create_match_minute_log(map) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_match_minute_log(map) :: {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_match_minute_log(attrs), to: MatchMinuteLogLib
@doc section: :match_minute_log
- @spec update_match_minute_log(MatchMinuteLog, map) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_match_minute_log(MatchMinuteLog, map) ::
+ {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_match_minute_log(match_minute_log, attrs), to: MatchMinuteLogLib
@doc section: :match_minute_log
- @spec delete_match_minute_log(MatchMinuteLog.t) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_match_minute_log(MatchMinuteLog.t()) ::
+ {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_match_minute_log(match_minute_log), to: MatchMinuteLogLib
@doc section: :match_minute_log
- @spec change_match_minute_log(MatchMinuteLog.t) :: Ecto.Changeset.t()
- @spec change_match_minute_log(MatchMinuteLog.t, map) :: Ecto.Changeset.t()
+ @spec change_match_minute_log(MatchMinuteLog.t()) :: Ecto.Changeset.t()
+ @spec change_match_minute_log(MatchMinuteLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_match_minute_log(match_minute_log, attrs \\ %{}), to: MatchMinuteLogLib
# MatchDayLogs
@@ -118,34 +118,36 @@ defmodule Teiserver.Logging do
defdelegate match_day_log_query(args), to: MatchDayLogQueries
@doc section: :match_day_log
- @spec list_match_day_logs(Teiserver.query_args()) :: [MatchDayLog.t]
+ @spec list_match_day_logs(Teiserver.query_args()) :: [MatchDayLog.t()]
defdelegate list_match_day_logs(args), to: MatchDayLogLib
@doc section: :match_day_log
- @spec get_match_day_log!(Date.t()) :: MatchDayLog.t
- @spec get_match_day_log!(Date.t(), Teiserver.query_args()) :: MatchDayLog.t
+ @spec get_match_day_log!(Date.t()) :: MatchDayLog.t()
+ @spec get_match_day_log!(Date.t(), Teiserver.query_args()) :: MatchDayLog.t()
defdelegate get_match_day_log!(date, query_args \\ []), to: MatchDayLogLib
@doc section: :match_day_log
- @spec get_match_day_log(Date.t()) :: MatchDayLog.t | nil
- @spec get_match_day_log(Date.t(), Teiserver.query_args()) :: MatchDayLog.t | nil
+ @spec get_match_day_log(Date.t()) :: MatchDayLog.t() | nil
+ @spec get_match_day_log(Date.t(), Teiserver.query_args()) :: MatchDayLog.t() | nil
defdelegate get_match_day_log(date, query_args \\ []), to: MatchDayLogLib
@doc section: :match_day_log
- @spec create_match_day_log(map) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_match_day_log(map) :: {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_match_day_log(attrs), to: MatchDayLogLib
@doc section: :match_day_log
- @spec update_match_day_log(MatchDayLog, map) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_match_day_log(MatchDayLog, map) ::
+ {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_match_day_log(match_day_log, attrs), to: MatchDayLogLib
@doc section: :match_day_log
- @spec delete_match_day_log(MatchDayLog.t) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_match_day_log(MatchDayLog.t()) ::
+ {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_match_day_log(match_day_log), to: MatchDayLogLib
@doc section: :match_day_log
- @spec change_match_day_log(MatchDayLog.t) :: Ecto.Changeset.t()
- @spec change_match_day_log(MatchDayLog.t, map) :: Ecto.Changeset.t()
+ @spec change_match_day_log(MatchDayLog.t()) :: Ecto.Changeset.t()
+ @spec change_match_day_log(MatchDayLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_match_day_log(match_day_log, attrs \\ %{}), to: MatchDayLogLib
# MatchWeekLogs
@@ -156,34 +158,36 @@ defmodule Teiserver.Logging do
defdelegate match_week_log_query(args), to: MatchWeekLogQueries
@doc section: :match_week_log
- @spec list_match_week_logs(Teiserver.query_args()) :: [MatchWeekLog.t]
+ @spec list_match_week_logs(Teiserver.query_args()) :: [MatchWeekLog.t()]
defdelegate list_match_week_logs(args), to: MatchWeekLogLib
@doc section: :match_week_log
- @spec get_match_week_log!(Date.t()) :: MatchWeekLog.t
- @spec get_match_week_log!(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t
+ @spec get_match_week_log!(Date.t()) :: MatchWeekLog.t()
+ @spec get_match_week_log!(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t()
defdelegate get_match_week_log!(date, query_args \\ []), to: MatchWeekLogLib
@doc section: :match_week_log
- @spec get_match_week_log(Date.t()) :: MatchWeekLog.t | nil
- @spec get_match_week_log(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t | nil
+ @spec get_match_week_log(Date.t()) :: MatchWeekLog.t() | nil
+ @spec get_match_week_log(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t() | nil
defdelegate get_match_week_log(date, query_args \\ []), to: MatchWeekLogLib
@doc section: :match_week_log
- @spec create_match_week_log(map) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_match_week_log(map) :: {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_match_week_log(attrs), to: MatchWeekLogLib
@doc section: :match_week_log
- @spec update_match_week_log(MatchWeekLog, map) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_match_week_log(MatchWeekLog, map) ::
+ {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_match_week_log(match_week_log, attrs), to: MatchWeekLogLib
@doc section: :match_week_log
- @spec delete_match_week_log(MatchWeekLog.t) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_match_week_log(MatchWeekLog.t()) ::
+ {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_match_week_log(match_week_log), to: MatchWeekLogLib
@doc section: :match_week_log
- @spec change_match_week_log(MatchWeekLog.t) :: Ecto.Changeset.t()
- @spec change_match_week_log(MatchWeekLog.t, map) :: Ecto.Changeset.t()
+ @spec change_match_week_log(MatchWeekLog.t()) :: Ecto.Changeset.t()
+ @spec change_match_week_log(MatchWeekLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_match_week_log(match_week_log, attrs \\ %{}), to: MatchWeekLogLib
# MatchMonthLogs
@@ -194,34 +198,36 @@ defmodule Teiserver.Logging do
defdelegate match_month_log_query(args), to: MatchMonthLogQueries
@doc section: :match_month_log
- @spec list_match_month_logs(Teiserver.query_args()) :: [MatchMonthLog.t]
+ @spec list_match_month_logs(Teiserver.query_args()) :: [MatchMonthLog.t()]
defdelegate list_match_month_logs(args), to: MatchMonthLogLib
@doc section: :match_month_log
- @spec get_match_month_log!(Date.t()) :: MatchMonthLog.t
- @spec get_match_month_log!(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t
+ @spec get_match_month_log!(Date.t()) :: MatchMonthLog.t()
+ @spec get_match_month_log!(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t()
defdelegate get_match_month_log!(date, query_args \\ []), to: MatchMonthLogLib
@doc section: :match_month_log
- @spec get_match_month_log(Date.t()) :: MatchMonthLog.t | nil
- @spec get_match_month_log(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t | nil
+ @spec get_match_month_log(Date.t()) :: MatchMonthLog.t() | nil
+ @spec get_match_month_log(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t() | nil
defdelegate get_match_month_log(date, query_args \\ []), to: MatchMonthLogLib
@doc section: :match_month_log
- @spec create_match_month_log(map) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_match_month_log(map) :: {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_match_month_log(attrs), to: MatchMonthLogLib
@doc section: :match_month_log
- @spec update_match_month_log(MatchMonthLog, map) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_match_month_log(MatchMonthLog, map) ::
+ {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_match_month_log(match_month_log, attrs), to: MatchMonthLogLib
@doc section: :match_month_log
- @spec delete_match_month_log(MatchMonthLog.t) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_match_month_log(MatchMonthLog.t()) ::
+ {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_match_month_log(match_month_log), to: MatchMonthLogLib
@doc section: :match_month_log
- @spec change_match_month_log(MatchMonthLog.t) :: Ecto.Changeset.t()
- @spec change_match_month_log(MatchMonthLog.t, map) :: Ecto.Changeset.t()
+ @spec change_match_month_log(MatchMonthLog.t()) :: Ecto.Changeset.t()
+ @spec change_match_month_log(MatchMonthLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_match_month_log(match_month_log, attrs \\ %{}), to: MatchMonthLogLib
# MatchQuarterLogs
@@ -232,34 +238,36 @@ defmodule Teiserver.Logging do
defdelegate match_quarter_log_query(args), to: MatchQuarterLogQueries
@doc section: :match_quarter_log
- @spec list_match_quarter_logs(Teiserver.query_args()) :: [MatchQuarterLog.t]
+ @spec list_match_quarter_logs(Teiserver.query_args()) :: [MatchQuarterLog.t()]
defdelegate list_match_quarter_logs(args), to: MatchQuarterLogLib
@doc section: :match_quarter_log
- @spec get_match_quarter_log!(Date.t()) :: MatchQuarterLog.t
- @spec get_match_quarter_log!(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t
+ @spec get_match_quarter_log!(Date.t()) :: MatchQuarterLog.t()
+ @spec get_match_quarter_log!(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t()
defdelegate get_match_quarter_log!(date, query_args \\ []), to: MatchQuarterLogLib
@doc section: :match_quarter_log
- @spec get_match_quarter_log(Date.t()) :: MatchQuarterLog.t | nil
- @spec get_match_quarter_log(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t | nil
+ @spec get_match_quarter_log(Date.t()) :: MatchQuarterLog.t() | nil
+ @spec get_match_quarter_log(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t() | nil
defdelegate get_match_quarter_log(date, query_args \\ []), to: MatchQuarterLogLib
@doc section: :match_quarter_log
- @spec create_match_quarter_log(map) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_match_quarter_log(map) :: {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_match_quarter_log(attrs), to: MatchQuarterLogLib
@doc section: :match_quarter_log
- @spec update_match_quarter_log(MatchQuarterLog, map) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_match_quarter_log(MatchQuarterLog, map) ::
+ {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_match_quarter_log(match_quarter_log, attrs), to: MatchQuarterLogLib
@doc section: :match_quarter_log
- @spec delete_match_quarter_log(MatchQuarterLog.t) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_match_quarter_log(MatchQuarterLog.t()) ::
+ {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_match_quarter_log(match_quarter_log), to: MatchQuarterLogLib
@doc section: :match_quarter_log
- @spec change_match_quarter_log(MatchQuarterLog.t) :: Ecto.Changeset.t()
- @spec change_match_quarter_log(MatchQuarterLog.t, map) :: Ecto.Changeset.t()
+ @spec change_match_quarter_log(MatchQuarterLog.t()) :: Ecto.Changeset.t()
+ @spec change_match_quarter_log(MatchQuarterLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_match_quarter_log(match_quarter_log, attrs \\ %{}), to: MatchQuarterLogLib
# MatchYearLogs
@@ -270,37 +278,38 @@ defmodule Teiserver.Logging do
defdelegate match_year_log_query(args), to: MatchYearLogQueries
@doc section: :match_year_log
- @spec list_match_year_logs(Teiserver.query_args()) :: [MatchYearLog.t]
+ @spec list_match_year_logs(Teiserver.query_args()) :: [MatchYearLog.t()]
defdelegate list_match_year_logs(args), to: MatchYearLogLib
@doc section: :match_year_log
- @spec get_match_year_log!(Date.t()) :: MatchYearLog.t
- @spec get_match_year_log!(Date.t(), Teiserver.query_args()) :: MatchYearLog.t
+ @spec get_match_year_log!(Date.t()) :: MatchYearLog.t()
+ @spec get_match_year_log!(Date.t(), Teiserver.query_args()) :: MatchYearLog.t()
defdelegate get_match_year_log!(date, query_args \\ []), to: MatchYearLogLib
@doc section: :match_year_log
- @spec get_match_year_log(Date.t()) :: MatchYearLog.t | nil
- @spec get_match_year_log(Date.t(), Teiserver.query_args()) :: MatchYearLog.t | nil
+ @spec get_match_year_log(Date.t()) :: MatchYearLog.t() | nil
+ @spec get_match_year_log(Date.t(), Teiserver.query_args()) :: MatchYearLog.t() | nil
defdelegate get_match_year_log(date, query_args \\ []), to: MatchYearLogLib
@doc section: :match_year_log
- @spec create_match_year_log(map) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_match_year_log(map) :: {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_match_year_log(attrs), to: MatchYearLogLib
@doc section: :match_year_log
- @spec update_match_year_log(MatchYearLog, map) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_match_year_log(MatchYearLog, map) ::
+ {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_match_year_log(match_year_log, attrs), to: MatchYearLogLib
@doc section: :match_year_log
- @spec delete_match_year_log(MatchYearLog.t) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_match_year_log(MatchYearLog.t()) ::
+ {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_match_year_log(match_year_log), to: MatchYearLogLib
@doc section: :match_year_log
- @spec change_match_year_log(MatchYearLog.t) :: Ecto.Changeset.t()
- @spec change_match_year_log(MatchYearLog.t, map) :: Ecto.Changeset.t()
+ @spec change_match_year_log(MatchYearLog.t()) :: Ecto.Changeset.t()
+ @spec change_match_year_log(MatchYearLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_match_year_log(match_year_log, attrs \\ %{}), to: MatchYearLogLib
-
# ServerMinuteLogs
alias Teiserver.Logging.{ServerMinuteLog, ServerMinuteLogLib, ServerMinuteLogQueries}
@@ -309,34 +318,36 @@ defmodule Teiserver.Logging do
defdelegate server_minute_log_query(args), to: ServerMinuteLogQueries
@doc section: :server_minute_log
- @spec list_server_minute_logs(Teiserver.query_args()) :: [ServerMinuteLog.t]
+ @spec list_server_minute_logs(Teiserver.query_args()) :: [ServerMinuteLog.t()]
defdelegate list_server_minute_logs(args), to: ServerMinuteLogLib
@doc section: :server_minute_log
- @spec get_server_minute_log!(DateTime.t()) :: ServerMinuteLog.t
- @spec get_server_minute_log!(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t
+ @spec get_server_minute_log!(DateTime.t()) :: ServerMinuteLog.t()
+ @spec get_server_minute_log!(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t()
defdelegate get_server_minute_log!(timestamp, query_args \\ []), to: ServerMinuteLogLib
@doc section: :server_minute_log
- @spec get_server_minute_log(DateTime.t()) :: ServerMinuteLog.t | nil
- @spec get_server_minute_log(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t | nil
+ @spec get_server_minute_log(DateTime.t()) :: ServerMinuteLog.t() | nil
+ @spec get_server_minute_log(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t() | nil
defdelegate get_server_minute_log(timestamp, query_args \\ []), to: ServerMinuteLogLib
@doc section: :server_minute_log
- @spec create_server_minute_log(map) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_server_minute_log(map) :: {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_server_minute_log(attrs), to: ServerMinuteLogLib
@doc section: :server_minute_log
- @spec update_server_minute_log(ServerMinuteLog, map) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_server_minute_log(ServerMinuteLog, map) ::
+ {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_server_minute_log(server_minute_log, attrs), to: ServerMinuteLogLib
@doc section: :server_minute_log
- @spec delete_server_minute_log(ServerMinuteLog.t) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_minute_log(ServerMinuteLog.t()) ::
+ {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_server_minute_log(server_minute_log), to: ServerMinuteLogLib
@doc section: :server_minute_log
- @spec change_server_minute_log(ServerMinuteLog.t) :: Ecto.Changeset.t()
- @spec change_server_minute_log(ServerMinuteLog.t, map) :: Ecto.Changeset.t()
+ @spec change_server_minute_log(ServerMinuteLog.t()) :: Ecto.Changeset.t()
+ @spec change_server_minute_log(ServerMinuteLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_server_minute_log(server_minute_log, attrs \\ %{}), to: ServerMinuteLogLib
# ServerDayLogs
@@ -347,34 +358,36 @@ defmodule Teiserver.Logging do
defdelegate server_day_log_query(args), to: ServerDayLogQueries
@doc section: :server_day_log
- @spec list_server_day_logs(Teiserver.query_args()) :: [ServerDayLog.t]
+ @spec list_server_day_logs(Teiserver.query_args()) :: [ServerDayLog.t()]
defdelegate list_server_day_logs(args), to: ServerDayLogLib
@doc section: :server_day_log
- @spec get_server_day_log!(Date.t()) :: ServerDayLog.t
- @spec get_server_day_log!(Date.t(), Teiserver.query_args()) :: ServerDayLog.t
+ @spec get_server_day_log!(Date.t()) :: ServerDayLog.t()
+ @spec get_server_day_log!(Date.t(), Teiserver.query_args()) :: ServerDayLog.t()
defdelegate get_server_day_log!(date, query_args \\ []), to: ServerDayLogLib
@doc section: :server_day_log
- @spec get_server_day_log(Date.t()) :: ServerDayLog.t | nil
- @spec get_server_day_log(Date.t(), Teiserver.query_args()) :: ServerDayLog.t | nil
+ @spec get_server_day_log(Date.t()) :: ServerDayLog.t() | nil
+ @spec get_server_day_log(Date.t(), Teiserver.query_args()) :: ServerDayLog.t() | nil
defdelegate get_server_day_log(date, query_args \\ []), to: ServerDayLogLib
@doc section: :server_day_log
- @spec create_server_day_log(map) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_server_day_log(map) :: {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_server_day_log(attrs), to: ServerDayLogLib
@doc section: :server_day_log
- @spec update_server_day_log(ServerDayLog, map) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_server_day_log(ServerDayLog, map) ::
+ {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_server_day_log(server_day_log, attrs), to: ServerDayLogLib
@doc section: :server_day_log
- @spec delete_server_day_log(ServerDayLog.t) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_day_log(ServerDayLog.t()) ::
+ {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_server_day_log(server_day_log), to: ServerDayLogLib
@doc section: :server_day_log
- @spec change_server_day_log(ServerDayLog.t) :: Ecto.Changeset.t()
- @spec change_server_day_log(ServerDayLog.t, map) :: Ecto.Changeset.t()
+ @spec change_server_day_log(ServerDayLog.t()) :: Ecto.Changeset.t()
+ @spec change_server_day_log(ServerDayLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_server_day_log(server_day_log, attrs \\ %{}), to: ServerDayLogLib
# ServerWeekLogs
@@ -385,34 +398,36 @@ defmodule Teiserver.Logging do
defdelegate server_week_log_query(args), to: ServerWeekLogQueries
@doc section: :server_week_log
- @spec list_server_week_logs(Teiserver.query_args()) :: [ServerWeekLog.t]
+ @spec list_server_week_logs(Teiserver.query_args()) :: [ServerWeekLog.t()]
defdelegate list_server_week_logs(args), to: ServerWeekLogLib
@doc section: :server_week_log
- @spec get_server_week_log!(Date.t()) :: ServerWeekLog.t
- @spec get_server_week_log!(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t
+ @spec get_server_week_log!(Date.t()) :: ServerWeekLog.t()
+ @spec get_server_week_log!(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t()
defdelegate get_server_week_log!(date, query_args \\ []), to: ServerWeekLogLib
@doc section: :server_week_log
- @spec get_server_week_log(Date.t()) :: ServerWeekLog.t | nil
- @spec get_server_week_log(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t | nil
+ @spec get_server_week_log(Date.t()) :: ServerWeekLog.t() | nil
+ @spec get_server_week_log(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t() | nil
defdelegate get_server_week_log(date, query_args \\ []), to: ServerWeekLogLib
@doc section: :server_week_log
- @spec create_server_week_log(map) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_server_week_log(map) :: {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_server_week_log(attrs), to: ServerWeekLogLib
@doc section: :server_week_log
- @spec update_server_week_log(ServerWeekLog, map) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_server_week_log(ServerWeekLog, map) ::
+ {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_server_week_log(server_week_log, attrs), to: ServerWeekLogLib
@doc section: :server_week_log
- @spec delete_server_week_log(ServerWeekLog.t) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_week_log(ServerWeekLog.t()) ::
+ {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_server_week_log(server_week_log), to: ServerWeekLogLib
@doc section: :server_week_log
- @spec change_server_week_log(ServerWeekLog.t) :: Ecto.Changeset.t()
- @spec change_server_week_log(ServerWeekLog.t, map) :: Ecto.Changeset.t()
+ @spec change_server_week_log(ServerWeekLog.t()) :: Ecto.Changeset.t()
+ @spec change_server_week_log(ServerWeekLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_server_week_log(server_week_log, attrs \\ %{}), to: ServerWeekLogLib
# ServerMonthLogs
@@ -423,34 +438,36 @@ defmodule Teiserver.Logging do
defdelegate server_month_log_query(args), to: ServerMonthLogQueries
@doc section: :server_month_log
- @spec list_server_month_logs(Teiserver.query_args()) :: [ServerMonthLog.t]
+ @spec list_server_month_logs(Teiserver.query_args()) :: [ServerMonthLog.t()]
defdelegate list_server_month_logs(args), to: ServerMonthLogLib
@doc section: :server_month_log
- @spec get_server_month_log!(Date.t()) :: ServerMonthLog.t
- @spec get_server_month_log!(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t
+ @spec get_server_month_log!(Date.t()) :: ServerMonthLog.t()
+ @spec get_server_month_log!(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t()
defdelegate get_server_month_log!(date, query_args \\ []), to: ServerMonthLogLib
@doc section: :server_month_log
- @spec get_server_month_log(Date.t()) :: ServerMonthLog.t | nil
- @spec get_server_month_log(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t | nil
+ @spec get_server_month_log(Date.t()) :: ServerMonthLog.t() | nil
+ @spec get_server_month_log(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t() | nil
defdelegate get_server_month_log(date, query_args \\ []), to: ServerMonthLogLib
@doc section: :server_month_log
- @spec create_server_month_log(map) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_server_month_log(map) :: {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_server_month_log(attrs), to: ServerMonthLogLib
@doc section: :server_month_log
- @spec update_server_month_log(ServerMonthLog, map) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_server_month_log(ServerMonthLog, map) ::
+ {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_server_month_log(server_month_log, attrs), to: ServerMonthLogLib
@doc section: :server_month_log
- @spec delete_server_month_log(ServerMonthLog.t) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_month_log(ServerMonthLog.t()) ::
+ {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_server_month_log(server_month_log), to: ServerMonthLogLib
@doc section: :server_month_log
- @spec change_server_month_log(ServerMonthLog.t) :: Ecto.Changeset.t()
- @spec change_server_month_log(ServerMonthLog.t, map) :: Ecto.Changeset.t()
+ @spec change_server_month_log(ServerMonthLog.t()) :: Ecto.Changeset.t()
+ @spec change_server_month_log(ServerMonthLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_server_month_log(server_month_log, attrs \\ %{}), to: ServerMonthLogLib
# ServerQuarterLogs
@@ -461,34 +478,37 @@ defmodule Teiserver.Logging do
defdelegate server_quarter_log_query(args), to: ServerQuarterLogQueries
@doc section: :server_quarter_log
- @spec list_server_quarter_logs(Teiserver.query_args()) :: [ServerQuarterLog.t]
+ @spec list_server_quarter_logs(Teiserver.query_args()) :: [ServerQuarterLog.t()]
defdelegate list_server_quarter_logs(args), to: ServerQuarterLogLib
@doc section: :server_quarter_log
- @spec get_server_quarter_log!(Date.t()) :: ServerQuarterLog.t
- @spec get_server_quarter_log!(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t
+ @spec get_server_quarter_log!(Date.t()) :: ServerQuarterLog.t()
+ @spec get_server_quarter_log!(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t()
defdelegate get_server_quarter_log!(date, query_args \\ []), to: ServerQuarterLogLib
@doc section: :server_quarter_log
- @spec get_server_quarter_log(Date.t()) :: ServerQuarterLog.t | nil
- @spec get_server_quarter_log(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t | nil
+ @spec get_server_quarter_log(Date.t()) :: ServerQuarterLog.t() | nil
+ @spec get_server_quarter_log(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t() | nil
defdelegate get_server_quarter_log(date, query_args \\ []), to: ServerQuarterLogLib
@doc section: :server_quarter_log
- @spec create_server_quarter_log(map) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_server_quarter_log(map) ::
+ {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_server_quarter_log(attrs), to: ServerQuarterLogLib
@doc section: :server_quarter_log
- @spec update_server_quarter_log(ServerQuarterLog, map) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_server_quarter_log(ServerQuarterLog, map) ::
+ {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_server_quarter_log(server_quarter_log, attrs), to: ServerQuarterLogLib
@doc section: :server_quarter_log
- @spec delete_server_quarter_log(ServerQuarterLog.t) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_quarter_log(ServerQuarterLog.t()) ::
+ {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_server_quarter_log(server_quarter_log), to: ServerQuarterLogLib
@doc section: :server_quarter_log
- @spec change_server_quarter_log(ServerQuarterLog.t) :: Ecto.Changeset.t()
- @spec change_server_quarter_log(ServerQuarterLog.t, map) :: Ecto.Changeset.t()
+ @spec change_server_quarter_log(ServerQuarterLog.t()) :: Ecto.Changeset.t()
+ @spec change_server_quarter_log(ServerQuarterLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_server_quarter_log(server_quarter_log, attrs \\ %{}), to: ServerQuarterLogLib
# ServerYearLogs
@@ -499,33 +519,35 @@ defmodule Teiserver.Logging do
defdelegate server_year_log_query(args), to: ServerYearLogQueries
@doc section: :server_year_log
- @spec list_server_year_logs(Teiserver.query_args()) :: [ServerYearLog.t]
+ @spec list_server_year_logs(Teiserver.query_args()) :: [ServerYearLog.t()]
defdelegate list_server_year_logs(args), to: ServerYearLogLib
@doc section: :server_year_log
- @spec get_server_year_log!(Date.t()) :: ServerYearLog.t
- @spec get_server_year_log!(Date.t(), Teiserver.query_args()) :: ServerYearLog.t
+ @spec get_server_year_log!(Date.t()) :: ServerYearLog.t()
+ @spec get_server_year_log!(Date.t(), Teiserver.query_args()) :: ServerYearLog.t()
defdelegate get_server_year_log!(date, query_args \\ []), to: ServerYearLogLib
@doc section: :server_year_log
- @spec get_server_year_log(Date.t()) :: ServerYearLog.t | nil
- @spec get_server_year_log(Date.t(), Teiserver.query_args()) :: ServerYearLog.t | nil
+ @spec get_server_year_log(Date.t()) :: ServerYearLog.t() | nil
+ @spec get_server_year_log(Date.t(), Teiserver.query_args()) :: ServerYearLog.t() | nil
defdelegate get_server_year_log(date, query_args \\ []), to: ServerYearLogLib
@doc section: :server_year_log
- @spec create_server_year_log(map) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t()}
+ @spec create_server_year_log(map) :: {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate create_server_year_log(attrs), to: ServerYearLogLib
@doc section: :server_year_log
- @spec update_server_year_log(ServerYearLog, map) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t()}
+ @spec update_server_year_log(ServerYearLog, map) ::
+ {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate update_server_year_log(server_year_log, attrs), to: ServerYearLogLib
@doc section: :server_year_log
- @spec delete_server_year_log(ServerYearLog.t) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t()}
+ @spec delete_server_year_log(ServerYearLog.t()) ::
+ {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
defdelegate delete_server_year_log(server_year_log), to: ServerYearLogLib
@doc section: :server_year_log
- @spec change_server_year_log(ServerYearLog.t) :: Ecto.Changeset.t()
- @spec change_server_year_log(ServerYearLog.t, map) :: Ecto.Changeset.t()
+ @spec change_server_year_log(ServerYearLog.t()) :: Ecto.Changeset.t()
+ @spec change_server_year_log(ServerYearLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_server_year_log(server_year_log, attrs \\ %{}), to: ServerYearLogLib
end
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index e556b5772..e4b72efc7 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -377,7 +377,9 @@ defmodule Teiserver.Game.LobbyLib do
})
end
- @doc false
+ @doc """
+ Returns a boolean regarding the existence of the lobby.
+ """
@spec lobby_exists?(Lobby.id()) :: boolean
def lobby_exists?(lobby_id) do
case Horde.Registry.lookup(Teiserver.LobbyRegistry, lobby_id) do
diff --git a/lib/teiserver/helpers/query_helper.ex b/lib/teiserver/helpers/query_helper.ex
index c4b6e4da9..857f333b1 100644
--- a/lib/teiserver/helpers/query_helper.ex
+++ b/lib/teiserver/helpers/query_helper.ex
@@ -2,7 +2,7 @@ defmodule Teiserver.Helpers.QueryHelper do
@moduledoc false
import Ecto.Query, warn: false
- @spec offset_query(Ecto.Query.t(), nil | Integer.t()) :: Ecto.Query.t()
+ @spec offset_query(Ecto.Query.t(), nil | non_neg_integer()) :: Ecto.Query.t()
def offset_query(query, nil), do: query
def offset_query(query, amount) do
@@ -10,7 +10,7 @@ defmodule Teiserver.Helpers.QueryHelper do
|> offset(^amount)
end
- @spec limit_query(Ecto.Query.t(), Integer.t() | :infinity) :: Ecto.Query.t()
+ @spec limit_query(Ecto.Query.t(), non_neg_integer() | :infinity) :: Ecto.Query.t()
def limit_query(query, :infinity), do: query
def limit_query(query, nil), do: query
diff --git a/lib/teiserver/logging/libs/match_day_log_lib.ex b/lib/teiserver/logging/libs/match_day_log_lib.ex
index ece9a1acb..3bb8793dc 100644
--- a/lib/teiserver/logging/libs/match_day_log_lib.ex
+++ b/lib/teiserver/logging/libs/match_day_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.MatchDayLogLib do
def get_match_day_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> MatchDayLogQueries.match_day_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.MatchDayLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_match_day_log(map) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_match_day_log(map) :: {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
def create_match_day_log(attrs) do
%MatchDayLog{}
|> MatchDayLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.MatchDayLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_match_day_log(MatchDayLog.t, map) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_match_day_log(MatchDayLog.t(), map) ::
+ {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
def update_match_day_log(%MatchDayLog{} = match_day_log, attrs) do
match_day_log
|> MatchDayLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.MatchDayLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_match_day_log(MatchDayLog.t) :: {:ok, MatchDayLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_match_day_log(MatchDayLog.t()) ::
+ {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
def delete_match_day_log(%MatchDayLog{} = match_day_log) do
Repo.delete(match_day_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.MatchDayLogLib do
%Ecto.Changeset{data: %MatchDayLog{}}
"""
- @spec change_match_day_log(MatchDayLog.t, map) :: Ecto.Changeset.t
+ @spec change_match_day_log(MatchDayLog.t(), map) :: Ecto.Changeset.t()
def change_match_day_log(%MatchDayLog{} = match_day_log, attrs \\ %{}) do
MatchDayLog.changeset(match_day_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/match_minute_log_lib.ex b/lib/teiserver/logging/libs/match_minute_log_lib.ex
index 75d58e27f..1dc267eab 100644
--- a/lib/teiserver/logging/libs/match_minute_log_lib.ex
+++ b/lib/teiserver/logging/libs/match_minute_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.MatchMinuteLogLib do
def get_match_minute_log(timestamp, query_args \\ []) do
(query_args ++ [timestamp: timestamp])
|> MatchMinuteLogQueries.match_minute_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.MatchMinuteLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_match_minute_log(map) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_match_minute_log(map) :: {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
def create_match_minute_log(attrs) do
%MatchMinuteLog{}
|> MatchMinuteLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.MatchMinuteLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_match_minute_log(MatchMinuteLog.t, map) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_match_minute_log(MatchMinuteLog.t(), map) ::
+ {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
def update_match_minute_log(%MatchMinuteLog{} = match_minute_log, attrs) do
match_minute_log
|> MatchMinuteLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.MatchMinuteLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_match_minute_log(MatchMinuteLog.t) :: {:ok, MatchMinuteLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_match_minute_log(MatchMinuteLog.t()) ::
+ {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
def delete_match_minute_log(%MatchMinuteLog{} = match_minute_log) do
Repo.delete(match_minute_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.MatchMinuteLogLib do
%Ecto.Changeset{data: %MatchMinuteLog{}}
"""
- @spec change_match_minute_log(MatchMinuteLog.t, map) :: Ecto.Changeset.t
+ @spec change_match_minute_log(MatchMinuteLog.t(), map) :: Ecto.Changeset.t()
def change_match_minute_log(%MatchMinuteLog{} = match_minute_log, attrs \\ %{}) do
MatchMinuteLog.changeset(match_minute_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/match_month_log_lib.ex b/lib/teiserver/logging/libs/match_month_log_lib.ex
index 8c53a8ce6..9e55aa87d 100644
--- a/lib/teiserver/logging/libs/match_month_log_lib.ex
+++ b/lib/teiserver/logging/libs/match_month_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.MatchMonthLogLib do
def get_match_month_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> MatchMonthLogQueries.match_month_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.MatchMonthLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_match_month_log(map) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_match_month_log(map) :: {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
def create_match_month_log(attrs) do
%MatchMonthLog{}
|> MatchMonthLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.MatchMonthLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_match_month_log(MatchMonthLog.t, map) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_match_month_log(MatchMonthLog.t(), map) ::
+ {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
def update_match_month_log(%MatchMonthLog{} = match_month_log, attrs) do
match_month_log
|> MatchMonthLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.MatchMonthLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_match_month_log(MatchMonthLog.t) :: {:ok, MatchMonthLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_match_month_log(MatchMonthLog.t()) ::
+ {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
def delete_match_month_log(%MatchMonthLog{} = match_month_log) do
Repo.delete(match_month_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.MatchMonthLogLib do
%Ecto.Changeset{data: %MatchMonthLog{}}
"""
- @spec change_match_month_log(MatchMonthLog.t, map) :: Ecto.Changeset.t
+ @spec change_match_month_log(MatchMonthLog.t(), map) :: Ecto.Changeset.t()
def change_match_month_log(%MatchMonthLog{} = match_month_log, attrs \\ %{}) do
MatchMonthLog.changeset(match_month_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/match_quarter_log_lib.ex b/lib/teiserver/logging/libs/match_quarter_log_lib.ex
index 7bbbf8dcc..c2233d2e2 100644
--- a/lib/teiserver/logging/libs/match_quarter_log_lib.ex
+++ b/lib/teiserver/logging/libs/match_quarter_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.MatchQuarterLogLib do
def get_match_quarter_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> MatchQuarterLogQueries.match_quarter_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.MatchQuarterLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_match_quarter_log(map) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_match_quarter_log(map) :: {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
def create_match_quarter_log(attrs) do
%MatchQuarterLog{}
|> MatchQuarterLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.MatchQuarterLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_match_quarter_log(MatchQuarterLog.t, map) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_match_quarter_log(MatchQuarterLog.t(), map) ::
+ {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
def update_match_quarter_log(%MatchQuarterLog{} = match_quarter_log, attrs) do
match_quarter_log
|> MatchQuarterLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.MatchQuarterLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_match_quarter_log(MatchQuarterLog.t) :: {:ok, MatchQuarterLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_match_quarter_log(MatchQuarterLog.t()) ::
+ {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
def delete_match_quarter_log(%MatchQuarterLog{} = match_quarter_log) do
Repo.delete(match_quarter_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.MatchQuarterLogLib do
%Ecto.Changeset{data: %MatchQuarterLog{}}
"""
- @spec change_match_quarter_log(MatchQuarterLog.t, map) :: Ecto.Changeset.t
+ @spec change_match_quarter_log(MatchQuarterLog.t(), map) :: Ecto.Changeset.t()
def change_match_quarter_log(%MatchQuarterLog{} = match_quarter_log, attrs \\ %{}) do
MatchQuarterLog.changeset(match_quarter_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/match_week_log_lib.ex b/lib/teiserver/logging/libs/match_week_log_lib.ex
index b9d1257cc..eb4fe16a0 100644
--- a/lib/teiserver/logging/libs/match_week_log_lib.ex
+++ b/lib/teiserver/logging/libs/match_week_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.MatchWeekLogLib do
def get_match_week_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> MatchWeekLogQueries.match_week_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.MatchWeekLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_match_week_log(map) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_match_week_log(map) :: {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
def create_match_week_log(attrs) do
%MatchWeekLog{}
|> MatchWeekLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.MatchWeekLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_match_week_log(MatchWeekLog.t, map) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_match_week_log(MatchWeekLog.t(), map) ::
+ {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
def update_match_week_log(%MatchWeekLog{} = match_week_log, attrs) do
match_week_log
|> MatchWeekLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.MatchWeekLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_match_week_log(MatchWeekLog.t) :: {:ok, MatchWeekLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_match_week_log(MatchWeekLog.t()) ::
+ {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
def delete_match_week_log(%MatchWeekLog{} = match_week_log) do
Repo.delete(match_week_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.MatchWeekLogLib do
%Ecto.Changeset{data: %MatchWeekLog{}}
"""
- @spec change_match_week_log(MatchWeekLog.t, map) :: Ecto.Changeset.t
+ @spec change_match_week_log(MatchWeekLog.t(), map) :: Ecto.Changeset.t()
def change_match_week_log(%MatchWeekLog{} = match_week_log, attrs \\ %{}) do
MatchWeekLog.changeset(match_week_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/match_year_log_lib.ex b/lib/teiserver/logging/libs/match_year_log_lib.ex
index bf752f453..f06995d44 100644
--- a/lib/teiserver/logging/libs/match_year_log_lib.ex
+++ b/lib/teiserver/logging/libs/match_year_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.MatchYearLogLib do
def get_match_year_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> MatchYearLogQueries.match_year_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.MatchYearLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_match_year_log(map) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_match_year_log(map) :: {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
def create_match_year_log(attrs) do
%MatchYearLog{}
|> MatchYearLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.MatchYearLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_match_year_log(MatchYearLog.t, map) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_match_year_log(MatchYearLog.t(), map) ::
+ {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
def update_match_year_log(%MatchYearLog{} = match_year_log, attrs) do
match_year_log
|> MatchYearLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.MatchYearLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_match_year_log(MatchYearLog.t) :: {:ok, MatchYearLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_match_year_log(MatchYearLog.t()) ::
+ {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
def delete_match_year_log(%MatchYearLog{} = match_year_log) do
Repo.delete(match_year_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.MatchYearLogLib do
%Ecto.Changeset{data: %MatchYearLog{}}
"""
- @spec change_match_year_log(MatchYearLog.t, map) :: Ecto.Changeset.t
+ @spec change_match_year_log(MatchYearLog.t(), map) :: Ecto.Changeset.t()
def change_match_year_log(%MatchYearLog{} = match_year_log, attrs \\ %{}) do
MatchYearLog.changeset(match_year_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/server_day_log_lib.ex b/lib/teiserver/logging/libs/server_day_log_lib.ex
index f57e22db7..cde25403b 100644
--- a/lib/teiserver/logging/libs/server_day_log_lib.ex
+++ b/lib/teiserver/logging/libs/server_day_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.ServerDayLogLib do
def get_server_day_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> ServerDayLogQueries.server_day_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.ServerDayLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_server_day_log(map) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_server_day_log(map) :: {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
def create_server_day_log(attrs) do
%ServerDayLog{}
|> ServerDayLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.ServerDayLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_server_day_log(ServerDayLog.t, map) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_server_day_log(ServerDayLog.t(), map) ::
+ {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
def update_server_day_log(%ServerDayLog{} = server_day_log, attrs) do
server_day_log
|> ServerDayLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.ServerDayLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_server_day_log(ServerDayLog.t) :: {:ok, ServerDayLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_server_day_log(ServerDayLog.t()) ::
+ {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
def delete_server_day_log(%ServerDayLog{} = server_day_log) do
Repo.delete(server_day_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.ServerDayLogLib do
%Ecto.Changeset{data: %ServerDayLog{}}
"""
- @spec change_server_day_log(ServerDayLog.t, map) :: Ecto.Changeset.t
+ @spec change_server_day_log(ServerDayLog.t(), map) :: Ecto.Changeset.t()
def change_server_day_log(%ServerDayLog{} = server_day_log, attrs \\ %{}) do
ServerDayLog.changeset(server_day_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/server_minute_log_lib.ex b/lib/teiserver/logging/libs/server_minute_log_lib.ex
index 2e40c8ecd..e1f50e4a6 100644
--- a/lib/teiserver/logging/libs/server_minute_log_lib.ex
+++ b/lib/teiserver/logging/libs/server_minute_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.ServerMinuteLogLib do
def get_server_minute_log(timestamp, query_args \\ []) do
(query_args ++ [timestamp: timestamp])
|> ServerMinuteLogQueries.server_minute_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.ServerMinuteLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_server_minute_log(map) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_server_minute_log(map) :: {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
def create_server_minute_log(attrs) do
%ServerMinuteLog{}
|> ServerMinuteLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.ServerMinuteLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_server_minute_log(ServerMinuteLog.t, map) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_server_minute_log(ServerMinuteLog.t(), map) ::
+ {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
def update_server_minute_log(%ServerMinuteLog{} = server_minute_log, attrs) do
server_minute_log
|> ServerMinuteLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.ServerMinuteLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_server_minute_log(ServerMinuteLog.t) :: {:ok, ServerMinuteLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_server_minute_log(ServerMinuteLog.t()) ::
+ {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
def delete_server_minute_log(%ServerMinuteLog{} = server_minute_log) do
Repo.delete(server_minute_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.ServerMinuteLogLib do
%Ecto.Changeset{data: %ServerMinuteLog{}}
"""
- @spec change_server_minute_log(ServerMinuteLog.t, map) :: Ecto.Changeset.t
+ @spec change_server_minute_log(ServerMinuteLog.t(), map) :: Ecto.Changeset.t()
def change_server_minute_log(%ServerMinuteLog{} = server_minute_log, attrs \\ %{}) do
ServerMinuteLog.changeset(server_minute_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/server_month_log_lib.ex b/lib/teiserver/logging/libs/server_month_log_lib.ex
index 15e471c4d..7ef21b4ad 100644
--- a/lib/teiserver/logging/libs/server_month_log_lib.ex
+++ b/lib/teiserver/logging/libs/server_month_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.ServerMonthLogLib do
def get_server_month_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> ServerMonthLogQueries.server_month_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.ServerMonthLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_server_month_log(map) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_server_month_log(map) :: {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
def create_server_month_log(attrs) do
%ServerMonthLog{}
|> ServerMonthLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.ServerMonthLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_server_month_log(ServerMonthLog.t, map) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_server_month_log(ServerMonthLog.t(), map) ::
+ {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
def update_server_month_log(%ServerMonthLog{} = server_month_log, attrs) do
server_month_log
|> ServerMonthLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.ServerMonthLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_server_month_log(ServerMonthLog.t) :: {:ok, ServerMonthLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_server_month_log(ServerMonthLog.t()) ::
+ {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
def delete_server_month_log(%ServerMonthLog{} = server_month_log) do
Repo.delete(server_month_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.ServerMonthLogLib do
%Ecto.Changeset{data: %ServerMonthLog{}}
"""
- @spec change_server_month_log(ServerMonthLog.t, map) :: Ecto.Changeset.t
+ @spec change_server_month_log(ServerMonthLog.t(), map) :: Ecto.Changeset.t()
def change_server_month_log(%ServerMonthLog{} = server_month_log, attrs \\ %{}) do
ServerMonthLog.changeset(server_month_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/server_quarter_log_lib.ex b/lib/teiserver/logging/libs/server_quarter_log_lib.ex
index 2483dde97..9e83f3cfd 100644
--- a/lib/teiserver/logging/libs/server_quarter_log_lib.ex
+++ b/lib/teiserver/logging/libs/server_quarter_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.ServerQuarterLogLib do
def get_server_quarter_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> ServerQuarterLogQueries.server_quarter_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,8 @@ defmodule Teiserver.Logging.ServerQuarterLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_server_quarter_log(map) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_server_quarter_log(map) ::
+ {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
def create_server_quarter_log(attrs) do
%ServerQuarterLog{}
|> ServerQuarterLog.changeset(attrs)
@@ -96,7 +97,8 @@ defmodule Teiserver.Logging.ServerQuarterLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_server_quarter_log(ServerQuarterLog.t, map) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_server_quarter_log(ServerQuarterLog.t(), map) ::
+ {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
def update_server_quarter_log(%ServerQuarterLog{} = server_quarter_log, attrs) do
server_quarter_log
|> ServerQuarterLog.changeset(attrs)
@@ -115,7 +117,8 @@ defmodule Teiserver.Logging.ServerQuarterLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_server_quarter_log(ServerQuarterLog.t) :: {:ok, ServerQuarterLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_server_quarter_log(ServerQuarterLog.t()) ::
+ {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
def delete_server_quarter_log(%ServerQuarterLog{} = server_quarter_log) do
Repo.delete(server_quarter_log)
end
@@ -129,7 +132,7 @@ defmodule Teiserver.Logging.ServerQuarterLogLib do
%Ecto.Changeset{data: %ServerQuarterLog{}}
"""
- @spec change_server_quarter_log(ServerQuarterLog.t, map) :: Ecto.Changeset.t
+ @spec change_server_quarter_log(ServerQuarterLog.t(), map) :: Ecto.Changeset.t()
def change_server_quarter_log(%ServerQuarterLog{} = server_quarter_log, attrs \\ %{}) do
ServerQuarterLog.changeset(server_quarter_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/server_week_log_lib.ex b/lib/teiserver/logging/libs/server_week_log_lib.ex
index fce346d2a..cdf5319ff 100644
--- a/lib/teiserver/logging/libs/server_week_log_lib.ex
+++ b/lib/teiserver/logging/libs/server_week_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.ServerWeekLogLib do
def get_server_week_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> ServerWeekLogQueries.server_week_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.ServerWeekLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_server_week_log(map) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_server_week_log(map) :: {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
def create_server_week_log(attrs) do
%ServerWeekLog{}
|> ServerWeekLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.ServerWeekLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_server_week_log(ServerWeekLog.t, map) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_server_week_log(ServerWeekLog.t(), map) ::
+ {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
def update_server_week_log(%ServerWeekLog{} = server_week_log, attrs) do
server_week_log
|> ServerWeekLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.ServerWeekLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_server_week_log(ServerWeekLog.t) :: {:ok, ServerWeekLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_server_week_log(ServerWeekLog.t()) ::
+ {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
def delete_server_week_log(%ServerWeekLog{} = server_week_log) do
Repo.delete(server_week_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.ServerWeekLogLib do
%Ecto.Changeset{data: %ServerWeekLog{}}
"""
- @spec change_server_week_log(ServerWeekLog.t, map) :: Ecto.Changeset.t
+ @spec change_server_week_log(ServerWeekLog.t(), map) :: Ecto.Changeset.t()
def change_server_week_log(%ServerWeekLog{} = server_week_log, attrs \\ %{}) do
ServerWeekLog.changeset(server_week_log, attrs)
end
diff --git a/lib/teiserver/logging/libs/server_year_log_lib.ex b/lib/teiserver/logging/libs/server_year_log_lib.ex
index 32f9189c1..b77fc5bbb 100644
--- a/lib/teiserver/logging/libs/server_year_log_lib.ex
+++ b/lib/teiserver/logging/libs/server_year_log_lib.ex
@@ -62,7 +62,7 @@ defmodule Teiserver.Logging.ServerYearLogLib do
def get_server_year_log(date, query_args \\ []) do
(query_args ++ [date: date])
|> ServerYearLogQueries.server_year_log_query()
- |> Repo.one
+ |> Repo.one()
end
@doc """
@@ -77,7 +77,7 @@ defmodule Teiserver.Logging.ServerYearLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec create_server_year_log(map) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t}
+ @spec create_server_year_log(map) :: {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
def create_server_year_log(attrs) do
%ServerYearLog{}
|> ServerYearLog.changeset(attrs)
@@ -96,7 +96,8 @@ defmodule Teiserver.Logging.ServerYearLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec update_server_year_log(ServerYearLog.t, map) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t}
+ @spec update_server_year_log(ServerYearLog.t(), map) ::
+ {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
def update_server_year_log(%ServerYearLog{} = server_year_log, attrs) do
server_year_log
|> ServerYearLog.changeset(attrs)
@@ -115,7 +116,8 @@ defmodule Teiserver.Logging.ServerYearLogLib do
{:error, %Ecto.Changeset{}}
"""
- @spec delete_server_year_log(ServerYearLog.t) :: {:ok, ServerYearLog.t} | {:error, Ecto.Changeset.t}
+ @spec delete_server_year_log(ServerYearLog.t()) ::
+ {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
def delete_server_year_log(%ServerYearLog{} = server_year_log) do
Repo.delete(server_year_log)
end
@@ -129,7 +131,7 @@ defmodule Teiserver.Logging.ServerYearLogLib do
%Ecto.Changeset{data: %ServerYearLog{}}
"""
- @spec change_server_year_log(ServerYearLog.t, map) :: Ecto.Changeset.t
+ @spec change_server_year_log(ServerYearLog.t(), map) :: Ecto.Changeset.t()
def change_server_year_log(%ServerYearLog{} = server_year_log, attrs \\ %{}) do
ServerYearLog.changeset(server_year_log, attrs)
end
diff --git a/lib/teiserver/settings/schemas/server_setting_type.ex b/lib/teiserver/settings/schemas/server_setting_type.ex
index 50627921f..5fcc84486 100644
--- a/lib/teiserver/settings/schemas/server_setting_type.ex
+++ b/lib/teiserver/settings/schemas/server_setting_type.ex
@@ -30,7 +30,7 @@ defmodule Teiserver.Settings.ServerSettingType do
field(:permissions, String.t() | [String.t()] | nil, default: nil)
field(:choices, [String.t()] | nil, default: nil)
- field(:default, String.t() | Integer.t() | boolean | nil, default: nil)
+ field(:default, String.t() | integer() | boolean | nil, default: nil)
field(:description, String.t() | nil, default: nil)
end
end
diff --git a/lib/teiserver/settings/schemas/user_setting.ex b/lib/teiserver/settings/schemas/user_setting.ex
index 4cf89f929..121df3ca0 100644
--- a/lib/teiserver/settings/schemas/user_setting.ex
+++ b/lib/teiserver/settings/schemas/user_setting.ex
@@ -21,6 +21,8 @@ defmodule Teiserver.Settings.UserSetting do
timestamps()
end
+ @type key :: String.t()
+
@type t :: %__MODULE__{
id: non_neg_integer(),
user_id: Teiserver.user_id(),
diff --git a/lib/teiserver/settings/schemas/user_setting_type.ex b/lib/teiserver/settings/schemas/user_setting_type.ex
index b48e0ac62..9ae9e6239 100644
--- a/lib/teiserver/settings/schemas/user_setting_type.ex
+++ b/lib/teiserver/settings/schemas/user_setting_type.ex
@@ -32,7 +32,7 @@ defmodule Teiserver.Settings.UserSettingType do
field(:permissions, String.t() | [String.t()] | nil, default: nil)
field(:choices, [String.t()] | nil, default: nil)
- field(:default, String.t() | Integer.t() | boolean | nil, default: nil)
+ field(:default, String.t() | integer() | boolean | nil, default: nil)
field(:description, String.t() | nil, default: nil)
end
end
diff --git a/mix.exs b/mix.exs
index c46c0f0b3..c227a9237 100644
--- a/mix.exs
+++ b/mix.exs
@@ -2,7 +2,7 @@ defmodule Teiserver.MixProject do
use Mix.Project
@source_url "https://github.com/Teifion/teiserver"
- @version "0.0.4"
+ @version "0.0.5"
def project do
[
@@ -167,7 +167,22 @@ defmodule Teiserver.MixProject do
# Settings
"Site settings": &(&1[:section] == :server_setting),
- "User settings": &(&1[:section] == :user_setting)
+ "User settings": &(&1[:section] == :user_setting),
+
+ # Logging
+ "Audit logs": &(&1[:section] == :audit_log),
+ "Match minute logs": &(&1[:section] == :match_minute_log),
+ "Match day logs": &(&1[:section] == :match_day_log),
+ "Match week logs": &(&1[:section] == :match_week_log),
+ "Match month logs": &(&1[:section] == :match_month_log),
+ "Match quarter logs": &(&1[:section] == :match_quarter_log),
+ "Match year logs": &(&1[:section] == :match_year_log),
+ "Server minute logs": &(&1[:section] == :server_minute_log),
+ "Server day logs": &(&1[:section] == :server_day_log),
+ "Server week logs": &(&1[:section] == :server_week_log),
+ "Server month logs": &(&1[:section] == :server_month_log),
+ "Server quarter logs": &(&1[:section] == :server_quarter_log),
+ "Server year logs": &(&1[:section] == :server_year_log)
]
end
From ca04ba5b41a8dd3147ea596d8dd24f885ca2cde9 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 7 Apr 2024 14:32:15 +0100
Subject: [PATCH 12/64] Removed telemetry and event database stuff, moved to
Angen instead
---
CHANGELOG.md | 2 -
README.md | 1 -
documentation/development/roadmap.md | 10 +-
documentation/guides/config.md | 2 +
documentation/guides/telemetry_events.md | 20 -
documentation/guides/testing.md | 24 +
lib/teiserver.ex | 1 -
lib/teiserver/application.ex | 14 +-
lib/teiserver/contexts/logging.ex | 499 ------------------
lib/teiserver/contexts/telemetry.ex | 60 ---
.../logging/libs/match_day_log_lib.ex | 138 -----
.../logging/libs/match_minute_log_lib.ex | 138 -----
.../logging/libs/match_month_log_lib.ex | 138 -----
.../logging/libs/match_quarter_log_lib.ex | 138 -----
.../logging/libs/match_week_log_lib.ex | 138 -----
.../logging/libs/match_year_log_lib.ex | 138 -----
.../logging/libs/server_day_log_lib.ex | 138 -----
.../logging/libs/server_minute_log_lib.ex | 138 -----
.../logging/libs/server_month_log_lib.ex | 138 -----
.../logging/libs/server_quarter_log_lib.ex | 139 -----
.../logging/libs/server_week_log_lib.ex | 138 -----
.../logging/libs/server_year_log_lib.ex | 138 -----
.../logging/queries/match_day_log_queries.ex | 75 ---
.../queries/match_minute_log_queries.ex | 69 ---
.../queries/match_month_log_queries.ex | 87 ---
.../queries/match_quarter_log_queries.ex | 87 ---
.../logging/queries/match_week_log_queries.ex | 87 ---
.../logging/queries/match_year_log_queries.ex | 81 ---
.../logging/queries/server_day_log_queries.ex | 75 ---
.../queries/server_minute_log_queries.ex | 69 ---
.../queries/server_month_log_queries.ex | 87 ---
.../queries/server_quarter_log_queries.ex | 87 ---
.../queries/server_week_log_queries.ex | 87 ---
.../queries/server_year_log_queries.ex | 81 ---
.../logging/schemas/match_day_log.ex | 32 --
.../logging/schemas/match_minute_log.ex | 32 --
.../logging/schemas/match_month_log.ex | 38 --
.../logging/schemas/match_quarter_log.ex | 38 --
.../logging/schemas/match_week_log.ex | 38 --
.../logging/schemas/match_year_log.ex | 35 --
.../logging/schemas/server_day_log.ex | 32 --
.../logging/schemas/server_minute_log.ex | 32 --
.../logging/schemas/server_month_log.ex | 38 --
.../logging/schemas/server_quarter_log.ex | 38 --
.../logging/schemas/server_week_log.ex | 38 --
.../logging/schemas/server_year_log.ex | 35 --
lib/teiserver/migrations/postgres/v02.ex | 76 ---
.../system/servers/cluster_member_server.ex | 18 +-
.../servers/cluster_member_supervisor.ex | 2 +-
.../telemetry/libs/event_type_lib.ex | 137 -----
.../telemetry/queries/event_type_queries.ex | 75 ---
.../telemetry/schemas/complex_anon_event.ex | 40 --
.../schemas/complex_clientapp_event.ex | 40 --
.../telemetry/schemas/complex_lobby_event.ex | 43 --
.../telemetry/schemas/complex_match_event.ex | 48 --
.../telemetry/schemas/complex_server_event.ex | 40 --
lib/teiserver/telemetry/schemas/event_type.ex | 33 --
.../telemetry/schemas/simple_anon_event.ex | 36 --
.../schemas/simple_clientapp_event.ex | 36 --
.../telemetry/schemas/simple_lobby_event.ex | 39 --
.../telemetry/schemas/simple_match_event.ex | 43 --
.../telemetry/schemas/simple_server_event.ex | 36 --
mix.exs | 13 +-
test/logging/libs/match_day_log_lib_test.exs | 98 ----
.../libs/match_minute_log_lib_test.exs | 98 ----
.../logging/libs/match_month_log_lib_test.exs | 102 ----
.../libs/match_quarter_log_lib_test.exs | 102 ----
test/logging/libs/match_week_log_lib_test.exs | 102 ----
test/logging/libs/match_year_log_lib_test.exs | 100 ----
test/logging/libs/server_day_log_lib_test.exs | 98 ----
.../libs/server_minute_log_lib_test.exs | 98 ----
.../libs/server_month_log_lib_test.exs | 102 ----
.../libs/server_quarter_log_lib_test.exs | 104 ----
.../logging/libs/server_week_log_lib_test.exs | 102 ----
.../logging/libs/server_year_log_lib_test.exs | 100 ----
.../queries/match_day_log_queries_test.exs | 47 --
.../queries/match_minute_log_queries_test.exs | 46 --
.../queries/match_month_log_queries_test.exs | 49 --
.../match_quarter_log_queries_test.exs | 49 --
.../queries/match_week_log_queries_test.exs | 49 --
.../queries/match_year_log_queries_test.exs | 48 --
.../queries/server_day_log_queries_test.exs | 47 --
.../server_minute_log_queries_test.exs | 46 --
.../queries/server_month_log_queries_test.exs | 49 --
.../server_quarter_log_queries_test.exs | 49 --
.../queries/server_week_log_queries_test.exs | 49 --
.../queries/server_year_log_queries_test.exs | 48 --
test/support/fixtures/logging_fixtures.ex | 173 ------
88 files changed, 47 insertions(+), 6351 deletions(-)
delete mode 100644 documentation/guides/telemetry_events.md
create mode 100644 documentation/guides/testing.md
delete mode 100644 lib/teiserver/contexts/telemetry.ex
delete mode 100644 lib/teiserver/logging/libs/match_day_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/match_minute_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/match_month_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/match_quarter_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/match_week_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/match_year_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/server_day_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/server_minute_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/server_month_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/server_quarter_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/server_week_log_lib.ex
delete mode 100644 lib/teiserver/logging/libs/server_year_log_lib.ex
delete mode 100644 lib/teiserver/logging/queries/match_day_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/match_minute_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/match_month_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/match_quarter_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/match_week_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/match_year_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/server_day_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/server_minute_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/server_month_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/server_quarter_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/server_week_log_queries.ex
delete mode 100644 lib/teiserver/logging/queries/server_year_log_queries.ex
delete mode 100644 lib/teiserver/logging/schemas/match_day_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_minute_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_month_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_quarter_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_week_log.ex
delete mode 100644 lib/teiserver/logging/schemas/match_year_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_day_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_minute_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_month_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_quarter_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_week_log.ex
delete mode 100644 lib/teiserver/logging/schemas/server_year_log.ex
delete mode 100644 lib/teiserver/telemetry/libs/event_type_lib.ex
delete mode 100644 lib/teiserver/telemetry/queries/event_type_queries.ex
delete mode 100644 lib/teiserver/telemetry/schemas/complex_anon_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/complex_clientapp_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/complex_lobby_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/complex_match_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/complex_server_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/event_type.ex
delete mode 100644 lib/teiserver/telemetry/schemas/simple_anon_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/simple_clientapp_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/simple_lobby_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/simple_match_event.ex
delete mode 100644 lib/teiserver/telemetry/schemas/simple_server_event.ex
delete mode 100644 test/logging/libs/match_day_log_lib_test.exs
delete mode 100644 test/logging/libs/match_minute_log_lib_test.exs
delete mode 100644 test/logging/libs/match_month_log_lib_test.exs
delete mode 100644 test/logging/libs/match_quarter_log_lib_test.exs
delete mode 100644 test/logging/libs/match_week_log_lib_test.exs
delete mode 100644 test/logging/libs/match_year_log_lib_test.exs
delete mode 100644 test/logging/libs/server_day_log_lib_test.exs
delete mode 100644 test/logging/libs/server_minute_log_lib_test.exs
delete mode 100644 test/logging/libs/server_month_log_lib_test.exs
delete mode 100644 test/logging/libs/server_quarter_log_lib_test.exs
delete mode 100644 test/logging/libs/server_week_log_lib_test.exs
delete mode 100644 test/logging/libs/server_year_log_lib_test.exs
delete mode 100644 test/logging/queries/match_day_log_queries_test.exs
delete mode 100644 test/logging/queries/match_minute_log_queries_test.exs
delete mode 100644 test/logging/queries/match_month_log_queries_test.exs
delete mode 100644 test/logging/queries/match_quarter_log_queries_test.exs
delete mode 100644 test/logging/queries/match_week_log_queries_test.exs
delete mode 100644 test/logging/queries/match_year_log_queries_test.exs
delete mode 100644 test/logging/queries/server_day_log_queries_test.exs
delete mode 100644 test/logging/queries/server_minute_log_queries_test.exs
delete mode 100644 test/logging/queries/server_month_log_queries_test.exs
delete mode 100644 test/logging/queries/server_quarter_log_queries_test.exs
delete mode 100644 test/logging/queries/server_week_log_queries_test.exs
delete mode 100644 test/logging/queries/server_year_log_queries_test.exs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 785cd70f6..a19a411ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,10 +2,8 @@
- Swapped `team_colour` for `player_colour`
- Refactored the client update process
- Added User and Server runtime settings
-- Added logging for server and match usage
- Added Telemetry events
-
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
- Added pubsub events for clients connecting, disconnecting and process destruction
diff --git a/README.md b/README.md
index 27378635d..f44cff0c2 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,6 @@ _Note: This README is for the unreleased master branch, please reference the
- User connectivity
- User to User communications
- Lobby system (planned)
-- Telemetry/Event logging (planned)
- Community management tools (planned)
- Steam integration (planned)
diff --git a/documentation/development/roadmap.md b/documentation/development/roadmap.md
index 593aa605a..c60e299be 100644
--- a/documentation/development/roadmap.md
+++ b/documentation/development/roadmap.md
@@ -6,11 +6,11 @@ This is not a rigid document, it is (especially at this stage) liable to change.
* `v0.0.2` - Client features (Connections)
* `v0.0.3` - Chat and Messaging (Communication)
* `v0.0.4` - Lobbies (Lobby and Game)
-* `v0.0.5` - Logging and Event telemetry (Telemetry and Logging)
+* `v0.0.5` - Site and User Settings, plus internal Telemetry (Settings, Telemetry)
* `v0.0.6` - Player relationships (Account and Community)
* `v0.0.7` - Moderation (Moderation and Account)
* `v0.0.8` - Parties (Community)
-* `v0.0.9` - Site and User Settings (Settings)
+* `v0.0.9` - tbd
* `v0.1` - Stability, tests and better examples on how to use it
At v0.1 I want the server to be in a state where developers can start to make use of it.
@@ -41,12 +41,6 @@ At v0.1 I want the server to be in a state where developers can start to make us
- Site settings
- User settings
-- Telemetry
- - In game events
- - Server events
- - Lobby events
- - User events
-
## Planned/intended features
- Administration
- Moderation
diff --git a/documentation/guides/config.md b/documentation/guides/config.md
index b81f4b075..5e827ec6c 100644
--- a/documentation/guides/config.md
+++ b/documentation/guides/config.md
@@ -58,6 +58,8 @@ A function used to determine if a lobby name is acceptable. Defaults to `Teiserv
## `fn_uuid_generator`
The function used to generate UUIDs. Defaults to `&Ecto.UUID.generate/0`.
+# Function extensions
+Teiserver has a number of functions which you will likely want to extend.
# Complete example config
```elixir
diff --git a/documentation/guides/telemetry_events.md b/documentation/guides/telemetry_events.md
deleted file mode 100644
index 2d8e94b3e..000000000
--- a/documentation/guides/telemetry_events.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Overview
-
-## Privacy warning
-- Understand what PII is
-- Know the laws of wherever you are providing a service
-- I am not a lawyer, if in doubt don't collect data
-
-## Event categories
-- Server
-- Lobby
-- ClientApp
-- Match
-
-## Limitations
-
-## Extension
-- How to extend it to add new data
-
-## Third party services
-I want to add the ability to forward all telemetry data straight to third parties making it easier to scales games in future but I've not had a chance to do this yet. If this is something you want please create a [github issue](https://github.com/Teifion/teiserver/issues) or [Pull Request](https://github.com/Teifion/teiserver/pulls) for it.
diff --git a/documentation/guides/testing.md b/documentation/guides/testing.md
new file mode 100644
index 000000000..04b6d5f9e
--- /dev/null
+++ b/documentation/guides/testing.md
@@ -0,0 +1,24 @@
+# Testing
+Teiserver aims to have as many functions tested as possible. More importantly Teiserver supplies a number of fixtures and functions to make the life of anybody testing it easier.
+
+## Fixtures
+Teiserver includes at least one fixture for every schema located in `/test/support/fixtures`. They follow a consistent naming pattern:
+```elixir
+Teiserver.Account.User -> Teiserver.AccountFixtures.user_fixture()
+Teiserver.Game.Match -> Teiserver.GameFixtures.incomplete_match_fixture()
+```
+
+Each fixture can be called as is or with a map which will dictate overrides for otherwise static or random values.
+
+```elixir
+Teiserver.AccountFixtures.user_fixture(%{
+ name: "MySpecific TestUser",
+ password: "A special password"
+})
+```
+
+## Dummy data
+Servers are much easier to debug or test when you have actual data. As such Teiserver has a number of functions dedicated to providing dummy data.
+
+TODO: Write docs for these, located in `/test/support/dummy_data`
+
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 327b0c37e..ad9e45268 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -41,7 +41,6 @@ defmodule Teiserver do
- **Logging**: Logging of events and numbers
- **Moderation**: Handling disruptive users
- **Settings**: Key-Value pairs for users and the system
- - **Telemetry**: Moment to moment events
"""
# Aliased types
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index aba8be08d..dea0f1e7e 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -42,19 +42,7 @@ defmodule Teiserver.Application do
add_cache(:ts_server_setting_cache, ttl: :timer.minutes(1)),
add_cache(:ts_user_setting_type_store),
add_cache(:ts_user_setting_cache, ttl: :timer.minutes(1)),
- add_cache(:ts_user_by_user_id_cache, ttl: :timer.minutes(5)),
-
- # Telemetry caches
- add_cache(:ts_property_types_cache),
- add_cache(:ts_simple_client_event_types_cache),
- add_cache(:ts_complex_client_event_types_cache),
- add_cache(:ts_simple_lobby_event_types_cache),
- add_cache(:ts_complex_lobby_event_types_cache),
- add_cache(:ts_simple_match_event_types_cache),
- add_cache(:ts_complex_match_event_types_cache),
- add_cache(:ts_simple_server_event_types_cache),
- add_cache(:ts_complex_server_event_types_cache),
- add_cache(:ts_account_smurf_key_types)
+ add_cache(:ts_user_by_user_id_cache, ttl: :timer.minutes(5))
]
opts = [strategy: :one_for_one, name: __MODULE__]
diff --git a/lib/teiserver/contexts/logging.ex b/lib/teiserver/contexts/logging.ex
index 3962cf227..bdc98125f 100644
--- a/lib/teiserver/contexts/logging.ex
+++ b/lib/teiserver/contexts/logging.ex
@@ -2,22 +2,6 @@ defmodule Teiserver.Logging do
@moduledoc """
The contextual module for:
- `Teiserver.Logging.AuditLog`
- - `Teiserver.Logging.CrashLog`
- - `Teiserver.Logging.MatchMinuteLog`
- - `Teiserver.Logging.MatchDayLog`
- - `Teiserver.Logging.MatchWeekLog`
- - `Teiserver.Logging.MatchQuarterLog`
- - `Teiserver.Logging.MatchYearLog`
- - `Teiserver.Logging.ServerMinuteLog`
- - `Teiserver.Logging.ServerDayLog`
- - `Teiserver.Logging.ServerWeekLog`
- - `Teiserver.Logging.ServerQuarterLog`
- - `Teiserver.Logging.ServerYearLog`
-
- ## Minutes through to years
- The system is designed to take a snapshot of activity every minute and roll these up into day logs at the end of each day. The system then later creates week, month, quarter and year snapshots from the day logs. While we could just roll up the day logs each time we need to make a query the space taken by the extra snapshots is very small and makes querying so much easier I decided to add the extra files/tables.
-
- Minute to minute logs are deleted periodically to save space but Day logs and beyond are designed to be kept.
"""
# AuditLogs
@@ -67,487 +51,4 @@ defmodule Teiserver.Logging do
@spec change_audit_log(AuditLog.t()) :: Ecto.Changeset.t()
@spec change_audit_log(AuditLog.t(), map) :: Ecto.Changeset.t()
defdelegate change_audit_log(audit_log, attrs \\ %{}), to: AuditLogLib
-
- # Crash logs
-
- # MatchMinuteLogs
- alias Teiserver.Logging.{MatchMinuteLog, MatchMinuteLogLib, MatchMinuteLogQueries}
-
- @doc false
- @spec match_minute_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate match_minute_log_query(args), to: MatchMinuteLogQueries
-
- @doc section: :match_minute_log
- @spec list_match_minute_logs(Teiserver.query_args()) :: [MatchMinuteLog.t()]
- defdelegate list_match_minute_logs(args), to: MatchMinuteLogLib
-
- @doc section: :match_minute_log
- @spec get_match_minute_log!(DateTime.t()) :: MatchMinuteLog.t()
- @spec get_match_minute_log!(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t()
- defdelegate get_match_minute_log!(timestamp, query_args \\ []), to: MatchMinuteLogLib
-
- @doc section: :match_minute_log
- @spec get_match_minute_log(DateTime.t()) :: MatchMinuteLog.t() | nil
- @spec get_match_minute_log(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t() | nil
- defdelegate get_match_minute_log(timestamp, query_args \\ []), to: MatchMinuteLogLib
-
- @doc section: :match_minute_log
- @spec create_match_minute_log(map) :: {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_match_minute_log(attrs), to: MatchMinuteLogLib
-
- @doc section: :match_minute_log
- @spec update_match_minute_log(MatchMinuteLog, map) ::
- {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_match_minute_log(match_minute_log, attrs), to: MatchMinuteLogLib
-
- @doc section: :match_minute_log
- @spec delete_match_minute_log(MatchMinuteLog.t()) ::
- {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_match_minute_log(match_minute_log), to: MatchMinuteLogLib
-
- @doc section: :match_minute_log
- @spec change_match_minute_log(MatchMinuteLog.t()) :: Ecto.Changeset.t()
- @spec change_match_minute_log(MatchMinuteLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_match_minute_log(match_minute_log, attrs \\ %{}), to: MatchMinuteLogLib
-
- # MatchDayLogs
- alias Teiserver.Logging.{MatchDayLog, MatchDayLogLib, MatchDayLogQueries}
-
- @doc false
- @spec match_day_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate match_day_log_query(args), to: MatchDayLogQueries
-
- @doc section: :match_day_log
- @spec list_match_day_logs(Teiserver.query_args()) :: [MatchDayLog.t()]
- defdelegate list_match_day_logs(args), to: MatchDayLogLib
-
- @doc section: :match_day_log
- @spec get_match_day_log!(Date.t()) :: MatchDayLog.t()
- @spec get_match_day_log!(Date.t(), Teiserver.query_args()) :: MatchDayLog.t()
- defdelegate get_match_day_log!(date, query_args \\ []), to: MatchDayLogLib
-
- @doc section: :match_day_log
- @spec get_match_day_log(Date.t()) :: MatchDayLog.t() | nil
- @spec get_match_day_log(Date.t(), Teiserver.query_args()) :: MatchDayLog.t() | nil
- defdelegate get_match_day_log(date, query_args \\ []), to: MatchDayLogLib
-
- @doc section: :match_day_log
- @spec create_match_day_log(map) :: {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_match_day_log(attrs), to: MatchDayLogLib
-
- @doc section: :match_day_log
- @spec update_match_day_log(MatchDayLog, map) ::
- {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_match_day_log(match_day_log, attrs), to: MatchDayLogLib
-
- @doc section: :match_day_log
- @spec delete_match_day_log(MatchDayLog.t()) ::
- {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_match_day_log(match_day_log), to: MatchDayLogLib
-
- @doc section: :match_day_log
- @spec change_match_day_log(MatchDayLog.t()) :: Ecto.Changeset.t()
- @spec change_match_day_log(MatchDayLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_match_day_log(match_day_log, attrs \\ %{}), to: MatchDayLogLib
-
- # MatchWeekLogs
- alias Teiserver.Logging.{MatchWeekLog, MatchWeekLogLib, MatchWeekLogQueries}
-
- @doc false
- @spec match_week_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate match_week_log_query(args), to: MatchWeekLogQueries
-
- @doc section: :match_week_log
- @spec list_match_week_logs(Teiserver.query_args()) :: [MatchWeekLog.t()]
- defdelegate list_match_week_logs(args), to: MatchWeekLogLib
-
- @doc section: :match_week_log
- @spec get_match_week_log!(Date.t()) :: MatchWeekLog.t()
- @spec get_match_week_log!(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t()
- defdelegate get_match_week_log!(date, query_args \\ []), to: MatchWeekLogLib
-
- @doc section: :match_week_log
- @spec get_match_week_log(Date.t()) :: MatchWeekLog.t() | nil
- @spec get_match_week_log(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t() | nil
- defdelegate get_match_week_log(date, query_args \\ []), to: MatchWeekLogLib
-
- @doc section: :match_week_log
- @spec create_match_week_log(map) :: {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_match_week_log(attrs), to: MatchWeekLogLib
-
- @doc section: :match_week_log
- @spec update_match_week_log(MatchWeekLog, map) ::
- {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_match_week_log(match_week_log, attrs), to: MatchWeekLogLib
-
- @doc section: :match_week_log
- @spec delete_match_week_log(MatchWeekLog.t()) ::
- {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_match_week_log(match_week_log), to: MatchWeekLogLib
-
- @doc section: :match_week_log
- @spec change_match_week_log(MatchWeekLog.t()) :: Ecto.Changeset.t()
- @spec change_match_week_log(MatchWeekLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_match_week_log(match_week_log, attrs \\ %{}), to: MatchWeekLogLib
-
- # MatchMonthLogs
- alias Teiserver.Logging.{MatchMonthLog, MatchMonthLogLib, MatchMonthLogQueries}
-
- @doc false
- @spec match_month_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate match_month_log_query(args), to: MatchMonthLogQueries
-
- @doc section: :match_month_log
- @spec list_match_month_logs(Teiserver.query_args()) :: [MatchMonthLog.t()]
- defdelegate list_match_month_logs(args), to: MatchMonthLogLib
-
- @doc section: :match_month_log
- @spec get_match_month_log!(Date.t()) :: MatchMonthLog.t()
- @spec get_match_month_log!(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t()
- defdelegate get_match_month_log!(date, query_args \\ []), to: MatchMonthLogLib
-
- @doc section: :match_month_log
- @spec get_match_month_log(Date.t()) :: MatchMonthLog.t() | nil
- @spec get_match_month_log(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t() | nil
- defdelegate get_match_month_log(date, query_args \\ []), to: MatchMonthLogLib
-
- @doc section: :match_month_log
- @spec create_match_month_log(map) :: {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_match_month_log(attrs), to: MatchMonthLogLib
-
- @doc section: :match_month_log
- @spec update_match_month_log(MatchMonthLog, map) ::
- {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_match_month_log(match_month_log, attrs), to: MatchMonthLogLib
-
- @doc section: :match_month_log
- @spec delete_match_month_log(MatchMonthLog.t()) ::
- {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_match_month_log(match_month_log), to: MatchMonthLogLib
-
- @doc section: :match_month_log
- @spec change_match_month_log(MatchMonthLog.t()) :: Ecto.Changeset.t()
- @spec change_match_month_log(MatchMonthLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_match_month_log(match_month_log, attrs \\ %{}), to: MatchMonthLogLib
-
- # MatchQuarterLogs
- alias Teiserver.Logging.{MatchQuarterLog, MatchQuarterLogLib, MatchQuarterLogQueries}
-
- @doc false
- @spec match_quarter_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate match_quarter_log_query(args), to: MatchQuarterLogQueries
-
- @doc section: :match_quarter_log
- @spec list_match_quarter_logs(Teiserver.query_args()) :: [MatchQuarterLog.t()]
- defdelegate list_match_quarter_logs(args), to: MatchQuarterLogLib
-
- @doc section: :match_quarter_log
- @spec get_match_quarter_log!(Date.t()) :: MatchQuarterLog.t()
- @spec get_match_quarter_log!(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t()
- defdelegate get_match_quarter_log!(date, query_args \\ []), to: MatchQuarterLogLib
-
- @doc section: :match_quarter_log
- @spec get_match_quarter_log(Date.t()) :: MatchQuarterLog.t() | nil
- @spec get_match_quarter_log(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t() | nil
- defdelegate get_match_quarter_log(date, query_args \\ []), to: MatchQuarterLogLib
-
- @doc section: :match_quarter_log
- @spec create_match_quarter_log(map) :: {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_match_quarter_log(attrs), to: MatchQuarterLogLib
-
- @doc section: :match_quarter_log
- @spec update_match_quarter_log(MatchQuarterLog, map) ::
- {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_match_quarter_log(match_quarter_log, attrs), to: MatchQuarterLogLib
-
- @doc section: :match_quarter_log
- @spec delete_match_quarter_log(MatchQuarterLog.t()) ::
- {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_match_quarter_log(match_quarter_log), to: MatchQuarterLogLib
-
- @doc section: :match_quarter_log
- @spec change_match_quarter_log(MatchQuarterLog.t()) :: Ecto.Changeset.t()
- @spec change_match_quarter_log(MatchQuarterLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_match_quarter_log(match_quarter_log, attrs \\ %{}), to: MatchQuarterLogLib
-
- # MatchYearLogs
- alias Teiserver.Logging.{MatchYearLog, MatchYearLogLib, MatchYearLogQueries}
-
- @doc false
- @spec match_year_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate match_year_log_query(args), to: MatchYearLogQueries
-
- @doc section: :match_year_log
- @spec list_match_year_logs(Teiserver.query_args()) :: [MatchYearLog.t()]
- defdelegate list_match_year_logs(args), to: MatchYearLogLib
-
- @doc section: :match_year_log
- @spec get_match_year_log!(Date.t()) :: MatchYearLog.t()
- @spec get_match_year_log!(Date.t(), Teiserver.query_args()) :: MatchYearLog.t()
- defdelegate get_match_year_log!(date, query_args \\ []), to: MatchYearLogLib
-
- @doc section: :match_year_log
- @spec get_match_year_log(Date.t()) :: MatchYearLog.t() | nil
- @spec get_match_year_log(Date.t(), Teiserver.query_args()) :: MatchYearLog.t() | nil
- defdelegate get_match_year_log(date, query_args \\ []), to: MatchYearLogLib
-
- @doc section: :match_year_log
- @spec create_match_year_log(map) :: {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_match_year_log(attrs), to: MatchYearLogLib
-
- @doc section: :match_year_log
- @spec update_match_year_log(MatchYearLog, map) ::
- {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_match_year_log(match_year_log, attrs), to: MatchYearLogLib
-
- @doc section: :match_year_log
- @spec delete_match_year_log(MatchYearLog.t()) ::
- {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_match_year_log(match_year_log), to: MatchYearLogLib
-
- @doc section: :match_year_log
- @spec change_match_year_log(MatchYearLog.t()) :: Ecto.Changeset.t()
- @spec change_match_year_log(MatchYearLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_match_year_log(match_year_log, attrs \\ %{}), to: MatchYearLogLib
-
- # ServerMinuteLogs
- alias Teiserver.Logging.{ServerMinuteLog, ServerMinuteLogLib, ServerMinuteLogQueries}
-
- @doc false
- @spec server_minute_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate server_minute_log_query(args), to: ServerMinuteLogQueries
-
- @doc section: :server_minute_log
- @spec list_server_minute_logs(Teiserver.query_args()) :: [ServerMinuteLog.t()]
- defdelegate list_server_minute_logs(args), to: ServerMinuteLogLib
-
- @doc section: :server_minute_log
- @spec get_server_minute_log!(DateTime.t()) :: ServerMinuteLog.t()
- @spec get_server_minute_log!(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t()
- defdelegate get_server_minute_log!(timestamp, query_args \\ []), to: ServerMinuteLogLib
-
- @doc section: :server_minute_log
- @spec get_server_minute_log(DateTime.t()) :: ServerMinuteLog.t() | nil
- @spec get_server_minute_log(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t() | nil
- defdelegate get_server_minute_log(timestamp, query_args \\ []), to: ServerMinuteLogLib
-
- @doc section: :server_minute_log
- @spec create_server_minute_log(map) :: {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_server_minute_log(attrs), to: ServerMinuteLogLib
-
- @doc section: :server_minute_log
- @spec update_server_minute_log(ServerMinuteLog, map) ::
- {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_server_minute_log(server_minute_log, attrs), to: ServerMinuteLogLib
-
- @doc section: :server_minute_log
- @spec delete_server_minute_log(ServerMinuteLog.t()) ::
- {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_server_minute_log(server_minute_log), to: ServerMinuteLogLib
-
- @doc section: :server_minute_log
- @spec change_server_minute_log(ServerMinuteLog.t()) :: Ecto.Changeset.t()
- @spec change_server_minute_log(ServerMinuteLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_server_minute_log(server_minute_log, attrs \\ %{}), to: ServerMinuteLogLib
-
- # ServerDayLogs
- alias Teiserver.Logging.{ServerDayLog, ServerDayLogLib, ServerDayLogQueries}
-
- @doc false
- @spec server_day_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate server_day_log_query(args), to: ServerDayLogQueries
-
- @doc section: :server_day_log
- @spec list_server_day_logs(Teiserver.query_args()) :: [ServerDayLog.t()]
- defdelegate list_server_day_logs(args), to: ServerDayLogLib
-
- @doc section: :server_day_log
- @spec get_server_day_log!(Date.t()) :: ServerDayLog.t()
- @spec get_server_day_log!(Date.t(), Teiserver.query_args()) :: ServerDayLog.t()
- defdelegate get_server_day_log!(date, query_args \\ []), to: ServerDayLogLib
-
- @doc section: :server_day_log
- @spec get_server_day_log(Date.t()) :: ServerDayLog.t() | nil
- @spec get_server_day_log(Date.t(), Teiserver.query_args()) :: ServerDayLog.t() | nil
- defdelegate get_server_day_log(date, query_args \\ []), to: ServerDayLogLib
-
- @doc section: :server_day_log
- @spec create_server_day_log(map) :: {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_server_day_log(attrs), to: ServerDayLogLib
-
- @doc section: :server_day_log
- @spec update_server_day_log(ServerDayLog, map) ::
- {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_server_day_log(server_day_log, attrs), to: ServerDayLogLib
-
- @doc section: :server_day_log
- @spec delete_server_day_log(ServerDayLog.t()) ::
- {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_server_day_log(server_day_log), to: ServerDayLogLib
-
- @doc section: :server_day_log
- @spec change_server_day_log(ServerDayLog.t()) :: Ecto.Changeset.t()
- @spec change_server_day_log(ServerDayLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_server_day_log(server_day_log, attrs \\ %{}), to: ServerDayLogLib
-
- # ServerWeekLogs
- alias Teiserver.Logging.{ServerWeekLog, ServerWeekLogLib, ServerWeekLogQueries}
-
- @doc false
- @spec server_week_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate server_week_log_query(args), to: ServerWeekLogQueries
-
- @doc section: :server_week_log
- @spec list_server_week_logs(Teiserver.query_args()) :: [ServerWeekLog.t()]
- defdelegate list_server_week_logs(args), to: ServerWeekLogLib
-
- @doc section: :server_week_log
- @spec get_server_week_log!(Date.t()) :: ServerWeekLog.t()
- @spec get_server_week_log!(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t()
- defdelegate get_server_week_log!(date, query_args \\ []), to: ServerWeekLogLib
-
- @doc section: :server_week_log
- @spec get_server_week_log(Date.t()) :: ServerWeekLog.t() | nil
- @spec get_server_week_log(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t() | nil
- defdelegate get_server_week_log(date, query_args \\ []), to: ServerWeekLogLib
-
- @doc section: :server_week_log
- @spec create_server_week_log(map) :: {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_server_week_log(attrs), to: ServerWeekLogLib
-
- @doc section: :server_week_log
- @spec update_server_week_log(ServerWeekLog, map) ::
- {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_server_week_log(server_week_log, attrs), to: ServerWeekLogLib
-
- @doc section: :server_week_log
- @spec delete_server_week_log(ServerWeekLog.t()) ::
- {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_server_week_log(server_week_log), to: ServerWeekLogLib
-
- @doc section: :server_week_log
- @spec change_server_week_log(ServerWeekLog.t()) :: Ecto.Changeset.t()
- @spec change_server_week_log(ServerWeekLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_server_week_log(server_week_log, attrs \\ %{}), to: ServerWeekLogLib
-
- # ServerMonthLogs
- alias Teiserver.Logging.{ServerMonthLog, ServerMonthLogLib, ServerMonthLogQueries}
-
- @doc false
- @spec server_month_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate server_month_log_query(args), to: ServerMonthLogQueries
-
- @doc section: :server_month_log
- @spec list_server_month_logs(Teiserver.query_args()) :: [ServerMonthLog.t()]
- defdelegate list_server_month_logs(args), to: ServerMonthLogLib
-
- @doc section: :server_month_log
- @spec get_server_month_log!(Date.t()) :: ServerMonthLog.t()
- @spec get_server_month_log!(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t()
- defdelegate get_server_month_log!(date, query_args \\ []), to: ServerMonthLogLib
-
- @doc section: :server_month_log
- @spec get_server_month_log(Date.t()) :: ServerMonthLog.t() | nil
- @spec get_server_month_log(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t() | nil
- defdelegate get_server_month_log(date, query_args \\ []), to: ServerMonthLogLib
-
- @doc section: :server_month_log
- @spec create_server_month_log(map) :: {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_server_month_log(attrs), to: ServerMonthLogLib
-
- @doc section: :server_month_log
- @spec update_server_month_log(ServerMonthLog, map) ::
- {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_server_month_log(server_month_log, attrs), to: ServerMonthLogLib
-
- @doc section: :server_month_log
- @spec delete_server_month_log(ServerMonthLog.t()) ::
- {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_server_month_log(server_month_log), to: ServerMonthLogLib
-
- @doc section: :server_month_log
- @spec change_server_month_log(ServerMonthLog.t()) :: Ecto.Changeset.t()
- @spec change_server_month_log(ServerMonthLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_server_month_log(server_month_log, attrs \\ %{}), to: ServerMonthLogLib
-
- # ServerQuarterLogs
- alias Teiserver.Logging.{ServerQuarterLog, ServerQuarterLogLib, ServerQuarterLogQueries}
-
- @doc false
- @spec server_quarter_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate server_quarter_log_query(args), to: ServerQuarterLogQueries
-
- @doc section: :server_quarter_log
- @spec list_server_quarter_logs(Teiserver.query_args()) :: [ServerQuarterLog.t()]
- defdelegate list_server_quarter_logs(args), to: ServerQuarterLogLib
-
- @doc section: :server_quarter_log
- @spec get_server_quarter_log!(Date.t()) :: ServerQuarterLog.t()
- @spec get_server_quarter_log!(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t()
- defdelegate get_server_quarter_log!(date, query_args \\ []), to: ServerQuarterLogLib
-
- @doc section: :server_quarter_log
- @spec get_server_quarter_log(Date.t()) :: ServerQuarterLog.t() | nil
- @spec get_server_quarter_log(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t() | nil
- defdelegate get_server_quarter_log(date, query_args \\ []), to: ServerQuarterLogLib
-
- @doc section: :server_quarter_log
- @spec create_server_quarter_log(map) ::
- {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_server_quarter_log(attrs), to: ServerQuarterLogLib
-
- @doc section: :server_quarter_log
- @spec update_server_quarter_log(ServerQuarterLog, map) ::
- {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_server_quarter_log(server_quarter_log, attrs), to: ServerQuarterLogLib
-
- @doc section: :server_quarter_log
- @spec delete_server_quarter_log(ServerQuarterLog.t()) ::
- {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_server_quarter_log(server_quarter_log), to: ServerQuarterLogLib
-
- @doc section: :server_quarter_log
- @spec change_server_quarter_log(ServerQuarterLog.t()) :: Ecto.Changeset.t()
- @spec change_server_quarter_log(ServerQuarterLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_server_quarter_log(server_quarter_log, attrs \\ %{}), to: ServerQuarterLogLib
-
- # ServerYearLogs
- alias Teiserver.Logging.{ServerYearLog, ServerYearLogLib, ServerYearLogQueries}
-
- @doc false
- @spec server_year_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate server_year_log_query(args), to: ServerYearLogQueries
-
- @doc section: :server_year_log
- @spec list_server_year_logs(Teiserver.query_args()) :: [ServerYearLog.t()]
- defdelegate list_server_year_logs(args), to: ServerYearLogLib
-
- @doc section: :server_year_log
- @spec get_server_year_log!(Date.t()) :: ServerYearLog.t()
- @spec get_server_year_log!(Date.t(), Teiserver.query_args()) :: ServerYearLog.t()
- defdelegate get_server_year_log!(date, query_args \\ []), to: ServerYearLogLib
-
- @doc section: :server_year_log
- @spec get_server_year_log(Date.t()) :: ServerYearLog.t() | nil
- @spec get_server_year_log(Date.t(), Teiserver.query_args()) :: ServerYearLog.t() | nil
- defdelegate get_server_year_log(date, query_args \\ []), to: ServerYearLogLib
-
- @doc section: :server_year_log
- @spec create_server_year_log(map) :: {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_server_year_log(attrs), to: ServerYearLogLib
-
- @doc section: :server_year_log
- @spec update_server_year_log(ServerYearLog, map) ::
- {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_server_year_log(server_year_log, attrs), to: ServerYearLogLib
-
- @doc section: :server_year_log
- @spec delete_server_year_log(ServerYearLog.t()) ::
- {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_server_year_log(server_year_log), to: ServerYearLogLib
-
- @doc section: :server_year_log
- @spec change_server_year_log(ServerYearLog.t()) :: Ecto.Changeset.t()
- @spec change_server_year_log(ServerYearLog.t(), map) :: Ecto.Changeset.t()
- defdelegate change_server_year_log(server_year_log, attrs \\ %{}), to: ServerYearLogLib
end
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
deleted file mode 100644
index 3840da4cc..000000000
--- a/lib/teiserver/contexts/telemetry.ex
+++ /dev/null
@@ -1,60 +0,0 @@
-defmodule Teiserver.Telemetry do
- @moduledoc """
- This page is a reference for the Telemetry data functions. For a guide on how to use the Telemetry features please refer to the [telemetry guide](guides/telemetry_events.md).
-
- The contextual module for:
- - `Teiserver.Telemetry.EventType`
-
- - `Teiserver.Telemetry.SimpleGameEvent`
- - `Teiserver.Telemetry.SimpleServerEvent`
- - `Teiserver.Telemetry.SimpleLobbyEvent`
- - `Teiserver.Telemetry.SimpleUserEvent`
- - `Teiserver.Telemetry.SimpleClientEvent`
- - `Teiserver.Telemetry.SimpleAnonEvent`
-
- - `Teiserver.Telemetry.ComplexGameEvent`
- - `Teiserver.Telemetry.ComplexServerEvent`
- - `Teiserver.Telemetry.ComplexLobbyEvent`
- - `Teiserver.Telemetry.ComplexUserEvent`
- - `Teiserver.Telemetry.ComplexClientEvent`
- - `Teiserver.Telemetry.ComplexAnonEvent`
- """
-
- # EventTypes
- alias Teiserver.Telemetry.{EventType, EventTypeLib, EventTypeQueries}
-
- @doc false
- @spec event_type_query(Teiserver.query_args()) :: Ecto.Query.t()
- defdelegate event_type_query(args), to: EventTypeQueries
-
- @doc section: :event_type
- @spec list_event_types(Teiserver.query_args()) :: [EventType.t()]
- defdelegate list_event_types(args), to: EventTypeLib
-
- @doc section: :event_type
- @spec get_event_type!(EventType.id()) :: EventType.t()
- @spec get_event_type!(EventType.id(), Teiserver.query_args()) :: EventType.t()
- defdelegate get_event_type!(event_type_id, query_args \\ []), to: EventTypeLib
-
- @doc section: :event_type
- @spec get_event_type(EventType.id()) :: EventType.t() | nil
- @spec get_event_type(EventType.id(), Teiserver.query_args()) :: EventType.t() | nil
- defdelegate get_event_type(event_type_id, query_args \\ []), to: EventTypeLib
-
- @doc section: :event_type
- @spec create_event_type(map) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_event_type(attrs), to: EventTypeLib
-
- @doc section: :event_type
- @spec update_event_type(EventType, map) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
- defdelegate update_event_type(event_type, attrs), to: EventTypeLib
-
- @doc section: :event_type
- @spec delete_event_type(EventType.t()) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
- defdelegate delete_event_type(event_type), to: EventTypeLib
-
- @doc section: :event_type
- @spec change_event_type(EventType.t()) :: Ecto.Changeset.t()
- @spec change_event_type(EventType.t(), map) :: Ecto.Changeset.t()
- defdelegate change_event_type(event_type, attrs \\ %{}), to: EventTypeLib
-end
diff --git a/lib/teiserver/logging/libs/match_day_log_lib.ex b/lib/teiserver/logging/libs/match_day_log_lib.ex
deleted file mode 100644
index 3bb8793dc..000000000
--- a/lib/teiserver/logging/libs/match_day_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.MatchDayLogLib do
- @moduledoc """
- Library of match_day_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{MatchDayLog, MatchDayLogQueries}
-
- @doc """
- Returns the list of match_day_logs.
-
- ## Examples
-
- iex> list_match_day_logs()
- [%MatchDayLog{}, ...]
-
- """
- @spec list_match_day_logs(Teiserver.query_args()) :: [MatchDayLog.t()]
- def list_match_day_logs(query_args) do
- query_args
- |> MatchDayLogQueries.match_day_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single match_day_log.
-
- Raises `Ecto.NoResultsError` if the MatchDayLog does not exist.
-
- ## Examples
-
- iex> get_match_day_log!(123)
- %MatchDayLog{}
-
- iex> get_match_day_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_match_day_log!(Date.t()) :: MatchDayLog.t()
- @spec get_match_day_log!(Date.t(), Teiserver.query_args()) :: MatchDayLog.t()
- def get_match_day_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchDayLogQueries.match_day_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single match_day_log.
-
- Returns nil if the MatchDayLog does not exist.
-
- ## Examples
-
- iex> get_match_day_log(123)
- %MatchDayLog{}
-
- iex> get_match_day_log(456)
- nil
-
- """
- @spec get_match_day_log(Date.t()) :: MatchDayLog.t() | nil
- @spec get_match_day_log(Date.t(), Teiserver.query_args()) :: MatchDayLog.t() | nil
- def get_match_day_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchDayLogQueries.match_day_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a match_day_log.
-
- ## Examples
-
- iex> create_match_day_log(%{field: value})
- {:ok, %MatchDayLog{}}
-
- iex> create_match_day_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_match_day_log(map) :: {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
- def create_match_day_log(attrs) do
- %MatchDayLog{}
- |> MatchDayLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a match_day_log.
-
- ## Examples
-
- iex> update_match_day_log(match_day_log, %{field: new_value})
- {:ok, %MatchDayLog{}}
-
- iex> update_match_day_log(match_day_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_match_day_log(MatchDayLog.t(), map) ::
- {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
- def update_match_day_log(%MatchDayLog{} = match_day_log, attrs) do
- match_day_log
- |> MatchDayLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a match_day_log.
-
- ## Examples
-
- iex> delete_match_day_log(match_day_log)
- {:ok, %MatchDayLog{}}
-
- iex> delete_match_day_log(match_day_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_match_day_log(MatchDayLog.t()) ::
- {:ok, MatchDayLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_match_day_log(%MatchDayLog{} = match_day_log) do
- Repo.delete(match_day_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking match_day_log changes.
-
- ## Examples
-
- iex> change_match_day_log(match_day_log)
- %Ecto.Changeset{data: %MatchDayLog{}}
-
- """
- @spec change_match_day_log(MatchDayLog.t(), map) :: Ecto.Changeset.t()
- def change_match_day_log(%MatchDayLog{} = match_day_log, attrs \\ %{}) do
- MatchDayLog.changeset(match_day_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/match_minute_log_lib.ex b/lib/teiserver/logging/libs/match_minute_log_lib.ex
deleted file mode 100644
index 1dc267eab..000000000
--- a/lib/teiserver/logging/libs/match_minute_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.MatchMinuteLogLib do
- @moduledoc """
- Library of match_minute_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{MatchMinuteLog, MatchMinuteLogQueries}
-
- @doc """
- Returns the list of match_minute_logs.
-
- ## Examples
-
- iex> list_match_minute_logs()
- [%MatchMinuteLog{}, ...]
-
- """
- @spec list_match_minute_logs(Teiserver.query_args()) :: [MatchMinuteLog.t()]
- def list_match_minute_logs(query_args) do
- query_args
- |> MatchMinuteLogQueries.match_minute_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single match_minute_log.
-
- Raises `Ecto.NoResultsError` if the MatchMinuteLog does not exist.
-
- ## Examples
-
- iex> get_match_minute_log!(123)
- %MatchMinuteLog{}
-
- iex> get_match_minute_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_match_minute_log!(DateTime.t()) :: MatchMinuteLog.t()
- @spec get_match_minute_log!(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t()
- def get_match_minute_log!(timestamp, query_args \\ []) do
- (query_args ++ [timestamp: timestamp])
- |> MatchMinuteLogQueries.match_minute_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single match_minute_log.
-
- Returns nil if the MatchMinuteLog does not exist.
-
- ## Examples
-
- iex> get_match_minute_log(123)
- %MatchMinuteLog{}
-
- iex> get_match_minute_log(456)
- nil
-
- """
- @spec get_match_minute_log(DateTime.t()) :: MatchMinuteLog.t() | nil
- @spec get_match_minute_log(DateTime.t(), Teiserver.query_args()) :: MatchMinuteLog.t() | nil
- def get_match_minute_log(timestamp, query_args \\ []) do
- (query_args ++ [timestamp: timestamp])
- |> MatchMinuteLogQueries.match_minute_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a match_minute_log.
-
- ## Examples
-
- iex> create_match_minute_log(%{field: value})
- {:ok, %MatchMinuteLog{}}
-
- iex> create_match_minute_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_match_minute_log(map) :: {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- def create_match_minute_log(attrs) do
- %MatchMinuteLog{}
- |> MatchMinuteLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a match_minute_log.
-
- ## Examples
-
- iex> update_match_minute_log(match_minute_log, %{field: new_value})
- {:ok, %MatchMinuteLog{}}
-
- iex> update_match_minute_log(match_minute_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_match_minute_log(MatchMinuteLog.t(), map) ::
- {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- def update_match_minute_log(%MatchMinuteLog{} = match_minute_log, attrs) do
- match_minute_log
- |> MatchMinuteLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a match_minute_log.
-
- ## Examples
-
- iex> delete_match_minute_log(match_minute_log)
- {:ok, %MatchMinuteLog{}}
-
- iex> delete_match_minute_log(match_minute_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_match_minute_log(MatchMinuteLog.t()) ::
- {:ok, MatchMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_match_minute_log(%MatchMinuteLog{} = match_minute_log) do
- Repo.delete(match_minute_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking match_minute_log changes.
-
- ## Examples
-
- iex> change_match_minute_log(match_minute_log)
- %Ecto.Changeset{data: %MatchMinuteLog{}}
-
- """
- @spec change_match_minute_log(MatchMinuteLog.t(), map) :: Ecto.Changeset.t()
- def change_match_minute_log(%MatchMinuteLog{} = match_minute_log, attrs \\ %{}) do
- MatchMinuteLog.changeset(match_minute_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/match_month_log_lib.ex b/lib/teiserver/logging/libs/match_month_log_lib.ex
deleted file mode 100644
index 9e55aa87d..000000000
--- a/lib/teiserver/logging/libs/match_month_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.MatchMonthLogLib do
- @moduledoc """
- Library of match_month_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{MatchMonthLog, MatchMonthLogQueries}
-
- @doc """
- Returns the list of match_month_logs.
-
- ## Examples
-
- iex> list_match_month_logs()
- [%MatchMonthLog{}, ...]
-
- """
- @spec list_match_month_logs(Teiserver.query_args()) :: [MatchMonthLog.t()]
- def list_match_month_logs(query_args) do
- query_args
- |> MatchMonthLogQueries.match_month_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single match_month_log.
-
- Raises `Ecto.NoResultsError` if the MatchMonthLog does not exist.
-
- ## Examples
-
- iex> get_match_month_log!(123)
- %MatchMonthLog{}
-
- iex> get_match_month_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_match_month_log!(Date.t()) :: MatchMonthLog.t()
- @spec get_match_month_log!(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t()
- def get_match_month_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchMonthLogQueries.match_month_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single match_month_log.
-
- Returns nil if the MatchMonthLog does not exist.
-
- ## Examples
-
- iex> get_match_month_log(123)
- %MatchMonthLog{}
-
- iex> get_match_month_log(456)
- nil
-
- """
- @spec get_match_month_log(Date.t()) :: MatchMonthLog.t() | nil
- @spec get_match_month_log(Date.t(), Teiserver.query_args()) :: MatchMonthLog.t() | nil
- def get_match_month_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchMonthLogQueries.match_month_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a match_month_log.
-
- ## Examples
-
- iex> create_match_month_log(%{field: value})
- {:ok, %MatchMonthLog{}}
-
- iex> create_match_month_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_match_month_log(map) :: {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
- def create_match_month_log(attrs) do
- %MatchMonthLog{}
- |> MatchMonthLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a match_month_log.
-
- ## Examples
-
- iex> update_match_month_log(match_month_log, %{field: new_value})
- {:ok, %MatchMonthLog{}}
-
- iex> update_match_month_log(match_month_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_match_month_log(MatchMonthLog.t(), map) ::
- {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
- def update_match_month_log(%MatchMonthLog{} = match_month_log, attrs) do
- match_month_log
- |> MatchMonthLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a match_month_log.
-
- ## Examples
-
- iex> delete_match_month_log(match_month_log)
- {:ok, %MatchMonthLog{}}
-
- iex> delete_match_month_log(match_month_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_match_month_log(MatchMonthLog.t()) ::
- {:ok, MatchMonthLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_match_month_log(%MatchMonthLog{} = match_month_log) do
- Repo.delete(match_month_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking match_month_log changes.
-
- ## Examples
-
- iex> change_match_month_log(match_month_log)
- %Ecto.Changeset{data: %MatchMonthLog{}}
-
- """
- @spec change_match_month_log(MatchMonthLog.t(), map) :: Ecto.Changeset.t()
- def change_match_month_log(%MatchMonthLog{} = match_month_log, attrs \\ %{}) do
- MatchMonthLog.changeset(match_month_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/match_quarter_log_lib.ex b/lib/teiserver/logging/libs/match_quarter_log_lib.ex
deleted file mode 100644
index c2233d2e2..000000000
--- a/lib/teiserver/logging/libs/match_quarter_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.MatchQuarterLogLib do
- @moduledoc """
- Library of match_quarter_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{MatchQuarterLog, MatchQuarterLogQueries}
-
- @doc """
- Returns the list of match_quarter_logs.
-
- ## Examples
-
- iex> list_match_quarter_logs()
- [%MatchQuarterLog{}, ...]
-
- """
- @spec list_match_quarter_logs(Teiserver.query_args()) :: [MatchQuarterLog.t()]
- def list_match_quarter_logs(query_args) do
- query_args
- |> MatchQuarterLogQueries.match_quarter_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single match_quarter_log.
-
- Raises `Ecto.NoResultsError` if the MatchQuarterLog does not exist.
-
- ## Examples
-
- iex> get_match_quarter_log!(123)
- %MatchQuarterLog{}
-
- iex> get_match_quarter_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_match_quarter_log!(Date.t()) :: MatchQuarterLog.t()
- @spec get_match_quarter_log!(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t()
- def get_match_quarter_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchQuarterLogQueries.match_quarter_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single match_quarter_log.
-
- Returns nil if the MatchQuarterLog does not exist.
-
- ## Examples
-
- iex> get_match_quarter_log(123)
- %MatchQuarterLog{}
-
- iex> get_match_quarter_log(456)
- nil
-
- """
- @spec get_match_quarter_log(Date.t()) :: MatchQuarterLog.t() | nil
- @spec get_match_quarter_log(Date.t(), Teiserver.query_args()) :: MatchQuarterLog.t() | nil
- def get_match_quarter_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchQuarterLogQueries.match_quarter_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a match_quarter_log.
-
- ## Examples
-
- iex> create_match_quarter_log(%{field: value})
- {:ok, %MatchQuarterLog{}}
-
- iex> create_match_quarter_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_match_quarter_log(map) :: {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- def create_match_quarter_log(attrs) do
- %MatchQuarterLog{}
- |> MatchQuarterLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a match_quarter_log.
-
- ## Examples
-
- iex> update_match_quarter_log(match_quarter_log, %{field: new_value})
- {:ok, %MatchQuarterLog{}}
-
- iex> update_match_quarter_log(match_quarter_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_match_quarter_log(MatchQuarterLog.t(), map) ::
- {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- def update_match_quarter_log(%MatchQuarterLog{} = match_quarter_log, attrs) do
- match_quarter_log
- |> MatchQuarterLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a match_quarter_log.
-
- ## Examples
-
- iex> delete_match_quarter_log(match_quarter_log)
- {:ok, %MatchQuarterLog{}}
-
- iex> delete_match_quarter_log(match_quarter_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_match_quarter_log(MatchQuarterLog.t()) ::
- {:ok, MatchQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_match_quarter_log(%MatchQuarterLog{} = match_quarter_log) do
- Repo.delete(match_quarter_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking match_quarter_log changes.
-
- ## Examples
-
- iex> change_match_quarter_log(match_quarter_log)
- %Ecto.Changeset{data: %MatchQuarterLog{}}
-
- """
- @spec change_match_quarter_log(MatchQuarterLog.t(), map) :: Ecto.Changeset.t()
- def change_match_quarter_log(%MatchQuarterLog{} = match_quarter_log, attrs \\ %{}) do
- MatchQuarterLog.changeset(match_quarter_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/match_week_log_lib.ex b/lib/teiserver/logging/libs/match_week_log_lib.ex
deleted file mode 100644
index eb4fe16a0..000000000
--- a/lib/teiserver/logging/libs/match_week_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.MatchWeekLogLib do
- @moduledoc """
- Library of match_week_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{MatchWeekLog, MatchWeekLogQueries}
-
- @doc """
- Returns the list of match_week_logs.
-
- ## Examples
-
- iex> list_match_week_logs()
- [%MatchWeekLog{}, ...]
-
- """
- @spec list_match_week_logs(Teiserver.query_args()) :: [MatchWeekLog.t()]
- def list_match_week_logs(query_args) do
- query_args
- |> MatchWeekLogQueries.match_week_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single match_week_log.
-
- Raises `Ecto.NoResultsError` if the MatchWeekLog does not exist.
-
- ## Examples
-
- iex> get_match_week_log!(123)
- %MatchWeekLog{}
-
- iex> get_match_week_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_match_week_log!(Date.t()) :: MatchWeekLog.t()
- @spec get_match_week_log!(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t()
- def get_match_week_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchWeekLogQueries.match_week_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single match_week_log.
-
- Returns nil if the MatchWeekLog does not exist.
-
- ## Examples
-
- iex> get_match_week_log(123)
- %MatchWeekLog{}
-
- iex> get_match_week_log(456)
- nil
-
- """
- @spec get_match_week_log(Date.t()) :: MatchWeekLog.t() | nil
- @spec get_match_week_log(Date.t(), Teiserver.query_args()) :: MatchWeekLog.t() | nil
- def get_match_week_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchWeekLogQueries.match_week_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a match_week_log.
-
- ## Examples
-
- iex> create_match_week_log(%{field: value})
- {:ok, %MatchWeekLog{}}
-
- iex> create_match_week_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_match_week_log(map) :: {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
- def create_match_week_log(attrs) do
- %MatchWeekLog{}
- |> MatchWeekLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a match_week_log.
-
- ## Examples
-
- iex> update_match_week_log(match_week_log, %{field: new_value})
- {:ok, %MatchWeekLog{}}
-
- iex> update_match_week_log(match_week_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_match_week_log(MatchWeekLog.t(), map) ::
- {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
- def update_match_week_log(%MatchWeekLog{} = match_week_log, attrs) do
- match_week_log
- |> MatchWeekLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a match_week_log.
-
- ## Examples
-
- iex> delete_match_week_log(match_week_log)
- {:ok, %MatchWeekLog{}}
-
- iex> delete_match_week_log(match_week_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_match_week_log(MatchWeekLog.t()) ::
- {:ok, MatchWeekLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_match_week_log(%MatchWeekLog{} = match_week_log) do
- Repo.delete(match_week_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking match_week_log changes.
-
- ## Examples
-
- iex> change_match_week_log(match_week_log)
- %Ecto.Changeset{data: %MatchWeekLog{}}
-
- """
- @spec change_match_week_log(MatchWeekLog.t(), map) :: Ecto.Changeset.t()
- def change_match_week_log(%MatchWeekLog{} = match_week_log, attrs \\ %{}) do
- MatchWeekLog.changeset(match_week_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/match_year_log_lib.ex b/lib/teiserver/logging/libs/match_year_log_lib.ex
deleted file mode 100644
index f06995d44..000000000
--- a/lib/teiserver/logging/libs/match_year_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.MatchYearLogLib do
- @moduledoc """
- Library of match_year_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{MatchYearLog, MatchYearLogQueries}
-
- @doc """
- Returns the list of match_year_logs.
-
- ## Examples
-
- iex> list_match_year_logs()
- [%MatchYearLog{}, ...]
-
- """
- @spec list_match_year_logs(Teiserver.query_args()) :: [MatchYearLog.t()]
- def list_match_year_logs(query_args) do
- query_args
- |> MatchYearLogQueries.match_year_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single match_year_log.
-
- Raises `Ecto.NoResultsError` if the MatchYearLog does not exist.
-
- ## Examples
-
- iex> get_match_year_log!(123)
- %MatchYearLog{}
-
- iex> get_match_year_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_match_year_log!(Date.t()) :: MatchYearLog.t()
- @spec get_match_year_log!(Date.t(), Teiserver.query_args()) :: MatchYearLog.t()
- def get_match_year_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchYearLogQueries.match_year_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single match_year_log.
-
- Returns nil if the MatchYearLog does not exist.
-
- ## Examples
-
- iex> get_match_year_log(123)
- %MatchYearLog{}
-
- iex> get_match_year_log(456)
- nil
-
- """
- @spec get_match_year_log(Date.t()) :: MatchYearLog.t() | nil
- @spec get_match_year_log(Date.t(), Teiserver.query_args()) :: MatchYearLog.t() | nil
- def get_match_year_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> MatchYearLogQueries.match_year_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a match_year_log.
-
- ## Examples
-
- iex> create_match_year_log(%{field: value})
- {:ok, %MatchYearLog{}}
-
- iex> create_match_year_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_match_year_log(map) :: {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
- def create_match_year_log(attrs) do
- %MatchYearLog{}
- |> MatchYearLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a match_year_log.
-
- ## Examples
-
- iex> update_match_year_log(match_year_log, %{field: new_value})
- {:ok, %MatchYearLog{}}
-
- iex> update_match_year_log(match_year_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_match_year_log(MatchYearLog.t(), map) ::
- {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
- def update_match_year_log(%MatchYearLog{} = match_year_log, attrs) do
- match_year_log
- |> MatchYearLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a match_year_log.
-
- ## Examples
-
- iex> delete_match_year_log(match_year_log)
- {:ok, %MatchYearLog{}}
-
- iex> delete_match_year_log(match_year_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_match_year_log(MatchYearLog.t()) ::
- {:ok, MatchYearLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_match_year_log(%MatchYearLog{} = match_year_log) do
- Repo.delete(match_year_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking match_year_log changes.
-
- ## Examples
-
- iex> change_match_year_log(match_year_log)
- %Ecto.Changeset{data: %MatchYearLog{}}
-
- """
- @spec change_match_year_log(MatchYearLog.t(), map) :: Ecto.Changeset.t()
- def change_match_year_log(%MatchYearLog{} = match_year_log, attrs \\ %{}) do
- MatchYearLog.changeset(match_year_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/server_day_log_lib.ex b/lib/teiserver/logging/libs/server_day_log_lib.ex
deleted file mode 100644
index cde25403b..000000000
--- a/lib/teiserver/logging/libs/server_day_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.ServerDayLogLib do
- @moduledoc """
- Library of server_day_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{ServerDayLog, ServerDayLogQueries}
-
- @doc """
- Returns the list of server_day_logs.
-
- ## Examples
-
- iex> list_server_day_logs()
- [%ServerDayLog{}, ...]
-
- """
- @spec list_server_day_logs(Teiserver.query_args()) :: [ServerDayLog.t()]
- def list_server_day_logs(query_args) do
- query_args
- |> ServerDayLogQueries.server_day_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single server_day_log.
-
- Raises `Ecto.NoResultsError` if the ServerDayLog does not exist.
-
- ## Examples
-
- iex> get_server_day_log!(123)
- %ServerDayLog{}
-
- iex> get_server_day_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_server_day_log!(Date.t()) :: ServerDayLog.t()
- @spec get_server_day_log!(Date.t(), Teiserver.query_args()) :: ServerDayLog.t()
- def get_server_day_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerDayLogQueries.server_day_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single server_day_log.
-
- Returns nil if the ServerDayLog does not exist.
-
- ## Examples
-
- iex> get_server_day_log(123)
- %ServerDayLog{}
-
- iex> get_server_day_log(456)
- nil
-
- """
- @spec get_server_day_log(Date.t()) :: ServerDayLog.t() | nil
- @spec get_server_day_log(Date.t(), Teiserver.query_args()) :: ServerDayLog.t() | nil
- def get_server_day_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerDayLogQueries.server_day_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a server_day_log.
-
- ## Examples
-
- iex> create_server_day_log(%{field: value})
- {:ok, %ServerDayLog{}}
-
- iex> create_server_day_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_server_day_log(map) :: {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
- def create_server_day_log(attrs) do
- %ServerDayLog{}
- |> ServerDayLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a server_day_log.
-
- ## Examples
-
- iex> update_server_day_log(server_day_log, %{field: new_value})
- {:ok, %ServerDayLog{}}
-
- iex> update_server_day_log(server_day_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_server_day_log(ServerDayLog.t(), map) ::
- {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
- def update_server_day_log(%ServerDayLog{} = server_day_log, attrs) do
- server_day_log
- |> ServerDayLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a server_day_log.
-
- ## Examples
-
- iex> delete_server_day_log(server_day_log)
- {:ok, %ServerDayLog{}}
-
- iex> delete_server_day_log(server_day_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_server_day_log(ServerDayLog.t()) ::
- {:ok, ServerDayLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_server_day_log(%ServerDayLog{} = server_day_log) do
- Repo.delete(server_day_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking server_day_log changes.
-
- ## Examples
-
- iex> change_server_day_log(server_day_log)
- %Ecto.Changeset{data: %ServerDayLog{}}
-
- """
- @spec change_server_day_log(ServerDayLog.t(), map) :: Ecto.Changeset.t()
- def change_server_day_log(%ServerDayLog{} = server_day_log, attrs \\ %{}) do
- ServerDayLog.changeset(server_day_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/server_minute_log_lib.ex b/lib/teiserver/logging/libs/server_minute_log_lib.ex
deleted file mode 100644
index e1f50e4a6..000000000
--- a/lib/teiserver/logging/libs/server_minute_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.ServerMinuteLogLib do
- @moduledoc """
- Library of server_minute_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{ServerMinuteLog, ServerMinuteLogQueries}
-
- @doc """
- Returns the list of server_minute_logs.
-
- ## Examples
-
- iex> list_server_minute_logs()
- [%ServerMinuteLog{}, ...]
-
- """
- @spec list_server_minute_logs(Teiserver.query_args()) :: [ServerMinuteLog.t()]
- def list_server_minute_logs(query_args) do
- query_args
- |> ServerMinuteLogQueries.server_minute_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single server_minute_log.
-
- Raises `Ecto.NoResultsError` if the ServerMinuteLog does not exist.
-
- ## Examples
-
- iex> get_server_minute_log!(123)
- %ServerMinuteLog{}
-
- iex> get_server_minute_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_server_minute_log!(DateTime.t()) :: ServerMinuteLog.t()
- @spec get_server_minute_log!(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t()
- def get_server_minute_log!(timestamp, query_args \\ []) do
- (query_args ++ [timestamp: timestamp])
- |> ServerMinuteLogQueries.server_minute_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single server_minute_log.
-
- Returns nil if the ServerMinuteLog does not exist.
-
- ## Examples
-
- iex> get_server_minute_log(123)
- %ServerMinuteLog{}
-
- iex> get_server_minute_log(456)
- nil
-
- """
- @spec get_server_minute_log(DateTime.t()) :: ServerMinuteLog.t() | nil
- @spec get_server_minute_log(DateTime.t(), Teiserver.query_args()) :: ServerMinuteLog.t() | nil
- def get_server_minute_log(timestamp, query_args \\ []) do
- (query_args ++ [timestamp: timestamp])
- |> ServerMinuteLogQueries.server_minute_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a server_minute_log.
-
- ## Examples
-
- iex> create_server_minute_log(%{field: value})
- {:ok, %ServerMinuteLog{}}
-
- iex> create_server_minute_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_server_minute_log(map) :: {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- def create_server_minute_log(attrs) do
- %ServerMinuteLog{}
- |> ServerMinuteLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a server_minute_log.
-
- ## Examples
-
- iex> update_server_minute_log(server_minute_log, %{field: new_value})
- {:ok, %ServerMinuteLog{}}
-
- iex> update_server_minute_log(server_minute_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_server_minute_log(ServerMinuteLog.t(), map) ::
- {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- def update_server_minute_log(%ServerMinuteLog{} = server_minute_log, attrs) do
- server_minute_log
- |> ServerMinuteLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a server_minute_log.
-
- ## Examples
-
- iex> delete_server_minute_log(server_minute_log)
- {:ok, %ServerMinuteLog{}}
-
- iex> delete_server_minute_log(server_minute_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_server_minute_log(ServerMinuteLog.t()) ::
- {:ok, ServerMinuteLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_server_minute_log(%ServerMinuteLog{} = server_minute_log) do
- Repo.delete(server_minute_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking server_minute_log changes.
-
- ## Examples
-
- iex> change_server_minute_log(server_minute_log)
- %Ecto.Changeset{data: %ServerMinuteLog{}}
-
- """
- @spec change_server_minute_log(ServerMinuteLog.t(), map) :: Ecto.Changeset.t()
- def change_server_minute_log(%ServerMinuteLog{} = server_minute_log, attrs \\ %{}) do
- ServerMinuteLog.changeset(server_minute_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/server_month_log_lib.ex b/lib/teiserver/logging/libs/server_month_log_lib.ex
deleted file mode 100644
index 7ef21b4ad..000000000
--- a/lib/teiserver/logging/libs/server_month_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.ServerMonthLogLib do
- @moduledoc """
- Library of server_month_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{ServerMonthLog, ServerMonthLogQueries}
-
- @doc """
- Returns the list of server_month_logs.
-
- ## Examples
-
- iex> list_server_month_logs()
- [%ServerMonthLog{}, ...]
-
- """
- @spec list_server_month_logs(Teiserver.query_args()) :: [ServerMonthLog.t()]
- def list_server_month_logs(query_args) do
- query_args
- |> ServerMonthLogQueries.server_month_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single server_month_log.
-
- Raises `Ecto.NoResultsError` if the ServerMonthLog does not exist.
-
- ## Examples
-
- iex> get_server_month_log!(123)
- %ServerMonthLog{}
-
- iex> get_server_month_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_server_month_log!(Date.t()) :: ServerMonthLog.t()
- @spec get_server_month_log!(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t()
- def get_server_month_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerMonthLogQueries.server_month_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single server_month_log.
-
- Returns nil if the ServerMonthLog does not exist.
-
- ## Examples
-
- iex> get_server_month_log(123)
- %ServerMonthLog{}
-
- iex> get_server_month_log(456)
- nil
-
- """
- @spec get_server_month_log(Date.t()) :: ServerMonthLog.t() | nil
- @spec get_server_month_log(Date.t(), Teiserver.query_args()) :: ServerMonthLog.t() | nil
- def get_server_month_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerMonthLogQueries.server_month_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a server_month_log.
-
- ## Examples
-
- iex> create_server_month_log(%{field: value})
- {:ok, %ServerMonthLog{}}
-
- iex> create_server_month_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_server_month_log(map) :: {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
- def create_server_month_log(attrs) do
- %ServerMonthLog{}
- |> ServerMonthLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a server_month_log.
-
- ## Examples
-
- iex> update_server_month_log(server_month_log, %{field: new_value})
- {:ok, %ServerMonthLog{}}
-
- iex> update_server_month_log(server_month_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_server_month_log(ServerMonthLog.t(), map) ::
- {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
- def update_server_month_log(%ServerMonthLog{} = server_month_log, attrs) do
- server_month_log
- |> ServerMonthLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a server_month_log.
-
- ## Examples
-
- iex> delete_server_month_log(server_month_log)
- {:ok, %ServerMonthLog{}}
-
- iex> delete_server_month_log(server_month_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_server_month_log(ServerMonthLog.t()) ::
- {:ok, ServerMonthLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_server_month_log(%ServerMonthLog{} = server_month_log) do
- Repo.delete(server_month_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking server_month_log changes.
-
- ## Examples
-
- iex> change_server_month_log(server_month_log)
- %Ecto.Changeset{data: %ServerMonthLog{}}
-
- """
- @spec change_server_month_log(ServerMonthLog.t(), map) :: Ecto.Changeset.t()
- def change_server_month_log(%ServerMonthLog{} = server_month_log, attrs \\ %{}) do
- ServerMonthLog.changeset(server_month_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/server_quarter_log_lib.ex b/lib/teiserver/logging/libs/server_quarter_log_lib.ex
deleted file mode 100644
index 9e83f3cfd..000000000
--- a/lib/teiserver/logging/libs/server_quarter_log_lib.ex
+++ /dev/null
@@ -1,139 +0,0 @@
-defmodule Teiserver.Logging.ServerQuarterLogLib do
- @moduledoc """
- Library of server_quarter_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{ServerQuarterLog, ServerQuarterLogQueries}
-
- @doc """
- Returns the list of server_quarter_logs.
-
- ## Examples
-
- iex> list_server_quarter_logs()
- [%ServerQuarterLog{}, ...]
-
- """
- @spec list_server_quarter_logs(Teiserver.query_args()) :: [ServerQuarterLog.t()]
- def list_server_quarter_logs(query_args) do
- query_args
- |> ServerQuarterLogQueries.server_quarter_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single server_quarter_log.
-
- Raises `Ecto.NoResultsError` if the ServerQuarterLog does not exist.
-
- ## Examples
-
- iex> get_server_quarter_log!(123)
- %ServerQuarterLog{}
-
- iex> get_server_quarter_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_server_quarter_log!(Date.t()) :: ServerQuarterLog.t()
- @spec get_server_quarter_log!(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t()
- def get_server_quarter_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerQuarterLogQueries.server_quarter_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single server_quarter_log.
-
- Returns nil if the ServerQuarterLog does not exist.
-
- ## Examples
-
- iex> get_server_quarter_log(123)
- %ServerQuarterLog{}
-
- iex> get_server_quarter_log(456)
- nil
-
- """
- @spec get_server_quarter_log(Date.t()) :: ServerQuarterLog.t() | nil
- @spec get_server_quarter_log(Date.t(), Teiserver.query_args()) :: ServerQuarterLog.t() | nil
- def get_server_quarter_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerQuarterLogQueries.server_quarter_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a server_quarter_log.
-
- ## Examples
-
- iex> create_server_quarter_log(%{field: value})
- {:ok, %ServerQuarterLog{}}
-
- iex> create_server_quarter_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_server_quarter_log(map) ::
- {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- def create_server_quarter_log(attrs) do
- %ServerQuarterLog{}
- |> ServerQuarterLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a server_quarter_log.
-
- ## Examples
-
- iex> update_server_quarter_log(server_quarter_log, %{field: new_value})
- {:ok, %ServerQuarterLog{}}
-
- iex> update_server_quarter_log(server_quarter_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_server_quarter_log(ServerQuarterLog.t(), map) ::
- {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- def update_server_quarter_log(%ServerQuarterLog{} = server_quarter_log, attrs) do
- server_quarter_log
- |> ServerQuarterLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a server_quarter_log.
-
- ## Examples
-
- iex> delete_server_quarter_log(server_quarter_log)
- {:ok, %ServerQuarterLog{}}
-
- iex> delete_server_quarter_log(server_quarter_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_server_quarter_log(ServerQuarterLog.t()) ::
- {:ok, ServerQuarterLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_server_quarter_log(%ServerQuarterLog{} = server_quarter_log) do
- Repo.delete(server_quarter_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking server_quarter_log changes.
-
- ## Examples
-
- iex> change_server_quarter_log(server_quarter_log)
- %Ecto.Changeset{data: %ServerQuarterLog{}}
-
- """
- @spec change_server_quarter_log(ServerQuarterLog.t(), map) :: Ecto.Changeset.t()
- def change_server_quarter_log(%ServerQuarterLog{} = server_quarter_log, attrs \\ %{}) do
- ServerQuarterLog.changeset(server_quarter_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/server_week_log_lib.ex b/lib/teiserver/logging/libs/server_week_log_lib.ex
deleted file mode 100644
index cdf5319ff..000000000
--- a/lib/teiserver/logging/libs/server_week_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.ServerWeekLogLib do
- @moduledoc """
- Library of server_week_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{ServerWeekLog, ServerWeekLogQueries}
-
- @doc """
- Returns the list of server_week_logs.
-
- ## Examples
-
- iex> list_server_week_logs()
- [%ServerWeekLog{}, ...]
-
- """
- @spec list_server_week_logs(Teiserver.query_args()) :: [ServerWeekLog.t()]
- def list_server_week_logs(query_args) do
- query_args
- |> ServerWeekLogQueries.server_week_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single server_week_log.
-
- Raises `Ecto.NoResultsError` if the ServerWeekLog does not exist.
-
- ## Examples
-
- iex> get_server_week_log!(123)
- %ServerWeekLog{}
-
- iex> get_server_week_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_server_week_log!(Date.t()) :: ServerWeekLog.t()
- @spec get_server_week_log!(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t()
- def get_server_week_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerWeekLogQueries.server_week_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single server_week_log.
-
- Returns nil if the ServerWeekLog does not exist.
-
- ## Examples
-
- iex> get_server_week_log(123)
- %ServerWeekLog{}
-
- iex> get_server_week_log(456)
- nil
-
- """
- @spec get_server_week_log(Date.t()) :: ServerWeekLog.t() | nil
- @spec get_server_week_log(Date.t(), Teiserver.query_args()) :: ServerWeekLog.t() | nil
- def get_server_week_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerWeekLogQueries.server_week_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a server_week_log.
-
- ## Examples
-
- iex> create_server_week_log(%{field: value})
- {:ok, %ServerWeekLog{}}
-
- iex> create_server_week_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_server_week_log(map) :: {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
- def create_server_week_log(attrs) do
- %ServerWeekLog{}
- |> ServerWeekLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a server_week_log.
-
- ## Examples
-
- iex> update_server_week_log(server_week_log, %{field: new_value})
- {:ok, %ServerWeekLog{}}
-
- iex> update_server_week_log(server_week_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_server_week_log(ServerWeekLog.t(), map) ::
- {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
- def update_server_week_log(%ServerWeekLog{} = server_week_log, attrs) do
- server_week_log
- |> ServerWeekLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a server_week_log.
-
- ## Examples
-
- iex> delete_server_week_log(server_week_log)
- {:ok, %ServerWeekLog{}}
-
- iex> delete_server_week_log(server_week_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_server_week_log(ServerWeekLog.t()) ::
- {:ok, ServerWeekLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_server_week_log(%ServerWeekLog{} = server_week_log) do
- Repo.delete(server_week_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking server_week_log changes.
-
- ## Examples
-
- iex> change_server_week_log(server_week_log)
- %Ecto.Changeset{data: %ServerWeekLog{}}
-
- """
- @spec change_server_week_log(ServerWeekLog.t(), map) :: Ecto.Changeset.t()
- def change_server_week_log(%ServerWeekLog{} = server_week_log, attrs \\ %{}) do
- ServerWeekLog.changeset(server_week_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/libs/server_year_log_lib.ex b/lib/teiserver/logging/libs/server_year_log_lib.ex
deleted file mode 100644
index b77fc5bbb..000000000
--- a/lib/teiserver/logging/libs/server_year_log_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.Logging.ServerYearLogLib do
- @moduledoc """
- Library of server_year_log related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Logging.{ServerYearLog, ServerYearLogQueries}
-
- @doc """
- Returns the list of server_year_logs.
-
- ## Examples
-
- iex> list_server_year_logs()
- [%ServerYearLog{}, ...]
-
- """
- @spec list_server_year_logs(Teiserver.query_args()) :: [ServerYearLog.t()]
- def list_server_year_logs(query_args) do
- query_args
- |> ServerYearLogQueries.server_year_log_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single server_year_log.
-
- Raises `Ecto.NoResultsError` if the ServerYearLog does not exist.
-
- ## Examples
-
- iex> get_server_year_log!(123)
- %ServerYearLog{}
-
- iex> get_server_year_log!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_server_year_log!(Date.t()) :: ServerYearLog.t()
- @spec get_server_year_log!(Date.t(), Teiserver.query_args()) :: ServerYearLog.t()
- def get_server_year_log!(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerYearLogQueries.server_year_log_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single server_year_log.
-
- Returns nil if the ServerYearLog does not exist.
-
- ## Examples
-
- iex> get_server_year_log(123)
- %ServerYearLog{}
-
- iex> get_server_year_log(456)
- nil
-
- """
- @spec get_server_year_log(Date.t()) :: ServerYearLog.t() | nil
- @spec get_server_year_log(Date.t(), Teiserver.query_args()) :: ServerYearLog.t() | nil
- def get_server_year_log(date, query_args \\ []) do
- (query_args ++ [date: date])
- |> ServerYearLogQueries.server_year_log_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a server_year_log.
-
- ## Examples
-
- iex> create_server_year_log(%{field: value})
- {:ok, %ServerYearLog{}}
-
- iex> create_server_year_log(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_server_year_log(map) :: {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
- def create_server_year_log(attrs) do
- %ServerYearLog{}
- |> ServerYearLog.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a server_year_log.
-
- ## Examples
-
- iex> update_server_year_log(server_year_log, %{field: new_value})
- {:ok, %ServerYearLog{}}
-
- iex> update_server_year_log(server_year_log, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_server_year_log(ServerYearLog.t(), map) ::
- {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
- def update_server_year_log(%ServerYearLog{} = server_year_log, attrs) do
- server_year_log
- |> ServerYearLog.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a server_year_log.
-
- ## Examples
-
- iex> delete_server_year_log(server_year_log)
- {:ok, %ServerYearLog{}}
-
- iex> delete_server_year_log(server_year_log)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_server_year_log(ServerYearLog.t()) ::
- {:ok, ServerYearLog.t()} | {:error, Ecto.Changeset.t()}
- def delete_server_year_log(%ServerYearLog{} = server_year_log) do
- Repo.delete(server_year_log)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking server_year_log changes.
-
- ## Examples
-
- iex> change_server_year_log(server_year_log)
- %Ecto.Changeset{data: %ServerYearLog{}}
-
- """
- @spec change_server_year_log(ServerYearLog.t(), map) :: Ecto.Changeset.t()
- def change_server_year_log(%ServerYearLog{} = server_year_log, attrs \\ %{}) do
- ServerYearLog.changeset(server_year_log, attrs)
- end
-end
diff --git a/lib/teiserver/logging/queries/match_day_log_queries.ex b/lib/teiserver/logging/queries/match_day_log_queries.ex
deleted file mode 100644
index 38c1e78e0..000000000
--- a/lib/teiserver/logging/queries/match_day_log_queries.ex
+++ /dev/null
@@ -1,75 +0,0 @@
-defmodule Teiserver.Logging.MatchDayLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.MatchDayLog
- require Logger
-
- @spec match_day_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def match_day_log_query(args) do
- query = from(match_day_logs in MatchDayLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(match_day_logs in query,
- where: match_day_logs.date == ^date
- )
- end
-
- def _where(query, :after, timestamp) do
- from(match_day_logs in query,
- where: match_day_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(match_day_logs in query,
- where: match_day_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(match_day_logs in query,
- order_by: [desc: match_day_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(match_day_logs in query,
- order_by: [asc: match_day_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/match_minute_log_queries.ex b/lib/teiserver/logging/queries/match_minute_log_queries.ex
deleted file mode 100644
index 5d949b5ab..000000000
--- a/lib/teiserver/logging/queries/match_minute_log_queries.ex
+++ /dev/null
@@ -1,69 +0,0 @@
-defmodule Teiserver.Logging.MatchMinuteLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.MatchMinuteLog
- require Logger
-
- @spec match_minute_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def match_minute_log_query(args) do
- query = from(match_minute_logs in MatchMinuteLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :after, timestamp) do
- from(match_minute_logs in query,
- where: match_minute_logs.timestamp >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(match_minute_logs in query,
- where: match_minute_logs.timestamp < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(match_minute_logs in query,
- order_by: [desc: match_minute_logs.timestamp]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(match_minute_logs in query,
- order_by: [asc: match_minute_logs.timestamp]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/match_month_log_queries.ex b/lib/teiserver/logging/queries/match_month_log_queries.ex
deleted file mode 100644
index 6bb39faf4..000000000
--- a/lib/teiserver/logging/queries/match_month_log_queries.ex
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule Teiserver.Logging.MatchMonthLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.MatchMonthLog
- require Logger
-
- @spec match_month_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def match_month_log_query(args) do
- query = from(match_month_logs in MatchMonthLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(match_month_logs in query,
- where: match_month_logs.date == ^date
- )
- end
-
- def _where(query, :year, year) do
- from(match_month_logs in query,
- where: match_month_logs.year == ^year
- )
- end
-
- def _where(query, :month, month) do
- from(match_month_logs in query,
- where: match_month_logs.month == ^month
- )
- end
-
- def _where(query, :after, timestamp) do
- from(match_month_logs in query,
- where: match_month_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(match_month_logs in query,
- where: match_month_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(match_month_logs in query,
- order_by: [desc: match_month_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(match_month_logs in query,
- order_by: [asc: match_month_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/match_quarter_log_queries.ex b/lib/teiserver/logging/queries/match_quarter_log_queries.ex
deleted file mode 100644
index 34bd4b1b8..000000000
--- a/lib/teiserver/logging/queries/match_quarter_log_queries.ex
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule Teiserver.Logging.MatchQuarterLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.MatchQuarterLog
- require Logger
-
- @spec match_quarter_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def match_quarter_log_query(args) do
- query = from(match_quarter_logs in MatchQuarterLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(match_quarter_logs in query,
- where: match_quarter_logs.date == ^date
- )
- end
-
- def _where(query, :year, year) do
- from(match_quarter_logs in query,
- where: match_quarter_logs.year == ^year
- )
- end
-
- def _where(query, :quarter, quarter) do
- from(match_quarter_logs in query,
- where: match_quarter_logs.quarter == ^quarter
- )
- end
-
- def _where(query, :after, timestamp) do
- from(match_quarter_logs in query,
- where: match_quarter_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(match_quarter_logs in query,
- where: match_quarter_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(match_quarter_logs in query,
- order_by: [desc: match_quarter_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(match_quarter_logs in query,
- order_by: [asc: match_quarter_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/match_week_log_queries.ex b/lib/teiserver/logging/queries/match_week_log_queries.ex
deleted file mode 100644
index 12dc7a3a9..000000000
--- a/lib/teiserver/logging/queries/match_week_log_queries.ex
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule Teiserver.Logging.MatchWeekLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.MatchWeekLog
- require Logger
-
- @spec match_week_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def match_week_log_query(args) do
- query = from(match_week_logs in MatchWeekLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(match_week_logs in query,
- where: match_week_logs.date == ^date
- )
- end
-
- def _where(query, :year, year) do
- from(match_week_logs in query,
- where: match_week_logs.year == ^year
- )
- end
-
- def _where(query, :week, week) do
- from(match_week_logs in query,
- where: match_week_logs.week == ^week
- )
- end
-
- def _where(query, :after, timestamp) do
- from(match_week_logs in query,
- where: match_week_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(match_week_logs in query,
- where: match_week_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(match_week_logs in query,
- order_by: [desc: match_week_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(match_week_logs in query,
- order_by: [asc: match_week_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/match_year_log_queries.ex b/lib/teiserver/logging/queries/match_year_log_queries.ex
deleted file mode 100644
index 0698bbbe1..000000000
--- a/lib/teiserver/logging/queries/match_year_log_queries.ex
+++ /dev/null
@@ -1,81 +0,0 @@
-defmodule Teiserver.Logging.MatchYearLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.MatchYearLog
- require Logger
-
- @spec match_year_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def match_year_log_query(args) do
- query = from(match_year_logs in MatchYearLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(match_year_logs in query,
- where: match_year_logs.date == ^date
- )
- end
-
- def _where(query, :year, year) do
- from(match_year_logs in query,
- where: match_year_logs.year == ^year
- )
- end
-
- def _where(query, :after, timestamp) do
- from(match_year_logs in query,
- where: match_year_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(match_year_logs in query,
- where: match_year_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(match_year_logs in query,
- order_by: [desc: match_year_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(match_year_logs in query,
- order_by: [asc: match_year_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/server_day_log_queries.ex b/lib/teiserver/logging/queries/server_day_log_queries.ex
deleted file mode 100644
index 27bccbfb5..000000000
--- a/lib/teiserver/logging/queries/server_day_log_queries.ex
+++ /dev/null
@@ -1,75 +0,0 @@
-defmodule Teiserver.Logging.ServerDayLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.ServerDayLog
- require Logger
-
- @spec server_day_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def server_day_log_query(args) do
- query = from(server_day_logs in ServerDayLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(server_day_logs in query,
- where: server_day_logs.date == ^date
- )
- end
-
- def _where(query, :after, timestamp) do
- from(server_day_logs in query,
- where: server_day_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(server_day_logs in query,
- where: server_day_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(server_day_logs in query,
- order_by: [desc: server_day_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(server_day_logs in query,
- order_by: [asc: server_day_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/server_minute_log_queries.ex b/lib/teiserver/logging/queries/server_minute_log_queries.ex
deleted file mode 100644
index c43f14a6b..000000000
--- a/lib/teiserver/logging/queries/server_minute_log_queries.ex
+++ /dev/null
@@ -1,69 +0,0 @@
-defmodule Teiserver.Logging.ServerMinuteLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.ServerMinuteLog
- require Logger
-
- @spec server_minute_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def server_minute_log_query(args) do
- query = from(server_minute_logs in ServerMinuteLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :after, timestamp) do
- from(server_minute_logs in query,
- where: server_minute_logs.timestamp >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(server_minute_logs in query,
- where: server_minute_logs.timestamp < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(server_minute_logs in query,
- order_by: [desc: server_minute_logs.timestamp]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(server_minute_logs in query,
- order_by: [asc: server_minute_logs.timestamp]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/server_month_log_queries.ex b/lib/teiserver/logging/queries/server_month_log_queries.ex
deleted file mode 100644
index 29f7c8a68..000000000
--- a/lib/teiserver/logging/queries/server_month_log_queries.ex
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule Teiserver.Logging.ServerMonthLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.ServerMonthLog
- require Logger
-
- @spec server_month_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def server_month_log_query(args) do
- query = from(server_month_logs in ServerMonthLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(server_month_logs in query,
- where: server_month_logs.date == ^date
- )
- end
-
- def _where(query, :year, year) do
- from(server_month_logs in query,
- where: server_month_logs.year == ^year
- )
- end
-
- def _where(query, :month, month) do
- from(server_month_logs in query,
- where: server_month_logs.month == ^month
- )
- end
-
- def _where(query, :after, timestamp) do
- from(server_month_logs in query,
- where: server_month_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(server_month_logs in query,
- where: server_month_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(server_month_logs in query,
- order_by: [desc: server_month_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(server_month_logs in query,
- order_by: [asc: server_month_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/server_quarter_log_queries.ex b/lib/teiserver/logging/queries/server_quarter_log_queries.ex
deleted file mode 100644
index fffde04d5..000000000
--- a/lib/teiserver/logging/queries/server_quarter_log_queries.ex
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule Teiserver.Logging.ServerQuarterLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.ServerQuarterLog
- require Logger
-
- @spec server_quarter_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def server_quarter_log_query(args) do
- query = from(server_quarter_logs in ServerQuarterLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(server_quarter_logs in query,
- where: server_quarter_logs.date == ^date
- )
- end
-
- def _where(query, :year, year) do
- from(server_quarter_logs in query,
- where: server_quarter_logs.year == ^year
- )
- end
-
- def _where(query, :quarter, quarter) do
- from(server_quarter_logs in query,
- where: server_quarter_logs.quarter == ^quarter
- )
- end
-
- def _where(query, :after, timestamp) do
- from(server_quarter_logs in query,
- where: server_quarter_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(server_quarter_logs in query,
- where: server_quarter_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(server_quarter_logs in query,
- order_by: [desc: server_quarter_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(server_quarter_logs in query,
- order_by: [asc: server_quarter_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/server_week_log_queries.ex b/lib/teiserver/logging/queries/server_week_log_queries.ex
deleted file mode 100644
index dad8bd48f..000000000
--- a/lib/teiserver/logging/queries/server_week_log_queries.ex
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule Teiserver.Logging.ServerWeekLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.ServerWeekLog
- require Logger
-
- @spec server_week_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def server_week_log_query(args) do
- query = from(server_week_logs in ServerWeekLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(server_week_logs in query,
- where: server_week_logs.date == ^date
- )
- end
-
- def _where(query, :year, year) do
- from(server_week_logs in query,
- where: server_week_logs.year == ^year
- )
- end
-
- def _where(query, :week, week) do
- from(server_week_logs in query,
- where: server_week_logs.week == ^week
- )
- end
-
- def _where(query, :after, timestamp) do
- from(server_week_logs in query,
- where: server_week_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(server_week_logs in query,
- where: server_week_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(server_week_logs in query,
- order_by: [desc: server_week_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(server_week_logs in query,
- order_by: [asc: server_week_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/queries/server_year_log_queries.ex b/lib/teiserver/logging/queries/server_year_log_queries.ex
deleted file mode 100644
index ff7e7c51a..000000000
--- a/lib/teiserver/logging/queries/server_year_log_queries.ex
+++ /dev/null
@@ -1,81 +0,0 @@
-defmodule Teiserver.Logging.ServerYearLogQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Logging.ServerYearLog
- require Logger
-
- @spec server_year_log_query(Teiserver.query_args()) :: Ecto.Query.t()
- def server_year_log_query(args) do
- query = from(server_year_logs in ServerYearLog)
-
- query
- |> do_where(date: args[:date])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :date, date) do
- from(server_year_logs in query,
- where: server_year_logs.date == ^date
- )
- end
-
- def _where(query, :year, year) do
- from(server_year_logs in query,
- where: server_year_logs.year == ^year
- )
- end
-
- def _where(query, :after, timestamp) do
- from(server_year_logs in query,
- where: server_year_logs.date >= ^timestamp
- )
- end
-
- def _where(query, :before, timestamp) do
- from(server_year_logs in query,
- where: server_year_logs.date < ^timestamp
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Newest first") do
- from(server_year_logs in query,
- order_by: [desc: server_year_logs.date]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(server_year_logs in query,
- order_by: [asc: server_year_logs.date]
- )
- end
-end
diff --git a/lib/teiserver/logging/schemas/match_day_log.ex b/lib/teiserver/logging/schemas/match_day_log.ex
deleted file mode 100644
index 1788b1723..000000000
--- a/lib/teiserver/logging/schemas/match_day_log.ex
+++ /dev/null
@@ -1,32 +0,0 @@
-defmodule Teiserver.Logging.MatchDayLog do
- @moduledoc """
- # MatchDayLog
- A log of the activity for that day on the match.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_match_day_logs" do
- field(:date, :date, primary_key: true)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(date data)a)
- |> validate_required(~w(date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/match_minute_log.ex b/lib/teiserver/logging/schemas/match_minute_log.ex
deleted file mode 100644
index 1afd7078b..000000000
--- a/lib/teiserver/logging/schemas/match_minute_log.ex
+++ /dev/null
@@ -1,32 +0,0 @@
-defmodule Teiserver.Logging.MatchMinuteLog do
- @moduledoc """
- # MatchMinuteLog
- A log of the activity for that minute on the server.
-
- ### Attributes
-
- * `:timestamp` - The timestamp this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_match_minute_logs" do
- field(:timestamp, :utc_datetime, primary_key: true)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- timestamp: DateTime.t(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(timestamp data)a)
- |> validate_required(~w(timestamp data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/match_month_log.ex b/lib/teiserver/logging/schemas/match_month_log.ex
deleted file mode 100644
index 69493ced9..000000000
--- a/lib/teiserver/logging/schemas/match_month_log.ex
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule Teiserver.Logging.MatchMonthLog do
- @moduledoc """
- # MatchMonthLog
- A log of the activity for that month on the match.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:year` - The year this log refers to
- * `:month` - The month this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_match_month_logs" do
- field(:year, :integer, primary_key: true)
- field(:month, :integer, primary_key: true)
- field(:date, :date)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- year: non_neg_integer(),
- month: non_neg_integer(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(year month date data)a)
- |> validate_required(~w(year month date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/match_quarter_log.ex b/lib/teiserver/logging/schemas/match_quarter_log.ex
deleted file mode 100644
index d4a2beb45..000000000
--- a/lib/teiserver/logging/schemas/match_quarter_log.ex
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule Teiserver.Logging.MatchQuarterLog do
- @moduledoc """
- # MatchQuarterLog
- A log of the activity for that quarter on the match.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:year` - The year this log refers to
- * `:quarter` - The quarter this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_match_quarter_logs" do
- field(:year, :integer, primary_key: true)
- field(:quarter, :integer, primary_key: true)
- field(:date, :date)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- year: non_neg_integer(),
- quarter: non_neg_integer(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(year quarter date data)a)
- |> validate_required(~w(year quarter date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/match_week_log.ex b/lib/teiserver/logging/schemas/match_week_log.ex
deleted file mode 100644
index 765db9eca..000000000
--- a/lib/teiserver/logging/schemas/match_week_log.ex
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule Teiserver.Logging.MatchWeekLog do
- @moduledoc """
- # MatchWeekLog
- A log of the activity for that week on the match.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:year` - The year this log refers to
- * `:week` - The week this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_match_week_logs" do
- field(:year, :integer, primary_key: true)
- field(:week, :integer, primary_key: true)
- field(:date, :date)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- year: non_neg_integer(),
- week: non_neg_integer(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(year week date data)a)
- |> validate_required(~w(year week date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/match_year_log.ex b/lib/teiserver/logging/schemas/match_year_log.ex
deleted file mode 100644
index d6ce30764..000000000
--- a/lib/teiserver/logging/schemas/match_year_log.ex
+++ /dev/null
@@ -1,35 +0,0 @@
-defmodule Teiserver.Logging.MatchYearLog do
- @moduledoc """
- # MatchYearLog
- A log of the activity for that year on the match.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:year` - The year this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_match_year_logs" do
- field(:year, :integer, primary_key: true)
- field(:date, :date)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- year: non_neg_integer(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(year date data)a)
- |> validate_required(~w(year date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/server_day_log.ex b/lib/teiserver/logging/schemas/server_day_log.ex
deleted file mode 100644
index 3fbd8ab3e..000000000
--- a/lib/teiserver/logging/schemas/server_day_log.ex
+++ /dev/null
@@ -1,32 +0,0 @@
-defmodule Teiserver.Logging.ServerDayLog do
- @moduledoc """
- # ServerDayLog
- A log of the activity for that day on the server.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_server_day_logs" do
- field(:date, :date, primary_key: true)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(date data)a)
- |> validate_required(~w(date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/server_minute_log.ex b/lib/teiserver/logging/schemas/server_minute_log.ex
deleted file mode 100644
index daa57ab61..000000000
--- a/lib/teiserver/logging/schemas/server_minute_log.ex
+++ /dev/null
@@ -1,32 +0,0 @@
-defmodule Teiserver.Logging.ServerMinuteLog do
- @moduledoc """
- # ServerMinuteLog
- A log of the activity for that minute on the server.
-
- ### Attributes
-
- * `:timestamp` - The timestamp this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_server_minute_logs" do
- field(:timestamp, :utc_datetime, primary_key: true)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- timestamp: DateTime.t(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(timestamp data)a)
- |> validate_required(~w(timestamp data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/server_month_log.ex b/lib/teiserver/logging/schemas/server_month_log.ex
deleted file mode 100644
index 06344b7c5..000000000
--- a/lib/teiserver/logging/schemas/server_month_log.ex
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule Teiserver.Logging.ServerMonthLog do
- @moduledoc """
- # ServerMonthLog
- A log of the activity for that month on the server.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:year` - The year this log refers to
- * `:month` - The month this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_server_month_logs" do
- field(:year, :integer, primary_key: true)
- field(:month, :integer, primary_key: true)
- field(:date, :date)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- year: non_neg_integer(),
- month: non_neg_integer(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(year month date data)a)
- |> validate_required(~w(year month date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/server_quarter_log.ex b/lib/teiserver/logging/schemas/server_quarter_log.ex
deleted file mode 100644
index 3e55c8b6d..000000000
--- a/lib/teiserver/logging/schemas/server_quarter_log.ex
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule Teiserver.Logging.ServerQuarterLog do
- @moduledoc """
- # ServerQuarterLog
- A log of the activity for that quarter on the server.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:year` - The year this log refers to
- * `:quarter` - The quarter this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_server_quarter_logs" do
- field(:year, :integer, primary_key: true)
- field(:quarter, :integer, primary_key: true)
- field(:date, :date)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- year: non_neg_integer(),
- quarter: non_neg_integer(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(year quarter date data)a)
- |> validate_required(~w(year quarter date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/server_week_log.ex b/lib/teiserver/logging/schemas/server_week_log.ex
deleted file mode 100644
index fc4c61642..000000000
--- a/lib/teiserver/logging/schemas/server_week_log.ex
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule Teiserver.Logging.ServerWeekLog do
- @moduledoc """
- # ServerWeekLog
- A log of the activity for that week on the server.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:year` - The year this log refers to
- * `:week` - The week this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_server_week_logs" do
- field(:year, :integer, primary_key: true)
- field(:week, :integer, primary_key: true)
- field(:date, :date)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- year: non_neg_integer(),
- week: non_neg_integer(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(year week date data)a)
- |> validate_required(~w(year week date data)a)
- end
-end
diff --git a/lib/teiserver/logging/schemas/server_year_log.ex b/lib/teiserver/logging/schemas/server_year_log.ex
deleted file mode 100644
index c796fa9f5..000000000
--- a/lib/teiserver/logging/schemas/server_year_log.ex
+++ /dev/null
@@ -1,35 +0,0 @@
-defmodule Teiserver.Logging.ServerYearLog do
- @moduledoc """
- # ServerYearLog
- A log of the activity for that year on the server.
-
- ### Attributes
-
- * `:date` - The date this log refers to
- * `:year` - The year this log refers to
- * `:data` - The data included
- """
- use TeiserverMacros, :schema
-
- @primary_key false
- schema "logging_server_year_logs" do
- field(:year, :integer, primary_key: true)
- field(:date, :date)
- field(:data, :map)
- end
-
- @type t :: %__MODULE__{
- date: Date.t(),
- year: non_neg_integer(),
- data: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(year date data)a)
- |> validate_required(~w(year date data)a)
- end
-end
diff --git a/lib/teiserver/migrations/postgres/v02.ex b/lib/teiserver/migrations/postgres/v02.ex
index 48c74037c..567b22465 100644
--- a/lib/teiserver/migrations/postgres/v02.ex
+++ b/lib/teiserver/migrations/postgres/v02.ex
@@ -16,82 +16,6 @@ defmodule Teiserver.Migrations.Postgres.V02 do
timestamps()
end
- # Logging - Server activity
- create_if_not_exists table(:logging_server_minute_logs, primary_key: false) do
- add(:timestamp, :utc_datetime, primary_key: true)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_server_day_logs, primary_key: false) do
- add(:date, :date, primary_key: true)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_server_week_logs, primary_key: false, prefix: prefix) do
- add(:year, :integer, primary_key: true)
- add(:week, :integer, primary_key: true)
- add(:date, :date)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_server_month_logs, primary_key: false, prefix: prefix) do
- add(:year, :integer, primary_key: true)
- add(:month, :integer, primary_key: true)
- add(:date, :date)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_server_quarter_logs, primary_key: false, prefix: prefix) do
- add(:year, :integer, primary_key: true)
- add(:quarter, :integer, primary_key: true)
- add(:date, :date)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_server_year_logs, primary_key: false, prefix: prefix) do
- add(:year, :integer, primary_key: true)
- add(:date, :date)
- add(:data, :jsonb)
- end
-
- # Logging - Match logs
- create_if_not_exists table(:logging_match_minute_logs, primary_key: false) do
- add(:timestamp, :utc_datetime, primary_key: true)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_match_day_logs, primary_key: false) do
- add(:date, :date, primary_key: true)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_match_week_logs, primary_key: false, prefix: prefix) do
- add(:year, :integer, primary_key: true)
- add(:week, :integer, primary_key: true)
- add(:date, :date)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_match_month_logs, primary_key: false, prefix: prefix) do
- add(:year, :integer, primary_key: true)
- add(:month, :integer, primary_key: true)
- add(:date, :date)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_match_quarter_logs, primary_key: false, prefix: prefix) do
- add(:year, :integer, primary_key: true)
- add(:quarter, :integer, primary_key: true)
- add(:date, :date)
- add(:data, :jsonb)
- end
-
- create_if_not_exists table(:logging_match_year_logs, primary_key: false, prefix: prefix) do
- add(:year, :integer, primary_key: true)
- add(:date, :date)
- add(:data, :jsonb)
- end
-
# Telemetry tables
create_if_not_exists table(:telemetry_event_types, prefix: prefix) do
add(:category, :string)
diff --git a/lib/teiserver/system/servers/cluster_member_server.ex b/lib/teiserver/system/servers/cluster_member_server.ex
index e2273d32c..c897707e6 100644
--- a/lib/teiserver/system/servers/cluster_member_server.ex
+++ b/lib/teiserver/system/servers/cluster_member_server.ex
@@ -1,6 +1,12 @@
-defmodule Teiserver.System.ClusterManager do
+defmodule Teiserver.System.ClusterMemberServer do
@moduledoc """
The cluster manager for handling adding nodes to a cluster.
+
+ You can disable this process with the config:
+ ```
+ config :teiserver,
+ teiserver_clustering: false
+ ```
"""
use GenServer
require Logger
@@ -28,13 +34,13 @@ defmodule Teiserver.System.ClusterManager do
@impl GenServer
def handle_call(other, from, state) do
- Logger.warning("unhandled call to ClusterManager: #{inspect(other)}. From: #{inspect(from)}")
+ Logger.warning("unhandled call to ClusterMemberServer: #{inspect(other)}. From: #{inspect(from)}")
{:reply, :not_implemented, state}
end
@impl GenServer
def handle_cast(other, state) do
- Logger.warning("unhandled cast to ClusterManager: #{inspect(other)}.")
+ Logger.warning("unhandled cast to ClusterMemberServer: #{inspect(other)}.")
{:noreply, state}
end
@@ -76,7 +82,7 @@ defmodule Teiserver.System.ClusterManager do
end
def handle_info({:nodeup, node_name}, state) do
- Logger.info("nodeup message to ClusterManager: #{inspect(node_name)}.")
+ Logger.info("nodeup message to ClusterMemberServer: #{inspect(node_name)}.")
{:noreply, state}
end
@@ -84,13 +90,13 @@ defmodule Teiserver.System.ClusterManager do
def handle_info({:nodedown, node_name}, state) do
node_to_remove = Atom.to_string(node_name)
ClusterMemberLib.delete_cluster_member(node_to_remove)
- Logger.warning("nodedown message to ClusterManager: #{inspect(node_name)}.")
+ Logger.warning("nodedown message to ClusterMemberServer: #{inspect(node_name)}.")
{:noreply, state}
end
@impl GenServer
def handle_info(other, state) do
- Logger.warning("unhandled message to ClusterManager: #{inspect(other)}.")
+ Logger.warning("unhandled message to ClusterMemberServer: #{inspect(other)}.")
{:noreply, state}
end
diff --git a/lib/teiserver/system/servers/cluster_member_supervisor.ex b/lib/teiserver/system/servers/cluster_member_supervisor.ex
index 970900bbe..c3efd3c84 100644
--- a/lib/teiserver/system/servers/cluster_member_supervisor.ex
+++ b/lib/teiserver/system/servers/cluster_member_supervisor.ex
@@ -38,7 +38,7 @@ defmodule Teiserver.System.ClusterManagerSupervisor do
defp start_cluster_manager() do
case DynamicSupervisor.start_child(
__MODULE__,
- {Teiserver.System.ClusterManager, []}
+ {Teiserver.System.ClusterMemberServer, []}
) do
{:ok, _pid} ->
:ok
diff --git a/lib/teiserver/telemetry/libs/event_type_lib.ex b/lib/teiserver/telemetry/libs/event_type_lib.ex
deleted file mode 100644
index 749d9b482..000000000
--- a/lib/teiserver/telemetry/libs/event_type_lib.ex
+++ /dev/null
@@ -1,137 +0,0 @@
-defmodule Teiserver.Telemetry.EventTypeLib do
- @moduledoc """
- Library of event_type related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.Telemetry.{EventType, EventTypeQueries}
-
- @doc """
- Returns the list of event_types.
-
- ## Examples
-
- iex> list_event_types()
- [%EventType{}, ...]
-
- """
- @spec list_event_types(Teiserver.query_args()) :: [EventType.t()]
- def list_event_types(query_args) do
- query_args
- |> EventTypeQueries.event_type_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single event_type.
-
- Raises `Ecto.NoResultsError` if the EventType does not exist.
-
- ## Examples
-
- iex> get_event_type!(123)
- %EventType{}
-
- iex> get_event_type!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_event_type!(EventType.id()) :: EventType.t()
- @spec get_event_type!(EventType.id(), Teiserver.query_args()) :: EventType.t()
- def get_event_type!(event_type_id, query_args \\ []) do
- (query_args ++ [id: event_type_id])
- |> EventTypeQueries.event_type_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single event_type.
-
- Returns nil if the EventType does not exist.
-
- ## Examples
-
- iex> get_event_type(123)
- %EventType{}
-
- iex> get_event_type(456)
- nil
-
- """
- @spec get_event_type(EventType.id()) :: EventType.t() | nil
- @spec get_event_type(EventType.id(), Teiserver.query_args()) :: EventType.t() | nil
- def get_event_type(event_type_id, query_args \\ []) do
- (query_args ++ [id: event_type_id])
- |> EventTypeQueries.event_type_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a event_type.
-
- ## Examples
-
- iex> create_event_type(%{field: value})
- {:ok, %EventType{}}
-
- iex> create_event_type(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_event_type(map) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
- def create_event_type(attrs) do
- %EventType{}
- |> EventType.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a event_type.
-
- ## Examples
-
- iex> update_event_type(event_type, %{field: new_value})
- {:ok, %EventType{}}
-
- iex> update_event_type(event_type, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_event_type(EventType.t(), map) ::
- {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
- def update_event_type(%EventType{} = event_type, attrs) do
- event_type
- |> EventType.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a event_type.
-
- ## Examples
-
- iex> delete_event_type(event_type)
- {:ok, %EventType{}}
-
- iex> delete_event_type(event_type)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_event_type(EventType.t()) :: {:ok, EventType.t()} | {:error, Ecto.Changeset.t()}
- def delete_event_type(%EventType{} = event_type) do
- Repo.delete(event_type)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking event_type changes.
-
- ## Examples
-
- iex> change_event_type(event_type)
- %Ecto.Changeset{data: %EventType{}}
-
- """
- @spec change_event_type(EventType.t(), map) :: Ecto.Changeset.t()
- def change_event_type(%EventType{} = event_type, attrs \\ %{}) do
- EventType.changeset(event_type, attrs)
- end
-end
diff --git a/lib/teiserver/telemetry/queries/event_type_queries.ex b/lib/teiserver/telemetry/queries/event_type_queries.ex
deleted file mode 100644
index 191eb1231..000000000
--- a/lib/teiserver/telemetry/queries/event_type_queries.ex
+++ /dev/null
@@ -1,75 +0,0 @@
-defmodule Teiserver.Telemetry.EventTypeQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.Telemetry.EventType
- require Logger
-
- @spec event_type_query(Teiserver.query_args()) :: Ecto.Query.t()
- def event_type_query(args) do
- query = from(event_types in EventType)
-
- query
- |> do_where(id: args[:id])
- |> do_where(args[:where])
- |> do_where(args[:search])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- defp do_where(query, nil), do: query
-
- defp do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :id, id_list) when is_list(id_list) do
- from(event_types in query,
- where: event_types.id in ^id_list
- )
- end
-
- def _where(query, :id, id) do
- from(event_types in query,
- where: event_types.id == ^id
- )
- end
-
- def _where(query, :name, name) do
- from(event_types in query,
- where: event_types.name == ^name
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) when is_list(params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Name (A-Z)") do
- from(event_types in query,
- order_by: [asc: event_types.name]
- )
- end
-
- def _order_by(query, "Name (Z-A)") do
- from(event_types in query,
- order_by: [desc: event_types.name]
- )
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/complex_anon_event.ex b/lib/teiserver/telemetry/schemas/complex_anon_event.ex
deleted file mode 100644
index 60411f65f..000000000
--- a/lib/teiserver/telemetry/schemas/complex_anon_event.ex
+++ /dev/null
@@ -1,40 +0,0 @@
-defmodule Teiserver.Telemetry.ComplexAnonEvent do
- @moduledoc """
- # ComplexAnonEvent
- A complex event taking place on a Client application but without a user_id to link it to.
-
- ### Attributes
-
- * `:hash_id` - A hash value representing the anonymous user allowing events from the same person to be grouped without linking them to a specific user profile
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- * `:details` - A key-value map of the details of the event
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_complex_anon_events" do
- field(:hash_id, Ecto.UUID)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
-
- field(:details, :map)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- hash_id: Ecto.UUID.t(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t(),
- details: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(hash_id event_type_id inserted_at details)a)
- |> validate_required(~w(hash_id event_type_id inserted_at details)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/complex_clientapp_event.ex b/lib/teiserver/telemetry/schemas/complex_clientapp_event.ex
deleted file mode 100644
index b4f8ebc43..000000000
--- a/lib/teiserver/telemetry/schemas/complex_clientapp_event.ex
+++ /dev/null
@@ -1,40 +0,0 @@
-defmodule Teiserver.Telemetry.ComplexClientappEvent do
- @moduledoc """
- # ComplexClientappEvent
- A complex event taking place on a Client application with a user attached
-
- ### Attributes
-
- * `:user_id` - The user this event took place for
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- * `:details` - A key-value map of the details of the event
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_complex_anon_events" do
- belongs_to(:user_id, Teiserver.Account.User)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
-
- field(:details, :map)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- user_id: Teiserver.user_id(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t(),
- details: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(user_id event_type_id inserted_at details)a)
- |> validate_required(~w(user_id event_type_id inserted_at details)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/complex_lobby_event.ex b/lib/teiserver/telemetry/schemas/complex_lobby_event.ex
deleted file mode 100644
index 122aeccdf..000000000
--- a/lib/teiserver/telemetry/schemas/complex_lobby_event.ex
+++ /dev/null
@@ -1,43 +0,0 @@
-defmodule Teiserver.Telemetry.ComplexLobbyEvent do
- @moduledoc """
- # ComplexLobbyEvent
- A complex event taking place inside a lobby
-
- ### Attributes
-
- * `:user_id` - The `Teiserver.Account.User` this event took place for
- * `:match_id` - The match_id of the lobby this took place in
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- * `:details` - A key-value map of the details of the event
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_complex_lobby_events" do
- belongs_to(:user_id, Teiserver.Account.User)
- belongs_to(:match_id, Teiserver.Game.Match)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
-
- field(:details, :map)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- user_id: Teiserver.user_id(),
- match_id: Teiserver.match_id(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t(),
- details: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(user_id match_id event_type_id inserted_at details)a)
- |> validate_required(~w(user_id match_id event_type_id inserted_at details)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/complex_match_event.ex b/lib/teiserver/telemetry/schemas/complex_match_event.ex
deleted file mode 100644
index 1b89b19ec..000000000
--- a/lib/teiserver/telemetry/schemas/complex_match_event.ex
+++ /dev/null
@@ -1,48 +0,0 @@
-defmodule Teiserver.Telemetry.ComplexMatchEvent do
- @moduledoc """
- # ComplexMatchEvent
- A complex event taking place inside of a match
-
- ### Attributes
-
- * `:user_id` - The `Teiserver.Account.User` this event took place for
- * `:match_id` - The `Teiserver.Game.Match` this took place in
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- * `:game_time_seconds` - The number of seconds elapsed in the game before the event took place
- * `:details` - A key-value map of the details of the event
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_complex_anon_events" do
- belongs_to(:user_id, Teiserver.Account.User)
- belongs_to(:match_id, Teiserver.Game.Match)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
-
- field(:game_time_seconds, :integer)
- field(:details, :map)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- user_id: Teiserver.user_id(),
- match_id: Teiserver.match_id(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t(),
- game_time_seconds: non_neg_integer(),
- details: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(user_id match_id event_type_id inserted_at game_time_seconds details)a)
- |> validate_required(
- ~w(user_id match_id event_type_id inserted_at game_time_seconds details)a
- )
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/complex_server_event.ex b/lib/teiserver/telemetry/schemas/complex_server_event.ex
deleted file mode 100644
index ffbc24274..000000000
--- a/lib/teiserver/telemetry/schemas/complex_server_event.ex
+++ /dev/null
@@ -1,40 +0,0 @@
-defmodule Teiserver.Telemetry.ComplexServerEvent do
- @moduledoc """
- # ComplexServerEvent
- A complex event taking place on a Client application with a user attached
-
- ### Attributes
-
- * `:user_id` - The user this event took place for
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- * `:details` - A key-value map of the details of the event
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_complex_anon_events" do
- belongs_to(:user_id, Teiserver.Account.User)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
-
- field(:details, :map)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- user_id: Teiserver.user_id(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t(),
- details: map()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(user_id event_type_id inserted_at details)a)
- |> validate_required(~w(user_id event_type_id inserted_at details)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/event_type.ex b/lib/teiserver/telemetry/schemas/event_type.ex
deleted file mode 100644
index d2dfa8227..000000000
--- a/lib/teiserver/telemetry/schemas/event_type.ex
+++ /dev/null
@@ -1,33 +0,0 @@
-defmodule Teiserver.Telemetry.EventType do
- @moduledoc """
- # EventType
- A name lookup for events to prevent us having to store a string for every single row.
-
- ### Attributes
-
- * `:category` - The category
- * `:name` - The name of the event
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_event_types" do
- field(:category, :string)
- field(:name, :string)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- id: id(),
- name: String.t()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(category name)a)
- |> validate_required(~w(category name)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/simple_anon_event.ex b/lib/teiserver/telemetry/schemas/simple_anon_event.ex
deleted file mode 100644
index 10ac81777..000000000
--- a/lib/teiserver/telemetry/schemas/simple_anon_event.ex
+++ /dev/null
@@ -1,36 +0,0 @@
-defmodule Teiserver.Telemetry.SimpleAnonEvent do
- @moduledoc """
- # SimpleAnonEvent
- A simple event taking place on a Client application but without a user_id to link it to.
-
- ### Attributes
-
- * `:hash_id` - A hash value representing the anonymous user allowing events from the same person to be grouped without linking them to a specific user profile
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_simple_anon_events" do
- field(:hash_id, Ecto.UUID)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- hash_id: Ecto.UUID.t(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(hash_id event_type_id inserted_at)a)
- |> validate_required(~w(hash_id event_type_id inserted_at)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/simple_clientapp_event.ex b/lib/teiserver/telemetry/schemas/simple_clientapp_event.ex
deleted file mode 100644
index 517768d48..000000000
--- a/lib/teiserver/telemetry/schemas/simple_clientapp_event.ex
+++ /dev/null
@@ -1,36 +0,0 @@
-defmodule Teiserver.Telemetry.SimpleClientappEvent do
- @moduledoc """
- # SimpleClientappEvent
- A complex event taking place on a Client application with a user attached
-
- ### Attributes
-
- * `:user_id` - The user this event took place for
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_complex_anon_events" do
- belongs_to(:user_id, Teiserver.Account.User)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- user_id: Teiserver.user_id(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(user_id event_type_id inserted_at)a)
- |> validate_required(~w(user_id event_type_id inserted_at)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/simple_lobby_event.ex b/lib/teiserver/telemetry/schemas/simple_lobby_event.ex
deleted file mode 100644
index ca4211308..000000000
--- a/lib/teiserver/telemetry/schemas/simple_lobby_event.ex
+++ /dev/null
@@ -1,39 +0,0 @@
-defmodule Teiserver.Telemetry.SimpleLobbyEvent do
- @moduledoc """
- # SimpleLobbyEvent
- A simple event taking place inside a lobby
-
- ### Attributes
-
- * `:user_id` - The `Teiserver.Account.User` this event took place for
- * `:match_id` - The match_id of the lobby this took place in
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_simple_lobby_events" do
- belongs_to(:user_id, Teiserver.Account.User)
- belongs_to(:match_id, Teiserver.Game.Match)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- user_id: Teiserver.user_id(),
- match_id: Teiserver.match_id(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(user_id match_id event_type_id inserted_at)a)
- |> validate_required(~w(user_id match_id event_type_id inserted_at)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/simple_match_event.ex b/lib/teiserver/telemetry/schemas/simple_match_event.ex
deleted file mode 100644
index de5a2fa46..000000000
--- a/lib/teiserver/telemetry/schemas/simple_match_event.ex
+++ /dev/null
@@ -1,43 +0,0 @@
-defmodule Teiserver.Telemetry.SimpleMatchEvent do
- @moduledoc """
- # SimpleMatchEvent
- A simple event taking place inside of a match
-
- ### Attributes
-
- * `:user_id` - The `Teiserver.Account.User` this event took place for
- * `:match_id` - The `Teiserver.Game.Match` this took place in
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- * `:game_time_seconds` - The number of seconds elapsed in the game before the event took place
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_simple_anon_events" do
- belongs_to(:user_id, Teiserver.Account.User)
- belongs_to(:match_id, Teiserver.Game.Match)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
-
- field(:game_time_seconds, :integer)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- user_id: Teiserver.user_id(),
- match_id: Teiserver.match_id(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t(),
- game_time_seconds: non_neg_integer()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(user_id match_id event_type_id inserted_at game_time_seconds)a)
- |> validate_required(~w(user_id match_id event_type_id inserted_at game_time_seconds)a)
- end
-end
diff --git a/lib/teiserver/telemetry/schemas/simple_server_event.ex b/lib/teiserver/telemetry/schemas/simple_server_event.ex
deleted file mode 100644
index cbf10a34f..000000000
--- a/lib/teiserver/telemetry/schemas/simple_server_event.ex
+++ /dev/null
@@ -1,36 +0,0 @@
-defmodule Teiserver.Telemetry.SimpleServerEvent do
- @moduledoc """
- # SimpleServerEvent
- A simple event taking place on a Client application with a user attached
-
- ### Attributes
-
- * `:user_id` - The user this event took place for
- * `:event_type_id` - The `Teiserver.Telemetry.EventType` this event belongs to
- * `:inserted_at` - The timestamp the event took place
- """
- use TeiserverMacros, :schema
-
- schema "telemetry_simple_anon_events" do
- belongs_to(:user_id, Teiserver.Account.User)
- belongs_to(:event_type, Teiserver.Telemetry.EventType)
- field(:inserted_at, :utc_datetime)
- end
-
- @type id :: non_neg_integer()
-
- @type t :: %__MODULE__{
- user_id: Teiserver.user_id(),
- event_type_id: Teiserver.Telemetry.EventType.id(),
- inserted_at: DateTime.t()
- }
-
- @doc false
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(user_id event_type_id inserted_at)a)
- |> validate_required(~w(user_id event_type_id inserted_at)a)
- end
-end
diff --git a/mix.exs b/mix.exs
index c227a9237..4e47b0a3a 100644
--- a/mix.exs
+++ b/mix.exs
@@ -59,7 +59,7 @@ defmodule Teiserver.MixProject do
"documentation/guides/program_structure.md",
"documentation/guides/snippets.md",
"documentation/guides/match_lifecycle.md",
- "documentation/guides/telemetry_events.md",
+ "documentation/guides/testing.md",
# Development
"documentation/development/features.md",
@@ -70,6 +70,8 @@ defmodule Teiserver.MixProject do
"documentation/pubsubs/match.md",
"documentation/pubsubs/user.md",
"documentation/pubsubs/communication.md",
+
+ # KW maps
"CHANGELOG.md": [title: "Changelog"]
]
end
@@ -94,8 +96,7 @@ defmodule Teiserver.MixProject do
Teiserver.Logging,
Teiserver.Matchmaking,
Teiserver.Moderation,
- Teiserver.Settings,
- Teiserver.Telemetry
+ Teiserver.Settings
],
Account: [
~r"Teiserver.Account.*"
@@ -127,9 +128,6 @@ defmodule Teiserver.MixProject do
Settings: [
~r"Teiserver.Settings.*"
],
- Telemetry: [
- ~r"Teiserver.Telemetry.*"
- ],
Helpers: [
~r"Teiserver.Helpers.*"
],
@@ -240,8 +238,7 @@ defmodule Teiserver.MixProject do
{:ecto_sql, "~> 3.10"},
{:postgrex, ">= 0.0.0"},
{:phoenix_pubsub, "~> 2.1"},
- {:telemetry_metrics, "~> 0.6"},
- {:telemetry_poller, "~> 1.0"},
+ {:telemetry, "~> 1.2.1"},
{:gettext, "~> 0.20"},
{:jason, "~> 1.2"},
{:argon2_elixir, "~> 3.0"},
diff --git a/test/logging/libs/match_day_log_lib_test.exs b/test/logging/libs/match_day_log_lib_test.exs
deleted file mode 100644
index 8b41c6d65..000000000
--- a/test/logging/libs/match_day_log_lib_test.exs
+++ /dev/null
@@ -1,98 +0,0 @@
-defmodule Teiserver.MatchDayLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.MatchDayLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(days: 1),
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "match_day_log" do
- alias Teiserver.Logging.MatchDayLog
-
- test "match_day_log_query/0 returns a query" do
- q = Logging.match_day_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_match_day_log/0 returns match_day_log" do
- # No match_day_log yet
- assert Logging.list_match_day_logs([]) == []
-
- # Add a match_day_log
- LoggingFixtures.match_day_log_fixture()
- assert Logging.list_match_day_logs([]) != []
- end
-
- test "get_match_day_log!/1 and get_match_day_log/1 returns the match_day_log with given id" do
- match_day_log = LoggingFixtures.match_day_log_fixture()
- assert Logging.get_match_day_log!(match_day_log.date) == match_day_log
- assert Logging.get_match_day_log(match_day_log.date) == match_day_log
- end
-
- test "create_match_day_log/1 with valid data creates a match_day_log" do
- assert {:ok, %MatchDayLog{} = match_day_log} =
- Logging.create_match_day_log(valid_attrs())
-
- assert match_day_log.data == %{"key" => 1}
- end
-
- test "create_match_day_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_match_day_log(invalid_attrs())
- end
-
- test "update_match_day_log/2 with valid data updates the match_day_log" do
- match_day_log = LoggingFixtures.match_day_log_fixture()
-
- assert {:ok, %MatchDayLog{} = match_day_log} =
- Logging.update_match_day_log(match_day_log, update_attrs())
-
- assert match_day_log.data == %{"other-key" => 2}
- end
-
- test "update_match_day_log/2 with invalid data returns error changeset" do
- match_day_log = LoggingFixtures.match_day_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_match_day_log(match_day_log, invalid_attrs())
-
- assert match_day_log == Logging.get_match_day_log!(match_day_log.date)
- end
-
- test "delete_match_day_log/1 deletes the match_day_log" do
- match_day_log = LoggingFixtures.match_day_log_fixture()
- assert {:ok, %MatchDayLog{}} = Logging.delete_match_day_log(match_day_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_match_day_log!(match_day_log.date)
- end
-
- assert Logging.get_match_day_log(match_day_log.date) == nil
- end
-
- test "change_match_day_log/1 returns a match_day_log changeset" do
- match_day_log = LoggingFixtures.match_day_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_match_day_log(match_day_log)
- end
- end
-end
diff --git a/test/logging/libs/match_minute_log_lib_test.exs b/test/logging/libs/match_minute_log_lib_test.exs
deleted file mode 100644
index 177239c71..000000000
--- a/test/logging/libs/match_minute_log_lib_test.exs
+++ /dev/null
@@ -1,98 +0,0 @@
-defmodule Teiserver.MatchMinuteLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.MatchMinuteLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- timestamp: Timex.now(),
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- timestamp: Timex.now() |> Timex.shift(minutes: 1),
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- timestamp: nil,
- data: nil
- }
- end
-
- describe "match_minute_log" do
- alias Teiserver.Logging.MatchMinuteLog
-
- test "match_minute_log_query/0 returns a query" do
- q = Logging.match_minute_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_match_minute_log/0 returns match_minute_log" do
- # No match_minute_log yet
- assert Logging.list_match_minute_logs([]) == []
-
- # Add a match_minute_log
- LoggingFixtures.match_minute_log_fixture()
- assert Logging.list_match_minute_logs([]) != []
- end
-
- test "get_match_minute_log!/1 and get_match_minute_log/1 returns the match_minute_log with given id" do
- match_minute_log = LoggingFixtures.match_minute_log_fixture()
- assert Logging.get_match_minute_log!(match_minute_log.timestamp) == match_minute_log
- assert Logging.get_match_minute_log(match_minute_log.timestamp) == match_minute_log
- end
-
- test "create_match_minute_log/1 with valid data creates a match_minute_log" do
- assert {:ok, %MatchMinuteLog{} = match_minute_log} =
- Logging.create_match_minute_log(valid_attrs())
-
- assert match_minute_log.data == %{"key" => 1}
- end
-
- test "create_match_minute_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_match_minute_log(invalid_attrs())
- end
-
- test "update_match_minute_log/2 with valid data updates the match_minute_log" do
- match_minute_log = LoggingFixtures.match_minute_log_fixture()
-
- assert {:ok, %MatchMinuteLog{} = match_minute_log} =
- Logging.update_match_minute_log(match_minute_log, update_attrs())
-
- assert match_minute_log.data == %{"other-key" => 2}
- end
-
- test "update_match_minute_log/2 with invalid data returns error changeset" do
- match_minute_log = LoggingFixtures.match_minute_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_match_minute_log(match_minute_log, invalid_attrs())
-
- assert match_minute_log == Logging.get_match_minute_log!(match_minute_log.timestamp)
- end
-
- test "delete_match_minute_log/1 deletes the match_minute_log" do
- match_minute_log = LoggingFixtures.match_minute_log_fixture()
- assert {:ok, %MatchMinuteLog{}} = Logging.delete_match_minute_log(match_minute_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_match_minute_log!(match_minute_log.timestamp)
- end
-
- assert Logging.get_match_minute_log(match_minute_log.timestamp) == nil
- end
-
- test "change_match_minute_log/1 returns a match_minute_log changeset" do
- match_minute_log = LoggingFixtures.match_minute_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_match_minute_log(match_minute_log)
- end
- end
-end
diff --git a/test/logging/libs/match_month_log_lib_test.exs b/test/logging/libs/match_month_log_lib_test.exs
deleted file mode 100644
index 13050f00c..000000000
--- a/test/logging/libs/match_month_log_lib_test.exs
+++ /dev/null
@@ -1,102 +0,0 @@
-defmodule Teiserver.MatchMonthLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.MatchMonthLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- year: 1,
- month: 1,
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(months: 1),
- year: 2,
- month: 2,
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "match_month_log" do
- alias Teiserver.Logging.MatchMonthLog
-
- test "match_month_log_query/0 returns a query" do
- q = Logging.match_month_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_match_month_log/0 returns match_month_log" do
- # No match_month_log yet
- assert Logging.list_match_month_logs([]) == []
-
- # Add a match_month_log
- LoggingFixtures.match_month_log_fixture()
- assert Logging.list_match_month_logs([]) != []
- end
-
- test "get_match_month_log!/1 and get_match_month_log/1 returns the match_month_log with given id" do
- match_month_log = LoggingFixtures.match_month_log_fixture()
- assert Logging.get_match_month_log!(match_month_log.date) == match_month_log
- assert Logging.get_match_month_log(match_month_log.date) == match_month_log
- end
-
- test "create_match_month_log/1 with valid data creates a match_month_log" do
- assert {:ok, %MatchMonthLog{} = match_month_log} =
- Logging.create_match_month_log(valid_attrs())
-
- assert match_month_log.data == %{"key" => 1}
- end
-
- test "create_match_month_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_match_month_log(invalid_attrs())
- end
-
- test "update_match_month_log/2 with valid data updates the match_month_log" do
- match_month_log = LoggingFixtures.match_month_log_fixture()
-
- assert {:ok, %MatchMonthLog{} = match_month_log} =
- Logging.update_match_month_log(match_month_log, update_attrs())
-
- assert match_month_log.data == %{"other-key" => 2}
- end
-
- test "update_match_month_log/2 with invalid data returns error changeset" do
- match_month_log = LoggingFixtures.match_month_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_match_month_log(match_month_log, invalid_attrs())
-
- assert match_month_log == Logging.get_match_month_log!(match_month_log.date)
- end
-
- test "delete_match_month_log/1 deletes the match_month_log" do
- match_month_log = LoggingFixtures.match_month_log_fixture()
- assert {:ok, %MatchMonthLog{}} = Logging.delete_match_month_log(match_month_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_match_month_log!(match_month_log.date)
- end
-
- assert Logging.get_match_month_log(match_month_log.date) == nil
- end
-
- test "change_match_month_log/1 returns a match_month_log changeset" do
- match_month_log = LoggingFixtures.match_month_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_match_month_log(match_month_log)
- end
- end
-end
diff --git a/test/logging/libs/match_quarter_log_lib_test.exs b/test/logging/libs/match_quarter_log_lib_test.exs
deleted file mode 100644
index 93b19b8c2..000000000
--- a/test/logging/libs/match_quarter_log_lib_test.exs
+++ /dev/null
@@ -1,102 +0,0 @@
-defmodule Teiserver.MatchQuarterLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.MatchQuarterLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- year: 1,
- quarter: 1,
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(months: 3),
- year: 2,
- quarter: 2,
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "match_quarter_log" do
- alias Teiserver.Logging.MatchQuarterLog
-
- test "match_quarter_log_query/0 returns a query" do
- q = Logging.match_quarter_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_match_quarter_log/0 returns match_quarter_log" do
- # No match_quarter_log yet
- assert Logging.list_match_quarter_logs([]) == []
-
- # Add a match_quarter_log
- LoggingFixtures.match_quarter_log_fixture()
- assert Logging.list_match_quarter_logs([]) != []
- end
-
- test "get_match_quarter_log!/1 and get_match_quarter_log/1 returns the match_quarter_log with given id" do
- match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
- assert Logging.get_match_quarter_log!(match_quarter_log.date) == match_quarter_log
- assert Logging.get_match_quarter_log(match_quarter_log.date) == match_quarter_log
- end
-
- test "create_match_quarter_log/1 with valid data creates a match_quarter_log" do
- assert {:ok, %MatchQuarterLog{} = match_quarter_log} =
- Logging.create_match_quarter_log(valid_attrs())
-
- assert match_quarter_log.data == %{"key" => 1}
- end
-
- test "create_match_quarter_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_match_quarter_log(invalid_attrs())
- end
-
- test "update_match_quarter_log/2 with valid data updates the match_quarter_log" do
- match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
-
- assert {:ok, %MatchQuarterLog{} = match_quarter_log} =
- Logging.update_match_quarter_log(match_quarter_log, update_attrs())
-
- assert match_quarter_log.data == %{"other-key" => 2}
- end
-
- test "update_match_quarter_log/2 with invalid data returns error changeset" do
- match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_match_quarter_log(match_quarter_log, invalid_attrs())
-
- assert match_quarter_log == Logging.get_match_quarter_log!(match_quarter_log.date)
- end
-
- test "delete_match_quarter_log/1 deletes the match_quarter_log" do
- match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
- assert {:ok, %MatchQuarterLog{}} = Logging.delete_match_quarter_log(match_quarter_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_match_quarter_log!(match_quarter_log.date)
- end
-
- assert Logging.get_match_quarter_log(match_quarter_log.date) == nil
- end
-
- test "change_match_quarter_log/1 returns a match_quarter_log changeset" do
- match_quarter_log = LoggingFixtures.match_quarter_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_match_quarter_log(match_quarter_log)
- end
- end
-end
diff --git a/test/logging/libs/match_week_log_lib_test.exs b/test/logging/libs/match_week_log_lib_test.exs
deleted file mode 100644
index cbc31504a..000000000
--- a/test/logging/libs/match_week_log_lib_test.exs
+++ /dev/null
@@ -1,102 +0,0 @@
-defmodule Teiserver.MatchWeekLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.MatchWeekLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- year: 1,
- week: 1,
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(weeks: 1),
- year: 2,
- week: 2,
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "match_week_log" do
- alias Teiserver.Logging.MatchWeekLog
-
- test "match_week_log_query/0 returns a query" do
- q = Logging.match_week_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_match_week_log/0 returns match_week_log" do
- # No match_week_log yet
- assert Logging.list_match_week_logs([]) == []
-
- # Add a match_week_log
- LoggingFixtures.match_week_log_fixture()
- assert Logging.list_match_week_logs([]) != []
- end
-
- test "get_match_week_log!/1 and get_match_week_log/1 returns the match_week_log with given id" do
- match_week_log = LoggingFixtures.match_week_log_fixture()
- assert Logging.get_match_week_log!(match_week_log.date) == match_week_log
- assert Logging.get_match_week_log(match_week_log.date) == match_week_log
- end
-
- test "create_match_week_log/1 with valid data creates a match_week_log" do
- assert {:ok, %MatchWeekLog{} = match_week_log} =
- Logging.create_match_week_log(valid_attrs())
-
- assert match_week_log.data == %{"key" => 1}
- end
-
- test "create_match_week_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_match_week_log(invalid_attrs())
- end
-
- test "update_match_week_log/2 with valid data updates the match_week_log" do
- match_week_log = LoggingFixtures.match_week_log_fixture()
-
- assert {:ok, %MatchWeekLog{} = match_week_log} =
- Logging.update_match_week_log(match_week_log, update_attrs())
-
- assert match_week_log.data == %{"other-key" => 2}
- end
-
- test "update_match_week_log/2 with invalid data returns error changeset" do
- match_week_log = LoggingFixtures.match_week_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_match_week_log(match_week_log, invalid_attrs())
-
- assert match_week_log == Logging.get_match_week_log!(match_week_log.date)
- end
-
- test "delete_match_week_log/1 deletes the match_week_log" do
- match_week_log = LoggingFixtures.match_week_log_fixture()
- assert {:ok, %MatchWeekLog{}} = Logging.delete_match_week_log(match_week_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_match_week_log!(match_week_log.date)
- end
-
- assert Logging.get_match_week_log(match_week_log.date) == nil
- end
-
- test "change_match_week_log/1 returns a match_week_log changeset" do
- match_week_log = LoggingFixtures.match_week_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_match_week_log(match_week_log)
- end
- end
-end
diff --git a/test/logging/libs/match_year_log_lib_test.exs b/test/logging/libs/match_year_log_lib_test.exs
deleted file mode 100644
index 7f1471c9c..000000000
--- a/test/logging/libs/match_year_log_lib_test.exs
+++ /dev/null
@@ -1,100 +0,0 @@
-defmodule Teiserver.MatchYearLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.MatchYearLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- year: 1,
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(years: 1),
- year: 2,
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "match_year_log" do
- alias Teiserver.Logging.MatchYearLog
-
- test "match_year_log_query/0 returns a query" do
- q = Logging.match_year_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_match_year_log/0 returns match_year_log" do
- # No match_year_log yet
- assert Logging.list_match_year_logs([]) == []
-
- # Add a match_year_log
- LoggingFixtures.match_year_log_fixture()
- assert Logging.list_match_year_logs([]) != []
- end
-
- test "get_match_year_log!/1 and get_match_year_log/1 returns the match_year_log with given id" do
- match_year_log = LoggingFixtures.match_year_log_fixture()
- assert Logging.get_match_year_log!(match_year_log.date) == match_year_log
- assert Logging.get_match_year_log(match_year_log.date) == match_year_log
- end
-
- test "create_match_year_log/1 with valid data creates a match_year_log" do
- assert {:ok, %MatchYearLog{} = match_year_log} =
- Logging.create_match_year_log(valid_attrs())
-
- assert match_year_log.data == %{"key" => 1}
- end
-
- test "create_match_year_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_match_year_log(invalid_attrs())
- end
-
- test "update_match_year_log/2 with valid data updates the match_year_log" do
- match_year_log = LoggingFixtures.match_year_log_fixture()
-
- assert {:ok, %MatchYearLog{} = match_year_log} =
- Logging.update_match_year_log(match_year_log, update_attrs())
-
- assert match_year_log.data == %{"other-key" => 2}
- end
-
- test "update_match_year_log/2 with invalid data returns error changeset" do
- match_year_log = LoggingFixtures.match_year_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_match_year_log(match_year_log, invalid_attrs())
-
- assert match_year_log == Logging.get_match_year_log!(match_year_log.date)
- end
-
- test "delete_match_year_log/1 deletes the match_year_log" do
- match_year_log = LoggingFixtures.match_year_log_fixture()
- assert {:ok, %MatchYearLog{}} = Logging.delete_match_year_log(match_year_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_match_year_log!(match_year_log.date)
- end
-
- assert Logging.get_match_year_log(match_year_log.date) == nil
- end
-
- test "change_match_year_log/1 returns a match_year_log changeset" do
- match_year_log = LoggingFixtures.match_year_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_match_year_log(match_year_log)
- end
- end
-end
diff --git a/test/logging/libs/server_day_log_lib_test.exs b/test/logging/libs/server_day_log_lib_test.exs
deleted file mode 100644
index 3068bdc12..000000000
--- a/test/logging/libs/server_day_log_lib_test.exs
+++ /dev/null
@@ -1,98 +0,0 @@
-defmodule Teiserver.ServerDayLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.ServerDayLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(days: 1),
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "server_day_log" do
- alias Teiserver.Logging.ServerDayLog
-
- test "server_day_log_query/0 returns a query" do
- q = Logging.server_day_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_server_day_log/0 returns server_day_log" do
- # No server_day_log yet
- assert Logging.list_server_day_logs([]) == []
-
- # Add a server_day_log
- LoggingFixtures.server_day_log_fixture()
- assert Logging.list_server_day_logs([]) != []
- end
-
- test "get_server_day_log!/1 and get_server_day_log/1 returns the server_day_log with given id" do
- server_day_log = LoggingFixtures.server_day_log_fixture()
- assert Logging.get_server_day_log!(server_day_log.date) == server_day_log
- assert Logging.get_server_day_log(server_day_log.date) == server_day_log
- end
-
- test "create_server_day_log/1 with valid data creates a server_day_log" do
- assert {:ok, %ServerDayLog{} = server_day_log} =
- Logging.create_server_day_log(valid_attrs())
-
- assert server_day_log.data == %{"key" => 1}
- end
-
- test "create_server_day_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_server_day_log(invalid_attrs())
- end
-
- test "update_server_day_log/2 with valid data updates the server_day_log" do
- server_day_log = LoggingFixtures.server_day_log_fixture()
-
- assert {:ok, %ServerDayLog{} = server_day_log} =
- Logging.update_server_day_log(server_day_log, update_attrs())
-
- assert server_day_log.data == %{"other-key" => 2}
- end
-
- test "update_server_day_log/2 with invalid data returns error changeset" do
- server_day_log = LoggingFixtures.server_day_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_server_day_log(server_day_log, invalid_attrs())
-
- assert server_day_log == Logging.get_server_day_log!(server_day_log.date)
- end
-
- test "delete_server_day_log/1 deletes the server_day_log" do
- server_day_log = LoggingFixtures.server_day_log_fixture()
- assert {:ok, %ServerDayLog{}} = Logging.delete_server_day_log(server_day_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_server_day_log!(server_day_log.date)
- end
-
- assert Logging.get_server_day_log(server_day_log.date) == nil
- end
-
- test "change_server_day_log/1 returns a server_day_log changeset" do
- server_day_log = LoggingFixtures.server_day_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_server_day_log(server_day_log)
- end
- end
-end
diff --git a/test/logging/libs/server_minute_log_lib_test.exs b/test/logging/libs/server_minute_log_lib_test.exs
deleted file mode 100644
index f3a25781b..000000000
--- a/test/logging/libs/server_minute_log_lib_test.exs
+++ /dev/null
@@ -1,98 +0,0 @@
-defmodule Teiserver.ServerMinuteLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.ServerMinuteLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- timestamp: Timex.now(),
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- timestamp: Timex.now() |> Timex.shift(minutes: 1),
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- timestamp: nil,
- data: nil
- }
- end
-
- describe "server_minute_log" do
- alias Teiserver.Logging.ServerMinuteLog
-
- test "server_minute_log_query/0 returns a query" do
- q = Logging.server_minute_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_server_minute_log/0 returns server_minute_log" do
- # No server_minute_log yet
- assert Logging.list_server_minute_logs([]) == []
-
- # Add a server_minute_log
- LoggingFixtures.server_minute_log_fixture()
- assert Logging.list_server_minute_logs([]) != []
- end
-
- test "get_server_minute_log!/1 and get_server_minute_log/1 returns the server_minute_log with given id" do
- server_minute_log = LoggingFixtures.server_minute_log_fixture()
- assert Logging.get_server_minute_log!(server_minute_log.timestamp) == server_minute_log
- assert Logging.get_server_minute_log(server_minute_log.timestamp) == server_minute_log
- end
-
- test "create_server_minute_log/1 with valid data creates a server_minute_log" do
- assert {:ok, %ServerMinuteLog{} = server_minute_log} =
- Logging.create_server_minute_log(valid_attrs())
-
- assert server_minute_log.data == %{"key" => 1}
- end
-
- test "create_server_minute_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_server_minute_log(invalid_attrs())
- end
-
- test "update_server_minute_log/2 with valid data updates the server_minute_log" do
- server_minute_log = LoggingFixtures.server_minute_log_fixture()
-
- assert {:ok, %ServerMinuteLog{} = server_minute_log} =
- Logging.update_server_minute_log(server_minute_log, update_attrs())
-
- assert server_minute_log.data == %{"other-key" => 2}
- end
-
- test "update_server_minute_log/2 with invalid data returns error changeset" do
- server_minute_log = LoggingFixtures.server_minute_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_server_minute_log(server_minute_log, invalid_attrs())
-
- assert server_minute_log == Logging.get_server_minute_log!(server_minute_log.timestamp)
- end
-
- test "delete_server_minute_log/1 deletes the server_minute_log" do
- server_minute_log = LoggingFixtures.server_minute_log_fixture()
- assert {:ok, %ServerMinuteLog{}} = Logging.delete_server_minute_log(server_minute_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_server_minute_log!(server_minute_log.timestamp)
- end
-
- assert Logging.get_server_minute_log(server_minute_log.timestamp) == nil
- end
-
- test "change_server_minute_log/1 returns a server_minute_log changeset" do
- server_minute_log = LoggingFixtures.server_minute_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_server_minute_log(server_minute_log)
- end
- end
-end
diff --git a/test/logging/libs/server_month_log_lib_test.exs b/test/logging/libs/server_month_log_lib_test.exs
deleted file mode 100644
index 1a7cd566c..000000000
--- a/test/logging/libs/server_month_log_lib_test.exs
+++ /dev/null
@@ -1,102 +0,0 @@
-defmodule Teiserver.ServerMonthLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.ServerMonthLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- year: 1,
- month: 1,
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(months: 1),
- year: 2,
- month: 2,
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "server_month_log" do
- alias Teiserver.Logging.ServerMonthLog
-
- test "server_month_log_query/0 returns a query" do
- q = Logging.server_month_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_server_month_log/0 returns server_month_log" do
- # No server_month_log yet
- assert Logging.list_server_month_logs([]) == []
-
- # Add a server_month_log
- LoggingFixtures.server_month_log_fixture()
- assert Logging.list_server_month_logs([]) != []
- end
-
- test "get_server_month_log!/1 and get_server_month_log/1 returns the server_month_log with given id" do
- server_month_log = LoggingFixtures.server_month_log_fixture()
- assert Logging.get_server_month_log!(server_month_log.date) == server_month_log
- assert Logging.get_server_month_log(server_month_log.date) == server_month_log
- end
-
- test "create_server_month_log/1 with valid data creates a server_month_log" do
- assert {:ok, %ServerMonthLog{} = server_month_log} =
- Logging.create_server_month_log(valid_attrs())
-
- assert server_month_log.data == %{"key" => 1}
- end
-
- test "create_server_month_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_server_month_log(invalid_attrs())
- end
-
- test "update_server_month_log/2 with valid data updates the server_month_log" do
- server_month_log = LoggingFixtures.server_month_log_fixture()
-
- assert {:ok, %ServerMonthLog{} = server_month_log} =
- Logging.update_server_month_log(server_month_log, update_attrs())
-
- assert server_month_log.data == %{"other-key" => 2}
- end
-
- test "update_server_month_log/2 with invalid data returns error changeset" do
- server_month_log = LoggingFixtures.server_month_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_server_month_log(server_month_log, invalid_attrs())
-
- assert server_month_log == Logging.get_server_month_log!(server_month_log.date)
- end
-
- test "delete_server_month_log/1 deletes the server_month_log" do
- server_month_log = LoggingFixtures.server_month_log_fixture()
- assert {:ok, %ServerMonthLog{}} = Logging.delete_server_month_log(server_month_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_server_month_log!(server_month_log.date)
- end
-
- assert Logging.get_server_month_log(server_month_log.date) == nil
- end
-
- test "change_server_month_log/1 returns a server_month_log changeset" do
- server_month_log = LoggingFixtures.server_month_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_server_month_log(server_month_log)
- end
- end
-end
diff --git a/test/logging/libs/server_quarter_log_lib_test.exs b/test/logging/libs/server_quarter_log_lib_test.exs
deleted file mode 100644
index f4c875347..000000000
--- a/test/logging/libs/server_quarter_log_lib_test.exs
+++ /dev/null
@@ -1,104 +0,0 @@
-defmodule Teiserver.ServerQuarterLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.ServerQuarterLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- year: 1,
- quarter: 1,
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(months: 3),
- year: 2,
- quarter: 2,
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- year: nil,
- quarter: nil,
- data: nil
- }
- end
-
- describe "server_quarter_log" do
- alias Teiserver.Logging.ServerQuarterLog
-
- test "server_quarter_log_query/0 returns a query" do
- q = Logging.server_quarter_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_server_quarter_log/0 returns server_quarter_log" do
- # No server_quarter_log yet
- assert Logging.list_server_quarter_logs([]) == []
-
- # Add a server_quarter_log
- LoggingFixtures.server_quarter_log_fixture()
- assert Logging.list_server_quarter_logs([]) != []
- end
-
- test "get_server_quarter_log!/1 and get_server_quarter_log/1 returns the server_quarter_log with given id" do
- server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
- assert Logging.get_server_quarter_log!(server_quarter_log.date) == server_quarter_log
- assert Logging.get_server_quarter_log(server_quarter_log.date) == server_quarter_log
- end
-
- test "create_server_quarter_log/1 with valid data creates a server_quarter_log" do
- assert {:ok, %ServerQuarterLog{} = server_quarter_log} =
- Logging.create_server_quarter_log(valid_attrs())
-
- assert server_quarter_log.data == %{"key" => 1}
- end
-
- test "create_server_quarter_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_server_quarter_log(invalid_attrs())
- end
-
- test "update_server_quarter_log/2 with valid data updates the server_quarter_log" do
- server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
-
- assert {:ok, %ServerQuarterLog{} = server_quarter_log} =
- Logging.update_server_quarter_log(server_quarter_log, update_attrs())
-
- assert server_quarter_log.data == %{"other-key" => 2}
- end
-
- test "update_server_quarter_log/2 with invalid data returns error changeset" do
- server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_server_quarter_log(server_quarter_log, invalid_attrs())
-
- assert server_quarter_log == Logging.get_server_quarter_log!(server_quarter_log.date)
- end
-
- test "delete_server_quarter_log/1 deletes the server_quarter_log" do
- server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
- assert {:ok, %ServerQuarterLog{}} = Logging.delete_server_quarter_log(server_quarter_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_server_quarter_log!(server_quarter_log.date)
- end
-
- assert Logging.get_server_quarter_log(server_quarter_log.date) == nil
- end
-
- test "change_server_quarter_log/1 returns a server_quarter_log changeset" do
- server_quarter_log = LoggingFixtures.server_quarter_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_server_quarter_log(server_quarter_log)
- end
- end
-end
diff --git a/test/logging/libs/server_week_log_lib_test.exs b/test/logging/libs/server_week_log_lib_test.exs
deleted file mode 100644
index 5eb21efc5..000000000
--- a/test/logging/libs/server_week_log_lib_test.exs
+++ /dev/null
@@ -1,102 +0,0 @@
-defmodule Teiserver.ServerWeekLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.ServerWeekLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- year: 1,
- week: 1,
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(weeks: 1),
- year: 2,
- week: 2,
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "server_week_log" do
- alias Teiserver.Logging.ServerWeekLog
-
- test "server_week_log_query/0 returns a query" do
- q = Logging.server_week_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_server_week_log/0 returns server_week_log" do
- # No server_week_log yet
- assert Logging.list_server_week_logs([]) == []
-
- # Add a server_week_log
- LoggingFixtures.server_week_log_fixture()
- assert Logging.list_server_week_logs([]) != []
- end
-
- test "get_server_week_log!/1 and get_server_week_log/1 returns the server_week_log with given id" do
- server_week_log = LoggingFixtures.server_week_log_fixture()
- assert Logging.get_server_week_log!(server_week_log.date) == server_week_log
- assert Logging.get_server_week_log(server_week_log.date) == server_week_log
- end
-
- test "create_server_week_log/1 with valid data creates a server_week_log" do
- assert {:ok, %ServerWeekLog{} = server_week_log} =
- Logging.create_server_week_log(valid_attrs())
-
- assert server_week_log.data == %{"key" => 1}
- end
-
- test "create_server_week_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_server_week_log(invalid_attrs())
- end
-
- test "update_server_week_log/2 with valid data updates the server_week_log" do
- server_week_log = LoggingFixtures.server_week_log_fixture()
-
- assert {:ok, %ServerWeekLog{} = server_week_log} =
- Logging.update_server_week_log(server_week_log, update_attrs())
-
- assert server_week_log.data == %{"other-key" => 2}
- end
-
- test "update_server_week_log/2 with invalid data returns error changeset" do
- server_week_log = LoggingFixtures.server_week_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_server_week_log(server_week_log, invalid_attrs())
-
- assert server_week_log == Logging.get_server_week_log!(server_week_log.date)
- end
-
- test "delete_server_week_log/1 deletes the server_week_log" do
- server_week_log = LoggingFixtures.server_week_log_fixture()
- assert {:ok, %ServerWeekLog{}} = Logging.delete_server_week_log(server_week_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_server_week_log!(server_week_log.date)
- end
-
- assert Logging.get_server_week_log(server_week_log.date) == nil
- end
-
- test "change_server_week_log/1 returns a server_week_log changeset" do
- server_week_log = LoggingFixtures.server_week_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_server_week_log(server_week_log)
- end
- end
-end
diff --git a/test/logging/libs/server_year_log_lib_test.exs b/test/logging/libs/server_year_log_lib_test.exs
deleted file mode 100644
index 068d5661b..000000000
--- a/test/logging/libs/server_year_log_lib_test.exs
+++ /dev/null
@@ -1,100 +0,0 @@
-defmodule Teiserver.ServerYearLogLibTest do
- @moduledoc false
- alias Teiserver.Logging.ServerYearLog
- alias Teiserver.Logging
- use Teiserver.Case, async: true
-
- alias Teiserver.LoggingFixtures
-
- defp valid_attrs do
- %{
- date: Timex.today(),
- year: 1,
- data: %{"key" => 1}
- }
- end
-
- defp update_attrs do
- %{
- date: Timex.today() |> Timex.shift(years: 1),
- year: 2,
- data: %{"other-key" => 2}
- }
- end
-
- defp invalid_attrs do
- %{
- date: nil,
- data: nil
- }
- end
-
- describe "server_year_log" do
- alias Teiserver.Logging.ServerYearLog
-
- test "server_year_log_query/0 returns a query" do
- q = Logging.server_year_log_query([])
- assert %Ecto.Query{} = q
- end
-
- test "list_server_year_log/0 returns server_year_log" do
- # No server_year_log yet
- assert Logging.list_server_year_logs([]) == []
-
- # Add a server_year_log
- LoggingFixtures.server_year_log_fixture()
- assert Logging.list_server_year_logs([]) != []
- end
-
- test "get_server_year_log!/1 and get_server_year_log/1 returns the server_year_log with given id" do
- server_year_log = LoggingFixtures.server_year_log_fixture()
- assert Logging.get_server_year_log!(server_year_log.date) == server_year_log
- assert Logging.get_server_year_log(server_year_log.date) == server_year_log
- end
-
- test "create_server_year_log/1 with valid data creates a server_year_log" do
- assert {:ok, %ServerYearLog{} = server_year_log} =
- Logging.create_server_year_log(valid_attrs())
-
- assert server_year_log.data == %{"key" => 1}
- end
-
- test "create_server_year_log/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Logging.create_server_year_log(invalid_attrs())
- end
-
- test "update_server_year_log/2 with valid data updates the server_year_log" do
- server_year_log = LoggingFixtures.server_year_log_fixture()
-
- assert {:ok, %ServerYearLog{} = server_year_log} =
- Logging.update_server_year_log(server_year_log, update_attrs())
-
- assert server_year_log.data == %{"other-key" => 2}
- end
-
- test "update_server_year_log/2 with invalid data returns error changeset" do
- server_year_log = LoggingFixtures.server_year_log_fixture()
-
- assert {:error, %Ecto.Changeset{}} =
- Logging.update_server_year_log(server_year_log, invalid_attrs())
-
- assert server_year_log == Logging.get_server_year_log!(server_year_log.date)
- end
-
- test "delete_server_year_log/1 deletes the server_year_log" do
- server_year_log = LoggingFixtures.server_year_log_fixture()
- assert {:ok, %ServerYearLog{}} = Logging.delete_server_year_log(server_year_log)
-
- assert_raise Ecto.NoResultsError, fn ->
- Logging.get_server_year_log!(server_year_log.date)
- end
-
- assert Logging.get_server_year_log(server_year_log.date) == nil
- end
-
- test "change_server_year_log/1 returns a server_year_log changeset" do
- server_year_log = LoggingFixtures.server_year_log_fixture()
- assert %Ecto.Changeset{} = Logging.change_server_year_log(server_year_log)
- end
- end
-end
diff --git a/test/logging/queries/match_day_log_queries_test.exs b/test/logging/queries/match_day_log_queries_test.exs
deleted file mode 100644
index 3bfef2061..000000000
--- a/test/logging/queries/match_day_log_queries_test.exs
+++ /dev/null
@@ -1,47 +0,0 @@
-defmodule Teiserver.MatchDayLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.MatchDayLogQueries
-
- describe "queries" do
- @empty_query MatchDayLogQueries.match_day_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- MatchDayLogQueries.match_day_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- MatchDayLogQueries.match_day_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- MatchDayLogQueries.match_day_log_query(
- where: [
- date: Timex.today(),
- after: Timex.today(),
- before: Timex.today()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/match_minute_log_queries_test.exs b/test/logging/queries/match_minute_log_queries_test.exs
deleted file mode 100644
index 2aa68dad5..000000000
--- a/test/logging/queries/match_minute_log_queries_test.exs
+++ /dev/null
@@ -1,46 +0,0 @@
-defmodule Teiserver.MatchMinuteLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.MatchMinuteLogQueries
-
- describe "queries" do
- @empty_query MatchMinuteLogQueries.match_minute_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- MatchMinuteLogQueries.match_minute_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- MatchMinuteLogQueries.match_minute_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- MatchMinuteLogQueries.match_minute_log_query(
- where: [
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/match_month_log_queries_test.exs b/test/logging/queries/match_month_log_queries_test.exs
deleted file mode 100644
index 3ca31386e..000000000
--- a/test/logging/queries/match_month_log_queries_test.exs
+++ /dev/null
@@ -1,49 +0,0 @@
-defmodule Teiserver.MatchMonthLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.MatchMonthLogQueries
-
- describe "queries" do
- @empty_query MatchMonthLogQueries.match_month_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- MatchMonthLogQueries.match_month_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- MatchMonthLogQueries.match_month_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- MatchMonthLogQueries.match_month_log_query(
- where: [
- date: Timex.today(),
- year: 123,
- month: 123,
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/match_quarter_log_queries_test.exs b/test/logging/queries/match_quarter_log_queries_test.exs
deleted file mode 100644
index aa787e14e..000000000
--- a/test/logging/queries/match_quarter_log_queries_test.exs
+++ /dev/null
@@ -1,49 +0,0 @@
-defmodule Teiserver.MatchQuarterLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.MatchQuarterLogQueries
-
- describe "queries" do
- @empty_query MatchQuarterLogQueries.match_quarter_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- MatchQuarterLogQueries.match_quarter_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- MatchQuarterLogQueries.match_quarter_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- MatchQuarterLogQueries.match_quarter_log_query(
- where: [
- date: Timex.today(),
- year: 123,
- quarter: 123,
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/match_week_log_queries_test.exs b/test/logging/queries/match_week_log_queries_test.exs
deleted file mode 100644
index 16fd6916e..000000000
--- a/test/logging/queries/match_week_log_queries_test.exs
+++ /dev/null
@@ -1,49 +0,0 @@
-defmodule Teiserver.MatchWeekLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.MatchWeekLogQueries
-
- describe "queries" do
- @empty_query MatchWeekLogQueries.match_week_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- MatchWeekLogQueries.match_week_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- MatchWeekLogQueries.match_week_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- MatchWeekLogQueries.match_week_log_query(
- where: [
- date: Timex.today(),
- year: 123,
- week: 123,
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/match_year_log_queries_test.exs b/test/logging/queries/match_year_log_queries_test.exs
deleted file mode 100644
index 32a67b0b6..000000000
--- a/test/logging/queries/match_year_log_queries_test.exs
+++ /dev/null
@@ -1,48 +0,0 @@
-defmodule Teiserver.MatchYearLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.MatchYearLogQueries
-
- describe "queries" do
- @empty_query MatchYearLogQueries.match_year_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- MatchYearLogQueries.match_year_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- MatchYearLogQueries.match_year_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- MatchYearLogQueries.match_year_log_query(
- where: [
- date: Timex.today(),
- year: 123,
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/server_day_log_queries_test.exs b/test/logging/queries/server_day_log_queries_test.exs
deleted file mode 100644
index 6b7f7c25c..000000000
--- a/test/logging/queries/server_day_log_queries_test.exs
+++ /dev/null
@@ -1,47 +0,0 @@
-defmodule Teiserver.ServerDayLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.ServerDayLogQueries
-
- describe "queries" do
- @empty_query ServerDayLogQueries.server_day_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- ServerDayLogQueries.server_day_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- ServerDayLogQueries.server_day_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- ServerDayLogQueries.server_day_log_query(
- where: [
- date: Timex.today(),
- after: Timex.today(),
- before: Timex.today()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/server_minute_log_queries_test.exs b/test/logging/queries/server_minute_log_queries_test.exs
deleted file mode 100644
index dfdc01afa..000000000
--- a/test/logging/queries/server_minute_log_queries_test.exs
+++ /dev/null
@@ -1,46 +0,0 @@
-defmodule Teiserver.ServerMinuteLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.ServerMinuteLogQueries
-
- describe "queries" do
- @empty_query ServerMinuteLogQueries.server_minute_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- ServerMinuteLogQueries.server_minute_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- ServerMinuteLogQueries.server_minute_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- ServerMinuteLogQueries.server_minute_log_query(
- where: [
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/server_month_log_queries_test.exs b/test/logging/queries/server_month_log_queries_test.exs
deleted file mode 100644
index 346e932c0..000000000
--- a/test/logging/queries/server_month_log_queries_test.exs
+++ /dev/null
@@ -1,49 +0,0 @@
-defmodule Teiserver.ServerMonthLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.ServerMonthLogQueries
-
- describe "queries" do
- @empty_query ServerMonthLogQueries.server_month_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- ServerMonthLogQueries.server_month_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- ServerMonthLogQueries.server_month_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- ServerMonthLogQueries.server_month_log_query(
- where: [
- date: Timex.today(),
- year: 123,
- month: 123,
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/server_quarter_log_queries_test.exs b/test/logging/queries/server_quarter_log_queries_test.exs
deleted file mode 100644
index 7492c7402..000000000
--- a/test/logging/queries/server_quarter_log_queries_test.exs
+++ /dev/null
@@ -1,49 +0,0 @@
-defmodule Teiserver.ServerQuarterLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.ServerQuarterLogQueries
-
- describe "queries" do
- @empty_query ServerQuarterLogQueries.server_quarter_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- ServerQuarterLogQueries.server_quarter_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- ServerQuarterLogQueries.server_quarter_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- ServerQuarterLogQueries.server_quarter_log_query(
- where: [
- date: Timex.today(),
- year: 123,
- quarter: 123,
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/server_week_log_queries_test.exs b/test/logging/queries/server_week_log_queries_test.exs
deleted file mode 100644
index 8830bba80..000000000
--- a/test/logging/queries/server_week_log_queries_test.exs
+++ /dev/null
@@ -1,49 +0,0 @@
-defmodule Teiserver.ServerWeekLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.ServerWeekLogQueries
-
- describe "queries" do
- @empty_query ServerWeekLogQueries.server_week_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- ServerWeekLogQueries.server_week_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- ServerWeekLogQueries.server_week_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- ServerWeekLogQueries.server_week_log_query(
- where: [
- date: Timex.today(),
- year: 123,
- week: 123,
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/logging/queries/server_year_log_queries_test.exs b/test/logging/queries/server_year_log_queries_test.exs
deleted file mode 100644
index 8a70ebf64..000000000
--- a/test/logging/queries/server_year_log_queries_test.exs
+++ /dev/null
@@ -1,48 +0,0 @@
-defmodule Teiserver.ServerYearLogQueriesTest do
- @moduledoc false
- use Teiserver.Case, async: true
-
- alias Teiserver.Logging.ServerYearLogQueries
-
- describe "queries" do
- @empty_query ServerYearLogQueries.server_year_log_query([])
-
- test "clauses" do
- # Null values, shouldn't error but shouldn't generate a query
- null_values =
- ServerYearLogQueries.server_year_log_query(
- where: [
- key1: "",
- key2: nil
- ]
- )
-
- assert null_values == @empty_query
- Repo.all(null_values)
-
- # If a key is not present in the query library it should error
- assert_raise(FunctionClauseError, fn ->
- ServerYearLogQueries.server_year_log_query(where: [not_a_key: 1])
- end)
-
- # we expect the query to run though it won't produce meaningful results
- all_values =
- ServerYearLogQueries.server_year_log_query(
- where: [
- date: Timex.today(),
- year: 123,
- after: Timex.now(),
- before: Timex.now()
- ],
- order_by: [
- "Newest first",
- "Oldest first"
- ],
- preload: []
- )
-
- assert all_values != @empty_query
- Repo.all(all_values)
- end
- end
-end
diff --git a/test/support/fixtures/logging_fixtures.ex b/test/support/fixtures/logging_fixtures.ex
index e661c4b37..0a66ee821 100644
--- a/test/support/fixtures/logging_fixtures.ex
+++ b/test/support/fixtures/logging_fixtures.ex
@@ -2,7 +2,6 @@ defmodule Teiserver.LoggingFixtures do
@moduledoc false
import Teiserver.AccountFixtures, only: [user_fixture: 0]
alias Teiserver.Logging.{AuditLog}
- alias Teiserver.Logging
@spec audit_log_fixture() :: AuditLog.t()
@spec audit_log_fixture(map) :: AuditLog.t()
@@ -37,176 +36,4 @@ defmodule Teiserver.LoggingFixtures do
)
|> Teiserver.Repo.insert!()
end
-
- # Match logs
- @spec match_minute_log_fixture() :: Logging.MatchMinuteLog.t()
- @spec match_minute_log_fixture(map) :: Logging.MatchMinuteLog.t()
- def match_minute_log_fixture(data \\ %{}) do
- Logging.MatchMinuteLog.changeset(
- %Logging.MatchMinuteLog{},
- %{
- timestamp: data[:timestamp] || Timex.now(),
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec match_day_log_fixture() :: Logging.MatchDayLog.t()
- @spec match_day_log_fixture(map) :: Logging.MatchDayLog.t()
- def match_day_log_fixture(data \\ %{}) do
- Logging.MatchDayLog.changeset(
- %Logging.MatchDayLog{},
- %{
- date: data[:date] || Timex.today(),
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec match_week_log_fixture() :: Logging.MatchWeekLog.t()
- @spec match_week_log_fixture(map) :: Logging.MatchWeekLog.t()
- def match_week_log_fixture(data \\ %{}) do
- Logging.MatchWeekLog.changeset(
- %Logging.MatchWeekLog{},
- %{
- date: data[:date] || Timex.today(),
- year: data[:year] || 1,
- week: data[:week] || 1,
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec match_month_log_fixture() :: Logging.MatchMonthLog.t()
- @spec match_month_log_fixture(map) :: Logging.MatchMonthLog.t()
- def match_month_log_fixture(data \\ %{}) do
- Logging.MatchMonthLog.changeset(
- %Logging.MatchMonthLog{},
- %{
- date: data[:date] || Timex.today(),
- year: data[:year] || 1,
- month: data[:month] || 1,
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec match_quarter_log_fixture() :: Logging.MatchQuarterLog.t()
- @spec match_quarter_log_fixture(map) :: Logging.MatchQuarterLog.t()
- def match_quarter_log_fixture(data \\ %{}) do
- Logging.MatchQuarterLog.changeset(
- %Logging.MatchQuarterLog{},
- %{
- date: data[:date] || Timex.today(),
- year: data[:year] || 1,
- quarter: data[:quarter] || 1,
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec match_year_log_fixture() :: Logging.MatchYearLog.t()
- @spec match_year_log_fixture(map) :: Logging.MatchYearLog.t()
- def match_year_log_fixture(data \\ %{}) do
- Logging.MatchYearLog.changeset(
- %Logging.MatchYearLog{},
- %{
- date: data[:date] || Timex.today(),
- year: data[:year] || 1,
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- # Server logs
- @spec server_minute_log_fixture() :: Logging.ServerMinuteLog.t()
- @spec server_minute_log_fixture(map) :: Logging.ServerMinuteLog.t()
- def server_minute_log_fixture(data \\ %{}) do
- Logging.ServerMinuteLog.changeset(
- %Logging.ServerMinuteLog{},
- %{
- timestamp: data[:timestamp] || Timex.now(),
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec server_day_log_fixture() :: Logging.ServerDayLog.t()
- @spec server_day_log_fixture(map) :: Logging.ServerDayLog.t()
- def server_day_log_fixture(data \\ %{}) do
- Logging.ServerDayLog.changeset(
- %Logging.ServerDayLog{},
- %{
- date: data[:date] || Timex.today(),
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec server_week_log_fixture() :: Logging.ServerWeekLog.t()
- @spec server_week_log_fixture(map) :: Logging.ServerWeekLog.t()
- def server_week_log_fixture(data \\ %{}) do
- Logging.ServerWeekLog.changeset(
- %Logging.ServerWeekLog{},
- %{
- date: data[:date] || Timex.today(),
- year: data[:year] || 1,
- week: data[:week] || 1,
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec server_month_log_fixture() :: Logging.ServerMonthLog.t()
- @spec server_month_log_fixture(map) :: Logging.ServerMonthLog.t()
- def server_month_log_fixture(data \\ %{}) do
- Logging.ServerMonthLog.changeset(
- %Logging.ServerMonthLog{},
- %{
- date: data[:date] || Timex.today(),
- year: data[:year] || 1,
- month: data[:month] || 1,
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec server_quarter_log_fixture() :: Logging.ServerQuarterLog.t()
- @spec server_quarter_log_fixture(map) :: Logging.ServerQuarterLog.t()
- def server_quarter_log_fixture(data \\ %{}) do
- Logging.ServerQuarterLog.changeset(
- %Logging.ServerQuarterLog{},
- %{
- date: data[:date] || Timex.today(),
- year: data[:year] || 1,
- quarter: data[:quarter] || 1,
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
-
- @spec server_year_log_fixture() :: Logging.ServerYearLog.t()
- @spec server_year_log_fixture(map) :: Logging.ServerYearLog.t()
- def server_year_log_fixture(data \\ %{}) do
- Logging.ServerYearLog.changeset(
- %Logging.ServerYearLog{},
- %{
- date: data[:date] || Timex.today(),
- year: data[:year] || 1,
- data: data[:data] || %{}
- }
- )
- |> Teiserver.Repo.insert!()
- end
end
From 5b7c9dfabf5e8677bf18b67df8f9ef7a7ae8baef Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 8 Apr 2024 18:18:36 +0100
Subject: [PATCH 13/64] Started putting in :telemetry events, mostly copied
from Oban right now
---
documentation/development/telemetry.md | 2 +
lib/teiserver/connections/client_server.ex | 36 ++++
lib/teiserver/contexts/telemetry.ex | 203 ++++++++++++++++++++
lib/teiserver/game/libs/lobby_lib.ex | 20 +-
lib/teiserver/game/libs/match_lib.ex | 5 +-
lib/teiserver/game/schemas/match.ex | 4 +-
lib/teiserver/game/servers/lobby_server.ex | 32 ++-
lib/teiserver/logging/libs/audit_log_lib.ex | 12 ++
lib/teiserver/migrations/postgres/v01.ex | 2 +
mix.exs | 1 +
10 files changed, 307 insertions(+), 10 deletions(-)
create mode 100644 documentation/development/telemetry.md
create mode 100644 lib/teiserver/contexts/telemetry.ex
diff --git a/documentation/development/telemetry.md b/documentation/development/telemetry.md
new file mode 100644
index 000000000..172d54b8b
--- /dev/null
+++ b/documentation/development/telemetry.md
@@ -0,0 +1,2 @@
+# Events
+Teiserver emits the following events:
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index 3e4cfb1c5..a5238668d 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -38,8 +38,20 @@ defmodule Teiserver.Connections.ClientServer do
new_connections = Enum.uniq([conn_pid | state.connections])
if state.client.connected? do
+ :telemetry.execute(
+ [:teiserver, :client, :added_connection],
+ %{},
+ %{user_id: state.user_id}
+ )
+
{:noreply, %State{state | connections: new_connections}}
else
+ :telemetry.execute(
+ [:teiserver, :client, :new_connection],
+ %{},
+ %{user_id: state.user_id}
+ )
+
new_client = %{state.client | connected?: true}
Teiserver.broadcast(state.client_topic, %{
@@ -56,6 +68,12 @@ defmodule Teiserver.Connections.ClientServer do
if Enum.empty?(partial_client) do
{:noreply, state}
else
+ :telemetry.execute(
+ [:teiserver, :client, :updated],
+ %{},
+ %{user_id: state.user_id}
+ )
+
new_client = struct(state.client, partial_client)
new_state = update_client(state, new_client, reason)
{:noreply, new_state}
@@ -78,6 +96,12 @@ defmodule Teiserver.Connections.ClientServer do
end
def handle_cast({:do_update_client_in_lobby, new_client, reason}, state) do
+ :telemetry.execute(
+ [:teiserver, :client, :update_in_lobby],
+ %{},
+ %{user_id: state.user_id}
+ )
+
new_state = update_client(state, new_client, reason)
{:noreply, new_state}
end
@@ -87,6 +111,12 @@ defmodule Teiserver.Connections.ClientServer do
def handle_cast({:purposeful_disconnect, pid}, state) do
new_state = lose_connection(pid, state)
+ :telemetry.execute(
+ [:teiserver, :client, :disconnect],
+ %{reason: :purposeful},
+ %{user_id: state.user_id}
+ )
+
if new_state.client.connected? do
{:noreply, new_state}
else
@@ -112,6 +142,12 @@ defmodule Teiserver.Connections.ClientServer do
end
def handle_info({:DOWN, _ref, :process, pid, _normal}, state) do
+ :telemetry.execute(
+ [:teiserver, :client, :disconnect],
+ %{reason: :down_message},
+ %{user_id: state.user_id}
+ )
+
new_state = lose_connection(pid, state)
{:noreply, new_state}
end
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
new file mode 100644
index 000000000..c145f23de
--- /dev/null
+++ b/lib/teiserver/contexts/telemetry.ex
@@ -0,0 +1,203 @@
+defmodule Teiserver.Telemetry do
+ require Logger
+
+ @handler_id "teiserver-default-logger"
+
+ @doc """
+ Attaches a default structured JSON Telemetry handler for logging.
+
+ This function attaches a handler that outputs logs with the following fields for job events:
+
+ * `args` — a map of the job's raw arguments
+ * `attempt` — the job's execution atttempt
+ * `duration` — the job's runtime duration, in the native time unit
+ * `event` — `job:start`, `job:stop`, `job:exception` depending on reporting telemetry event
+ * `error` — a formatted error banner, without the extended stacktrace
+ * `id` — the job's id
+ * `meta` — a map of the job's raw metadata
+ * `queue` — the job's queue
+ * `source` — always "teiserver"
+ * `state` — the execution state, one of "success", "failure", "cancelled", "discard", or
+ "snoozed"
+ * `system_time` — when the job started, in microseconds
+ * `tags` — the job's tags
+ * `worker` — the job's worker module
+
+ And the following fields for stager events:
+
+ * `event` — always `stager:switch`
+ * `message` — information about the mode switch
+ * `mode` — either `"local"` or `"global"`
+ * `source` — always "teiserver"
+
+ ## Options
+
+ * `:level` — The log level to use for logging output, defaults to `:info`
+ * `:encode` — Whether to encode log output as JSON, defaults to `true`
+
+ ## Examples
+
+ Attach a logger at the default `:info` level with JSON encoding:
+
+ :ok = Teiserver.Telemetry.attach_default_logger()
+
+ Attach a logger at the `:debug` level:
+
+ :ok = Teiserver.Telemetry.attach_default_logger(level: :debug)
+
+ Attach a logger with JSON logging disabled:
+
+ :ok = Teiserver.Telemetry.attach_default_logger(encode: false)
+ """
+ @spec attach_default_logger(Logger.level() | Keyword.t()) :: :ok | {:error, :already_exists}
+ def attach_default_logger(opts \\ [encode: true, level: :info])
+
+ def attach_default_logger(level) when is_atom(level) do
+ attach_default_logger(level: level)
+ end
+
+ def attach_default_logger(opts) when is_list(opts) do
+ events = event_list()
+
+ opts =
+ opts
+ |> Keyword.put_new(:encode, true)
+ |> Keyword.put_new(:level, :info)
+
+ :telemetry.attach_many(@handler_id, events, &__MODULE__.handle_event/4, opts)
+ end
+
+ def event_list() do
+ [
+ [:teiserver, :client, :added_connection],
+ [:teiserver, :client, :new_connection],
+ [:teiserver, :client, :updated],
+ [:teiserver, :client, :update_in_lobby],
+ [:teiserver, :client, :disconnect],
+
+ [:teiserver, :lobby, :add_client],
+ [:teiserver, :lobby, :remove_client],
+ [:teiserver, :lobby, :cycle],
+ [:teiserver, :lobby, :start_match],
+
+ [:teiserver, :logging, :add_audit_log]
+ ]
+ end
+
+ @doc """
+ Undoes `Teiserver.Telemetry.attach_default_logger/1` by detaching the attached logger.
+
+ ## Examples
+
+ Detach a previously attached logger:
+
+ :ok = Teiserver.Telemetry.attach_default_logger()
+ :ok = Teiserver.Telemetry.detach_default_logger()
+
+ Attempt to detach when a logger wasn't attached:
+
+ {:error, :not_found} = Teiserver.Telemetry.detach_default_logger()
+ """
+ @doc since: "2.15.0"
+ @spec detach_default_logger() :: :ok | {:error, :not_found}
+ def detach_default_logger do
+ :telemetry.detach(@handler_id)
+ end
+
+ @doc false
+ @spec handle_event([atom()], map(), map(), Keyword.t()) :: :ok
+ # def handle_event([:teiserver, :job, event], measure, meta, opts) do
+ # log(opts, fn ->
+ # details = Map.take(meta.job, ~w(attempt args id max_attempts meta queue tags worker)a)
+
+ # extra =
+ # case event do
+ # :start ->
+ # %{event: "job:start", system_time: measure.system_time}
+
+ # :stop ->
+ # %{
+ # duration: convert(measure.duration),
+ # event: "job:stop",
+ # queue_time: convert(measure.queue_time),
+ # state: meta.state
+ # }
+
+ # :exception ->
+ # %{
+ # error: Exception.format_banner(meta.kind, meta.reason, meta.stacktrace),
+ # event: "job:exception",
+ # duration: convert(measure.duration),
+ # queue_time: convert(measure.queue_time),
+ # state: meta.state
+ # }
+ # end
+
+ # Map.merge(details, extra)
+ # end)
+ # end
+
+ # def handle_event([:teiserver, :stager, :switch], _measure, %{mode: mode}, opts) do
+ # log(opts, fn ->
+ # case mode do
+ # :local ->
+ # %{
+ # event: "stager:switch",
+ # mode: "local",
+ # message:
+ # "job staging switched to local mode. local mode polls for jobs for every queue; " <>
+ # "restore global mode with a functional notifier"
+ # }
+
+ # :global ->
+ # %{
+ # event: "stager:switch",
+ # mode: "global",
+ # message: "job staging switched back to global mode"
+ # }
+ # end
+ # end)
+ # end
+
+ def handle_event([:teiserver, a, b], measure, meta, opts) do
+ IO.puts "#{__MODULE__}:#{__ENV__.line}"
+ IO.inspect {{a, b}, measure, meta, opts}
+ IO.puts ""
+
+ # log(opts, fn ->
+ # case mode do
+ # :local ->
+ # %{
+ # event: "stager:switch",
+ # mode: "local",
+ # message:
+ # "job staging switched to local mode. local mode polls for jobs for every queue; " <>
+ # "restore global mode with a functional notifier"
+ # }
+
+ # :global ->
+ # %{
+ # event: "stager:switch",
+ # mode: "global",
+ # message: "job staging switched back to global mode"
+ # }
+ # end
+ # end)
+ end
+
+ # defp log(opts, fun) do
+ # level = Keyword.fetch!(opts, :level)
+
+ # Logger.log(level, fn ->
+ # output = Map.put(fun.(), :source, "teiserver")
+
+ # if Keyword.fetch!(opts, :encode) do
+ # Jason.encode_to_iodata!(output)
+ # else
+ # output
+ # end
+ # end)
+ # end
+
+ # defp convert(value), do: System.convert_time_unit(value, :native, :microsecond)
+end
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index e4b72efc7..5233ce344 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -257,7 +257,8 @@ defmodule Teiserver.Game.LobbyLib do
rated?: true,
host_id: host_id,
processed?: false,
- lobby_opened_at: Timex.now()
+ lobby_opened_at: Timex.now(),
+ lobby_id: lobby_id
})
cast_lobby(lobby_id, {:cycle_lobby, match.id})
@@ -279,6 +280,23 @@ defmodule Teiserver.Game.LobbyLib do
cast_lobby(lobby_id, :lobby_start_match)
end
+ @doc """
+ Used to tell a lobby process the current match has stopped. Optionally provide a reason as to why
+
+ ## Examples
+
+ iex> lobby_end_match(123, "reason")
+ :ok
+
+ iex> lobby_end_match(456, "reason")
+ nil
+ """
+ @spec lobby_end_match(Lobby.id()) :: :ok
+ @spec lobby_end_match(Lobby.id(), String.t()) :: :ok
+ def lobby_end_match(lobby_id, reason \\ "normal") when is_binary(lobby_id) do
+ cast_lobby(lobby_id, {:lobby_end_match, reason})
+ end
+
@doc """
Used to tell a lobby process the current match has started
diff --git a/lib/teiserver/game/libs/match_lib.ex b/lib/teiserver/game/libs/match_lib.ex
index c83165b14..eb0bc8ccb 100644
--- a/lib/teiserver/game/libs/match_lib.ex
+++ b/lib/teiserver/game/libs/match_lib.ex
@@ -1,6 +1,6 @@
defmodule Teiserver.Game.MatchLib do
@moduledoc """
- TODO: Library of match related functions.
+ Library of match related functions.
"""
use TeiserverMacros, :library
alias Teiserver.Game.{Match, MatchQueries, Lobby, MatchTypeLib}
@@ -127,6 +127,9 @@ defmodule Teiserver.Game.MatchLib do
Game.update_match_membership(mm, attrs)
end)
+ # Tell the lobby server the match has ended
+ Game.cycle_lobby(match.lobby_id)
+
# Finally return the updated match
updated_match
end
diff --git a/lib/teiserver/game/schemas/match.ex b/lib/teiserver/game/schemas/match.ex
index 7f419fa5b..3f9f42878 100644
--- a/lib/teiserver/game/schemas/match.ex
+++ b/lib/teiserver/game/schemas/match.ex
@@ -51,6 +51,7 @@ defmodule Teiserver.Game.Match do
field(:match_duration_seconds, :integer)
# Memberships
+ field(:lobby_id, Ecto.UUID)
belongs_to(:host, Teiserver.Account.User, type: Ecto.UUID)
belongs_to(:type, Teiserver.Game.MatchType)
has_many(:members, Teiserver.Game.MatchMembership)
@@ -91,6 +92,7 @@ defmodule Teiserver.Game.Match do
# This will be something queried enough it's worth storing as it's own value
match_duration_seconds: non_neg_integer(),
host_id: Teiserver.user_id(),
+ lobby_id: Teiserver.lobby_id(),
host: Teiserver.Account.User.t(),
type_id: Teiserver.Game.MatchType.id(),
type: Teiserver.Game.MatchType.t(),
@@ -106,7 +108,7 @@ defmodule Teiserver.Game.Match do
struct
|> cast(
attrs,
- ~w(name tags public? rated? game_name game_version winning_team team_count team_size processed? lobby_opened_at match_started_at match_ended_at ended_normally? match_duration_seconds host_id type_id)a
+ ~w(name tags public? rated? game_name game_version winning_team team_count team_size processed? lobby_opened_at match_started_at match_ended_at ended_normally? match_duration_seconds host_id type_id lobby_id)a
)
|> validate_required(~w(public? rated? host_id)a)
end
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index fa4f68fbc..7c1a1c11f 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -14,7 +14,7 @@ defmodule Teiserver.Game.LobbyServer do
defmodule State do
@moduledoc false
- defstruct [:lobby, :lobby_id, :host_id, :match_id, :lobby_topic, :match_topic, :update_id]
+ defstruct [:lobby, :lobby_id, :host_id, :match_id, :lobby_topic, :update_id]
end
@impl true
@@ -41,6 +41,11 @@ defmodule Teiserver.Game.LobbyServer do
{:reply, {:error, reason}, state}
{true, _} ->
+ :telemetry.execute(
+ [:teiserver, :lobby, :add_client],
+ %{},
+ %{user_id: user_id}
+ )
{shared_secret, new_state} = do_add_client(user_id, state)
{:reply, {:ok, shared_secret, state.lobby}, new_state}
end
@@ -64,6 +69,11 @@ defmodule Teiserver.Game.LobbyServer do
def handle_cast({:remove_client, user_id}, state) do
if Enum.member?(state.lobby.members, user_id) do
+ :telemetry.execute(
+ [:teiserver, :lobby, :remove_client],
+ %{},
+ %{user_id: user_id}
+ )
new_state = do_remove_client(user_id, state)
{:noreply, new_state}
else
@@ -72,9 +82,6 @@ defmodule Teiserver.Game.LobbyServer do
end
def handle_cast({:cycle_lobby, match_id}, state) do
- match_topic = nil
- # match_topic = Game.match_topic(match.id)
-
new_state =
update_lobby(state, %{
match_id: match_id,
@@ -82,7 +89,13 @@ defmodule Teiserver.Game.LobbyServer do
match_type: nil
})
- {:noreply, %{new_state | match_id: match_id, match_topic: match_topic}}
+ :telemetry.execute(
+ [:teiserver, :lobby, :cycle],
+ %{},
+ %{match_id: match_id}
+ )
+
+ {:noreply, %{new_state | match_id: match_id}}
end
def handle_cast(:lobby_start_match, state) do
@@ -91,6 +104,12 @@ defmodule Teiserver.Game.LobbyServer do
match_ongoing?: true
})
+ :telemetry.execute(
+ [:teiserver, :lobby, :start_match],
+ %{players: state.lobby.players},
+ %{match_id: state.match_id}
+ )
+
{:noreply, new_state}
end
@@ -367,8 +386,7 @@ defmodule Teiserver.Game.LobbyServer do
host_id: lobby.host_id,
match_id: nil,
lobby: lobby,
- lobby_topic: LobbyLib.lobby_topic(id),
- match_topic: nil
+ lobby_topic: LobbyLib.lobby_topic(id)
}}
end
end
diff --git a/lib/teiserver/logging/libs/audit_log_lib.ex b/lib/teiserver/logging/libs/audit_log_lib.ex
index 523a6149f..b330f775f 100644
--- a/lib/teiserver/logging/libs/audit_log_lib.ex
+++ b/lib/teiserver/logging/libs/audit_log_lib.ex
@@ -98,6 +98,7 @@ defmodule Teiserver.Logging.AuditLogLib do
details: details
})
|> Repo.insert()
+ |> maybe_emit_event
end
@doc """
@@ -113,8 +114,19 @@ defmodule Teiserver.Logging.AuditLogLib do
details: details
})
|> Repo.insert()
+ |> maybe_emit_event
end
+ defp maybe_emit_event({:ok, %AuditLog{} = audit_log}) do
+ :telemetry.execute(
+ [:teiserver, :logging, :add_audit_log],
+ %{action: audit_log.action},
+ %{log_id: audit_log.id}
+ )
+ {:ok, audit_log}
+ end
+ defp maybe_emit_event(v), do: v
+
@doc """
Updates a audit_log.
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index 181a369a4..55a5c0c45 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -72,6 +72,8 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:public?, :boolean)
add(:rated?, :boolean)
+ add(:lobby_id, :uuid)
+
add(:game_name, :string)
add(:game_version, :string)
diff --git a/mix.exs b/mix.exs
index 4e47b0a3a..d8e30054c 100644
--- a/mix.exs
+++ b/mix.exs
@@ -59,6 +59,7 @@ defmodule Teiserver.MixProject do
"documentation/guides/program_structure.md",
"documentation/guides/snippets.md",
"documentation/guides/match_lifecycle.md",
+ "documentation/guides/telemetry.md",
"documentation/guides/testing.md",
# Development
From 0a5b0f209890ca48e793d3e1de6de41e51cdde7c Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 14 Apr 2024 21:34:22 +0100
Subject: [PATCH 14/64] Added github action
---
.github/workflows/elixir.yml | 92 ++++++++++++++++++++++++++++++++++++
README.md | 2 +-
mix.exs | 3 +-
3 files changed, 94 insertions(+), 3 deletions(-)
create mode 100644 .github/workflows/elixir.yml
diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml
new file mode 100644
index 000000000..72a1857f9
--- /dev/null
+++ b/.github/workflows/elixir.yml
@@ -0,0 +1,92 @@
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+
+name: Build and test
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ types: [opened, synchronize, reopened]
+ workflow_dispatch:
+
+# Sets the ENV `MIX_ENV` to `test` for running tests
+env:
+ MIX_ENV: test
+ ELIXIR_VER: '1.16.2'
+ OTP_VER: '25.0.4'
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ name: Build and test
+
+ # Set up a Postgres DB service. By default, Phoenix applications
+ # use Postgres. This creates a database for running tests.
+ # Additional services can be defined here if required.
+ services:
+ db:
+ image: postgres:15
+ ports: ['5432:5432']
+ env:
+ POSTGRES_DB: teiserver_test
+ POSTGRES_USER: teiserver_test
+ POSTGRES_PASSWORD: 123456789
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ steps:
+ # Step: Setup Elixir + Erlang image as the base.
+ - name: Set up Elixir
+ uses: erlef/setup-beam@v1
+ with:
+ otp-version: ${{ env.OTP_VER }}
+ elixir-version: ${{ env.ELIXIR_VER }}
+
+ # Step: Check out the code.
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ # Step: Define how to cache deps. Restores existing cache if present.
+ - name: Cache deps
+ id: cache-deps
+ uses: actions/cache@v4
+ env:
+ cache-name: cache-elixir-deps
+ with:
+ path: deps
+ key: ${{ runner.os }}-mix-${{ env.cache-name }}-${{ hashFiles('**/mix.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-mix-${{ env.cache-name }}-
+
+ # Step: Define how to cache the `_build` directory. After the first run,
+ # this speeds up tests runs a lot. This includes not re-compiling our
+ # project's downloaded deps every run.
+ - name: Cache compiled build
+ id: cache-build
+ uses: actions/cache@v4
+ env:
+ cache-name: cache-compiled-build
+ with:
+ path: _build
+ key: ${{ runner.os }}-mix-${{ env.cache-name }}-${{ hashFiles('**/mix.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-mix-${{ env.cache-name }}-
+
+ # Step: Download project dependencies. If unchanged, uses
+ # the cached version.
+ - name: Install dependencies
+ run: mix deps.get
+
+ # Step: Execute the tests.
+ - name: Run tests
+ run: mix test
diff --git a/README.md b/README.md
index f44cff0c2..519c41792 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ First add to your dependencies in `mix.exs`.
```elixir
def deps do
[
- {:teiserver, "~> 0.0.3"}
+ {:teiserver, "~> 0.0.5"}
]
end
```
diff --git a/mix.exs b/mix.exs
index d8e30054c..ef931b0ab 100644
--- a/mix.exs
+++ b/mix.exs
@@ -253,8 +253,7 @@ defmodule Teiserver.MixProject do
{:ex_doc, "~> 0.31", only: :dev, runtime: false},
{:excoveralls, "~> 0.15.3", only: :test, runtime: false},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
- {:floki, ">= 0.34.0", only: :test},
- {:dialyxir, "~> 1.1", only: [:dev], runtime: false}
+ {:floki, ">= 0.34.0", only: :test}
]
end
From e957f94e0d90c15535c23bbfdd08f289fdb6d7b6 Mon Sep 17 00:00:00 2001
From: Lexon <44340857+L-e-x-o-n@users.noreply.github.com>
Date: Sun, 14 Apr 2024 23:11:15 +0200
Subject: [PATCH 15/64] Add github action badge to readme.md
Note: Action shows build and test workflow status of branch 0.0.5 and will probably need to be updated to show status of a different branch in the future
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 519c41792..c0a633f08 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,8 @@
+
+
_Note: This README is for the unreleased master branch, please reference the
From bffa0cfabd7d54fadcde50a8a193e08c4cda1fc9 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 17 Apr 2024 14:33:12 +0100
Subject: [PATCH 16/64] Login improvements
---
documentation/guides/hello_world.md | 2 +-
lib/teiserver/account/libs/user_lib.ex | 59 ++++++++++
lib/teiserver/api.ex | 108 ++++++++++++++++--
lib/teiserver/application.ex | 8 +-
.../logging/queries/audit_log_queries.ex | 12 ++
.../settings/libs/server_setting_lib.ex | 4 +
.../settings/libs/server_setting_type_lib.ex | 28 ++++-
lib/teiserver/system/libs/startup_lib.ex | 29 +++++
test/api_test.exs | 54 ++++++++-
.../queries/audit_log_queries_test.exs | 2 +
10 files changed, 287 insertions(+), 19 deletions(-)
create mode 100644 lib/teiserver/system/libs/startup_lib.ex
diff --git a/documentation/guides/hello_world.md b/documentation/guides/hello_world.md
index fbe85b719..e13f41eb7 100644
--- a/documentation/guides/hello_world.md
+++ b/documentation/guides/hello_world.md
@@ -127,7 +127,7 @@ defmodule HelloWorldServer.TcpIn do
def data_in("login " <> data, state) do
[name, password] = String.split(data, " ")
- case Api.maybe_authenticate_user(name, password) do
+ case Api.maybe_authenticate_user_by_name(name, password) do
{:ok, user} ->
Api.connect_user(user)
{%{state | user_id: user.id}, "You are now logged in as '#{user.name}'"}
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index d4dd88750..a0fc685c8 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -281,6 +281,65 @@ defmodule Teiserver.Account.UserLib do
User.valid_password?(plaintext_password, user.password)
end
+ @spec register_failed_login(User.id(), String.t() | nil, String.t() | atom) :: :ok
+ def register_failed_login(_, _, :rate_limit), do: :ok
+ def register_failed_login(nil, _, _), do: :ok
+ def register_failed_login(user_id, ip, reason) do
+ Cachex.incr(:ts_login_count_ip, ip)
+ Cachex.incr(:ts_login_count_user, user_id)
+
+ Teiserver.Logging.create_audit_log(user_id, ip, "failed-login", %{reason: reason})
+
+ :ok
+ end
+
+ @doc """
+ Given a userid and optionally an IP, check if we have hit the maximum number of
+ login attempts for this user.
+ """
+ @spec allow_login_attempt?(User.id(), String.t() | nil) :: boolean
+ def allow_login_attempt?(userid, ip \\ nil) do
+ cond do
+ allow_ip_login_attempt?(ip) == false ->
+ false
+
+ allow_user_login_attempt?(userid) == false ->
+ false
+
+ true ->
+ true
+ end
+ end
+
+ @spec allow_ip_login_attempt?(String.t()) :: boolean
+ defp allow_ip_login_attempt?(nil), do: true
+ defp allow_ip_login_attempt?(ip) do
+ max_allowed_ip = Teiserver.Settings.get_server_setting_value("login.ip_rate_limit")
+
+ if max_allowed_ip == nil do
+ true
+ else
+ current_ip_count = Cachex.fetch!(:ts_login_count_ip, ip, fn -> 0 end)
+
+ # As long as we're below the max it's okay
+ current_ip_count <= max_allowed_ip
+ end
+ end
+
+ @spec allow_user_login_attempt?(User.id()) :: boolean
+ defp allow_user_login_attempt?(userid) do
+ max_allowed_user = Teiserver.Settings.get_server_setting_value("login.user_rate_limit")
+
+ if max_allowed_user == nil do
+ true
+ else
+ current_user_count = Cachex.fetch!(:ts_login_count_user, userid, fn -> 0 end)
+
+ # As long as we're below the max it's okay
+ current_user_count <= max_allowed_user
+ end
+ end
+
@doc """
Generates a strong, though not very human readable, password.
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index 7df142654..c5bdd0f66 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -31,34 +31,115 @@ defmodule Teiserver.Api do
@doc """
Takes a name and password, tries to authenticate the user.
+ Optionally accepts an IP for rate limiting purposes.
+
## Examples
- iex> maybe_authenticate_user("Alice", "password1")
+ iex> maybe_authenticate_user_by_name("Alice", "password1", "127.0.0.1")
{:ok, %User{}}
- iex> maybe_authenticate_user("Bob", "bad password")
+ iex> maybe_authenticate_user_by_name("Bob", "bad password", "127.0.0.1")
{:error, :bad_password}
- iex> maybe_authenticate_user("Chris", "password1")
+ iex> maybe_authenticate_user_by_name("Chris", "password1", "127.0.0.1")
{:error, :no_user}
"""
@doc section: :user
- @spec maybe_authenticate_user(String.t(), String.t()) ::
- {:ok, Account.User.t()} | {:error, :no_user | :bad_password}
- def maybe_authenticate_user(name, password) do
+ @spec maybe_authenticate_user_by_name(String.t(), String.t(), String.t() | nil) ::
+ {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
+ def maybe_authenticate_user_by_name(name, password, ip \\ nil) do
case Account.get_user_by_name(name) do
nil ->
{:error, :no_user}
user ->
- if Teiserver.Account.valid_password?(user, password) do
- {:ok, user}
- else
- {:error, :bad_password}
- end
+ do_maybe_authenticate_user(user, password, ip)
+ end
+ end
+
+ @doc """
+ Takes a email and password, tries to authenticate the user.
+
+ Optionally accepts an IP for rate limiting purposes.
+
+ ## Examples
+
+ iex> maybe_authenticate_user_by_email("alice@domain", "password1", "127.0.0.1")
+ {:ok, %User{}}
+
+ iex> maybe_authenticate_user_by_email("bob@domain", "bad password", "127.0.0.1")
+ {:error, :bad_password}
+
+ iex> maybe_authenticate_user_by_email("chris@domain", "password1", "127.0.0.1")
+ {:error, :no_user}
+ """
+ @doc section: :user
+ @spec maybe_authenticate_user_by_email(String.t(), String.t(), String.t() | nil) ::
+ {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
+ def maybe_authenticate_user_by_email(email, password, ip \\ nil) do
+ case Account.get_user_by_email(email) do
+ nil ->
+ {:error, :no_user}
+
+ user ->
+ do_maybe_authenticate_user(user, password, ip)
+ end
+ end
+
+ @doc """
+ Takes a id and password, tries to authenticate the user.
+
+ Optionally accepts an IP for rate limiting purposes.
+
+ ## Examples
+
+ iex> maybe_authenticate_user_by_id("a5f2e06b-a89b-45b2-aeae-87e45d02f8f8", "password1", "127.0.0.1")
+ {:ok, %User{}}
+
+ iex> maybe_authenticate_user_by_id("7f50a62b-1e7c-440a-b851-5dc076f1a6cc", "bad password", "127.0.0.1")
+ {:error, :bad_password}
+
+ iex> maybe_authenticate_user_by_id("f8cfc144-eb45-4b09-b738-07705baae6c8", "password1", "127.0.0.1")
+ {:error, :no_user}
+ """
+ @doc section: :user
+ @spec maybe_authenticate_user_by_id(String.t(), String.t(), String.t() | nil) ::
+ {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
+ def maybe_authenticate_user_by_id(id, password, ip \\ nil) do
+ case Account.get_user_by_id(id) do
+ nil ->
+ {:error, :no_user}
+
+ user ->
+ do_maybe_authenticate_user(user, password, ip)
end
end
+ @spec do_maybe_authenticate_user(Account.User.t(), String.t(), String.t() | nil) :: {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
+ defp do_maybe_authenticate_user(user, password, ip) do
+ rate_limit_allow? = UserLib.allow_login_attempt?(user.id, ip)
+
+ result = if rate_limit_allow? do
+ if Teiserver.Account.valid_password?(user, password) do
+ {:ok, user}
+ else
+ {:error, :bad_password}
+ end
+ else
+ {:error, :rate_limit}
+ end
+
+ # We might want to register the failed login attempt
+ case result do
+ {:error, reason} ->
+ UserLib.register_failed_login(user.id, ip, reason)
+ _ ->
+ :ok
+ end
+
+ result
+ end
+
@doc """
Makes use of `Teiserver.Connections.ClientLib.connect_user/1` to connect
and then also subscribes you to the following pubsubs:
@@ -70,11 +151,14 @@ defmodule Teiserver.Api do
@doc section: :client
@spec connect_user(Teiserver.user_id()) :: Connections.Client.t()
def connect_user(user_id) when is_binary(user_id) do
- Connections.connect_user(user_id)
+ client = Connections.connect_user(user_id)
# Sleep to prevent this current process getting the messages related to the connection
:timer.sleep(100)
Teiserver.subscribe(Connections.client_topic(user_id))
Teiserver.subscribe(Communication.user_messaging_topic(user_id))
+
+ # Return the client
+ client
end
@doc """
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index dea0f1e7e..add49f3e5 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -42,7 +42,11 @@ defmodule Teiserver.Application do
add_cache(:ts_server_setting_cache, ttl: :timer.minutes(1)),
add_cache(:ts_user_setting_type_store),
add_cache(:ts_user_setting_cache, ttl: :timer.minutes(1)),
- add_cache(:ts_user_by_user_id_cache, ttl: :timer.minutes(5))
+ add_cache(:ts_user_by_user_id_cache, ttl: :timer.minutes(5)),
+
+ # Login rate limiting
+ add_cache(:ts_login_count_ip, ttl: :timer.minutes(5)),
+ add_cache(:ts_login_count_user, ttl: :timer.minutes(5))
]
opts = [strategy: :one_for_one, name: __MODULE__]
@@ -52,6 +56,8 @@ defmodule Teiserver.Application do
Teiserver.System.ClusterManagerSupervisor.start_cluster_manager_supervisor_children()
end
+ Teiserver.System.StartupLib.perform()
+
start_result
end
diff --git a/lib/teiserver/logging/queries/audit_log_queries.ex b/lib/teiserver/logging/queries/audit_log_queries.ex
index 616182986..af4b18aef 100644
--- a/lib/teiserver/logging/queries/audit_log_queries.ex
+++ b/lib/teiserver/logging/queries/audit_log_queries.ex
@@ -44,6 +44,18 @@ defmodule Teiserver.Logging.AuditLogQueries do
)
end
+ def _where(query, :user_id, user_id_list) when is_list(user_id_list) do
+ from(audit_logs in query,
+ where: audit_logs.user_id in ^user_id_list
+ )
+ end
+
+ def _where(query, :user_id, user_id) do
+ from(audit_logs in query,
+ where: audit_logs.user_id == ^user_id
+ )
+ end
+
def _where(query, :action, action_list) when is_list(action_list) do
from(audit_logs in query,
where: audit_logs.action in ^action_list
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index d7f43ba39..a79788052 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -110,8 +110,12 @@ defmodule Teiserver.Settings.ServerSettingLib do
end
@spec convert_from_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
+ defp convert_from_raw_value(nil, _), do: nil
defp convert_from_raw_value(raw_value, "string"), do: raw_value
+ defp convert_from_raw_value(raw_value, "integer") when is_integer(raw_value), do: raw_value
defp convert_from_raw_value(raw_value, "integer"), do: String.to_integer(raw_value)
+ defp convert_from_raw_value(true, "boolean"), do: true
+ defp convert_from_raw_value(false, "boolean"), do: false
defp convert_from_raw_value(raw_value, "boolean"), do: raw_value == "t"
defp convert_from_raw_value(_, _), do: nil
diff --git a/lib/teiserver/settings/libs/server_setting_type_lib.ex b/lib/teiserver/settings/libs/server_setting_type_lib.ex
index ffeb97cd5..56de35d05 100644
--- a/lib/teiserver/settings/libs/server_setting_type_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_type_lib.ex
@@ -25,10 +25,36 @@ defmodule Teiserver.Settings.ServerSettingTypeLib do
v
end
+ @doc """
+ ### Required keys
+ * `:key` - The string key of the setting, this is the internal name used for the setting
+ * `:label` - The user-facing label used for the setting
+ * `:section` - A string referencing how the setting should be grouped
+ * `:type` - The type of value which should be parsed out, can be one of: `string`, `boolean`, `integer`
+
+ ### Optional attributes
+ * `:permissions` - A permission set (string or list of strings) used to check if a given user can edit this setting
+ * `:choices` - A list of acceptable choices for `string` based types
+ * `:default` - The default value for a setting if one is not set, defaults to `nil`
+ * `:description` - A longer description which can be used to provide more information to users
+
+ ## Examples
+ ```
+ add_server_setting_type(%{
+ key: "login.ip_rate_limit",
+ label: "Login rate limit per IP",
+ section: "Login",
+ type: "integer",
+ permissions: "Admin",
+ default: 3,
+ description: "The upper bound on how many failed attempts a given IP can perform before all further attempts will be blocked"
+ })
+ ```
+ """
@spec add_server_setting_type(map()) :: {:ok, ServerSettingType.t()} | {:error, String.t()}
def add_server_setting_type(args) do
if not Enum.member?(~w(string integer boolean), args.type) do
- raise "Invalid type, must be one of `string`, `integer` or `boolean`"
+ raise "Invalid type of '#{args.type}', must be one of 'string', 'integer' or 'boolean'"
end
existing_keys = list_server_setting_type_keys()
diff --git a/lib/teiserver/system/libs/startup_lib.ex b/lib/teiserver/system/libs/startup_lib.ex
new file mode 100644
index 000000000..327175ed6
--- /dev/null
+++ b/lib/teiserver/system/libs/startup_lib.ex
@@ -0,0 +1,29 @@
+defmodule Teiserver.System.StartupLib do
+ @moduledoc false
+ # Functionality executed during the Teisever startup process.
+
+ alias Teiserver.Settings
+
+ @spec perform() :: any()
+ def perform do
+ Settings.add_server_setting_type(%{
+ key: "login.ip_rate_limit",
+ label: "Login rate limit per IP",
+ section: "Login",
+ type: "integer",
+ permissions: "Admin",
+ default: 3,
+ description: "The upper bound on how many failed attempts a given IP can perform before all further attempts will be blocked"
+ })
+
+ Settings.add_server_setting_type(%{
+ key: "login.user_rate_limit",
+ label: "Login rate limit per User",
+ section: "Login",
+ type: "integer",
+ permissions: "Admin",
+ default: nil,
+ description: "The upper bound on how many failed attempts a given user can have before their logins are blocked."
+ })
+ end
+end
diff --git a/test/api_test.exs b/test/api_test.exs
index d5fee1e44..1d653c9bc 100644
--- a/test/api_test.exs
+++ b/test/api_test.exs
@@ -9,12 +9,58 @@ defmodule ApiTest do
alias Teiserver.Account.User
describe "API functionality" do
- test "maybe_authenticate_user/2" do
+ test "maybe_authenticate_user_by_name/2" do
user = AccountFixtures.user_fixture()
- assert Api.maybe_authenticate_user("--- no name ---", "password") == {:error, :no_user}
- assert Api.maybe_authenticate_user(user.name, "bad_password") == {:error, :bad_password}
- assert Api.maybe_authenticate_user(user.name, "password") == {:ok, user}
+ assert Api.maybe_authenticate_user_by_name("--- no name ---", "password") == {:error, :no_user}
+ assert Api.maybe_authenticate_user_by_name(user.name, "bad_password") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_name(user.name, "password") == {:ok, user}
+ end
+
+ test "maybe_authenticate_user_by_email/2" do
+ user = AccountFixtures.user_fixture()
+
+ assert Api.maybe_authenticate_user_by_email("--- no email ---", "password") == {:error, :no_user}
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_email(user.email, "password") == {:ok, user}
+ end
+
+ test "maybe_authenticate_user_by_id/2" do
+ user = AccountFixtures.user_fixture()
+
+ assert Api.maybe_authenticate_user_by_id("e986ed95-b46f-4ad5-8168-fdb575a623f6", "password") == {:error, :no_user}
+ assert Api.maybe_authenticate_user_by_id(user.id, "bad_password") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_id(user.id, "password") == {:ok, user}
+ end
+
+ test "maybe_authenticate_user rate limit/2" do
+ user = AccountFixtures.user_fixture()
+
+ # No attempts so far, lets check for audit logs
+ logs = Teiserver.Logging.list_audit_logs(where: [
+ user_id: user.id
+ ])
+ assert Enum.empty?(logs)
+
+ # Bad login
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :bad_password}
+
+ # Ensure it was logged
+ [log] = Teiserver.Logging.list_audit_logs(where: [
+ user_id: user.id
+ ])
+
+ assert log.ip == "my-ip"
+ assert log.details == %{"reason" => "bad_password"}
+ assert log.action == "failed-login"
+ assert log.user_id == user.id
+
+ # Now do it a few more times to trip the breaker
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :bad_password}
+
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :rate_limit}
end
test "register_user/3" do
diff --git a/test/logging/queries/audit_log_queries_test.exs b/test/logging/queries/audit_log_queries_test.exs
index 6cd00594e..a88fefcf5 100644
--- a/test/logging/queries/audit_log_queries_test.exs
+++ b/test/logging/queries/audit_log_queries_test.exs
@@ -31,6 +31,8 @@ defmodule Teiserver.AuditLogQueriesTest do
where: [
id: [1, 2],
id: 1,
+ user_id: ["0ea89483-80da-4041-9e41-fcb152c24168", "7fa72464-e3b6-42e8-935e-608adc65608e"],
+ user_id: "57b86216-5a32-4e76-bad0-1012a825667b",
action: ["action1", "action2"],
action: "action",
detail_equal: {"key", "value"},
From 6d39ca6aaccb3bad2c6dc4d273438adf3260cc64 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 17 Apr 2024 14:55:28 +0100
Subject: [PATCH 17/64] Emit metric on failed login
---
lib/teiserver/account/libs/user_lib.ex | 6 ++++++
lib/teiserver/contexts/telemetry.ex | 2 ++
2 files changed, 8 insertions(+)
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index a0fc685c8..32d0f7aa6 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -288,6 +288,12 @@ defmodule Teiserver.Account.UserLib do
Cachex.incr(:ts_login_count_ip, ip)
Cachex.incr(:ts_login_count_user, user_id)
+ :telemetry.execute(
+ [:teiserver, :user, :failed_login],
+ %{reason: reason},
+ %{user_id: user_id, ip: ip}
+ )
+
Teiserver.Logging.create_audit_log(user_id, ip, "failed-login", %{reason: reason})
:ok
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
index c145f23de..6d90df45a 100644
--- a/lib/teiserver/contexts/telemetry.ex
+++ b/lib/teiserver/contexts/telemetry.ex
@@ -69,6 +69,8 @@ defmodule Teiserver.Telemetry do
def event_list() do
[
+ [:teiserver, :user, :failed_login],
+
[:teiserver, :client, :added_connection],
[:teiserver, :client, :new_connection],
[:teiserver, :client, :updated],
From 93a773024897e7f1513a31bd753aa67c7b0d8b88 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 20 May 2024 11:01:12 +0100
Subject: [PATCH 18/64] Expanded login options
---
CHANGELOG.md | 3 ++
documentation/development/features.md | 1 +
lib/teiserver.ex | 8 +++++
lib/teiserver/account/libs/user_lib.ex | 25 ++++++++++++++
lib/teiserver/api.ex | 6 ++--
lib/teiserver/connections/libs/client_lib.ex | 15 +++++----
lib/teiserver/connections/schemas/client.ex | 4 ++-
lib/teiserver/contexts/connections.ex | 4 +--
lib/teiserver/game/libs/lobby_lib.ex | 34 +++++++++++---------
lib/teiserver/migrations/postgres/v01.ex | 6 +++-
10 files changed, 78 insertions(+), 28 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a19a411ab..a60366da2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,9 @@
- Refactored the client update process
- Added User and Server runtime settings
- Added Telemetry events
+- Added rate limiting of login attempts
+- Added more options for connecting clients (currently just `bot?`)
+- Added support for Angen to provide guest accounts
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/documentation/development/features.md b/documentation/development/features.md
index b2886340c..b0aaa6ae8 100644
--- a/documentation/development/features.md
+++ b/documentation/development/features.md
@@ -9,6 +9,7 @@
## Connections
### Clients
- Tracking
+- Login attempt rate limiting
## Communication
- Room messages
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index ad9e45268..a868eb37b 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -76,6 +76,14 @@ defmodule Teiserver do
UUID.uuid5(nil, base)
end
+ @doc """
+ Gets the custom node name as set in the config `:teiserver, :node_name`
+ """
+ @spec get_node_name() :: atom
+ def get_node_name() do
+ to_string(Application.get_env(:teiserver, :node_name) || Node.self())
+ end
+
# PubSub delegation
@doc false
@spec broadcast(String.t(), map()) :: :ok
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index 32d0f7aa6..90d8c36f6 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -430,4 +430,29 @@ defmodule Teiserver.Account.UserLib do
def default_user_name_acceptable?(_name) do
true
end
+
+ @name_parts1 ~w(serene energised humble auspicious decisive exemplary cheerful determined playful spry springy)
+ @name_parts2 ~w(
+ maroon cherry rose ruby
+ amber carrot
+ lemon beige
+ mint lime cadmium
+ aqua cerulean
+ lavender indigo
+ magenta amethyst
+ )
+ @name_parts3 ~w(hamster gerbil cat dog falcon eagle mole fox tiger panda elephant lion cow dove whale dolphin squid dragon snake platypus badger)
+
+ @doc """
+ Generates a name for guests
+ """
+ @spec generate_guest_name() :: String.t()
+ def generate_guest_name() do
+ case :rand.uniform(3) do
+ 1 -> [@name_parts1, @name_parts2]
+ 2 -> [@name_parts1, @name_parts3]
+ 3 -> [@name_parts2, @name_parts3]
+ end
+ |> Enum.map_join(" ", fn l -> Enum.random(l) |> String.capitalize() end)
+ end
end
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index c5bdd0f66..d0475680a 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -149,9 +149,9 @@ defmodule Teiserver.Api do
Always returns `:ok`
"""
@doc section: :client
- @spec connect_user(Teiserver.user_id()) :: Connections.Client.t()
- def connect_user(user_id) when is_binary(user_id) do
- client = Connections.connect_user(user_id)
+ @spec connect_user(Teiserver.user_id(), list) :: Connections.Client.t()
+ def connect_user(user_id, opts \\ []) when is_binary(user_id) do
+ client = Connections.connect_user(user_id, opts)
# Sleep to prevent this current process getting the messages related to the connection
:timer.sleep(100)
Teiserver.subscribe(Connections.client_topic(user_id))
diff --git a/lib/teiserver/connections/libs/client_lib.ex b/lib/teiserver/connections/libs/client_lib.ex
index 84b20eddb..8a2259fc3 100644
--- a/lib/teiserver/connections/libs/client_lib.ex
+++ b/lib/teiserver/connections/libs/client_lib.ex
@@ -144,18 +144,20 @@ defmodule Teiserver.Connections.ClientLib do
Given a user_id, log them in. If the user already exists as a client then the existing
client is returned.
+ The optional `opts` argument is passed through to the ClientServer starting up.
+
The calling process will be listed as a connection for the client
the client will monitor it for the purposes of tracking if the
given client is still connected.
"""
- @spec connect_user(Teiserver.user_id()) :: Client.t()
- def connect_user(user_id) do
+ @spec connect_user(Teiserver.user_id(), list()) :: Client.t()
+ def connect_user(user_id, opts \\ []) do
if client_exists?(user_id) do
cast_client(user_id, {:add_connection, self()})
get_client(user_id)
else
client = Client.new(user_id)
- _pid = start_client_server(client)
+ _pid = start_client_server(client, opts)
cast_client(user_id, {:add_connection, self()})
client
end
@@ -188,14 +190,15 @@ defmodule Teiserver.Connections.ClientLib do
# Process stuff
@doc false
- @spec start_client_server(Client.t()) :: pid()
- def start_client_server(%Client{} = client) do
+ @spec start_client_server(Client.t(), list) :: pid()
+ def start_client_server(%Client{} = client, opts) do
{:ok, server_pid} =
DynamicSupervisor.start_child(Teiserver.ClientSupervisor, {
Teiserver.Connections.ClientServer,
name: "client_#{client.id}",
data: %{
- client: client
+ client: client,
+ opts: opts
}
})
diff --git a/lib/teiserver/connections/schemas/client.ex b/lib/teiserver/connections/schemas/client.ex
index a509a836c..5bd1796bb 100644
--- a/lib/teiserver/connections/schemas/client.ex
+++ b/lib/teiserver/connections/schemas/client.ex
@@ -10,6 +10,7 @@ defmodule Teiserver.Connections.Client do
* `:last_disconnected` - When disconnected, stores a DateTime of when the client was last connected
* `:lobby_id` - nil or the id of the lobby current occupied by this client
* `:in_game?` - True when the client is in-game
+ * `:bot?` - True when the client connects and registers itself as a bot, a bot cannot play games but can engage in things outside of them (e.g. chatting, hosting lobbies)
* `:afk?` - True when the client has not sent an activity message for a while
* `:ready?` - A flag set by the client to show it is ready to proceed in the current lobby
* `:player?` - When in a lobby or match, set to true if the client is playing and false if not (e.g. spectator)
@@ -27,12 +28,13 @@ defmodule Teiserver.Connections.Client do
@derive {Jason.Encoder,
only:
- ~w(id connected? last_disconnected afk? party_id in_game? lobby_id ready? player? player_number team_number player_colour sync lobby_host? update_id)a}
+ ~w(id connected? last_disconnected bot? afk? party_id in_game? lobby_id ready? player? player_number team_number player_colour sync lobby_host? update_id)a}
typedstruct do
field(:id, Teiserver.user_id())
field(:connected?, boolean, default: false)
field(:last_disconnected, DateTime.t())
+ field(:bot?, boolean, default: false)
field(:afk?, boolean, default: false)
field(:party_id, Teiserver.party_id())
field(:in_game?, boolean, default: false)
diff --git a/lib/teiserver/contexts/connections.ex b/lib/teiserver/contexts/connections.ex
index 73b5f390e..f12db9ce8 100644
--- a/lib/teiserver/contexts/connections.ex
+++ b/lib/teiserver/contexts/connections.ex
@@ -52,8 +52,8 @@ defmodule Teiserver.Connections do
defdelegate update_client_in_lobby(user_id, updates, reason), to: ClientLib
@doc section: :client
- @spec connect_user(Teiserver.user_id()) :: Client.t()
- defdelegate connect_user(user_id), to: ClientLib
+ @spec connect_user(Teiserver.user_id(), list) :: Client.t()
+ defdelegate connect_user(user_id, opts \\ []), to: ClientLib
@doc section: :client
@spec disconnect_user(Teiserver.user_id()) :: :ok
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index 5233ce344..7f1071191 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -11,21 +11,21 @@ defmodule Teiserver.Game.LobbyLib do
def lobby_topic(lobby_id), do: "Teiserver.Game.Lobby:#{lobby_id}"
@doc """
- Subscribes the process to lobby updates for this user
+ Subscribes the process to lobby updates for this lobby
"""
- @spec subscribe_to_lobby(User.id() | User.t() | Client.t()) :: :ok
- def subscribe_to_lobby(lobby_or_lobby_id) do
- lobby_or_lobby_id
+ @spec subscribe_to_lobby(Lobby.id()) :: :ok
+ def subscribe_to_lobby(lobby_id) do
+ lobby_id
|> lobby_topic()
|> Teiserver.subscribe()
end
@doc """
- Unsubscribes the process to lobby updates for this user
+ Unsubscribes the process to lobby updates for this lobby
"""
- @spec unsubscribe_from_lobby(User.id() | User.t() | Client.t()) :: :ok
- def unsubscribe_from_lobby(lobby_or_lobby_id) do
- lobby_or_lobby_id
+ @spec unsubscribe_from_lobby(Lobby.id()) :: :ok
+ def unsubscribe_from_lobby(lobby_id) do
+ lobby_id
|> lobby_topic()
|> Teiserver.unsubscribe()
end
@@ -229,9 +229,11 @@ defmodule Teiserver.Game.LobbyLib do
) do
{:ok, lobby.id}
else
- :failure1 -> :fail_result1
- :failure2 -> :fail_result2
- :failure3 -> :fail_result3
+ {:error, reason} ->
+ {:error, reason}
+
+ nil ->
+ {:error, "Unable to cycle lobby, cycle_lobby returned nil indicating the process does not exist"}
end
end
end
@@ -375,11 +377,13 @@ defmodule Teiserver.Game.LobbyLib do
def start_lobby_server(host_id, name) do
lobby = Lobby.new(host_id, name)
- {:ok, _pid} =
- lobby
- |> do_start_lobby_server()
+ case do_start_lobby_server(lobby) do
+ {:ok, _pid} ->
+ {:ok, lobby}
- {:ok, lobby}
+ v ->
+ v
+ end
end
# Process stuff
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index 55a5c0c45..c1b6c05f5 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -48,7 +48,11 @@ defmodule Teiserver.Migrations.Postgres.V01 do
timestamps()
end
- # execute "CREATE INDEX IF NOT EXISTS lower_username ON #{prefix}.account_users (LOWER(name))"
+ if prefix do
+ execute "CREATE INDEX IF NOT EXISTS lower_username ON #{prefix}.account_users (LOWER(name))"
+ else
+ execute "CREATE INDEX IF NOT EXISTS lower_username ON account_users (LOWER(name))"
+ end
create_if_not_exists(unique_index(:account_users, [:email], prefix: prefix))
create_if_not_exists table(:account_extra_user_data, primary_key: false, prefix: prefix) do
From 8cb0ee1544d0685698c20e4349c016b23290e06f Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 20 May 2024 20:26:34 +0100
Subject: [PATCH 19/64] Tweaked some emitters
---
lib/teiserver/connections/client_server.ex | 23 +++++++++++++---------
lib/teiserver/contexts/telemetry.ex | 11 +++--------
lib/teiserver/game/servers/lobby_server.ex | 16 +++++++--------
3 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index a5238668d..c0739681a 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -39,16 +39,16 @@ defmodule Teiserver.Connections.ClientServer do
if state.client.connected? do
:telemetry.execute(
- [:teiserver, :client, :added_connection],
- %{},
+ [:teiserver, :client, :event],
+ %{type: :added_connection},
%{user_id: state.user_id}
)
{:noreply, %State{state | connections: new_connections}}
else
:telemetry.execute(
- [:teiserver, :client, :new_connection],
- %{},
+ [:teiserver, :client, :event],
+ %{type: :new_connection},
%{user_id: state.user_id}
)
@@ -69,8 +69,8 @@ defmodule Teiserver.Connections.ClientServer do
{:noreply, state}
else
:telemetry.execute(
- [:teiserver, :client, :updated],
- %{},
+ [:teiserver, :client, :event],
+ %{type: :updated},
%{user_id: state.user_id}
)
@@ -97,8 +97,8 @@ defmodule Teiserver.Connections.ClientServer do
def handle_cast({:do_update_client_in_lobby, new_client, reason}, state) do
:telemetry.execute(
- [:teiserver, :client, :update_in_lobby],
- %{},
+ [:teiserver, :client, :event],
+ %{type: :update_in_lobby},
%{user_id: state.user_id}
)
@@ -263,7 +263,7 @@ defmodule Teiserver.Connections.ClientServer do
@impl true
@spec init(map) :: {:ok, map}
- def init(%{client: %Client{id: id} = client}) do
+ def init(%{client: %Client{id: id} = client, opts: opts}) do
# Logger.metadata(request_id: "ClientServer##{id}")
:timer.send_interval(@heartbeat_frequency_ms, :heartbeat)
@@ -280,6 +280,11 @@ defmodule Teiserver.Connections.ClientServer do
id
)
+ # Handle opts
+ client = struct(client, %{
+ bot?: (opts[:bot?] || false)
+ })
+
# After being created a client will typically have
# a connection be added, it is possible in some cases
# for a timing issue to happen where the connection will not correctly
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
index 6d90df45a..be1a9b237 100644
--- a/lib/teiserver/contexts/telemetry.ex
+++ b/lib/teiserver/contexts/telemetry.ex
@@ -67,20 +67,15 @@ defmodule Teiserver.Telemetry do
:telemetry.attach_many(@handler_id, events, &__MODULE__.handle_event/4, opts)
end
+ @spec event_list() :: list(list(atom))
def event_list() do
[
[:teiserver, :user, :failed_login],
- [:teiserver, :client, :added_connection],
- [:teiserver, :client, :new_connection],
- [:teiserver, :client, :updated],
- [:teiserver, :client, :update_in_lobby],
+ [:teiserver, :client, :event],
[:teiserver, :client, :disconnect],
- [:teiserver, :lobby, :add_client],
- [:teiserver, :lobby, :remove_client],
- [:teiserver, :lobby, :cycle],
- [:teiserver, :lobby, :start_match],
+ [:teiserver, :lobby, :event],
[:teiserver, :logging, :add_audit_log]
]
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index 7c1a1c11f..1dc7b2c3b 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -42,8 +42,8 @@ defmodule Teiserver.Game.LobbyServer do
{true, _} ->
:telemetry.execute(
- [:teiserver, :lobby, :add_client],
- %{},
+ [:teiserver, :lobby, :event],
+ %{type: :add_client},
%{user_id: user_id}
)
{shared_secret, new_state} = do_add_client(user_id, state)
@@ -70,8 +70,8 @@ defmodule Teiserver.Game.LobbyServer do
def handle_cast({:remove_client, user_id}, state) do
if Enum.member?(state.lobby.members, user_id) do
:telemetry.execute(
- [:teiserver, :lobby, :remove_client],
- %{},
+ [:teiserver, :lobby, :event],
+ %{type: :remove_client},
%{user_id: user_id}
)
new_state = do_remove_client(user_id, state)
@@ -90,8 +90,8 @@ defmodule Teiserver.Game.LobbyServer do
})
:telemetry.execute(
- [:teiserver, :lobby, :cycle],
- %{},
+ [:teiserver, :lobby, :event],
+ %{type: :cycle},
%{match_id: match_id}
)
@@ -105,8 +105,8 @@ defmodule Teiserver.Game.LobbyServer do
})
:telemetry.execute(
- [:teiserver, :lobby, :start_match],
- %{players: state.lobby.players},
+ [:teiserver, :lobby, :event],
+ %{type: :start_match},
%{match_id: state.match_id}
)
From a339fb95125aed59a8371dfbd64950edad3170ab Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 20 May 2024 21:46:33 +0100
Subject: [PATCH 20/64] Query guard fixes
---
lib/teiserver/account/queries/user_queries.ex | 2 +-
lib/teiserver/communication/queries/direct_message_queries.ex | 2 +-
lib/teiserver/communication/queries/match_message_queries.ex | 2 +-
lib/teiserver/communication/queries/room_message_queries.ex | 2 +-
lib/teiserver/communication/queries/room_queries.ex | 2 +-
lib/teiserver/game/queries/match_membership_queries.ex | 2 +-
lib/teiserver/game/queries/match_queries.ex | 2 +-
lib/teiserver/game/queries/match_setting_queries.ex | 2 +-
lib/teiserver/game/queries/match_setting_type_queries.ex | 2 +-
lib/teiserver/game/queries/match_type_queries.ex | 2 +-
lib/teiserver/logging/queries/audit_log_queries.ex | 2 +-
lib/teiserver/settings/queries/server_setting_queries.ex | 2 +-
lib/teiserver/settings/queries/user_setting_queries.ex | 2 +-
lib/teiserver/system/queries/cluster_member_queries.ex | 2 +-
14 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/lib/teiserver/account/queries/user_queries.ex b/lib/teiserver/account/queries/user_queries.ex
index f571d73ed..fb3635104 100644
--- a/lib/teiserver/account/queries/user_queries.ex
+++ b/lib/teiserver/account/queries/user_queries.ex
@@ -197,7 +197,7 @@ defmodule Teiserver.Account.UserQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/communication/queries/direct_message_queries.ex b/lib/teiserver/communication/queries/direct_message_queries.ex
index 119d4de2b..6ec2ecd4f 100644
--- a/lib/teiserver/communication/queries/direct_message_queries.ex
+++ b/lib/teiserver/communication/queries/direct_message_queries.ex
@@ -94,7 +94,7 @@ defmodule Teiserver.Communication.DirectMessageQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/communication/queries/match_message_queries.ex b/lib/teiserver/communication/queries/match_message_queries.ex
index 928703ff4..3b5403674 100644
--- a/lib/teiserver/communication/queries/match_message_queries.ex
+++ b/lib/teiserver/communication/queries/match_message_queries.ex
@@ -82,7 +82,7 @@ defmodule Teiserver.Communication.MatchMessageQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/communication/queries/room_message_queries.ex b/lib/teiserver/communication/queries/room_message_queries.ex
index 9928fc703..2a3283e59 100644
--- a/lib/teiserver/communication/queries/room_message_queries.ex
+++ b/lib/teiserver/communication/queries/room_message_queries.ex
@@ -82,7 +82,7 @@ defmodule Teiserver.Communication.RoomMessageQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/communication/queries/room_queries.ex b/lib/teiserver/communication/queries/room_queries.ex
index 7aa4b6379..03a569fb2 100644
--- a/lib/teiserver/communication/queries/room_queries.ex
+++ b/lib/teiserver/communication/queries/room_queries.ex
@@ -64,7 +64,7 @@ defmodule Teiserver.Communication.RoomQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/game/queries/match_membership_queries.ex b/lib/teiserver/game/queries/match_membership_queries.ex
index f8ad2da6a..74f252605 100644
--- a/lib/teiserver/game/queries/match_membership_queries.ex
+++ b/lib/teiserver/game/queries/match_membership_queries.ex
@@ -90,7 +90,7 @@ defmodule Teiserver.Game.MatchMembershipQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/game/queries/match_queries.ex b/lib/teiserver/game/queries/match_queries.ex
index 3f47dbd39..42bc5b0a5 100644
--- a/lib/teiserver/game/queries/match_queries.ex
+++ b/lib/teiserver/game/queries/match_queries.ex
@@ -65,7 +65,7 @@ defmodule Teiserver.Game.MatchQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/game/queries/match_setting_queries.ex b/lib/teiserver/game/queries/match_setting_queries.ex
index 118124595..fdd4a45ce 100644
--- a/lib/teiserver/game/queries/match_setting_queries.ex
+++ b/lib/teiserver/game/queries/match_setting_queries.ex
@@ -71,7 +71,7 @@ defmodule Teiserver.Game.MatchSettingQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/game/queries/match_setting_type_queries.ex b/lib/teiserver/game/queries/match_setting_type_queries.ex
index dd9efe125..3b9774f85 100644
--- a/lib/teiserver/game/queries/match_setting_type_queries.ex
+++ b/lib/teiserver/game/queries/match_setting_type_queries.ex
@@ -59,7 +59,7 @@ defmodule Teiserver.Game.MatchSettingTypeQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/game/queries/match_type_queries.ex b/lib/teiserver/game/queries/match_type_queries.ex
index a36d9c4c8..d7b1506e7 100644
--- a/lib/teiserver/game/queries/match_type_queries.ex
+++ b/lib/teiserver/game/queries/match_type_queries.ex
@@ -58,7 +58,7 @@ defmodule Teiserver.Game.MatchTypeQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/logging/queries/audit_log_queries.ex b/lib/teiserver/logging/queries/audit_log_queries.ex
index af4b18aef..9b22622d3 100644
--- a/lib/teiserver/logging/queries/audit_log_queries.ex
+++ b/lib/teiserver/logging/queries/audit_log_queries.ex
@@ -119,7 +119,7 @@ defmodule Teiserver.Logging.AuditLogQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/settings/queries/server_setting_queries.ex b/lib/teiserver/settings/queries/server_setting_queries.ex
index 365c213fe..2c5b89768 100644
--- a/lib/teiserver/settings/queries/server_setting_queries.ex
+++ b/lib/teiserver/settings/queries/server_setting_queries.ex
@@ -81,7 +81,7 @@ defmodule Teiserver.Settings.ServerSettingQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/settings/queries/user_setting_queries.ex b/lib/teiserver/settings/queries/user_setting_queries.ex
index 70bfb04f8..b3cda393c 100644
--- a/lib/teiserver/settings/queries/user_setting_queries.ex
+++ b/lib/teiserver/settings/queries/user_setting_queries.ex
@@ -94,7 +94,7 @@ defmodule Teiserver.Settings.UserSettingQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
diff --git a/lib/teiserver/system/queries/cluster_member_queries.ex b/lib/teiserver/system/queries/cluster_member_queries.ex
index 87cc28c6d..5192f12f5 100644
--- a/lib/teiserver/system/queries/cluster_member_queries.ex
+++ b/lib/teiserver/system/queries/cluster_member_queries.ex
@@ -63,7 +63,7 @@ defmodule Teiserver.System.ClusterMemberQueries do
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
- defp do_order_by(query, params) when is_list(params) do
+ defp do_order_by(query, params) do
params
|> List.wrap()
|> Enum.reduce(query, fn key, query_acc ->
From a768137d81a813aba0b5aaecbbd87f8ec1fd0ceb Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 26 May 2024 13:13:35 +0100
Subject: [PATCH 21/64] Cluster member server fixes
---
lib/teiserver/contexts/account.ex | 4 +++
.../system/servers/cluster_member_server.ex | 36 ++++++++++---------
2 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/lib/teiserver/contexts/account.ex b/lib/teiserver/contexts/account.ex
index 51dcb4944..b56d0ccdf 100644
--- a/lib/teiserver/contexts/account.ex
+++ b/lib/teiserver/contexts/account.ex
@@ -86,6 +86,10 @@ defmodule Teiserver.Account do
@spec allow?(Teiserver.user_id() | User.t(), [String.t()] | String.t()) :: boolean
defdelegate allow?(user_or_user_id, permission_or_permissions), to: UserLib
+ @doc section: :user
+ @spec generate_guest_name() :: String.t()
+ defdelegate generate_guest_name(), to: UserLib
+
@doc section: :user
@spec restricted?(Teiserver.user_id() | User.t(), [String.t()] | String.t()) :: boolean
defdelegate restricted?(user_or_user_id, permission_or_permissions), to: UserLib
diff --git a/lib/teiserver/system/servers/cluster_member_server.ex b/lib/teiserver/system/servers/cluster_member_server.ex
index c897707e6..632e1879c 100644
--- a/lib/teiserver/system/servers/cluster_member_server.ex
+++ b/lib/teiserver/system/servers/cluster_member_server.ex
@@ -10,7 +10,7 @@ defmodule Teiserver.System.ClusterMemberServer do
"""
use GenServer
require Logger
- alias Teiserver.System.ClusterMemberLib
+ alias Teiserver.System.{ClusterMember, ClusterMemberLib}
@startup_delay 500
@@ -111,32 +111,36 @@ defmodule Teiserver.System.ClusterMemberServer do
members ->
members
- |> Enum.reduce_while(false, fn cluster_member_entity, acc ->
- node_name = String.to_atom(cluster_member_entity.host)
-
- case Node.connect(node_name) do
- true ->
- {:halt, true}
-
- false ->
- {:cont, acc}
-
- :ignored ->
- {:cont, acc}
- end
- end)
+ |> Enum.reduce_while(false, &attempt_connection/2)
|> case do
true ->
Logger.info("Node successfully joined the cluster: #{inspect(Node.self())}")
true
false ->
- Logger.error("Node failed to successfully join the cluster: #{inspect(Node.self())}")
+ names = members
+ |> Enum.map_join(", ", fn m -> m.host end)
+
+ Logger.error("Node #{inspect(Node.self())} failed to successfully join the cluster, tried: #{names}")
false
end
end
end
+ @spec attempt_connection(ClusterMember.t(), boolean()) :: {:halt | :cont, boolean()}
+ defp attempt_connection(%ClusterMember{host: host}, acc) do
+ case Node.connect(String.to_atom(host)) do
+ true ->
+ {:halt, true}
+
+ false ->
+ {:cont, acc}
+
+ :ignored ->
+ {:cont, acc}
+ end
+ end
+
@spec repo_ready?() :: boolean
defp repo_ready?() do
case Ecto.Repo.all_running() do
From e541561e8e603d931eda10d9434505f1176dd294 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 27 May 2024 11:42:51 +0100
Subject: [PATCH 22/64] Tweaked some client events
---
lib/teiserver/connections/client_server.ex | 4 ++--
lib/teiserver/contexts/telemetry.ex | 4 +++-
lib/teiserver/migrations/postgres/v02.ex | 11 -----------
3 files changed, 5 insertions(+), 14 deletions(-)
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index c0739681a..ff8a424fd 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -39,7 +39,7 @@ defmodule Teiserver.Connections.ClientServer do
if state.client.connected? do
:telemetry.execute(
- [:teiserver, :client, :event],
+ [:teiserver, :client, :connect],
%{type: :added_connection},
%{user_id: state.user_id}
)
@@ -47,7 +47,7 @@ defmodule Teiserver.Connections.ClientServer do
{:noreply, %State{state | connections: new_connections}}
else
:telemetry.execute(
- [:teiserver, :client, :event],
+ [:teiserver, :client, :connect],
%{type: :new_connection},
%{user_id: state.user_id}
)
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
index be1a9b237..e3c102565 100644
--- a/lib/teiserver/contexts/telemetry.ex
+++ b/lib/teiserver/contexts/telemetry.ex
@@ -72,9 +72,11 @@ defmodule Teiserver.Telemetry do
[
[:teiserver, :user, :failed_login],
- [:teiserver, :client, :event],
+ [:teiserver, :client, :connect],
[:teiserver, :client, :disconnect],
+ [:teiserver, :client, :event],
+
[:teiserver, :lobby, :event],
[:teiserver, :logging, :add_audit_log]
diff --git a/lib/teiserver/migrations/postgres/v02.ex b/lib/teiserver/migrations/postgres/v02.ex
index 567b22465..aa7027296 100644
--- a/lib/teiserver/migrations/postgres/v02.ex
+++ b/lib/teiserver/migrations/postgres/v02.ex
@@ -15,21 +15,10 @@ defmodule Teiserver.Migrations.Postgres.V02 do
timestamps()
end
-
- # Telemetry tables
- create_if_not_exists table(:telemetry_event_types, prefix: prefix) do
- add(:category, :string)
- add(:name, :string)
- end
-
- create_if_not_exists(unique_index(:telemetry_event_types, [:category, :name], prefix: prefix))
end
@spec down(map) :: any
def down(%{prefix: prefix, quoted_prefix: _quoted}) do
- # Telemetry
- drop_if_exists(table(:telemetry_event_types, prefix: prefix))
-
# Logging
drop_if_exists(table(:audit_logs, prefix: prefix))
end
From e3242bede8a551bad2019d286a5d6d86da521dd1 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 27 May 2024 23:53:36 +0100
Subject: [PATCH 23/64] Expanded telemetry events slightly
---
lib/teiserver/contexts/telemetry.ex | 3 +++
lib/teiserver/game/servers/lobby_server.ex | 8 ++++----
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
index e3c102565..eea010c34 100644
--- a/lib/teiserver/contexts/telemetry.ex
+++ b/lib/teiserver/contexts/telemetry.ex
@@ -77,6 +77,9 @@ defmodule Teiserver.Telemetry do
[:teiserver, :client, :event],
+
+ [:teiserver, :lobby, :start_match],
+ [:teiserver, :lobby, :cycle],
[:teiserver, :lobby, :event],
[:teiserver, :logging, :add_audit_log]
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index 1dc7b2c3b..e450f136e 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -90,8 +90,8 @@ defmodule Teiserver.Game.LobbyServer do
})
:telemetry.execute(
- [:teiserver, :lobby, :event],
- %{type: :cycle},
+ [:teiserver, :lobby, :cycle],
+ %{},
%{match_id: match_id}
)
@@ -105,8 +105,8 @@ defmodule Teiserver.Game.LobbyServer do
})
:telemetry.execute(
- [:teiserver, :lobby, :event],
- %{type: :start_match},
+ [:teiserver, :lobby, :start_match],
+ %{},
%{match_id: state.match_id}
)
From a6051554e85775c0a45cbccd54127b4ce53a8fe1 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Thu, 13 Jun 2024 00:15:05 +0100
Subject: [PATCH 24/64] Telemetry tweaks, test.ci now used for PR tests
---
.github/workflows/elixir.yml | 2 +-
lib/teiserver/connections/client_server.ex | 8 ++++----
lib/teiserver/contexts/telemetry.ex | 12 ++++++++----
lib/teiserver/game/servers/lobby_server.ex | 16 ++++++++--------
mix.exs | 5 ++---
5 files changed, 23 insertions(+), 20 deletions(-)
diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml
index 72a1857f9..20defdd02 100644
--- a/.github/workflows/elixir.yml
+++ b/.github/workflows/elixir.yml
@@ -89,4 +89,4 @@ jobs:
# Step: Execute the tests.
- name: Run tests
- run: mix test
+ run: mix test.ci
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index ff8a424fd..2a82f8d38 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -69,8 +69,8 @@ defmodule Teiserver.Connections.ClientServer do
{:noreply, state}
else
:telemetry.execute(
- [:teiserver, :client, :event],
- %{type: :updated},
+ [:teiserver, :client, :updated],
+ %{change_count: Enum.count(partial_client)},
%{user_id: state.user_id}
)
@@ -97,8 +97,8 @@ defmodule Teiserver.Connections.ClientServer do
def handle_cast({:do_update_client_in_lobby, new_client, reason}, state) do
:telemetry.execute(
- [:teiserver, :client, :event],
- %{type: :update_in_lobby},
+ [:teiserver, :client, :updated_in_lobby],
+ %{},
%{user_id: state.user_id}
)
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
index eea010c34..781efc2b8 100644
--- a/lib/teiserver/contexts/telemetry.ex
+++ b/lib/teiserver/contexts/telemetry.ex
@@ -70,18 +70,22 @@ defmodule Teiserver.Telemetry do
@spec event_list() :: list(list(atom))
def event_list() do
[
+ # User
[:teiserver, :user, :failed_login],
+ # Client
[:teiserver, :client, :connect],
[:teiserver, :client, :disconnect],
+ [:teiserver, :client, :updated],
+ [:teiserver, :client, :updated_in_lobby],
- [:teiserver, :client, :event],
-
-
+ # Lobby
[:teiserver, :lobby, :start_match],
[:teiserver, :lobby, :cycle],
- [:teiserver, :lobby, :event],
+ [:teiserver, :lobby, :add_client],
+ [:teiserver, :lobby, :remove_client],
+ # Logging
[:teiserver, :logging, :add_audit_log]
]
end
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index e450f136e..526eb3623 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -42,9 +42,9 @@ defmodule Teiserver.Game.LobbyServer do
{true, _} ->
:telemetry.execute(
- [:teiserver, :lobby, :event],
- %{type: :add_client},
- %{user_id: user_id}
+ [:teiserver, :lobby, :add_client],
+ %{},
+ %{user_id: user_id, lobby_id: state.lobby_id}
)
{shared_secret, new_state} = do_add_client(user_id, state)
{:reply, {:ok, shared_secret, state.lobby}, new_state}
@@ -70,9 +70,9 @@ defmodule Teiserver.Game.LobbyServer do
def handle_cast({:remove_client, user_id}, state) do
if Enum.member?(state.lobby.members, user_id) do
:telemetry.execute(
- [:teiserver, :lobby, :event],
- %{type: :remove_client},
- %{user_id: user_id}
+ [:teiserver, :lobby, :remove_client],
+ %{},
+ %{lobby_id: state.lobby_id, user_id: user_id}
)
new_state = do_remove_client(user_id, state)
{:noreply, new_state}
@@ -92,7 +92,7 @@ defmodule Teiserver.Game.LobbyServer do
:telemetry.execute(
[:teiserver, :lobby, :cycle],
%{},
- %{match_id: match_id}
+ %{match_id: match_id, lobby_id: state.lobby_id}
)
{:noreply, %{new_state | match_id: match_id}}
@@ -107,7 +107,7 @@ defmodule Teiserver.Game.LobbyServer do
:telemetry.execute(
[:teiserver, :lobby, :start_match],
%{},
- %{match_id: state.match_id}
+ %{match_id: state.match_id, lobby_id: state.lobby_id}
)
{:noreply, new_state}
diff --git a/mix.exs b/mix.exs
index ef931b0ab..1acb41bcc 100644
--- a/mix.exs
+++ b/mix.exs
@@ -286,9 +286,8 @@ defmodule Teiserver.MixProject do
"test.ci": [
"format --check-formatted",
"deps.unlock --check-unused",
- "credo --strict",
- "test --raise",
- "dialyzer"
+ # "credo --strict",
+ "test --raise"
]
]
end
From 168cac5d733b75881078da025a618165db3ce1f2 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 24 Jun 2024 08:34:17 +0100
Subject: [PATCH 25/64] Updated elixir version
---
.tool-versions | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.tool-versions b/.tool-versions
index b05c3242c..960884cbe 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,2 +1,2 @@
-erlang 26.2
-elixir 1.15.7-otp-26
+erlang 27.0
+elixir 1.17.1-otp-27
From d176e4a1b79686450ab0ce1d4ff7ee7f29219766 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 24 Jun 2024 08:54:10 +0100
Subject: [PATCH 26/64] Updated deps
---
mix.exs | 4 ++--
mix.lock | 36 ++++++++++++++++++------------------
2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/mix.exs b/mix.exs
index 1acb41bcc..b0ce0ba6c 100644
--- a/mix.exs
+++ b/mix.exs
@@ -242,7 +242,7 @@ defmodule Teiserver.MixProject do
{:telemetry, "~> 1.2.1"},
{:gettext, "~> 0.20"},
{:jason, "~> 1.2"},
- {:argon2_elixir, "~> 3.0"},
+ {:argon2_elixir, "~> 4.0"},
{:timex, "~> 3.7.5"},
{:typedstruct, "~> 0.5.2", runtime: false},
{:horde, "~> 0.9"},
@@ -251,7 +251,7 @@ defmodule Teiserver.MixProject do
# Dev and Test stuff
{:ex_doc, "~> 0.31", only: :dev, runtime: false},
- {:excoveralls, "~> 0.15.3", only: :test, runtime: false},
+ {:excoveralls, "~> 0.18.1", only: :test, runtime: false},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
{:floki, ">= 0.34.0", only: :test}
]
diff --git a/mix.lock b/mix.lock
index 4e9d1d9e3..e938c647d 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,26 +1,26 @@
%{
- "argon2_elixir": {:hex, :argon2_elixir, "3.2.1", "f47740bf9f2a39ffef79ba48eb25dea2ee37bcc7eadf91d49615591d1a6fce1a", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "a813b78217394530b5fcf4c8070feee43df03ffef938d044019169c766315690"},
+ "argon2_elixir": {:hex, :argon2_elixir, "4.0.0", "7f6cd2e4a93a37f61d58a367d82f830ad9527082ff3c820b8197a8a736648941", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f9da27cf060c9ea61b1bd47837a28d7e48a8f6fa13a745e252556c14f9132c7f"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
- "credo": {:hex, :credo, "1.7.2", "fdee3a7cb553d8f2e773569181f0a4a2bb7d192e27e325404cc31b354f59d68c", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dd15d6fbc280f6cf9b269f41df4e4992dee6615939653b164ef951f60afcb68e"},
+ "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
- "delta_crdt": {:hex, :delta_crdt, "0.6.4", "79d235eef82a58bb0cb668bc5b9558d2e65325ccb46b74045f20b36fd41671da", [:mix], [{:merkle_map, "~> 0.2.0", [hex: :merkle_map, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4a81f579c06aeeb625db54c6c109859a38aa00d837e3e7f8ac27b40cea34885a"},
+ "delta_crdt": {:hex, :delta_crdt, "0.6.5", "c7bb8c2c7e60f59e46557ab4e0224f67ba22f04c02826e273738f3dcc4767adc", [:mix], [{:merkle_map, "~> 0.2.0", [hex: :merkle_map, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c6ae23a525d30f96494186dd11bf19ed9ae21d9fe2c1f1b217d492a7cc7294ae"},
"dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"},
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
- "ecto": {:hex, :ecto, "3.11.1", "4b4972b717e7ca83d30121b12998f5fcdc62ba0ed4f20fd390f16f3270d85c3e", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebd3d3772cd0dfcd8d772659e41ed527c28b2a8bde4b00fe03e0463da0f1983b"},
- "ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
- "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
+ "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
+ "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"},
+ "elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
- "ex_doc": {:hex, :ex_doc, "0.31.0", "06eb1dfd787445d9cab9a45088405593dd3bb7fe99e097eaa71f37ba80c7a676", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5350cafa6b7f77bdd107aa2199fe277acf29d739aba5aee7e865fc680c62a110"},
- "excoveralls": {:hex, :excoveralls, "0.15.3", "54bb54043e1cf5fe431eb3db36b25e8fd62cf3976666bafe491e3fa5e29eba47", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8eb5d8134d84c327685f7bb8f1db4147f1363c3c9533928234e496e3070114e"},
- "expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"},
+ "ex_doc": {:hex, :ex_doc, "0.34.1", "9751a0419bc15bc7580c73fde506b17b07f6402a1e5243be9e0f05a68c723368", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d441f1a86a235f59088978eff870de2e815e290e44a8bd976fe5d64470a4c9d2"},
+ "excoveralls": {:hex, :excoveralls, "0.18.1", "a6f547570c6b24ec13f122a5634833a063aec49218f6fff27de9df693a15588c", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d65f79db146bb20399f23046015974de0079668b9abb2f5aac074d078da60b8d"},
+ "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
- "floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"},
+ "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
"gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
"horde": {:hex, :horde, "0.9.0", "522342bd7149aeed453c97692a8bca9cf7c9368c5a489afd802e575dc8df54a6", [:mix], [{:delta_crdt, "~> 0.6.2", [hex: :delta_crdt, repo: "hexpm", optional: false]}, {:libring, "~> 1.4", [hex: :libring, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 0.5.0 or ~> 1.0", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "fae11e5bc9c980038607d0c3338cdf7f97124a5d5382fd4b6fb6beaab8e214fe"},
@@ -28,24 +28,24 @@
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
"libring": {:hex, :libring, "1.6.0", "d5dca4bcb1765f862ab59f175b403e356dec493f565670e0bacc4b35e109ce0d", [:mix], [], "hexpm", "5e91ece396af4bce99953d49ee0b02f698cd38326d93cd068361038167484319"},
- "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"},
- "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
- "makeup_erlang": {:hex, :makeup_erlang, "0.1.3", "d684f4bac8690e70b06eb52dad65d26de2eefa44cd19d64a8095e1417df7c8fd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "b78dc853d2e670ff6390b605d807263bf606da3c82be37f9d7f68635bd886fc9"},
+ "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
+ "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
+ "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
"merkle_map": {:hex, :merkle_map, "0.2.1", "01a88c87a6b9fb594c67c17ebaf047ee55ffa34e74297aa583ed87148006c4c8", [:mix], [], "hexpm", "fed4d143a5c8166eee4fa2b49564f3c4eace9cb252f0a82c1613bba905b2d04d"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
- "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
+ "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
- "postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"},
- "sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"},
+ "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"},
+ "sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
- "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
+ "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
"typed_ecto_schema": {:hex, :typed_ecto_schema, "0.4.1", "a373ca6f693f4de84cde474a67467a9cb9051a8a7f3f615f1e23dc74b75237fa", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "85c6962f79d35bf543dd5659c6adc340fd2480cacc6f25d2cc2933ea6e8fcb3b"},
- "typedstruct": {:hex, :typedstruct, "0.5.2", "a317be3ddfd020da09e1af8418b2653449541836eb5ff23bfdc642a5a4adcc59", [:make, :mix], [], "hexpm", "f9343bc65be73a550194e509c3110be966cb005bb7cba41614f29052e5aa408d"},
+ "typedstruct": {:hex, :typedstruct, "0.5.3", "d68ae424251a41b81a8d0c485328ab48edbd3858f3565bbdac21b43c056fc9b4", [:make, :mix], [], "hexpm", "b53b8186701417c0b2782bf02a2db5524f879b8488f91d1d83b97d84c2943432"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
From a321e9f807b03030ec733a43568c453c8746a924 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 24 Jun 2024 13:27:42 +0100
Subject: [PATCH 27/64] mix format
---
lib/teiserver/account/libs/user_lib.ex | 2 +
lib/teiserver/api.ex | 19 ++++---
lib/teiserver/connections/client_server.ex | 7 ++-
lib/teiserver/contexts/telemetry.ex | 6 +-
lib/teiserver/game/libs/lobby_lib.ex | 3 +-
lib/teiserver/game/servers/lobby_server.ex | 2 +
lib/teiserver/logging/libs/audit_log_lib.ex | 2 +
lib/teiserver/migrations/postgres/v01.ex | 7 ++-
lib/teiserver/system/libs/startup_lib.ex | 6 +-
.../system/servers/cluster_member_server.ex | 13 ++++-
test/api_test.exs | 56 +++++++++++++------
.../queries/audit_log_queries_test.exs | 5 +-
12 files changed, 89 insertions(+), 39 deletions(-)
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index 90d8c36f6..277e54f0b 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -284,6 +284,7 @@ defmodule Teiserver.Account.UserLib do
@spec register_failed_login(User.id(), String.t() | nil, String.t() | atom) :: :ok
def register_failed_login(_, _, :rate_limit), do: :ok
def register_failed_login(nil, _, _), do: :ok
+
def register_failed_login(user_id, ip, reason) do
Cachex.incr(:ts_login_count_ip, ip)
Cachex.incr(:ts_login_count_user, user_id)
@@ -319,6 +320,7 @@ defmodule Teiserver.Account.UserLib do
@spec allow_ip_login_attempt?(String.t()) :: boolean
defp allow_ip_login_attempt?(nil), do: true
+
defp allow_ip_login_attempt?(ip) do
max_allowed_ip = Teiserver.Settings.get_server_setting_value("login.ip_rate_limit")
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index d0475680a..9eeea6c9b 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -115,24 +115,27 @@ defmodule Teiserver.Api do
end
end
- @spec do_maybe_authenticate_user(Account.User.t(), String.t(), String.t() | nil) :: {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
+ @spec do_maybe_authenticate_user(Account.User.t(), String.t(), String.t() | nil) ::
+ {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
defp do_maybe_authenticate_user(user, password, ip) do
rate_limit_allow? = UserLib.allow_login_attempt?(user.id, ip)
- result = if rate_limit_allow? do
- if Teiserver.Account.valid_password?(user, password) do
- {:ok, user}
+ result =
+ if rate_limit_allow? do
+ if Teiserver.Account.valid_password?(user, password) do
+ {:ok, user}
+ else
+ {:error, :bad_password}
+ end
else
- {:error, :bad_password}
+ {:error, :rate_limit}
end
- else
- {:error, :rate_limit}
- end
# We might want to register the failed login attempt
case result do
{:error, reason} ->
UserLib.register_failed_login(user.id, ip, reason)
+
_ ->
:ok
end
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index 2a82f8d38..f78dade40 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -281,9 +281,10 @@ defmodule Teiserver.Connections.ClientServer do
)
# Handle opts
- client = struct(client, %{
- bot?: (opts[:bot?] || false)
- })
+ client =
+ struct(client, %{
+ bot?: opts[:bot?] || false
+ })
# After being created a client will typically have
# a connection be added, it is possible in some cases
diff --git a/lib/teiserver/contexts/telemetry.ex b/lib/teiserver/contexts/telemetry.ex
index 781efc2b8..391684465 100644
--- a/lib/teiserver/contexts/telemetry.ex
+++ b/lib/teiserver/contexts/telemetry.ex
@@ -166,9 +166,9 @@ defmodule Teiserver.Telemetry do
# end
def handle_event([:teiserver, a, b], measure, meta, opts) do
- IO.puts "#{__MODULE__}:#{__ENV__.line}"
- IO.inspect {{a, b}, measure, meta, opts}
- IO.puts ""
+ IO.puts("#{__MODULE__}:#{__ENV__.line}")
+ IO.inspect({{a, b}, measure, meta, opts})
+ IO.puts("")
# log(opts, fn ->
# case mode do
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index 7f1071191..7f4a8de76 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -233,7 +233,8 @@ defmodule Teiserver.Game.LobbyLib do
{:error, reason}
nil ->
- {:error, "Unable to cycle lobby, cycle_lobby returned nil indicating the process does not exist"}
+ {:error,
+ "Unable to cycle lobby, cycle_lobby returned nil indicating the process does not exist"}
end
end
end
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index 526eb3623..a42d2ffca 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -46,6 +46,7 @@ defmodule Teiserver.Game.LobbyServer do
%{},
%{user_id: user_id, lobby_id: state.lobby_id}
)
+
{shared_secret, new_state} = do_add_client(user_id, state)
{:reply, {:ok, shared_secret, state.lobby}, new_state}
end
@@ -74,6 +75,7 @@ defmodule Teiserver.Game.LobbyServer do
%{},
%{lobby_id: state.lobby_id, user_id: user_id}
)
+
new_state = do_remove_client(user_id, state)
{:noreply, new_state}
else
diff --git a/lib/teiserver/logging/libs/audit_log_lib.ex b/lib/teiserver/logging/libs/audit_log_lib.ex
index b330f775f..1a4dd310f 100644
--- a/lib/teiserver/logging/libs/audit_log_lib.ex
+++ b/lib/teiserver/logging/libs/audit_log_lib.ex
@@ -123,8 +123,10 @@ defmodule Teiserver.Logging.AuditLogLib do
%{action: audit_log.action},
%{log_id: audit_log.id}
)
+
{:ok, audit_log}
end
+
defp maybe_emit_event(v), do: v
@doc """
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index c1b6c05f5..0565b9e16 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -49,10 +49,13 @@ defmodule Teiserver.Migrations.Postgres.V01 do
end
if prefix do
- execute "CREATE INDEX IF NOT EXISTS lower_username ON #{prefix}.account_users (LOWER(name))"
+ execute(
+ "CREATE INDEX IF NOT EXISTS lower_username ON #{prefix}.account_users (LOWER(name))"
+ )
else
- execute "CREATE INDEX IF NOT EXISTS lower_username ON account_users (LOWER(name))"
+ execute("CREATE INDEX IF NOT EXISTS lower_username ON account_users (LOWER(name))")
end
+
create_if_not_exists(unique_index(:account_users, [:email], prefix: prefix))
create_if_not_exists table(:account_extra_user_data, primary_key: false, prefix: prefix) do
diff --git a/lib/teiserver/system/libs/startup_lib.ex b/lib/teiserver/system/libs/startup_lib.ex
index 327175ed6..accef3b32 100644
--- a/lib/teiserver/system/libs/startup_lib.ex
+++ b/lib/teiserver/system/libs/startup_lib.ex
@@ -13,7 +13,8 @@ defmodule Teiserver.System.StartupLib do
type: "integer",
permissions: "Admin",
default: 3,
- description: "The upper bound on how many failed attempts a given IP can perform before all further attempts will be blocked"
+ description:
+ "The upper bound on how many failed attempts a given IP can perform before all further attempts will be blocked"
})
Settings.add_server_setting_type(%{
@@ -23,7 +24,8 @@ defmodule Teiserver.System.StartupLib do
type: "integer",
permissions: "Admin",
default: nil,
- description: "The upper bound on how many failed attempts a given user can have before their logins are blocked."
+ description:
+ "The upper bound on how many failed attempts a given user can have before their logins are blocked."
})
end
end
diff --git a/lib/teiserver/system/servers/cluster_member_server.ex b/lib/teiserver/system/servers/cluster_member_server.ex
index 632e1879c..a7a362a73 100644
--- a/lib/teiserver/system/servers/cluster_member_server.ex
+++ b/lib/teiserver/system/servers/cluster_member_server.ex
@@ -34,7 +34,10 @@ defmodule Teiserver.System.ClusterMemberServer do
@impl GenServer
def handle_call(other, from, state) do
- Logger.warning("unhandled call to ClusterMemberServer: #{inspect(other)}. From: #{inspect(from)}")
+ Logger.warning(
+ "unhandled call to ClusterMemberServer: #{inspect(other)}. From: #{inspect(from)}"
+ )
+
{:reply, :not_implemented, state}
end
@@ -118,10 +121,14 @@ defmodule Teiserver.System.ClusterMemberServer do
true
false ->
- names = members
+ names =
+ members
|> Enum.map_join(", ", fn m -> m.host end)
- Logger.error("Node #{inspect(Node.self())} failed to successfully join the cluster, tried: #{names}")
+ Logger.error(
+ "Node #{inspect(Node.self())} failed to successfully join the cluster, tried: #{names}"
+ )
+
false
end
end
diff --git a/test/api_test.exs b/test/api_test.exs
index 1d653c9bc..10bfe00f7 100644
--- a/test/api_test.exs
+++ b/test/api_test.exs
@@ -12,23 +12,33 @@ defmodule ApiTest do
test "maybe_authenticate_user_by_name/2" do
user = AccountFixtures.user_fixture()
- assert Api.maybe_authenticate_user_by_name("--- no name ---", "password") == {:error, :no_user}
- assert Api.maybe_authenticate_user_by_name(user.name, "bad_password") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_name("--- no name ---", "password") ==
+ {:error, :no_user}
+
+ assert Api.maybe_authenticate_user_by_name(user.name, "bad_password") ==
+ {:error, :bad_password}
+
assert Api.maybe_authenticate_user_by_name(user.name, "password") == {:ok, user}
end
test "maybe_authenticate_user_by_email/2" do
user = AccountFixtures.user_fixture()
- assert Api.maybe_authenticate_user_by_email("--- no email ---", "password") == {:error, :no_user}
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_email("--- no email ---", "password") ==
+ {:error, :no_user}
+
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password") ==
+ {:error, :bad_password}
+
assert Api.maybe_authenticate_user_by_email(user.email, "password") == {:ok, user}
end
test "maybe_authenticate_user_by_id/2" do
user = AccountFixtures.user_fixture()
- assert Api.maybe_authenticate_user_by_id("e986ed95-b46f-4ad5-8168-fdb575a623f6", "password") == {:error, :no_user}
+ assert Api.maybe_authenticate_user_by_id("e986ed95-b46f-4ad5-8168-fdb575a623f6", "password") ==
+ {:error, :no_user}
+
assert Api.maybe_authenticate_user_by_id(user.id, "bad_password") == {:error, :bad_password}
assert Api.maybe_authenticate_user_by_id(user.id, "password") == {:ok, user}
end
@@ -37,18 +47,26 @@ defmodule ApiTest do
user = AccountFixtures.user_fixture()
# No attempts so far, lets check for audit logs
- logs = Teiserver.Logging.list_audit_logs(where: [
- user_id: user.id
- ])
+ logs =
+ Teiserver.Logging.list_audit_logs(
+ where: [
+ user_id: user.id
+ ]
+ )
+
assert Enum.empty?(logs)
# Bad login
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ {:error, :bad_password}
# Ensure it was logged
- [log] = Teiserver.Logging.list_audit_logs(where: [
- user_id: user.id
- ])
+ [log] =
+ Teiserver.Logging.list_audit_logs(
+ where: [
+ user_id: user.id
+ ]
+ )
assert log.ip == "my-ip"
assert log.details == %{"reason" => "bad_password"}
@@ -56,11 +74,17 @@ defmodule ApiTest do
assert log.user_id == user.id
# Now do it a few more times to trip the breaker
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :bad_password}
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :bad_password}
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :bad_password}
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ {:error, :bad_password}
+
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ {:error, :bad_password}
+
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ {:error, :bad_password}
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") == {:error, :rate_limit}
+ assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ {:error, :rate_limit}
end
test "register_user/3" do
diff --git a/test/logging/queries/audit_log_queries_test.exs b/test/logging/queries/audit_log_queries_test.exs
index a88fefcf5..ea205235d 100644
--- a/test/logging/queries/audit_log_queries_test.exs
+++ b/test/logging/queries/audit_log_queries_test.exs
@@ -31,7 +31,10 @@ defmodule Teiserver.AuditLogQueriesTest do
where: [
id: [1, 2],
id: 1,
- user_id: ["0ea89483-80da-4041-9e41-fcb152c24168", "7fa72464-e3b6-42e8-935e-608adc65608e"],
+ user_id: [
+ "0ea89483-80da-4041-9e41-fcb152c24168",
+ "7fa72464-e3b6-42e8-935e-608adc65608e"
+ ],
user_id: "57b86216-5a32-4e76-bad0-1012a825667b",
action: ["action1", "action2"],
action: "action",
From 904c46450361f520d3b89d6e86f681c6e675af67 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 24 Jun 2024 21:54:14 +0100
Subject: [PATCH 28/64] Moved test fixtures outside the main Teiserver
namespace
---
.gitignore | 1 +
CHANGELOG.md | 1 +
documentation/guides/testing.md | 4 ++--
lib/teiserver/api.ex | 13 ++++++++-----
lib/teiserver/connections/libs/client_lib.ex | 2 +-
lib/teiserver/migrations/migration.ex | 2 +-
mix.exs | 2 +-
test/account/extra_user_data_test.exs | 2 +-
test/account/user_lib_test.exs | 2 +-
test/account/user_test.exs | 2 +-
test/api_test.exs | 4 ++--
test/communication/libs/direct_message_lib_test.exs | 2 +-
test/communication/libs/match_message_lib_test.exs | 8 +++++++-
test/communication/libs/room_lib_test.exs | 2 +-
test/communication/libs/room_message_lib_test.exs | 2 +-
test/connections/client_in_lobby_test.exs | 2 +-
test/connections/client_lib_test.exs | 2 +-
test/connections/client_server_test.exs | 2 +-
test/game/libs/lobby_lib_test.exs | 2 +-
test/game/libs/match_lib_test.exs | 2 +-
test/game/libs/match_membership_lib_test.exs | 2 +-
test/game/libs/match_setting_lib_test.exs | 2 +-
test/game/libs/match_setting_type_lib_test.exs | 2 +-
test/game/libs/match_type_lib_test.exs | 2 +-
test/game/lobby_server_test.exs | 2 +-
test/logging/libs/audit_log_lib_test.exs | 2 +-
test/settings/server_setting_test.exs | 2 +-
test/settings/user_setting_test.exs | 2 +-
test/support/fixtures/account_fixtures.ex | 2 +-
test/support/fixtures/communication_fixtures.ex | 6 +++---
test/support/fixtures/connection_fixtures.ex | 4 ++--
test/support/fixtures/game_fixtures.ex | 6 +++---
test/support/fixtures/logging_fixtures.ex | 4 ++--
test/support/fixtures/settings_fixtures.ex | 4 ++--
34 files changed, 56 insertions(+), 45 deletions(-)
diff --git a/.gitignore b/.gitignore
index 666215e9e..e68659adf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,3 +35,4 @@ teiserver-*.tar
# Notes I put in for myself I don't want on github
/zignore
+/bin
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a60366da2..baf481ca2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
## v0.0.5
+- Swapped to Elixir 1.17
- Swapped `team_colour` for `player_colour`
- Refactored the client update process
- Added User and Server runtime settings
diff --git a/documentation/guides/testing.md b/documentation/guides/testing.md
index 04b6d5f9e..6150e58cb 100644
--- a/documentation/guides/testing.md
+++ b/documentation/guides/testing.md
@@ -4,14 +4,14 @@ Teiserver aims to have as many functions tested as possible. More importantly Te
## Fixtures
Teiserver includes at least one fixture for every schema located in `/test/support/fixtures`. They follow a consistent naming pattern:
```elixir
-Teiserver.Account.User -> Teiserver.AccountFixtures.user_fixture()
+Teiserver.Account.User -> Teiserver.Fixtures.AccountFixtures.user_fixture()
Teiserver.Game.Match -> Teiserver.GameFixtures.incomplete_match_fixture()
```
Each fixture can be called as is or with a map which will dictate overrides for otherwise static or random values.
```elixir
-Teiserver.AccountFixtures.user_fixture(%{
+Teiserver.Fixtures.AccountFixtures.user_fixture(%{
name: "MySpecific TestUser",
password: "A special password"
})
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index 9eeea6c9b..68998ea6c 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -152,13 +152,16 @@ defmodule Teiserver.Api do
Always returns `:ok`
"""
@doc section: :client
- @spec connect_user(Teiserver.user_id(), list) :: Connections.Client.t()
+ @spec connect_user(Teiserver.user_id(), list) :: Connections.Client.t() | nil
def connect_user(user_id, opts \\ []) when is_binary(user_id) do
client = Connections.connect_user(user_id, opts)
- # Sleep to prevent this current process getting the messages related to the connection
- :timer.sleep(100)
- Teiserver.subscribe(Connections.client_topic(user_id))
- Teiserver.subscribe(Communication.user_messaging_topic(user_id))
+
+ if client do
+ # Sleep to prevent this current process getting the messages related to the connection
+ :timer.sleep(100)
+ Teiserver.subscribe(Connections.client_topic(user_id))
+ Teiserver.subscribe(Communication.user_messaging_topic(user_id))
+ end
# Return the client
client
diff --git a/lib/teiserver/connections/libs/client_lib.ex b/lib/teiserver/connections/libs/client_lib.ex
index 8a2259fc3..c7b65ce26 100644
--- a/lib/teiserver/connections/libs/client_lib.ex
+++ b/lib/teiserver/connections/libs/client_lib.ex
@@ -150,7 +150,7 @@ defmodule Teiserver.Connections.ClientLib do
the client will monitor it for the purposes of tracking if the
given client is still connected.
"""
- @spec connect_user(Teiserver.user_id(), list()) :: Client.t()
+ @spec connect_user(Teiserver.user_id(), list()) :: Client.t() | nil
def connect_user(user_id, opts \\ []) do
if client_exists?(user_id) do
cast_client(user_id, {:add_connection, self()})
diff --git a/lib/teiserver/migrations/migration.ex b/lib/teiserver/migrations/migration.ex
index 2d1e70f99..6e4050649 100644
--- a/lib/teiserver/migrations/migration.ex
+++ b/lib/teiserver/migrations/migration.ex
@@ -187,7 +187,7 @@ defmodule Teiserver.Migration do
end
defp migrator do
- case repo().__adapter__ do
+ case repo().__adapter__() do
Ecto.Adapters.Postgres -> Teiserver.Migrations.Postgres
Ecto.Adapters.SQLite3 -> Teiserver.Migrations.SQLite
_ -> Keyword.fetch!(repo().config(), :migrator)
diff --git a/mix.exs b/mix.exs
index b0ce0ba6c..f30209b48 100644
--- a/mix.exs
+++ b/mix.exs
@@ -8,7 +8,7 @@ defmodule Teiserver.MixProject do
[
app: :teiserver,
version: @version,
- elixir: "~> 1.14",
+ elixir: "~> 1.17",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
deps: deps(),
diff --git a/test/account/extra_user_data_test.exs b/test/account/extra_user_data_test.exs
index a2302a657..067369ed4 100644
--- a/test/account/extra_user_data_test.exs
+++ b/test/account/extra_user_data_test.exs
@@ -2,7 +2,7 @@ defmodule Account.ExtraUserDataTest do
@moduledoc false
use Teiserver.Case, async: true
- alias Teiserver.AccountFixtures
+ alias Teiserver.Fixtures.AccountFixtures
alias Teiserver.Account.ExtraUserData
describe "ExtraUserData" do
diff --git a/test/account/user_lib_test.exs b/test/account/user_lib_test.exs
index 7e28b4a69..d7a773eb2 100644
--- a/test/account/user_lib_test.exs
+++ b/test/account/user_lib_test.exs
@@ -3,7 +3,7 @@ defmodule Teiserver.UserLibTest do
use Teiserver.Case, async: true
alias Teiserver.Account
- alias Teiserver.AccountFixtures
+ alias Teiserver.Fixtures.AccountFixtures
describe "users" do
alias Teiserver.Account.User
diff --git a/test/account/user_test.exs b/test/account/user_test.exs
index 5627d7be7..cc23a9f17 100644
--- a/test/account/user_test.exs
+++ b/test/account/user_test.exs
@@ -2,7 +2,7 @@ defmodule Account.UserTest do
@moduledoc false
use Teiserver.Case, async: true
- alias Teiserver.AccountFixtures
+ alias Teiserver.Fixtures.AccountFixtures
alias Teiserver.Account.User
describe "User" do
diff --git a/test/api_test.exs b/test/api_test.exs
index 10bfe00f7..b717e7195 100644
--- a/test/api_test.exs
+++ b/test/api_test.exs
@@ -1,11 +1,11 @@
defmodule ApiTest do
@moduledoc false
- alias Teiserver.CommunicationFixtures
+ alias Teiserver.Fixtures.CommunicationFixtures
use Teiserver.Case, async: true
alias Phoenix.PubSub
alias Teiserver.Api
- alias Teiserver.AccountFixtures
+ alias Teiserver.Fixtures.AccountFixtures
alias Teiserver.Account.User
describe "API functionality" do
diff --git a/test/communication/libs/direct_message_lib_test.exs b/test/communication/libs/direct_message_lib_test.exs
index adad2655d..c2ab5cdac 100644
--- a/test/communication/libs/direct_message_lib_test.exs
+++ b/test/communication/libs/direct_message_lib_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.DirectMessageLibTest do
alias Teiserver.Communication
use Teiserver.Case, async: true
- alias Teiserver.{CommunicationFixtures, ConnectionFixtures, AccountFixtures}
+ alias Teiserver.Fixtures.{CommunicationFixtures, ConnectionFixtures, AccountFixtures}
defp valid_attrs do
%{
diff --git a/test/communication/libs/match_message_lib_test.exs b/test/communication/libs/match_message_lib_test.exs
index ba67dc7d3..a0605e710 100644
--- a/test/communication/libs/match_message_lib_test.exs
+++ b/test/communication/libs/match_message_lib_test.exs
@@ -4,7 +4,13 @@ defmodule Teiserver.MatchMessageLibTest do
use Teiserver.Case, async: true
alias Teiserver.Communication
- alias Teiserver.{CommunicationFixtures, AccountFixtures, ConnectionFixtures, GameFixtures}
+
+ alias Teiserver.Fixtures.{
+ CommunicationFixtures,
+ AccountFixtures,
+ ConnectionFixtures,
+ GameFixtures
+ }
defp valid_attrs do
%{
diff --git a/test/communication/libs/room_lib_test.exs b/test/communication/libs/room_lib_test.exs
index 8bc913fef..ca4412440 100644
--- a/test/communication/libs/room_lib_test.exs
+++ b/test/communication/libs/room_lib_test.exs
@@ -3,7 +3,7 @@ defmodule Teiserver.RoomLibTest do
use Teiserver.Case, async: true
alias Teiserver.Communication
- alias Teiserver.CommunicationFixtures
+ alias Teiserver.Fixtures.CommunicationFixtures
describe "room" do
alias Teiserver.Communication.Room
diff --git a/test/communication/libs/room_message_lib_test.exs b/test/communication/libs/room_message_lib_test.exs
index bd682e9c7..852fb58d2 100644
--- a/test/communication/libs/room_message_lib_test.exs
+++ b/test/communication/libs/room_message_lib_test.exs
@@ -5,7 +5,7 @@ defmodule Teiserver.RoomMessageLibTest do
alias Teiserver.Communication
alias Phoenix.PubSub
- alias Teiserver.{CommunicationFixtures, AccountFixtures, ConnectionFixtures}
+ alias Teiserver.Fixtures.{CommunicationFixtures, AccountFixtures, ConnectionFixtures}
defp valid_attrs do
%{
diff --git a/test/connections/client_in_lobby_test.exs b/test/connections/client_in_lobby_test.exs
index 70fcf1974..a430569a1 100644
--- a/test/connections/client_in_lobby_test.exs
+++ b/test/connections/client_in_lobby_test.exs
@@ -3,7 +3,7 @@ defmodule Connections.ClientInLobbyLibTest do
use Teiserver.Case, async: false
alias Teiserver.{Connections, Game}
- alias Teiserver.{ConnectionFixtures, GameFixtures}
+ alias Teiserver.Fixtures.{ConnectionFixtures, GameFixtures}
describe "ClientLib" do
test "update_client_in_lobby" do
diff --git a/test/connections/client_lib_test.exs b/test/connections/client_lib_test.exs
index 717b2f774..687aedfd4 100644
--- a/test/connections/client_lib_test.exs
+++ b/test/connections/client_lib_test.exs
@@ -3,7 +3,7 @@ defmodule Connections.ClientLibTest do
use Teiserver.Case, async: true
alias Teiserver.Connections
- alias Teiserver.ConnectionFixtures
+ alias Teiserver.Fixtures.ConnectionFixtures
describe "ClientLib" do
test "server lifecycle" do
diff --git a/test/connections/client_server_test.exs b/test/connections/client_server_test.exs
index 6aa319cea..8e35de66b 100644
--- a/test/connections/client_server_test.exs
+++ b/test/connections/client_server_test.exs
@@ -3,7 +3,7 @@ defmodule Connections.ClientServerTest do
use Teiserver.Case, async: true
alias Teiserver.Connections
- alias Teiserver.{AccountFixtures, ConnectionFixtures}
+ alias Teiserver.Fixtures.{AccountFixtures, ConnectionFixtures}
describe "Client server" do
test "server lifecycle" do
diff --git a/test/game/libs/lobby_lib_test.exs b/test/game/libs/lobby_lib_test.exs
index 71e2da36b..4ea92f235 100644
--- a/test/game/libs/lobby_lib_test.exs
+++ b/test/game/libs/lobby_lib_test.exs
@@ -3,7 +3,7 @@ defmodule Teiserver.Game.LobbyLibTest do
use Teiserver.Case, async: true
alias Teiserver.Game
- alias Teiserver.{ConnectionFixtures, GameFixtures}
+ alias Teiserver.Fixtures.{ConnectionFixtures, GameFixtures}
describe "LobbyLib" do
test "Creating and stopping server" do
diff --git a/test/game/libs/match_lib_test.exs b/test/game/libs/match_lib_test.exs
index c8e641e2d..8144966ff 100644
--- a/test/game/libs/match_lib_test.exs
+++ b/test/game/libs/match_lib_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.MatchLibAsyncTest do
use Teiserver.Case, async: false
alias Teiserver.{Game, Connections}
- alias Teiserver.{GameFixtures, AccountFixtures, ConnectionFixtures}
+ alias Teiserver.Fixtures.{GameFixtures, AccountFixtures, ConnectionFixtures}
defp valid_attrs do
%{
diff --git a/test/game/libs/match_membership_lib_test.exs b/test/game/libs/match_membership_lib_test.exs
index b9fe2632f..43f774a5e 100644
--- a/test/game/libs/match_membership_lib_test.exs
+++ b/test/game/libs/match_membership_lib_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.MatchMembershipLibTest do
alias Teiserver.Game
use Teiserver.Case, async: true
- alias Teiserver.{GameFixtures, AccountFixtures}
+ alias Teiserver.Fixtures.{GameFixtures, AccountFixtures}
defp valid_attrs do
%{
diff --git a/test/game/libs/match_setting_lib_test.exs b/test/game/libs/match_setting_lib_test.exs
index 317014501..d0024a02c 100644
--- a/test/game/libs/match_setting_lib_test.exs
+++ b/test/game/libs/match_setting_lib_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.MatchSettingLibTest do
alias Teiserver.Game
use Teiserver.Case, async: true
- alias Teiserver.{GameFixtures}
+ alias Teiserver.Fixtures.{GameFixtures}
defp valid_attrs do
%{
diff --git a/test/game/libs/match_setting_type_lib_test.exs b/test/game/libs/match_setting_type_lib_test.exs
index a8ff40727..073eec3bb 100644
--- a/test/game/libs/match_setting_type_lib_test.exs
+++ b/test/game/libs/match_setting_type_lib_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.MatchSettingTypeLibTest do
alias Teiserver.Game
use Teiserver.Case, async: true
- alias Teiserver.{GameFixtures}
+ alias Teiserver.Fixtures.{GameFixtures}
defp valid_attrs do
%{
diff --git a/test/game/libs/match_type_lib_test.exs b/test/game/libs/match_type_lib_test.exs
index e3bb14186..8c9b582db 100644
--- a/test/game/libs/match_type_lib_test.exs
+++ b/test/game/libs/match_type_lib_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.MatchTypeLibTest do
alias Teiserver.Game
use Teiserver.Case, async: true
- alias Teiserver.{GameFixtures}
+ alias Teiserver.Fixtures.{GameFixtures}
defp valid_attrs do
%{
diff --git a/test/game/lobby_server_test.exs b/test/game/lobby_server_test.exs
index 0f2281985..6d373ae1f 100644
--- a/test/game/lobby_server_test.exs
+++ b/test/game/lobby_server_test.exs
@@ -3,7 +3,7 @@ defmodule Teiserver.Game.LobbyServerTest do
use Teiserver.Case, async: true
alias Teiserver.{Game, Connections}
- alias Teiserver.ConnectionFixtures
+ alias Teiserver.Fixtures.ConnectionFixtures
describe "Lobby server" do
test "server lifecycle" do
diff --git a/test/logging/libs/audit_log_lib_test.exs b/test/logging/libs/audit_log_lib_test.exs
index 2f5fbf52e..8f7b2fdc0 100644
--- a/test/logging/libs/audit_log_lib_test.exs
+++ b/test/logging/libs/audit_log_lib_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.AuditLogLibTest do
alias Teiserver.Logging
use Teiserver.Case, async: true
- alias Teiserver.{LoggingFixtures, AccountFixtures}
+ alias Teiserver.Fixtures.{LoggingFixtures, AccountFixtures}
defp valid_attrs do
%{
diff --git a/test/settings/server_setting_test.exs b/test/settings/server_setting_test.exs
index b2b5b8d89..e8dd3446f 100644
--- a/test/settings/server_setting_test.exs
+++ b/test/settings/server_setting_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.ServerSettingTest do
use Teiserver.Case, async: false
alias Teiserver.Settings
- alias Teiserver.{SettingsFixtures}
+ alias Teiserver.Fixtures.SettingsFixtures
defp valid_attrs do
%{
diff --git a/test/settings/user_setting_test.exs b/test/settings/user_setting_test.exs
index 73ad6ee82..372c21f61 100644
--- a/test/settings/user_setting_test.exs
+++ b/test/settings/user_setting_test.exs
@@ -4,7 +4,7 @@ defmodule Teiserver.UserSettingTest do
use Teiserver.Case, async: false
alias Teiserver.Settings
- alias Teiserver.{AccountFixtures, SettingsFixtures}
+ alias Teiserver.Fixtures.{AccountFixtures, SettingsFixtures}
defp valid_attrs do
%{
diff --git a/test/support/fixtures/account_fixtures.ex b/test/support/fixtures/account_fixtures.ex
index c3ba49ee1..b193c76e5 100644
--- a/test/support/fixtures/account_fixtures.ex
+++ b/test/support/fixtures/account_fixtures.ex
@@ -1,4 +1,4 @@
-defmodule Teiserver.AccountFixtures do
+defmodule Teiserver.Fixtures.AccountFixtures do
@moduledoc false
alias Teiserver.Account.{User, ExtraUserData}
diff --git a/test/support/fixtures/communication_fixtures.ex b/test/support/fixtures/communication_fixtures.ex
index f834ca8de..085653db5 100644
--- a/test/support/fixtures/communication_fixtures.ex
+++ b/test/support/fixtures/communication_fixtures.ex
@@ -1,7 +1,7 @@
-defmodule Teiserver.CommunicationFixtures do
+defmodule Teiserver.Fixtures.CommunicationFixtures do
@moduledoc false
- import Teiserver.AccountFixtures, only: [user_fixture: 0]
- import Teiserver.GameFixtures, only: [incomplete_match_fixture: 0]
+ import Teiserver.Fixtures.AccountFixtures, only: [user_fixture: 0]
+ import Teiserver.Fixtures.GameFixtures, only: [incomplete_match_fixture: 0]
alias Teiserver.Communication.{Room, RoomMessage, DirectMessage, MatchMessage}
@spec room_fixture() :: Room.t()
diff --git a/test/support/fixtures/connection_fixtures.ex b/test/support/fixtures/connection_fixtures.ex
index df1a1a5bd..3db0f69d9 100644
--- a/test/support/fixtures/connection_fixtures.ex
+++ b/test/support/fixtures/connection_fixtures.ex
@@ -1,4 +1,4 @@
-defmodule Teiserver.ConnectionFixtures do
+defmodule Teiserver.Fixtures.ConnectionFixtures do
@moduledoc false
alias Teiserver.Connections
@@ -7,7 +7,7 @@ defmodule Teiserver.ConnectionFixtures do
@spec client_fixture() :: {pid, Teiserver.Account.User}
@spec client_fixture(Teiserver.Account.User) :: {pid, Teiserver.Account.User}
def client_fixture(user \\ nil) do
- user = user || Teiserver.AccountFixtures.user_fixture()
+ user = user || Teiserver.Fixtures.AccountFixtures.user_fixture()
conn = TestConn.new()
TestConn.run(conn, fn ->
diff --git a/test/support/fixtures/game_fixtures.ex b/test/support/fixtures/game_fixtures.ex
index 3d03e0bf2..8b9367226 100644
--- a/test/support/fixtures/game_fixtures.ex
+++ b/test/support/fixtures/game_fixtures.ex
@@ -1,9 +1,9 @@
-defmodule Teiserver.GameFixtures do
+defmodule Teiserver.Fixtures.GameFixtures do
@moduledoc false
alias Teiserver.Game
alias Teiserver.Game.{Lobby, Match, MatchType, MatchMembership, MatchSettingType, MatchSetting}
- import Teiserver.AccountFixtures, only: [user_fixture: 0]
- import Teiserver.ConnectionFixtures, only: [client_fixture: 0]
+ import Teiserver.Fixtures.AccountFixtures, only: [user_fixture: 0]
+ import Teiserver.Fixtures.ConnectionFixtures, only: [client_fixture: 0]
@spec lobby_fixture() :: Lobby.t()
@spec lobby_fixture(map) :: Lobby.t()
diff --git a/test/support/fixtures/logging_fixtures.ex b/test/support/fixtures/logging_fixtures.ex
index 0a66ee821..5b1d63bf4 100644
--- a/test/support/fixtures/logging_fixtures.ex
+++ b/test/support/fixtures/logging_fixtures.ex
@@ -1,6 +1,6 @@
-defmodule Teiserver.LoggingFixtures do
+defmodule Teiserver.Fixtures.LoggingFixtures do
@moduledoc false
- import Teiserver.AccountFixtures, only: [user_fixture: 0]
+ import Teiserver.Fixtures.AccountFixtures, only: [user_fixture: 0]
alias Teiserver.Logging.{AuditLog}
@spec audit_log_fixture() :: AuditLog.t()
diff --git a/test/support/fixtures/settings_fixtures.ex b/test/support/fixtures/settings_fixtures.ex
index 51d9ac59a..66a8d870a 100644
--- a/test/support/fixtures/settings_fixtures.ex
+++ b/test/support/fixtures/settings_fixtures.ex
@@ -1,8 +1,8 @@
-defmodule Teiserver.SettingsFixtures do
+defmodule Teiserver.Fixtures.SettingsFixtures do
@moduledoc false
alias Teiserver.Settings
alias Teiserver.Settings.{ServerSettingType, ServerSetting, UserSetting}
- import Teiserver.AccountFixtures, only: [user_fixture: 0]
+ import Teiserver.Fixtures.AccountFixtures, only: [user_fixture: 0]
@spec server_setting_type_fixture() :: ServerSettingType.t()
@spec server_setting_type_fixture(map) :: ServerSettingType.t()
From 5523677fe01ba9c23a5ae57d4d88825992c1c5b5 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 26 Jun 2024 17:32:57 +0100
Subject: [PATCH 29/64] Minor bugfix
---
.gitignore | 1 -
lib/teiserver/game/libs/lobby_lib.ex | 3 +++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index e68659adf..666215e9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,4 +35,3 @@ teiserver-*.tar
# Notes I put in for myself I don't want on github
/zignore
-/bin
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index 7f4a8de76..50e50b0ae 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -202,6 +202,9 @@ defmodule Teiserver.Game.LobbyLib do
client = Connections.get_client(host_id)
cond do
+ host_id == nil ->
+ {:error, "No host_id provided"}
+
client == nil ->
{:error, "Client is not connected"}
From 80cd661fbfb7a7eaa72d240e80a34e19ff56e4a6 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 26 Jun 2024 17:41:53 +0100
Subject: [PATCH 30/64] Moved caches into their own supervisor trees
---
lib/teiserver.ex | 2 +-
lib/teiserver/application.ex | 28 ++------------
lib/teiserver/caches/login_count_cache.ex | 22 +++++++++++
lib/teiserver/caches/server_settings_cache.ex | 22 +++++++++++
lib/teiserver/caches/user_settings_cache.ex | 23 ++++++++++++
lib/teiserver/helpers/cache_helper.ex | 37 +++++++++++++++++++
.../system/servers/cache_cluster_server.ex | 15 --------
7 files changed, 109 insertions(+), 40 deletions(-)
create mode 100644 lib/teiserver/caches/login_count_cache.ex
create mode 100644 lib/teiserver/caches/server_settings_cache.ex
create mode 100644 lib/teiserver/caches/user_settings_cache.ex
create mode 100644 lib/teiserver/helpers/cache_helper.ex
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index a868eb37b..51188a2fe 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -99,5 +99,5 @@ defmodule Teiserver do
# Cluster cache delegation
@spec invalidate_cache(atom, any) :: :ok
- defdelegate invalidate_cache(table, key_or_keys), to: Teiserver.System.CacheClusterServer
+ defdelegate invalidate_cache(table, key_or_keys), to: Teiserver.Helpers.CacheHelper
end
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index add49f3e5..f82f7dc3e 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -37,16 +37,10 @@ defmodule Teiserver.Application do
# {Registry, [keys: :unique, members: :auto, name: Teiserver.LocalMMQueueRegistry]},
# {Registry, [keys: :unique, members: :auto, name: Teiserver.LocalMMMatchRegistry]}
- # DB Lookup caches
- add_cache(:ts_server_setting_type_store),
- add_cache(:ts_server_setting_cache, ttl: :timer.minutes(1)),
- add_cache(:ts_user_setting_type_store),
- add_cache(:ts_user_setting_cache, ttl: :timer.minutes(1)),
- add_cache(:ts_user_by_user_id_cache, ttl: :timer.minutes(5)),
-
- # Login rate limiting
- add_cache(:ts_login_count_ip, ttl: :timer.minutes(5)),
- add_cache(:ts_login_count_user, ttl: :timer.minutes(5))
+ # Caches
+ Teiserver.Caches.UserSettingCache,
+ Teiserver.Caches.ServerSettingCache,
+ Teiserver.Caches.LoginCountCache
]
opts = [strategy: :one_for_one, name: __MODULE__]
@@ -60,18 +54,4 @@ defmodule Teiserver.Application do
start_result
end
-
- @spec add_cache(atom) :: map()
- @spec add_cache(atom, list) :: map()
- defp add_cache(name, opts \\ []) when is_atom(name) do
- %{
- id: name,
- start:
- {Cachex, :start_link,
- [
- name,
- opts
- ]}
- }
- end
end
diff --git a/lib/teiserver/caches/login_count_cache.ex b/lib/teiserver/caches/login_count_cache.ex
new file mode 100644
index 000000000..0aa7364ad
--- /dev/null
+++ b/lib/teiserver/caches/login_count_cache.ex
@@ -0,0 +1,22 @@
+defmodule Teiserver.Caches.LoginCountCache do
+ @moduledoc """
+ Cache and setup for communication stuff
+ """
+
+ use Supervisor
+ import Teiserver.Helpers.CacheHelper, only: [add_cache: 2]
+
+ def start_link(opts) do
+ Supervisor.start_link(__MODULE__, :ok, opts)
+ end
+
+ @impl true
+ def init(:ok) do
+ children = [
+ add_cache(:ts_login_count_ip, ttl: :timer.minutes(5)),
+ add_cache(:ts_login_count_user, ttl: :timer.minutes(5))
+ ]
+
+ Supervisor.init(children, strategy: :one_for_all)
+ end
+end
diff --git a/lib/teiserver/caches/server_settings_cache.ex b/lib/teiserver/caches/server_settings_cache.ex
new file mode 100644
index 000000000..f346a3885
--- /dev/null
+++ b/lib/teiserver/caches/server_settings_cache.ex
@@ -0,0 +1,22 @@
+defmodule Teiserver.Caches.ServerSettingCache do
+ @moduledoc """
+ Cache and setup for communication stuff
+ """
+
+ use Supervisor
+ import Teiserver.Helpers.CacheHelper, only: [add_cache: 1, add_cache: 2]
+
+ def start_link(opts) do
+ Supervisor.start_link(__MODULE__, :ok, opts)
+ end
+
+ @impl true
+ def init(:ok) do
+ children = [
+ add_cache(:ts_server_setting_type_store),
+ add_cache(:ts_server_setting_cache, ttl: :timer.minutes(1))
+ ]
+
+ Supervisor.init(children, strategy: :one_for_all)
+ end
+end
diff --git a/lib/teiserver/caches/user_settings_cache.ex b/lib/teiserver/caches/user_settings_cache.ex
new file mode 100644
index 000000000..a491f566f
--- /dev/null
+++ b/lib/teiserver/caches/user_settings_cache.ex
@@ -0,0 +1,23 @@
+defmodule Teiserver.Caches.UserSettingCache do
+ @moduledoc """
+ Cache and setup for communication stuff
+ """
+
+ use Supervisor
+ import Teiserver.Helpers.CacheHelper, only: [add_cache: 1, add_cache: 2]
+
+ def start_link(opts) do
+ Supervisor.start_link(__MODULE__, :ok, opts)
+ end
+
+ @impl true
+ def init(:ok) do
+ children = [
+ add_cache(:ts_user_setting_type_store),
+ add_cache(:ts_user_setting_cache, ttl: :timer.minutes(1)),
+ add_cache(:ts_user_by_user_id_cache, ttl: :timer.minutes(5))
+ ]
+
+ Supervisor.init(children, strategy: :one_for_all)
+ end
+end
diff --git a/lib/teiserver/helpers/cache_helper.ex b/lib/teiserver/helpers/cache_helper.ex
new file mode 100644
index 000000000..fdb8147fd
--- /dev/null
+++ b/lib/teiserver/helpers/cache_helper.ex
@@ -0,0 +1,37 @@
+defmodule Teiserver.Helpers.CacheHelper do
+ @moduledoc """
+ A set of functions to interact with the various caches in the system.
+ """
+
+ @doc """
+ Invalidates the cache for this table/key on this node and all other nodes
+ in the cluster.
+ """
+ @spec invalidate_cache(atom, any) :: :ok
+ def invalidate_cache(table, key_or_keys) do
+ key_or_keys
+ |> List.wrap()
+ |> Enum.each(fn key ->
+ Cachex.del(table, key)
+ end)
+
+ Phoenix.PubSub.broadcast(
+ Teiserver.PubSub,
+ "cache_cluster",
+ {:cache_cluster, :delete, Node.self(), table, key_or_keys}
+ )
+ end
+
+ @spec add_cache(atom, list) :: map()
+ def add_cache(name, opts \\ []) when is_atom(name) do
+ %{
+ id: name,
+ start:
+ {Cachex, :start_link,
+ [
+ name,
+ opts
+ ]}
+ }
+ end
+end
diff --git a/lib/teiserver/system/servers/cache_cluster_server.ex b/lib/teiserver/system/servers/cache_cluster_server.ex
index e3ed50980..acccd9012 100644
--- a/lib/teiserver/system/servers/cache_cluster_server.ex
+++ b/lib/teiserver/system/servers/cache_cluster_server.ex
@@ -10,21 +10,6 @@ defmodule Teiserver.System.CacheClusterServer do
GenServer.start_link(__MODULE__, nil, opts)
end
- @spec invalidate_cache(atom, any) :: :ok
- def invalidate_cache(table, key_or_keys) do
- key_or_keys
- |> List.wrap()
- |> Enum.each(fn key ->
- Cachex.del(table, key)
- end)
-
- Phoenix.PubSub.broadcast(
- Teiserver.PubSub,
- "cache_cluster",
- {:cache_cluster, :delete, Node.self(), table, key_or_keys}
- )
- end
-
@impl true
def handle_info({:cache_cluster, :delete, from_node, table, key_or_keys}, state) do
if from_node != Node.self() do
From ff833f443f80c8037695965a2768174793e88129 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Thu, 27 Jun 2024 00:10:25 +0100
Subject: [PATCH 31/64] Swapped to use utc_datetimes for all timestamps
---
lib/teiserver/account/schemas/user.ex | 2 +-
lib/teiserver/communication/schemas/room.ex | 2 +-
lib/teiserver/game/schemas/match.ex | 2 +-
lib/teiserver/logging/schemas/audit_log.ex | 2 +-
lib/teiserver/migrations/postgres/v01.ex | 14 +++++++-------
lib/teiserver/migrations/postgres/v02.ex | 2 +-
lib/teiserver/settings/libs/server_setting_lib.ex | 1 +
lib/teiserver/settings/schemas/server_setting.ex | 2 +-
lib/teiserver/settings/schemas/user_setting.ex | 2 +-
lib/teiserver/system/schemas/cluster_member.ex | 2 +-
test/support/fixtures/account_fixtures.ex | 12 ++++++------
test/support/fixtures/logging_fixtures.ex | 2 --
12 files changed, 22 insertions(+), 23 deletions(-)
diff --git a/lib/teiserver/account/schemas/user.ex b/lib/teiserver/account/schemas/user.ex
index dcfc48367..a861d28e1 100644
--- a/lib/teiserver/account/schemas/user.ex
+++ b/lib/teiserver/account/schemas/user.ex
@@ -57,7 +57,7 @@ defmodule Teiserver.Account.User do
has_one(:extra_data, Teiserver.Account.ExtraUserData)
- timestamps()
+ timestamps(type: :utc_datetime)
end
@type id :: Ecto.UUID.t()
diff --git a/lib/teiserver/communication/schemas/room.ex b/lib/teiserver/communication/schemas/room.ex
index a4631d7ec..21ca8b8b1 100644
--- a/lib/teiserver/communication/schemas/room.ex
+++ b/lib/teiserver/communication/schemas/room.ex
@@ -13,7 +13,7 @@ defmodule Teiserver.Communication.Room do
schema "communication_rooms" do
field(:name, :string)
- timestamps()
+ timestamps(type: :utc_datetime)
end
@type id :: non_neg_integer()
diff --git a/lib/teiserver/game/schemas/match.ex b/lib/teiserver/game/schemas/match.ex
index 3f9f42878..ca5e2c1a1 100644
--- a/lib/teiserver/game/schemas/match.ex
+++ b/lib/teiserver/game/schemas/match.ex
@@ -63,7 +63,7 @@ defmodule Teiserver.Game.Match do
# has_many :rating_logs, Teiserver.Game.RatingLog
# belongs_to :lobby_policy, Teiserver.Game.LobbyPolicy
- timestamps()
+ timestamps(type: :utc_datetime)
end
@type id :: Ecto.UUID.t()
diff --git a/lib/teiserver/logging/schemas/audit_log.ex b/lib/teiserver/logging/schemas/audit_log.ex
index e463f822b..8dd5b0a7b 100644
--- a/lib/teiserver/logging/schemas/audit_log.ex
+++ b/lib/teiserver/logging/schemas/audit_log.ex
@@ -18,7 +18,7 @@ defmodule Teiserver.Logging.AuditLog do
field(:ip, :string)
belongs_to(:user, Teiserver.Account.User, type: Ecto.UUID)
- timestamps()
+ timestamps(type: :utc_datetime)
end
@type id :: non_neg_integer()
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index 0565b9e16..65712b61b 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -17,7 +17,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:id, :uuid, primary_key: true, null: false)
add(:host, :string, null: false)
- timestamps()
+ timestamps(type: :utc_datetime)
end
# Accounts
@@ -45,7 +45,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:smurf_of_id, references(:account_users, on_delete: :nothing, type: :uuid))
- timestamps()
+ timestamps(type: :utc_datetime)
end
if prefix do
@@ -99,7 +99,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:host_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
add(:type_id, references(:game_match_types, on_delete: :nothing))
- timestamps()
+ timestamps(type: :utc_datetime)
end
create_if_not_exists table(:game_match_memberships, primary_key: false) do
@@ -139,7 +139,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
# Communications
create_if_not_exists table(:communication_rooms, prefix: prefix) do
add(:name, :string)
- timestamps()
+ timestamps(type: :utc_datetime)
end
create_if_not_exists table(:communication_room_messages, prefix: prefix) do
@@ -173,7 +173,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:key, :string, primary_key: true)
add(:value, :string)
- timestamps()
+ timestamps(type: :utc_datetime)
end
create_if_not_exists table(:settings_user_setting_type, prefix: prefix) do
@@ -181,7 +181,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:value, :string)
add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
- timestamps()
+ timestamps(type: :utc_datetime)
end
create_if_not_exists table(:settings_user_settings, prefix: prefix) do
@@ -189,7 +189,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:value, :string)
add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
- timestamps()
+ timestamps(type: :utc_datetime)
end
create_if_not_exists(index(:settings_user_settings, [:user_id], prefix: prefix))
diff --git a/lib/teiserver/migrations/postgres/v02.ex b/lib/teiserver/migrations/postgres/v02.ex
index aa7027296..cc6ae15ce 100644
--- a/lib/teiserver/migrations/postgres/v02.ex
+++ b/lib/teiserver/migrations/postgres/v02.ex
@@ -13,7 +13,7 @@ defmodule Teiserver.Migrations.Postgres.V02 do
add(:ip, :string)
add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
- timestamps()
+ timestamps(type: :utc_datetime)
end
end
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index a79788052..7830011fb 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -133,6 +133,7 @@ defmodule Teiserver.Settings.ServerSettingLib do
value: raw_value
})
+ Teiserver.invalidate_cache(:ts_server_setting_cache, key)
:ok
server_setting ->
diff --git a/lib/teiserver/settings/schemas/server_setting.ex b/lib/teiserver/settings/schemas/server_setting.ex
index b6f032750..38c6b0d66 100644
--- a/lib/teiserver/settings/schemas/server_setting.ex
+++ b/lib/teiserver/settings/schemas/server_setting.ex
@@ -17,7 +17,7 @@ defmodule Teiserver.Settings.ServerSetting do
field(:key, :string, primary_key: true)
field(:value, :string)
- timestamps()
+ timestamps(type: :utc_datetime)
end
@type key :: String.t()
diff --git a/lib/teiserver/settings/schemas/user_setting.ex b/lib/teiserver/settings/schemas/user_setting.ex
index 121df3ca0..9fd375750 100644
--- a/lib/teiserver/settings/schemas/user_setting.ex
+++ b/lib/teiserver/settings/schemas/user_setting.ex
@@ -18,7 +18,7 @@ defmodule Teiserver.Settings.UserSetting do
field(:key, :string)
field(:value, :string)
- timestamps()
+ timestamps(type: :utc_datetime)
end
@type key :: String.t()
diff --git a/lib/teiserver/system/schemas/cluster_member.ex b/lib/teiserver/system/schemas/cluster_member.ex
index 41516c870..dfabdbb5d 100644
--- a/lib/teiserver/system/schemas/cluster_member.ex
+++ b/lib/teiserver/system/schemas/cluster_member.ex
@@ -14,7 +14,7 @@ defmodule Teiserver.System.ClusterMember do
schema "teiserver_cluster_members" do
field(:host, :string)
- timestamps()
+ timestamps(type: :utc_datetime)
end
@type id :: Ecto.UUID.t()
diff --git a/test/support/fixtures/account_fixtures.ex b/test/support/fixtures/account_fixtures.ex
index b193c76e5..1d8cbf307 100644
--- a/test/support/fixtures/account_fixtures.ex
+++ b/test/support/fixtures/account_fixtures.ex
@@ -10,12 +10,12 @@ defmodule Teiserver.Fixtures.AccountFixtures do
User.changeset(
%User{},
%{
- name: data["name"] || "user_name_#{r}",
- email: data["email"] || "user_email_#{r}",
- password: data["password"] || "password",
- groups: data["groups"] || [],
- permissions: data["permissions"] || [],
- restrictions: data["restrictions"] || []
+ name: data[:name] || "user_name_#{r}",
+ email: data[:email] || "user_email_#{r}",
+ password: data[:password] || "password",
+ groups: data[:groups] || [],
+ permissions: data[:permissions] || [],
+ restrictions: data[:restrictions] || []
},
:full
)
diff --git a/test/support/fixtures/logging_fixtures.ex b/test/support/fixtures/logging_fixtures.ex
index 5b1d63bf4..1be442274 100644
--- a/test/support/fixtures/logging_fixtures.ex
+++ b/test/support/fixtures/logging_fixtures.ex
@@ -3,7 +3,6 @@ defmodule Teiserver.Fixtures.LoggingFixtures do
import Teiserver.Fixtures.AccountFixtures, only: [user_fixture: 0]
alias Teiserver.Logging.{AuditLog}
- @spec audit_log_fixture() :: AuditLog.t()
@spec audit_log_fixture(map) :: AuditLog.t()
def audit_log_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
@@ -20,7 +19,6 @@ defmodule Teiserver.Fixtures.LoggingFixtures do
|> Teiserver.Repo.insert!()
end
- @spec anonymous_audit_log_fixture() :: AuditLog.t()
@spec anonymous_audit_log_fixture(map) :: AuditLog.t()
def anonymous_audit_log_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
From 94fe5b6afb39f2bf722fd5678e2f2f6f8ad89ea9 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Thu, 27 Jun 2024 00:13:27 +0100
Subject: [PATCH 32/64] Removed mix.lock
---
.gitignore | 2 ++
mix.lock | 53 -----------------------------------------------------
2 files changed, 2 insertions(+), 53 deletions(-)
delete mode 100644 mix.lock
diff --git a/.gitignore b/.gitignore
index 666215e9e..e913b2836 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,5 +33,7 @@ teiserver-*.tar
.elixir_ls/*
.idea
+mix.lock
+
# Notes I put in for myself I don't want on github
/zignore
diff --git a/mix.lock b/mix.lock
deleted file mode 100644
index e938c647d..000000000
--- a/mix.lock
+++ /dev/null
@@ -1,53 +0,0 @@
-%{
- "argon2_elixir": {:hex, :argon2_elixir, "4.0.0", "7f6cd2e4a93a37f61d58a367d82f830ad9527082ff3c820b8197a8a736648941", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f9da27cf060c9ea61b1bd47837a28d7e48a8f6fa13a745e252556c14f9132c7f"},
- "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
- "cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
- "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
- "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
- "comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
- "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
- "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
- "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
- "delta_crdt": {:hex, :delta_crdt, "0.6.5", "c7bb8c2c7e60f59e46557ab4e0224f67ba22f04c02826e273738f3dcc4767adc", [:mix], [{:merkle_map, "~> 0.2.0", [hex: :merkle_map, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c6ae23a525d30f96494186dd11bf19ed9ae21d9fe2c1f1b217d492a7cc7294ae"},
- "dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"},
- "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
- "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
- "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"},
- "elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
- "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
- "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
- "ex_doc": {:hex, :ex_doc, "0.34.1", "9751a0419bc15bc7580c73fde506b17b07f6402a1e5243be9e0f05a68c723368", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d441f1a86a235f59088978eff870de2e815e290e44a8bd976fe5d64470a4c9d2"},
- "excoveralls": {:hex, :excoveralls, "0.18.1", "a6f547570c6b24ec13f122a5634833a063aec49218f6fff27de9df693a15588c", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d65f79db146bb20399f23046015974de0079668b9abb2f5aac074d078da60b8d"},
- "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
- "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
- "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
- "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
- "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
- "horde": {:hex, :horde, "0.9.0", "522342bd7149aeed453c97692a8bca9cf7c9368c5a489afd802e575dc8df54a6", [:mix], [{:delta_crdt, "~> 0.6.2", [hex: :delta_crdt, repo: "hexpm", optional: false]}, {:libring, "~> 1.4", [hex: :libring, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 0.5.0 or ~> 1.0", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "fae11e5bc9c980038607d0c3338cdf7f97124a5d5382fd4b6fb6beaab8e214fe"},
- "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
- "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
- "jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
- "libring": {:hex, :libring, "1.6.0", "d5dca4bcb1765f862ab59f175b403e356dec493f565670e0bacc4b35e109ce0d", [:mix], [], "hexpm", "5e91ece396af4bce99953d49ee0b02f698cd38326d93cd068361038167484319"},
- "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
- "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
- "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
- "merkle_map": {:hex, :merkle_map, "0.2.1", "01a88c87a6b9fb594c67c17ebaf047ee55ffa34e74297aa583ed87148006c4c8", [:mix], [], "hexpm", "fed4d143a5c8166eee4fa2b49564f3c4eace9cb252f0a82c1613bba905b2d04d"},
- "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
- "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
- "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
- "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
- "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
- "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"},
- "sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"},
- "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
- "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
- "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
- "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
- "timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
- "typed_ecto_schema": {:hex, :typed_ecto_schema, "0.4.1", "a373ca6f693f4de84cde474a67467a9cb9051a8a7f3f615f1e23dc74b75237fa", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "85c6962f79d35bf543dd5659c6adc340fd2480cacc6f25d2cc2933ea6e8fcb3b"},
- "typedstruct": {:hex, :typedstruct, "0.5.3", "d68ae424251a41b81a8d0c485328ab48edbd3858f3565bbdac21b43c056fc9b4", [:make, :mix], [], "hexpm", "b53b8186701417c0b2782bf02a2db5524f879b8488f91d1d83b97d84c2943432"},
- "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
- "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
- "unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
- "uuid": {:hex, :uuid, "1.1.8", "e22fc04499de0de3ed1116b770c7737779f226ceefa0badb3592e64d5cfb4eb9", [:mix], [], "hexpm", "c790593b4c3b601f5dc2378baae7efaf5b3d73c4c6456ba85759905be792f2ac"},
-}
From fb3e946989e35ef2f39e0f71ff703436a8ab7aef Mon Sep 17 00:00:00 2001
From: Teifion
Date: Thu, 27 Jun 2024 00:15:41 +0100
Subject: [PATCH 33/64] Tweaked Elixir version for github
---
.github/workflows/elixir.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml
index 20defdd02..ff6b8f4a9 100644
--- a/.github/workflows/elixir.yml
+++ b/.github/workflows/elixir.yml
@@ -16,8 +16,8 @@ on:
# Sets the ENV `MIX_ENV` to `test` for running tests
env:
MIX_ENV: test
- ELIXIR_VER: '1.16.2'
- OTP_VER: '25.0.4'
+ ELIXIR_VER: '1.17.1'
+ OTP_VER: '27.0'
permissions:
contents: read
From bf0d48fe06b5dfd1c41dd434f9f65a08646b0c27 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Thu, 27 Jun 2024 00:19:08 +0100
Subject: [PATCH 34/64] Fixed failing tests from fixture change
---
test/account/user_lib_test.exs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/test/account/user_lib_test.exs b/test/account/user_lib_test.exs
index d7a773eb2..98c3795a1 100644
--- a/test/account/user_lib_test.exs
+++ b/test/account/user_lib_test.exs
@@ -101,14 +101,14 @@ defmodule Teiserver.UserLibTest do
end
test "valid_password?/2" do
- user = AccountFixtures.user_fixture(%{"password" => "password"})
+ user = AccountFixtures.user_fixture(%{password: "password"})
assert Account.valid_password?(user, "password")
refute Account.valid_password?(user, "bad_password")
end
test "allow?/2" do
# User must have all of the required permissions
- user = AccountFixtures.user_fixture(%{"groups" => ["perm1", "perm2"]})
+ user = AccountFixtures.user_fixture(%{groups: ["perm1", "perm2"]})
assert Account.allow?(user, "perm1")
assert Account.allow?(user.id, "perm1")
assert Account.allow?(user.id, ["perm1"])
@@ -129,7 +129,7 @@ defmodule Teiserver.UserLibTest do
test "refute?/2" do
# Possessing any of the restrictions results in a true value
- user = AccountFixtures.user_fixture(%{"restrictions" => ["restrict1", "restrict2"]})
+ user = AccountFixtures.user_fixture(%{restrictions: ["restrict1", "restrict2"]})
assert Account.restricted?(user, "restrict1")
assert Account.restricted?(user.id, "restrict1")
assert Account.restricted?(user.id, ["restrict1"])
From 81e2a20da50cdfb647656a1be9348c9d23d6e136 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sat, 29 Jun 2024 12:44:44 +0100
Subject: [PATCH 35/64] Added some match query options
---
lib/teiserver/game/libs/match_type_lib.ex | 2 +-
lib/teiserver/game/queries/match_queries.ex | 86 ++++++++++++++-------
lib/teiserver/game/schemas/match.ex | 2 +-
3 files changed, 60 insertions(+), 30 deletions(-)
diff --git a/lib/teiserver/game/libs/match_type_lib.ex b/lib/teiserver/game/libs/match_type_lib.ex
index 89cdfdb0a..11d671f76 100644
--- a/lib/teiserver/game/libs/match_type_lib.ex
+++ b/lib/teiserver/game/libs/match_type_lib.ex
@@ -27,7 +27,7 @@ defmodule Teiserver.Game.MatchTypeLib do
Can be over-ridden using the config [fn_calculate_match_type](config.html#fn_calculate_match_type)
"""
@spec default_calculate_match_type(Lobby.t()) :: String.t()
- def default_calculate_match_type(lobby) do
+ def default_calculate_match_type(%Lobby{} = lobby) do
if Enum.count(lobby.members) == 2 do
"Duel"
else
diff --git a/lib/teiserver/game/queries/match_queries.ex b/lib/teiserver/game/queries/match_queries.ex
index 42bc5b0a5..517b828f6 100644
--- a/lib/teiserver/game/queries/match_queries.ex
+++ b/lib/teiserver/game/queries/match_queries.ex
@@ -32,21 +32,51 @@ defmodule Teiserver.Game.MatchQueries do
def _where(query, _, ""), do: query
def _where(query, _, nil), do: query
- def _where(query, :id, id_list) when is_list(id_list) do
+ def _where(query, :id, id_list) do
from(matches in query,
- where: matches.id in ^id_list
+ where: matches.id in ^List.wrap(id_list)
)
end
- def _where(query, :id, id) do
+ def _where(query, :name, name) do
from(matches in query,
- where: matches.id == ^id
+ where: matches.name == ^name
)
end
- def _where(query, :name, name) do
+ def _where(query, :duration_gt, seconds) do
from(matches in query,
- where: matches.name == ^name
+ where: matches.match_duration_seconds > ^seconds
+ )
+ end
+
+ def _where(query, :duration_lt, seconds) do
+ from(matches in query,
+ where: matches.match_duration_seconds < ^seconds
+ )
+ end
+
+ def _where(query, :started_after, timestamp) do
+ from(matches in query,
+ where: matches.match_started_at >= ^timestamp
+ )
+ end
+
+ def _where(query, :started_before, timestamp) do
+ from(matches in query,
+ where: matches.match_started_at < ^timestamp
+ )
+ end
+
+ def _where(query, :ended_after, timestamp) do
+ from(matches in query,
+ where: matches.match_ended_at >= ^timestamp
+ )
+ end
+
+ def _where(query, :ended_before, timestamp) do
+ from(matches in query,
+ where: matches.match_ended_at < ^timestamp
)
end
@@ -101,26 +131,26 @@ defmodule Teiserver.Game.MatchQueries do
@spec do_preload(Ecto.Query.t(), List.t() | nil) :: Ecto.Query.t()
defp do_preload(query, nil), do: query
- defp do_preload(query, _), do: query
- # defp do_preload(query, preloads) do
- # preloads
- # |> List.wrap
- # |> Enum.reduce(query, fn key, query_acc ->
- # _preload(query_acc, key)
- # end)
- # end
-
- # @spec _preload(Ecto.Query.t(), any) :: Ecto.Query.t()
- # def _preload(query, :relation) do
- # from match in query,
- # left_join: relations in assoc(match, :relation),
- # preload: [relation: relations]
- # end
-
- # def _preload(query, {:relation, join_query}) do
- # from match in query,
- # left_join: relations in subquery(join_query),
- # on: relations.id == query.relation_id,
- # preload: [relation: relations]
- # end
+ defp do_preload(query, preloads) do
+ preloads
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _preload(query_acc, key)
+ end)
+ end
+
+ @spec _preload(Ecto.Query.t(), any) :: Ecto.Query.t()
+ def _preload(query, :members) do
+ from(match in query,
+ left_join: members in assoc(match, :members),
+ preload: [members: members]
+ )
+ end
+
+ def _preload(query, :settings) do
+ from(match in query,
+ left_join: settings in assoc(match, :settings),
+ preload: [settings: settings]
+ )
+ end
end
diff --git a/lib/teiserver/game/schemas/match.ex b/lib/teiserver/game/schemas/match.ex
index ca5e2c1a1..8d83ebff3 100644
--- a/lib/teiserver/game/schemas/match.ex
+++ b/lib/teiserver/game/schemas/match.ex
@@ -55,7 +55,7 @@ defmodule Teiserver.Game.Match do
belongs_to(:host, Teiserver.Account.User, type: Ecto.UUID)
belongs_to(:type, Teiserver.Game.MatchType)
has_many(:members, Teiserver.Game.MatchMembership)
- has_many(:match_settings, Teiserver.Game.MatchSetting)
+ has_many(:settings, Teiserver.Game.MatchSetting)
# Relationships we expect to add
# belongs_to :queue, Teiserver.Game.MatchmakingQueue
From 5b51d3999facdb857d29524e7e0c6708c60ebf4e Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sat, 29 Jun 2024 21:42:02 +0100
Subject: [PATCH 36/64] Added messaging around match start/end
---
CHANGELOG.md | 1 +
documentation/pubsubs/match.md | 22 ++++++++++++++++++++++
lib/teiserver/api.ex | 4 ++--
lib/teiserver/game/servers/lobby_server.ex | 21 +++++++++++++++++++++
4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index baf481ca2..3c216f89c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
- Swapped to Elixir 1.17
- Swapped `team_colour` for `player_colour`
- Refactored the client update process
+- Added messaging around match start/end
- Added User and Server runtime settings
- Added Telemetry events
- Added rate limiting of login attempts
diff --git a/documentation/pubsubs/match.md b/documentation/pubsubs/match.md
index e81b56c10..a38b2f0da 100644
--- a/documentation/pubsubs/match.md
+++ b/documentation/pubsubs/match.md
@@ -87,6 +87,28 @@ Note this will be sent in addition to normal client updated messages but by doin
}
```
+### Match start - `:match_start`
+Indicates the match is starting. This will typically follow the `:lobby_updated` message where `match_ongoing?` is set to true.
+
+```elixir
+%{
+ event: :match_start,
+ match_id: Match.id(),
+ lobby_id: Lobby.id()
+}
+```
+
+### Match end - `:match_end`
+Indicates the match has ended. This will typically follow the `:lobby_updated` message where `match_ongoing?` is set to false.
+
+```elixir
+%{
+ event: :match_end,
+ match_id: Match.id(),
+ lobby_id: Lobby.id()
+}
+```
+
### Closed - `:lobby_closed`
- `:lobby_id` - The id of the lobby closed
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
index 68998ea6c..c865742fa 100644
--- a/lib/teiserver/api.ex
+++ b/lib/teiserver/api.ex
@@ -281,8 +281,8 @@ defmodule Teiserver.Api do
# Match
@doc section: :match
- @spec start_match(Lobby.t()) :: Match.t()
- defdelegate start_match(lobby), to: MatchLib
+ @spec start_match(Teiserver.lobby_id()) :: Match.t()
+ defdelegate start_match(lobby_id), to: MatchLib
@doc section: :match
@spec end_match(Match.id(), map()) :: Match.t()
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index a42d2ffca..45dd0156d 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -97,6 +97,18 @@ defmodule Teiserver.Game.LobbyServer do
%{match_id: match_id, lobby_id: state.lobby_id}
)
+ # We specifically reference the original state here
+ if state.match_id != nil and state.match_ongoing? do
+ Teiserver.broadcast(
+ state.lobby_topic,
+ %{
+ event: :match_end,
+ match_id: state.match_id,
+ lobby_id: state.lobby_id
+ }
+ )
+ end
+
{:noreply, %{new_state | match_id: match_id}}
end
@@ -106,6 +118,15 @@ defmodule Teiserver.Game.LobbyServer do
match_ongoing?: true
})
+ Teiserver.broadcast(
+ state.lobby_topic,
+ %{
+ event: :match_start,
+ match_id: state.match_id,
+ lobby_id: state.lobby_id
+ }
+ )
+
:telemetry.execute(
[:teiserver, :lobby, :start_match],
%{},
From ddb7c944040744b546637a70788a094b62ca988e Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sat, 29 Jun 2024 21:45:41 +0100
Subject: [PATCH 37/64] Fixed test
---
lib/teiserver/game/servers/lobby_server.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index 45dd0156d..7d6d3ff46 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -98,7 +98,7 @@ defmodule Teiserver.Game.LobbyServer do
)
# We specifically reference the original state here
- if state.match_id != nil and state.match_ongoing? do
+ if state.match_id != nil and state.lobby.match_ongoing? do
Teiserver.broadcast(
state.lobby_topic,
%{
From f3ab0fdb06c47fe65e4ea3411bebd77e60e34d82 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 10 Jul 2024 00:13:23 +0100
Subject: [PATCH 38/64] Caching improvements
---
CHANGELOG.md | 1 +
lib/teiserver/application.ex | 3 ++-
lib/teiserver/caches/server_settings_cache.ex | 4 ++--
lib/teiserver/caches/type_lookup_cache.ex | 22 +++++++++++++++++++
lib/teiserver/caches/user_settings_cache.ex | 4 ++--
lib/teiserver/contexts/game.ex | 4 ++--
lib/teiserver/game/libs/match_lib.ex | 2 +-
.../game/libs/match_setting_type_lib.ex | 22 +++++++++++++++----
lib/teiserver/game/libs/match_type_lib.ex | 13 +++++++++++
.../game/libs/match_setting_type_lib_test.exs | 4 ++--
10 files changed, 65 insertions(+), 14 deletions(-)
create mode 100644 lib/teiserver/caches/type_lookup_cache.ex
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3c216f89c..c7fdb23c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@
- Added rate limiting of login attempts
- Added more options for connecting clients (currently just `bot?`)
- Added support for Angen to provide guest accounts
+- Added caching for some db calls
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index f82f7dc3e..b63a05946 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -40,7 +40,8 @@ defmodule Teiserver.Application do
# Caches
Teiserver.Caches.UserSettingCache,
Teiserver.Caches.ServerSettingCache,
- Teiserver.Caches.LoginCountCache
+ Teiserver.Caches.LoginCountCache,
+ Teiserver.Caches.TypeLookupCache,
]
opts = [strategy: :one_for_one, name: __MODULE__]
diff --git a/lib/teiserver/caches/server_settings_cache.ex b/lib/teiserver/caches/server_settings_cache.ex
index f346a3885..a0a9292f7 100644
--- a/lib/teiserver/caches/server_settings_cache.ex
+++ b/lib/teiserver/caches/server_settings_cache.ex
@@ -4,7 +4,7 @@ defmodule Teiserver.Caches.ServerSettingCache do
"""
use Supervisor
- import Teiserver.Helpers.CacheHelper, only: [add_cache: 1, add_cache: 2]
+ import Teiserver.Helpers.CacheHelper, only: [add_cache: 2]
def start_link(opts) do
Supervisor.start_link(__MODULE__, :ok, opts)
@@ -13,7 +13,7 @@ defmodule Teiserver.Caches.ServerSettingCache do
@impl true
def init(:ok) do
children = [
- add_cache(:ts_server_setting_type_store),
+ add_cache(:ts_server_setting_type_store, ttl: :timer.minutes(5)),
add_cache(:ts_server_setting_cache, ttl: :timer.minutes(1))
]
diff --git a/lib/teiserver/caches/type_lookup_cache.ex b/lib/teiserver/caches/type_lookup_cache.ex
new file mode 100644
index 000000000..fcbfd64ad
--- /dev/null
+++ b/lib/teiserver/caches/type_lookup_cache.ex
@@ -0,0 +1,22 @@
+defmodule Teiserver.Caches.TypeLookupCache do
+ @moduledoc """
+ Cache for tracking type_ids of various fields to prevent repeated DB lookups
+ """
+
+ use Supervisor
+ import Teiserver.Helpers.CacheHelper, only: [add_cache: 2]
+
+ def start_link(opts) do
+ Supervisor.start_link(__MODULE__, :ok, opts)
+ end
+
+ @impl true
+ def init(:ok) do
+ children = [
+ add_cache(:ts_match_type_lookup, ttl: :timer.minutes(5)),
+ add_cache(:ts_match_setting_type_lookup, ttl: :timer.minutes(5)),
+ ]
+
+ Supervisor.init(children, strategy: :one_for_all)
+ end
+end
diff --git a/lib/teiserver/caches/user_settings_cache.ex b/lib/teiserver/caches/user_settings_cache.ex
index a491f566f..c4887da73 100644
--- a/lib/teiserver/caches/user_settings_cache.ex
+++ b/lib/teiserver/caches/user_settings_cache.ex
@@ -4,7 +4,7 @@ defmodule Teiserver.Caches.UserSettingCache do
"""
use Supervisor
- import Teiserver.Helpers.CacheHelper, only: [add_cache: 1, add_cache: 2]
+ import Teiserver.Helpers.CacheHelper, only: [add_cache: 2]
def start_link(opts) do
Supervisor.start_link(__MODULE__, :ok, opts)
@@ -13,7 +13,7 @@ defmodule Teiserver.Caches.UserSettingCache do
@impl true
def init(:ok) do
children = [
- add_cache(:ts_user_setting_type_store),
+ add_cache(:ts_user_setting_type_store, ttl: :timer.minutes(5)),
add_cache(:ts_user_setting_cache, ttl: :timer.minutes(1)),
add_cache(:ts_user_by_user_id_cache, ttl: :timer.minutes(5))
]
diff --git a/lib/teiserver/contexts/game.ex b/lib/teiserver/contexts/game.ex
index b0031e51b..0bc6f73c4 100644
--- a/lib/teiserver/contexts/game.ex
+++ b/lib/teiserver/contexts/game.ex
@@ -292,8 +292,8 @@ defmodule Teiserver.Game do
defdelegate create_match_setting_type(attrs), to: MatchSettingTypeLib
@doc section: :match_setting_type
- @spec get_or_create_match_setting_type(String.t()) :: MatchSettingType.id()
- defdelegate get_or_create_match_setting_type(name), to: MatchSettingTypeLib
+ @spec get_or_create_match_setting_type_id(String.t()) :: MatchSettingType.id()
+ defdelegate get_or_create_match_setting_type_id(name), to: MatchSettingTypeLib
@doc section: :match_setting_type
@spec update_match_setting_type(MatchSettingType, map) ::
diff --git a/lib/teiserver/game/libs/match_lib.ex b/lib/teiserver/game/libs/match_lib.ex
index eb0bc8ccb..1da794f76 100644
--- a/lib/teiserver/game/libs/match_lib.ex
+++ b/lib/teiserver/game/libs/match_lib.ex
@@ -66,7 +66,7 @@ defmodule Teiserver.Game.MatchLib do
{:ok, _settings} =
lobby.game_settings
|> Enum.map(fn {key, value} ->
- type_id = Game.get_or_create_match_setting_type(key)
+ type_id = Game.get_or_create_match_setting_type_id(key)
%{type_id: type_id, match_id: match.id, value: value}
end)
|> Game.create_many_match_settings()
diff --git a/lib/teiserver/game/libs/match_setting_type_lib.ex b/lib/teiserver/game/libs/match_setting_type_lib.ex
index a9544e68d..fcb055c71 100644
--- a/lib/teiserver/game/libs/match_setting_type_lib.ex
+++ b/lib/teiserver/game/libs/match_setting_type_lib.ex
@@ -93,15 +93,29 @@ defmodule Teiserver.Game.MatchSettingTypeLib do
## Examples
- iex> get_or_create_match_setting_type("existing")
+ iex> get_or_create_match_setting_type_id("existing")
123
- iex> get_or_create_match_setting_type("non-existing")
+ iex> get_or_create_match_setting_type_id("non-existing")
1234
"""
- @spec get_or_create_match_setting_type(String.t()) :: MatchSettingType.id()
- def get_or_create_match_setting_type(name) do
+ @spec get_or_create_match_setting_type_id(String.t()) :: MatchSettingType.id()
+ def get_or_create_match_setting_type_id(name) do
+ case Cachex.get(:ts_match_setting_type_lookup, name) do
+ {:ok, nil} ->
+ result = do_get_or_create_match_setting_type_id(name)
+ Cachex.put(:ts_match_setting_type_lookup, name, result)
+ result
+
+ {:ok, value} ->
+ value
+ end
+
+ end
+
+ @spec do_get_or_create_match_setting_type_id(String.t()) :: MatchSettingType.id()
+ def do_get_or_create_match_setting_type_id(name) do
name = String.trim(name)
query =
diff --git a/lib/teiserver/game/libs/match_type_lib.ex b/lib/teiserver/game/libs/match_type_lib.ex
index 11d671f76..be2506acb 100644
--- a/lib/teiserver/game/libs/match_type_lib.ex
+++ b/lib/teiserver/game/libs/match_type_lib.ex
@@ -158,6 +158,19 @@ defmodule Teiserver.Game.MatchTypeLib do
"""
@spec get_or_create_match_type(String.t()) :: MatchType.t()
def get_or_create_match_type(match_type_name) do
+ case Cachex.get(:ts_match_type_lookup, match_type_name) do
+ {:ok, nil} ->
+ result = do_get_or_create_match_type(match_type_name)
+ Cachex.put(:ts_match_type_lookup, match_type_name, result)
+ result
+
+ {:ok, value} ->
+ value
+ end
+ end
+
+ @spec do_get_or_create_match_type(String.t()) :: MatchType.t()
+ defp do_get_or_create_match_type(match_type_name) do
case get_match_type_by_name_or_id(match_type_name) do
nil ->
{:ok, match_type} = create_match_type(%{name: match_type_name})
diff --git a/test/game/libs/match_setting_type_lib_test.exs b/test/game/libs/match_setting_type_lib_test.exs
index 073eec3bb..855d0f6c9 100644
--- a/test/game/libs/match_setting_type_lib_test.exs
+++ b/test/game/libs/match_setting_type_lib_test.exs
@@ -41,12 +41,12 @@ defmodule Teiserver.MatchSettingTypeLibTest do
assert Game.list_match_setting_types([]) != []
end
- test "get_or_create_match_setting_type/1 returns an id" do
+ test "get_or_create_match_setting_type_id/1 returns an id" do
# No match_setting_type yet
assert Game.list_match_setting_types([]) == []
# Add a match_setting_type
- type_id = Game.get_or_create_match_setting_type("test-name")
+ type_id = Game.get_or_create_match_setting_type_id("test-name")
assert is_integer(type_id)
[the_type] = Game.list_match_setting_types([])
From a1567ab2b07c853b1e436795ee411f667d486bbd Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 10 Jul 2024 23:54:19 +0100
Subject: [PATCH 39/64] Server settings use text and added player_count to
matches
---
CHANGELOG.md | 2 +
lib/teiserver/game/libs/match_lib.ex | 1 +
lib/teiserver/game/schemas/match.ex | 6 ++-
.../game/schemas/match_membership.ex | 2 +-
lib/teiserver/migrations/postgres/v01.ex | 12 +----
.../settings/libs/server_setting_lib.ex | 50 ++++++++++++-------
.../settings/libs/server_setting_type_lib.ex | 7 ++-
.../settings/schemas/server_setting_type.ex | 2 +
8 files changed, 48 insertions(+), 34 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7fdb23c3..a6e2513df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@
- Added more options for connecting clients (currently just `bot?`)
- Added support for Angen to provide guest accounts
- Added caching for some db calls
+- Changed server settings to use `text` type behind the scenes and added ability to validate themz
+- Added `player_count` as a property to matches
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/lib/teiserver/game/libs/match_lib.ex b/lib/teiserver/game/libs/match_lib.ex
index 1da794f76..898234246 100644
--- a/lib/teiserver/game/libs/match_lib.ex
+++ b/lib/teiserver/game/libs/match_lib.ex
@@ -46,6 +46,7 @@ defmodule Teiserver.Game.MatchLib do
team_count: team_count,
team_size: team_size,
match_started_at: Timex.now(),
+ player_count: Enum.count(clients),
type_id: type_id
})
diff --git a/lib/teiserver/game/schemas/match.ex b/lib/teiserver/game/schemas/match.ex
index 8d83ebff3..a4741b0ff 100644
--- a/lib/teiserver/game/schemas/match.ex
+++ b/lib/teiserver/game/schemas/match.ex
@@ -47,8 +47,9 @@ defmodule Teiserver.Game.Match do
field(:match_started_at, :utc_datetime)
field(:match_ended_at, :utc_datetime)
- # This will be something queried enough it's worth storing as it's own value
+ # These will be something queried enough it's worth storing as it's own value
field(:match_duration_seconds, :integer)
+ field(:player_count, :integer)
# Memberships
field(:lobby_id, Ecto.UUID)
@@ -91,6 +92,7 @@ defmodule Teiserver.Game.Match do
# This will be something queried enough it's worth storing as it's own value
match_duration_seconds: non_neg_integer(),
+ player_count: non_neg_integer(),
host_id: Teiserver.user_id(),
lobby_id: Teiserver.lobby_id(),
host: Teiserver.Account.User.t(),
@@ -108,7 +110,7 @@ defmodule Teiserver.Game.Match do
struct
|> cast(
attrs,
- ~w(name tags public? rated? game_name game_version winning_team team_count team_size processed? lobby_opened_at match_started_at match_ended_at ended_normally? match_duration_seconds host_id type_id lobby_id)a
+ ~w(name tags public? rated? game_name game_version winning_team team_count team_size processed? lobby_opened_at match_started_at match_ended_at ended_normally? match_duration_seconds player_count host_id type_id lobby_id)a
)
|> validate_required(~w(public? rated? host_id)a)
end
diff --git a/lib/teiserver/game/schemas/match_membership.ex b/lib/teiserver/game/schemas/match_membership.ex
index e36e352a9..b6f38a064 100644
--- a/lib/teiserver/game/schemas/match_membership.ex
+++ b/lib/teiserver/game/schemas/match_membership.ex
@@ -22,7 +22,7 @@ defmodule Teiserver.Game.MatchMembership do
field(:team_number, :integer, default: nil)
field(:win?, :boolean, default: nil)
- field(:party_id, :string, default: nil)
+ field(:party_id, Ecto.UUID, default: nil)
field(:left_after_seconds, :integer, default: nil)
end
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index 65712b61b..c13c8939f 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -95,6 +95,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:match_ended_at, :utc_datetime)
add(:match_duration_seconds, :integer)
+ add(:player_count, :integer)
add(:host_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
add(:type_id, references(:game_match_types, on_delete: :nothing))
@@ -171,15 +172,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
# Settings
create_if_not_exists table(:settings_server_settings, primary_key: false, prefix: prefix) do
add(:key, :string, primary_key: true)
- add(:value, :string)
-
- timestamps(type: :utc_datetime)
- end
-
- create_if_not_exists table(:settings_user_setting_type, prefix: prefix) do
- add(:key, :string)
- add(:value, :string)
- add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
+ add(:value, :text)
timestamps(type: :utc_datetime)
end
@@ -212,7 +205,6 @@ defmodule Teiserver.Migrations.Postgres.V01 do
# Config
drop_if_exists(table(:settings_server_settings, prefix: prefix))
- drop_if_exists(table(:settings_user_setting_type, prefix: prefix))
drop_if_exists(table(:settings_user_settings, prefix: prefix))
# Accounts
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index 7830011fb..f237c3865 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -3,7 +3,7 @@ defmodule Teiserver.Settings.ServerSettingLib do
A library of functions for working with `Teiserver.Settings.ServerSetting`
"""
use TeiserverMacros, :library
- alias Teiserver.Settings.{ServerSetting, ServerSettingQueries, ServerSettingTypeLib}
+ alias Teiserver.Settings.{ServerSetting, ServerSettingQueries, ServerSettingTypeLib, ServerSettingType}
@doc """
Returns the list of server_settings.
@@ -35,7 +35,6 @@ defmodule Teiserver.Settings.ServerSettingLib do
** (Ecto.NoResultsError)
"""
- @spec get_server_setting!(ServerSetting.key()) :: ServerSetting.t()
@spec get_server_setting!(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t()
def get_server_setting!(key, query_args \\ []) do
(query_args ++ [key: key])
@@ -57,7 +56,6 @@ defmodule Teiserver.Settings.ServerSettingLib do
nil
"""
- @spec get_server_setting(ServerSetting.key()) :: ServerSetting.t() | nil
@spec get_server_setting(ServerSetting.key(), Teiserver.query_args()) :: ServerSetting.t() | nil
def get_server_setting(key, query_args \\ []) do
(query_args ++ [key: key])
@@ -120,29 +118,43 @@ defmodule Teiserver.Settings.ServerSettingLib do
defp convert_from_raw_value(_, _), do: nil
@spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) ::
- :ok
+ :ok | {:error, String.t()}
def set_server_setting_value(key, value) do
type = ServerSettingTypeLib.get_server_setting_type(key)
raw_value = convert_to_raw_value(value, type.type)
- case get_server_setting(key) do
- nil ->
- {:ok, _} =
- create_server_setting(%{
- key: key,
- value: raw_value
- })
-
- Teiserver.invalidate_cache(:ts_server_setting_cache, key)
- :ok
-
- server_setting ->
- {:ok, _} = update_server_setting(server_setting, %{"value" => raw_value})
- Teiserver.invalidate_cache(:ts_server_setting_cache, key)
- :ok
+ case value_is_valid?(type, value) do
+ :ok ->
+ case get_server_setting(key) do
+ nil ->
+ {:ok, _} =
+ create_server_setting(%{
+ key: key,
+ value: raw_value
+ })
+
+ Teiserver.invalidate_cache(:ts_server_setting_cache, key)
+ :ok
+
+ server_setting ->
+ {:ok, _} = update_server_setting(server_setting, %{"value" => raw_value})
+ Teiserver.invalidate_cache(:ts_server_setting_cache, key)
+ :ok
+ end
+ {:error, reason} ->
+ {:error, reason}
end
end
+ @doc """
+
+ """
+ @spec value_is_valid?(ServerSettingType.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok | {:error, String.t()}
+ def value_is_valid?(%{validation: nil}, _), do: :ok
+ def value_is_valid?(%{validation: validator_function}, value) do
+ validator_function.(value)
+ end
+
@spec convert_to_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
defp convert_to_raw_value(value, "string"), do: value
defp convert_to_raw_value(value, "integer"), do: to_string(value)
diff --git a/lib/teiserver/settings/libs/server_setting_type_lib.ex b/lib/teiserver/settings/libs/server_setting_type_lib.ex
index 56de35d05..02f6294ad 100644
--- a/lib/teiserver/settings/libs/server_setting_type_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_type_lib.ex
@@ -37,6 +37,7 @@ defmodule Teiserver.Settings.ServerSettingTypeLib do
* `:choices` - A list of acceptable choices for `string` based types
* `:default` - The default value for a setting if one is not set, defaults to `nil`
* `:description` - A longer description which can be used to provide more information to users
+ * `:validator` - A function taking a single value and returning `:ok | {:error, String.t()}` of if the value given is acceptable for the setting type
## Examples
```
@@ -47,7 +48,8 @@ defmodule Teiserver.Settings.ServerSettingTypeLib do
type: "integer",
permissions: "Admin",
default: 3,
- description: "The upper bound on how many failed attempts a given IP can perform before all further attempts will be blocked"
+ description: "The upper bound on how many failed attempts a given IP can perform before all further attempts will be blocked",
+ validator: (fn v -> if String.length(v) > 6, do: :ok, else: {:error, "Must be at least 6 characters long"} end)
})
```
"""
@@ -71,7 +73,8 @@ defmodule Teiserver.Settings.ServerSettingTypeLib do
permissions: Map.get(args, :permissions),
choices: Map.get(args, :choices),
default: Map.get(args, :default),
- description: Map.get(args, :description)
+ description: Map.get(args, :description),
+ validator: Map.get(args, :validator)
}
# Update our list of all keys
diff --git a/lib/teiserver/settings/schemas/server_setting_type.ex b/lib/teiserver/settings/schemas/server_setting_type.ex
index 5fcc84486..bff45d951 100644
--- a/lib/teiserver/settings/schemas/server_setting_type.ex
+++ b/lib/teiserver/settings/schemas/server_setting_type.ex
@@ -15,6 +15,7 @@ defmodule Teiserver.Settings.ServerSettingType do
* `:choices` - A list of acceptable choices for `string` based types
* `:default` - The default value for a setting if one is not set, defaults to `nil`
* `:description` - A longer description which can be used to provide more information to users
+ * `:validator` - A function taking a single value and returning a `:ok | {:error, String.t()}` of if the value given is acceptable for the setting type
"""
use TypedStruct
@@ -32,5 +33,6 @@ defmodule Teiserver.Settings.ServerSettingType do
field(:choices, [String.t()] | nil, default: nil)
field(:default, String.t() | integer() | boolean | nil, default: nil)
field(:description, String.t() | nil, default: nil)
+ field(:validator, function() | nil, default: nil)
end
end
From 8768b786c36f3e0690f035700d7e0792a1e7d385 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Fri, 12 Jul 2024 00:35:52 +0100
Subject: [PATCH 40/64] Added some query options
---
lib/teiserver/game/queries/match_queries.ex | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lib/teiserver/game/queries/match_queries.ex b/lib/teiserver/game/queries/match_queries.ex
index 517b828f6..19c03ce5f 100644
--- a/lib/teiserver/game/queries/match_queries.ex
+++ b/lib/teiserver/game/queries/match_queries.ex
@@ -44,6 +44,18 @@ defmodule Teiserver.Game.MatchQueries do
)
end
+ def _where(query, :ended_normally?, ended_normally?) do
+ from(matches in query,
+ where: matches.ended_normally? == ^ended_normally?
+ )
+ end
+
+ def _where(query, :processed?, processed?) do
+ from(matches in query,
+ where: matches.processed? == ^processed?
+ )
+ end
+
def _where(query, :duration_gt, seconds) do
from(matches in query,
where: matches.match_duration_seconds > ^seconds
From 6c7665f6d51b759760c5b28308171a1a0b9e1666 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Fri, 12 Jul 2024 23:28:36 +0100
Subject: [PATCH 41/64] Added indexes
---
lib/teiserver/migrations/postgres/v01.ex | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index c13c8939f..705fe3875 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -67,6 +67,8 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:data, :jsonb)
end
+ create_if_not_exists(unique_index(:account_extra_user_data, [:user_id], prefix: prefix))
+
# Game
create_if_not_exists table(:game_match_types, prefix: prefix) do
add(:name, :string)
@@ -103,6 +105,8 @@ defmodule Teiserver.Migrations.Postgres.V01 do
timestamps(type: :utc_datetime)
end
+ create_if_not_exists(index(:game_matches, [:match_started_at], prefix: prefix))
+
create_if_not_exists table(:game_match_memberships, primary_key: false) do
add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid),
primary_key: true,
@@ -122,6 +126,8 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:party_id, :string)
end
+ create_if_not_exists(index(:game_match_memberships, [:match_id], prefix: prefix))
+
create_if_not_exists table(:game_match_setting_types) do
add(:name, :string)
end
@@ -137,6 +143,8 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:value, :string)
end
+ create_if_not_exists(index(:game_match_settings, [:match_id], prefix: prefix))
+
# Communications
create_if_not_exists table(:communication_rooms, prefix: prefix) do
add(:name, :string)
@@ -151,6 +159,9 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:room_id, references(:communication_rooms, on_delete: :nothing))
end
+ create_if_not_exists(index(:communication_room_messages, [:sender_id], prefix: prefix))
+ create_if_not_exists(index(:communication_room_messages, [:room_id], prefix: prefix))
+
create_if_not_exists table(:communication_direct_messages, prefix: prefix) do
add(:content, :text)
add(:inserted_at, :utc_datetime)
@@ -161,6 +172,9 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:to_id, references(:account_users, on_delete: :nothing, type: :uuid), type: :uuid)
end
+ create_if_not_exists(index(:communication_direct_messages, [:sender_id], prefix: prefix))
+ create_if_not_exists(index(:communication_direct_messages, [:to_id], prefix: prefix))
+
create_if_not_exists table(:communication_match_messages, prefix: prefix) do
add(:content, :text)
add(:inserted_at, :utc_datetime)
@@ -169,6 +183,8 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:match_id, references(:game_matches, on_delete: :nothing, type: :uuid), type: :uuid)
end
+ create_if_not_exists(index(:communication_match_messages, [:match_id], prefix: prefix))
+
# Settings
create_if_not_exists table(:settings_server_settings, primary_key: false, prefix: prefix) do
add(:key, :string, primary_key: true)
From 3135113327a89cd73079e0617c033a844f42ab0a Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 15 Jul 2024 18:38:42 +0100
Subject: [PATCH 42/64] Added user choices to matches
---
.github/workflows/elixir.yml | 2 +-
CHANGELOG.md | 1 +
README.md | 9 +-
lib/teiserver/application.ex | 8 +-
lib/teiserver/caches/type_lookup_cache.ex | 1 +
lib/teiserver/contexts/game.ex | 98 +++++++++
lib/teiserver/game/libs/user_choice_lib.ex | 179 ++++++++++++++++
.../game/libs/user_choice_type_lib.ex | 191 ++++++++++++++++++
lib/teiserver/game/queries/match_queries.ex | 14 ++
.../game/queries/match_setting_queries.ex | 24 +--
.../game/queries/user_choice_queries.ex | 108 ++++++++++
.../game/queries/user_choice_type_queries.ex | 108 ++++++++++
lib/teiserver/game/schemas/lobby.ex | 2 +
lib/teiserver/game/schemas/match.ex | 8 +-
lib/teiserver/game/schemas/user_choice.ex | 41 ++++
.../game/schemas/user_choice_type.ex | 33 +++
lib/teiserver/helpers/query_helper.ex | 8 -
lib/teiserver/migrations/postgres/v01.ex | 25 ++-
.../settings/libs/server_setting_lib.ex | 4 +-
.../settings/schemas/user_setting.ex | 2 +
mix.exs | 2 +-
test/game/libs/match_membership_lib_test.exs | 9 +-
test/game/libs/user_choice_lib_test.exs | 158 +++++++++++++++
test/game/libs/user_choice_type_lib_test.exs | 109 ++++++++++
test/game/queries/match_queries_test.exs | 11 +-
test/game/queries/match_type_queries_test.exs | 3 +-
.../game/queries/user_choice_queries_test.exs | 56 +++++
.../queries/user_choice_type_queries_test.exs | 48 +++++
test/support/fixtures/game_fixtures.ex | 44 +++-
test/support/fixtures/settings_fixtures.ex | 3 +-
.../20240110214150_add_teiserver_tables.exs | 2 +-
31 files changed, 1252 insertions(+), 59 deletions(-)
create mode 100644 lib/teiserver/game/libs/user_choice_lib.ex
create mode 100644 lib/teiserver/game/libs/user_choice_type_lib.ex
create mode 100644 lib/teiserver/game/queries/user_choice_queries.ex
create mode 100644 lib/teiserver/game/queries/user_choice_type_queries.ex
create mode 100644 lib/teiserver/game/schemas/user_choice.ex
create mode 100644 lib/teiserver/game/schemas/user_choice_type.ex
create mode 100644 test/game/libs/user_choice_lib_test.exs
create mode 100644 test/game/libs/user_choice_type_lib_test.exs
create mode 100644 test/game/queries/user_choice_queries_test.exs
create mode 100644 test/game/queries/user_choice_type_queries_test.exs
diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml
index ff6b8f4a9..2dbe8cbc3 100644
--- a/.github/workflows/elixir.yml
+++ b/.github/workflows/elixir.yml
@@ -8,7 +8,7 @@ name: Build and test
on:
push:
branches:
- - master
+ - main
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a6e2513df..ffc280231 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
- Added caching for some db calls
- Changed server settings to use `text` type behind the scenes and added ability to validate themz
- Added `player_count` as a property to matches
+- Added concept of user choices to represent pre-game choices made by users (e.g. in-game faction)
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/README.md b/README.md
index c0a633f08..6dfb4630f 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
-_Note: This README is for the unreleased master branch, please reference the
+_Note: This README is for the unreleased main branch, please reference the
[official documentation on hexdocs][hexdoc] for the latest stable release._
[hexdoc]: https://hexdocs.pm/teiserver/Teiserver.html
@@ -56,10 +56,3 @@ defmodule MyApp.Repo.Migrations.AddTeiserverTables do
end
end
```
-
-Add this to your Application supervision tree:
-```elixir
-children = [
- {Teiserver, Application.get_env(:my_app, Teiserver)}
-]
-```
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index b63a05946..4279f1863 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -7,7 +7,7 @@ defmodule Teiserver.Application do
def start(_type, _args) do
children = [
{Phoenix.PubSub, name: Teiserver.PubSub},
- Teiserver.System.ClusterManagerSupervisor,
+ # Teiserver.System.ClusterManagerSupervisor,
Teiserver.System.CacheClusterServer,
# Servers not part of the general slew of things
@@ -47,9 +47,9 @@ defmodule Teiserver.Application do
opts = [strategy: :one_for_one, name: __MODULE__]
start_result = Supervisor.start_link(children, opts)
- if Application.get_env(:teiserver, :teiserver_clustering, true) do
- Teiserver.System.ClusterManagerSupervisor.start_cluster_manager_supervisor_children()
- end
+ # if Application.get_env(:teiserver, :teiserver_clustering, true) do
+ # Teiserver.System.ClusterManagerSupervisor.start_cluster_manager_supervisor_children()
+ # end
Teiserver.System.StartupLib.perform()
diff --git a/lib/teiserver/caches/type_lookup_cache.ex b/lib/teiserver/caches/type_lookup_cache.ex
index fcbfd64ad..ec26c73d5 100644
--- a/lib/teiserver/caches/type_lookup_cache.ex
+++ b/lib/teiserver/caches/type_lookup_cache.ex
@@ -15,6 +15,7 @@ defmodule Teiserver.Caches.TypeLookupCache do
children = [
add_cache(:ts_match_type_lookup, ttl: :timer.minutes(5)),
add_cache(:ts_match_setting_type_lookup, ttl: :timer.minutes(5)),
+ add_cache(:ts_user_choice_type_lookup, ttl: :timer.minutes(5)),
]
Supervisor.init(children, strategy: :one_for_all)
diff --git a/lib/teiserver/contexts/game.ex b/lib/teiserver/contexts/game.ex
index 0bc6f73c4..843db7f95 100644
--- a/lib/teiserver/contexts/game.ex
+++ b/lib/teiserver/contexts/game.ex
@@ -362,6 +362,104 @@ defmodule Teiserver.Game do
@spec change_match_setting(MatchSetting.t(), map) :: Ecto.Changeset.t()
defdelegate change_match_setting(match_setting, attrs \\ %{}), to: MatchSettingLib
+ # UserChoiceTypes
+ alias Teiserver.Game.{UserChoiceType, UserChoiceTypeLib, UserChoiceTypeQueries}
+
+ @doc false
+ @spec user_choice_type_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate user_choice_type_query(args), to: UserChoiceTypeQueries
+
+ @doc section: :user_choice_type
+ @spec list_user_choice_types(Teiserver.query_args()) :: [UserChoiceType.t()]
+ defdelegate list_user_choice_types(args), to: UserChoiceTypeLib
+
+ @doc section: :user_choice_type
+ @spec get_user_choice_type!(UserChoiceType.id()) :: UserChoiceType.t()
+ @spec get_user_choice_type!(UserChoiceType.id(), Teiserver.query_args()) ::
+ UserChoiceType.t()
+ defdelegate get_user_choice_type!(user_choice_type_id, query_args \\ []),
+ to: UserChoiceTypeLib
+
+ @doc section: :user_choice_type
+ @spec get_user_choice_type(UserChoiceType.id()) :: UserChoiceType.t() | nil
+ @spec get_user_choice_type(UserChoiceType.id(), Teiserver.query_args()) ::
+ UserChoiceType.t() | nil
+ defdelegate get_user_choice_type(user_choice_type_id, query_args \\ []),
+ to: UserChoiceTypeLib
+
+ @doc section: :user_choice_type
+ @spec create_user_choice_type(map) ::
+ {:ok, UserChoiceType.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate create_user_choice_type(attrs), to: UserChoiceTypeLib
+
+ @doc section: :user_choice_type
+ @spec get_or_create_user_choice_type_id(String.t()) :: UserChoiceType.id()
+ defdelegate get_or_create_user_choice_type_id(name), to: UserChoiceTypeLib
+
+ @doc section: :user_choice_type
+ @spec update_user_choice_type(UserChoiceType, map) ::
+ {:ok, UserChoiceType.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate update_user_choice_type(user_choice_type, attrs), to: UserChoiceTypeLib
+
+ @doc section: :user_choice_type
+ @spec delete_user_choice_type(UserChoiceType.t()) ::
+ {:ok, UserChoiceType.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_user_choice_type(user_choice_type), to: UserChoiceTypeLib
+
+ @doc section: :user_choice_type
+ @spec change_user_choice_type(UserChoiceType.t()) :: Ecto.Changeset.t()
+ @spec change_user_choice_type(UserChoiceType.t(), map) :: Ecto.Changeset.t()
+ defdelegate change_user_choice_type(user_choice_type, attrs \\ %{}), to: UserChoiceTypeLib
+
+ # UserChoices
+ alias Teiserver.Game.{UserChoice, UserChoiceLib, UserChoiceQueries}
+
+ @doc false
+ @spec user_choice_query(Teiserver.query_args()) :: Ecto.Query.t()
+ defdelegate user_choice_query(args), to: UserChoiceQueries
+
+ @doc section: :user_choice
+ @spec list_user_choices(Teiserver.query_args()) :: [UserChoice.t()]
+ defdelegate list_user_choices(args), to: UserChoiceLib
+
+ @doc section: :user_choice
+ @spec get_user_choices_map(Teiserver.match_id(), Teiserver.user_id()) :: %{String.t() => String.t()}
+ defdelegate get_user_choices_map(match_id, user_id), to: UserChoiceLib
+
+ @doc section: :user_choice
+ @spec get_user_choice!(Teiserver.match_id(), Teiserver.user_id(), UserChoiceType.id(), Teiserver.query_args()) ::
+ UserChoice.t()
+ defdelegate get_user_choice!(match_id, user_id, setting_type_id, query_args \\ []), to: UserChoiceLib
+
+ @doc section: :user_choice
+ @spec get_user_choice(Teiserver.match_id(), Teiserver.user_id(), UserChoiceType.id(), Teiserver.query_args()) ::
+ UserChoice.t() | nil
+ defdelegate get_user_choice(match_id, user_id, setting_type_id, query_args \\ []), to: UserChoiceLib
+
+ @doc section: :user_choice
+ @spec create_user_choice(map) :: {:ok, UserChoice.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate create_user_choice(attrs), to: UserChoiceLib
+
+ @doc section: :user_choices
+ @spec create_many_user_choices([map]) ::
+ {:ok, UserChoice.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate create_many_user_choices(attr_list), to: UserChoiceLib
+
+ @doc section: :user_choice
+ @spec update_user_choice(UserChoice, map) ::
+ {:ok, UserChoice.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate update_user_choice(user_choice, attrs), to: UserChoiceLib
+
+ @doc section: :user_choice
+ @spec delete_user_choice(UserChoice.t()) ::
+ {:ok, UserChoice.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate delete_user_choice(user_choice), to: UserChoiceLib
+
+ @doc section: :user_choice
+ @spec change_user_choice(UserChoice.t()) :: Ecto.Changeset.t()
+ @spec change_user_choice(UserChoice.t(), map) :: Ecto.Changeset.t()
+ defdelegate change_user_choice(user_choice, attrs \\ %{}), to: UserChoiceLib
+
# Match results/stats/extra data
# Game data file stuff (e.g. unit data if added by devs)
# Server Managed Lobbies
diff --git a/lib/teiserver/game/libs/user_choice_lib.ex b/lib/teiserver/game/libs/user_choice_lib.ex
new file mode 100644
index 000000000..865eda8ab
--- /dev/null
+++ b/lib/teiserver/game/libs/user_choice_lib.ex
@@ -0,0 +1,179 @@
+defmodule Teiserver.Game.UserChoiceLib do
+ @moduledoc """
+ TODO: Library of user_choice related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Game.{UserChoice, UserChoiceQueries, UserChoiceType}
+
+ @doc """
+ Returns the list of user_choices.
+
+ ## Examples
+
+ iex> list_user_choices()
+ [%UserChoice{}, ...]
+
+ """
+ @spec list_user_choices(Teiserver.query_args()) :: [UserChoice.t()]
+ def list_user_choices(query_args) do
+ query_args
+ |> UserChoiceQueries.user_choice_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Returns a key => value map of match choices for a given match_id.
+
+ ## Examples
+
+ iex> get_user_choices_map(123)
+ %{"key1" => "value1", "key2" => "value2"}
+
+ iex> get_user_choices_map(456)
+ %{}
+
+ """
+ @spec get_user_choices_map(Teiserver.match_id(), Teiserver.user_id()) :: %{String.t() => String.t()}
+ def get_user_choices_map(match_id, user_id) do
+ list_user_choices(where: [match_id: match_id, user_id: user_id], preload: [:type])
+ |> Map.new(fn ms ->
+ {ms.type.name, ms.value}
+ end)
+ end
+
+ @doc """
+ Gets a single user_choice.
+
+ Raises `Ecto.NoResultsError` if the UserChoice does not exist.
+
+ ## Examples
+
+ iex> get_user_choice!("29a42cef-2239-4a1d-8359-947310647a3b", "74e27850-f16f-4981-9077-ea0ddd4a0d8a", 123)
+ %UserChoice{}
+
+ iex> get_user_choice!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_user_choice!(Teiserver.match_id(), Teiserver.user_id(),UserChoiceType.id(), Teiserver.query_args()) ::
+ UserChoice.t()
+ def get_user_choice!(match_id, user_id, choice_type_id, query_args \\ []) do
+ (query_args ++ [match_id: match_id, user_id: user_id, choice_type_id: choice_type_id])
+ |> UserChoiceQueries.user_choice_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single user_choice.
+
+ Returns nil if the UserChoice does not exist.
+
+ ## Examples
+
+ iex> get_user_choice(123)
+ %UserChoice{}
+
+ iex> get_user_choice(456)
+ nil
+
+ """
+ @spec get_user_choice(Teiserver.match_id(), Teiserver.user_id(), UserChoiceType.id(), Teiserver.query_args()) ::
+ UserChoice.t() | nil
+ def get_user_choice(match_id, user_id, choice_type_id, query_args \\ []) do
+ (query_args ++ [match_id: match_id, user_id: user_id, choice_type_id: choice_type_id])
+ |> UserChoiceQueries.user_choice_query()
+ |> Repo.one()
+ end
+
+ @doc """
+ Creates a user_choice.
+
+ ## Examples
+
+ iex> create_user_choice(%{field: value})
+ {:ok, %UserChoice{}}
+
+ iex> create_user_choice(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_user_choice(map) :: {:ok, UserChoice.t()} | {:error, Ecto.Changeset.t()}
+ def create_user_choice(attrs) do
+ %UserChoice{}
+ |> UserChoice.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Creates many user_choices. Not unlike most other create functions this will raise an exception on failure and should not be caught using the normal case functions.
+
+ Expects a map of values which can be turned into valid match choices.
+
+ ## Examples
+
+ iex> create_many_user_choices([%{field: value}])
+ {:ok, %UserChoice{}}
+
+ iex> create_many_user_choices([%{field: bad_value}])
+ raise Postgrex.Error
+
+ """
+ @spec create_many_user_choices([map]) :: {:ok, map}
+ def create_many_user_choices(attr_list) do
+ Ecto.Multi.new()
+ |> Ecto.Multi.insert_all(:insert_all, UserChoice, attr_list)
+ |> Teiserver.Repo.transaction()
+ end
+
+ @doc """
+ Updates a user_choice.
+
+ ## Examples
+
+ iex> update_user_choice(user_choice, %{field: new_value})
+ {:ok, %UserChoice{}}
+
+ iex> update_user_choice(user_choice, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_user_choice(UserChoice.t(), map) ::
+ {:ok, UserChoice.t()} | {:error, Ecto.Changeset.t()}
+ def update_user_choice(%UserChoice{} = user_choice, attrs) do
+ user_choice
+ |> UserChoice.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a user_choice.
+
+ ## Examples
+
+ iex> delete_user_choice(user_choice)
+ {:ok, %UserChoice{}}
+
+ iex> delete_user_choice(user_choice)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_user_choice(UserChoice.t()) ::
+ {:ok, UserChoice.t()} | {:error, Ecto.Changeset.t()}
+ def delete_user_choice(%UserChoice{} = user_choice) do
+ Repo.delete(user_choice)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking user_choice changes.
+
+ ## Examples
+
+ iex> change_user_choice(user_choice)
+ %Ecto.Changeset{data: %UserChoice{}}
+
+ """
+ @spec change_user_choice(UserChoice.t(), map) :: Ecto.Changeset.t()
+ def change_user_choice(%UserChoice{} = user_choice, attrs \\ %{}) do
+ UserChoice.changeset(user_choice, attrs)
+ end
+end
diff --git a/lib/teiserver/game/libs/user_choice_type_lib.ex b/lib/teiserver/game/libs/user_choice_type_lib.ex
new file mode 100644
index 000000000..0e6dbdeac
--- /dev/null
+++ b/lib/teiserver/game/libs/user_choice_type_lib.ex
@@ -0,0 +1,191 @@
+defmodule Teiserver.Game.UserChoiceTypeLib do
+ @moduledoc """
+ TODO: Library of user_choice_type related functions.
+ """
+ use TeiserverMacros, :library
+ alias Teiserver.Game.{UserChoiceType, UserChoiceTypeQueries}
+
+ @doc """
+ Returns the list of user_choice_types.
+
+ ## Examples
+
+ iex> list_user_choice_types()
+ [%UserChoiceType{}, ...]
+
+ """
+ @spec list_user_choice_types(Teiserver.query_args()) :: [UserChoiceType.t()]
+ def list_user_choice_types(query_args) do
+ query_args
+ |> UserChoiceTypeQueries.user_choice_type_query()
+ |> Repo.all()
+ end
+
+ @doc """
+ Gets a single user_choice_type.
+
+ Raises `Ecto.NoResultsError` if the UserChoiceType does not exist.
+
+ ## Examples
+
+ iex> get_user_choice_type!(123)
+ %UserChoiceType{}
+
+ iex> get_user_choice_type!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ @spec get_user_choice_type!(UserChoiceType.id(), Teiserver.query_args()) ::
+ UserChoiceType.t()
+ def get_user_choice_type!(user_choice_type_id, query_args \\ []) do
+ (query_args ++ [id: user_choice_type_id])
+ |> UserChoiceTypeQueries.user_choice_type_query()
+ |> Repo.one!()
+ end
+
+ @doc """
+ Gets a single user_choice_type.
+
+ Returns nil if the UserChoiceType does not exist.
+
+ ## Examples
+
+ iex> get_user_choice_type(123)
+ %UserChoiceType{}
+
+ iex> get_user_choice_type(456)
+ nil
+
+ """
+ @spec get_user_choice_type(UserChoiceType.id(), Teiserver.query_args()) ::
+ UserChoiceType.t() | nil
+ def get_user_choice_type(user_choice_type_id, query_args \\ []) do
+ (query_args ++ [id: user_choice_type_id])
+ |> UserChoiceTypeQueries.user_choice_type_query()
+ |> Repo.one()
+ end
+
+ @doc """
+ Creates a user_choice_type.
+
+ ## Examples
+
+ iex> create_user_choice_type(%{field: value})
+ {:ok, %UserChoiceType{}}
+
+ iex> create_user_choice_type(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec create_user_choice_type(map) ::
+ {:ok, UserChoiceType.t()} | {:error, Ecto.Changeset.t()}
+ def create_user_choice_type(attrs) do
+ %UserChoiceType{}
+ |> UserChoiceType.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Gets the ID of a user_choice_type, if the type doesn't exist
+ it will create the user_choice_type and return the id of that type
+
+ ## Examples
+
+ iex> get_or_create_user_choice_type_id("existing")
+ 123
+
+ iex> get_or_create_user_choice_type_id("non-existing")
+ 1234
+
+ """
+ @spec get_or_create_user_choice_type_id(String.t()) :: UserChoiceType.id()
+ def get_or_create_user_choice_type_id(name) do
+ case Cachex.get(:ts_user_choice_type_lookup, name) do
+ {:ok, nil} ->
+ result = do_get_or_create_user_choice_type_id(name)
+ Cachex.put(:ts_user_choice_type_lookup, name, result)
+ result
+
+ {:ok, value} ->
+ value
+ end
+
+ end
+
+ @spec do_get_or_create_user_choice_type_id(String.t()) :: UserChoiceType.id()
+ def do_get_or_create_user_choice_type_id(name) do
+ name = String.trim(name)
+
+ query =
+ UserChoiceTypeQueries.user_choice_type_query(
+ where: [name: name],
+ select: [:id],
+ order_by: ["Name (A-Z)"]
+ )
+
+ case Repo.all(query) do
+ [] ->
+ {:ok, user_choice_type} =
+ %UserChoiceType{}
+ |> UserChoiceType.changeset(%{name: name})
+ |> Repo.insert()
+
+ user_choice_type.id
+
+ [%{id: id} | _] ->
+ id
+ end
+ end
+
+ @doc """
+ Updates a user_choice_type.
+
+ ## Examples
+
+ iex> update_user_choice_type(user_choice_type, %{field: new_value})
+ {:ok, %UserChoiceType{}}
+
+ iex> update_user_choice_type(user_choice_type, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec update_user_choice_type(UserChoiceType.t(), map) ::
+ {:ok, UserChoiceType.t()} | {:error, Ecto.Changeset.t()}
+ def update_user_choice_type(%UserChoiceType{} = user_choice_type, attrs) do
+ user_choice_type
+ |> UserChoiceType.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a user_choice_type.
+
+ ## Examples
+
+ iex> delete_user_choice_type(user_choice_type)
+ {:ok, %UserChoiceType{}}
+
+ iex> delete_user_choice_type(user_choice_type)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ @spec delete_user_choice_type(UserChoiceType.t()) ::
+ {:ok, UserChoiceType.t()} | {:error, Ecto.Changeset.t()}
+ def delete_user_choice_type(%UserChoiceType{} = user_choice_type) do
+ Repo.delete(user_choice_type)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking user_choice_type changes.
+
+ ## Examples
+
+ iex> change_user_choice_type(user_choice_type)
+ %Ecto.Changeset{data: %UserChoiceType{}}
+
+ """
+ @spec change_user_choice_type(UserChoiceType.t(), map) :: Ecto.Changeset.t()
+ def change_user_choice_type(%UserChoiceType{} = user_choice_type, attrs \\ %{}) do
+ UserChoiceType.changeset(user_choice_type, attrs)
+ end
+end
diff --git a/lib/teiserver/game/queries/match_queries.ex b/lib/teiserver/game/queries/match_queries.ex
index 19c03ce5f..a81e57555 100644
--- a/lib/teiserver/game/queries/match_queries.ex
+++ b/lib/teiserver/game/queries/match_queries.ex
@@ -152,6 +152,13 @@ defmodule Teiserver.Game.MatchQueries do
end
@spec _preload(Ecto.Query.t(), any) :: Ecto.Query.t()
+ def _preload(query, :type) do
+ from(match in query,
+ left_join: types in assoc(match, :type),
+ preload: [type: types]
+ )
+ end
+
def _preload(query, :members) do
from(match in query,
left_join: members in assoc(match, :members),
@@ -165,4 +172,11 @@ defmodule Teiserver.Game.MatchQueries do
preload: [settings: settings]
)
end
+
+ def _preload(query, :choices) do
+ from(match in query,
+ left_join: choices in assoc(match, :choices),
+ preload: [choices: choices]
+ )
+ end
end
diff --git a/lib/teiserver/game/queries/match_setting_queries.ex b/lib/teiserver/game/queries/match_setting_queries.ex
index fdd4a45ce..c842f3019 100644
--- a/lib/teiserver/game/queries/match_setting_queries.ex
+++ b/lib/teiserver/game/queries/match_setting_queries.ex
@@ -33,38 +33,38 @@ defmodule Teiserver.Game.MatchSettingQueries do
def _where(query, _, nil), do: query
def _where(query, :match_id, match_ids) when is_list(match_ids) do
- from(match_settingss in query,
- where: match_settingss.match_id in ^match_ids
+ from(match_settings in query,
+ where: match_settings.match_id in ^match_ids
)
end
def _where(query, :match_id, match_id) do
- from(match_settingss in query,
- where: match_settingss.match_id == ^match_id
+ from(match_settings in query,
+ where: match_settings.match_id == ^match_id
)
end
def _where(query, :type_id, type_ids) when is_list(type_ids) do
- from(match_settingss in query,
- where: match_settingss.type_id in ^type_ids
+ from(match_settings in query,
+ where: match_settings.type_id in ^type_ids
)
end
def _where(query, :type_id, type_id) do
- from(match_settingss in query,
- where: match_settingss.type_id == ^type_id
+ from(match_settings in query,
+ where: match_settings.type_id == ^type_id
)
end
def _where(query, :value, values) when is_list(values) do
- from(match_settingss in query,
- where: match_settingss.value in ^values
+ from(match_settings in query,
+ where: match_settings.value in ^values
)
end
def _where(query, :value, value) do
- from(match_settingss in query,
- where: match_settingss.value == ^value
+ from(match_settings in query,
+ where: match_settings.value == ^value
)
end
diff --git a/lib/teiserver/game/queries/user_choice_queries.ex b/lib/teiserver/game/queries/user_choice_queries.ex
new file mode 100644
index 000000000..881dcb6ad
--- /dev/null
+++ b/lib/teiserver/game/queries/user_choice_queries.ex
@@ -0,0 +1,108 @@
+defmodule Teiserver.Game.UserChoiceQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Game.UserChoice
+ require Logger
+
+ @spec user_choice_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def user_choice_query(args) do
+ query = from(user_choices in UserChoice)
+
+ query
+ |> do_where(id: args[:id])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_preload(args[:preload])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), atom(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :match_id, match_ids) do
+ from(user_choices in query,
+ where: user_choices.match_id in ^List.wrap(match_ids)
+ )
+ end
+
+ def _where(query, :user_id, user_ids) do
+ from(user_choices in query,
+ where: user_choices.user_id in ^List.wrap(user_ids)
+ )
+ end
+
+ def _where(query, :type_id, type_ids) do
+ from(user_choices in query,
+ where: user_choices.type_id in ^List.wrap(type_ids)
+ )
+ end
+
+ def _where(query, :value, value) do
+ from(user_choices in query,
+ where: user_choices.value in ^List.wrap(value)
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Value (A-Z)") do
+ from(user_choices in query,
+ order_by: [asc: user_choices.value]
+ )
+ end
+
+ def _order_by(query, "Value (Z-A)") do
+ from(user_choices in query,
+ order_by: [desc: user_choices.value]
+ )
+ end
+
+ @spec do_preload(Ecto.Query.t(), list() | nil) :: Ecto.Query.t()
+ defp do_preload(query, nil), do: query
+
+ defp do_preload(query, preloads) do
+ preloads
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _preload(query_acc, key)
+ end)
+ end
+
+ @spec _preload(Ecto.Query.t(), any) :: Ecto.Query.t()
+ def _preload(query, :type) do
+ from(user_choices in query,
+ left_join: types in assoc(user_choices, :type),
+ preload: [type: types]
+ )
+ end
+
+ def _preload(query, :match) do
+ from(user_choices in query,
+ left_join: matches in assoc(user_choices, :match),
+ preload: [match: matches]
+ )
+ end
+end
diff --git a/lib/teiserver/game/queries/user_choice_type_queries.ex b/lib/teiserver/game/queries/user_choice_type_queries.ex
new file mode 100644
index 000000000..4e6eab6fe
--- /dev/null
+++ b/lib/teiserver/game/queries/user_choice_type_queries.ex
@@ -0,0 +1,108 @@
+defmodule Teiserver.Game.UserChoiceTypeQueries do
+ @moduledoc false
+ use TeiserverMacros, :queries
+ alias Teiserver.Game.UserChoiceType
+ require Logger
+
+ @spec user_choice_type_query(Teiserver.query_args()) :: Ecto.Query.t()
+ def user_choice_type_query(args) do
+ query = from(user_choice_types in UserChoiceType)
+
+ query
+ |> do_where(id: args[:id])
+ |> do_where(args[:where])
+ |> do_where(args[:search])
+ |> do_preload(args[:preload])
+ |> do_order_by(args[:order_by])
+ |> QueryHelper.query_select(args[:select])
+ |> QueryHelper.limit_query(args[:limit] || 50)
+ end
+
+ @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
+ defp do_where(query, nil), do: query
+
+ defp do_where(query, params) do
+ params
+ |> Enum.reduce(query, fn {key, value}, query_acc ->
+ _where(query_acc, key, value)
+ end)
+ end
+
+ @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t()
+ def _where(query, _, ""), do: query
+ def _where(query, _, nil), do: query
+
+ def _where(query, :id, id_list) when is_list(id_list) do
+ from(user_choice_types in query,
+ where: user_choice_types.id in ^id_list
+ )
+ end
+
+ def _where(query, :id, id) do
+ from(user_choice_types in query,
+ where: user_choice_types.id == ^id
+ )
+ end
+
+ def _where(query, :name, name_list) when is_list(name_list) do
+ from(user_choice_types in query,
+ where: user_choice_types.name in ^name_list
+ )
+ end
+
+ def _where(query, :name, name) do
+ from(user_choice_types in query,
+ where: user_choice_types.name == ^name
+ )
+ end
+
+ @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
+ defp do_order_by(query, nil), do: query
+
+ defp do_order_by(query, params) do
+ params
+ |> List.wrap()
+ |> Enum.reduce(query, fn key, query_acc ->
+ _order_by(query_acc, key)
+ end)
+ end
+
+ @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
+ def _order_by(query, "Name (A-Z)") do
+ from(user_choice_types in query,
+ order_by: [asc: user_choice_types.name]
+ )
+ end
+
+ def _order_by(query, "Name (Z-A)") do
+ from(user_choice_types in query,
+ order_by: [desc: user_choice_types.name]
+ )
+ end
+
+ @spec do_preload(Ecto.Query.t(), List.t() | nil) :: Ecto.Query.t()
+ defp do_preload(query, nil), do: query
+
+ defp do_preload(query, _), do: query
+ # defp do_preload(query, preloads) do
+ # preloads
+ # |> List.wrap
+ # |> Enum.reduce(query, fn key, query_acc ->
+ # _preload(query_acc, key)
+ # end)
+ # end
+
+ # @spec _preload(Ecto.Query.t(), any) :: Ecto.Query.t()
+ # def _preload(query, :relation) do
+ # from user_choice_type in query,
+ # left_join: relations in assoc(user_choice_type, :relation),
+ # preload: [relation: relations]
+ # end
+
+ # def _preload(query, {:relation, join_query}) do
+ # from user_choice_type in query,
+ # left_join: relations in subquery(join_query),
+ # on: relations.id == query.relation_id,
+ # preload: [relation: relations]
+ # end
+end
diff --git a/lib/teiserver/game/schemas/lobby.ex b/lib/teiserver/game/schemas/lobby.ex
index 72c6c6d09..528fce8ad 100644
--- a/lib/teiserver/game/schemas/lobby.ex
+++ b/lib/teiserver/game/schemas/lobby.ex
@@ -24,6 +24,7 @@ defmodule Teiserver.Game.Lobby do
* `:game_name` - String of the game name
* `:game_version` - String of the game version
* `:game_settings` - Map of the settings to be used in starting the game
+ * `:user_settings` - Map of the settings to be used for each player, each key is a player id and the value is a key-value map of setting type to value
* `:players` - List of user_ids as players, source of truth is still client state
* `:spectators` - List of user_ids spectating, source of truth is still client state
* `:members` - Total list of all user_ids who are members of the lobby
@@ -69,6 +70,7 @@ defmodule Teiserver.Game.Lobby do
# Game stuff
field(:game_settings, map(), default: %{})
+ field(:user_settings, map(), default: %{})
field(:players, [Teiserver.user_id()], default: [])
field(:spectators, [Teiserver.user_id()], default: [])
diff --git a/lib/teiserver/game/schemas/match.ex b/lib/teiserver/game/schemas/match.ex
index a4741b0ff..025e3d719 100644
--- a/lib/teiserver/game/schemas/match.ex
+++ b/lib/teiserver/game/schemas/match.ex
@@ -22,7 +22,6 @@ defmodule Teiserver.Game.Match do
* `:ended_normally?` - True if the match was ended in a normal manner, false if ended in an abnormal manner (e.g. crashed)
* `:match_duration_seconds` - The duration of the game in seconds as indicated by the game host
* `:host` - The user account hosting the lobby
-
"""
use TeiserverMacros, :schema
@@ -55,8 +54,10 @@ defmodule Teiserver.Game.Match do
field(:lobby_id, Ecto.UUID)
belongs_to(:host, Teiserver.Account.User, type: Ecto.UUID)
belongs_to(:type, Teiserver.Game.MatchType)
+
has_many(:members, Teiserver.Game.MatchMembership)
has_many(:settings, Teiserver.Game.MatchSetting)
+ has_many(:choices, Teiserver.Game.UserChoice)
# Relationships we expect to add
# belongs_to :queue, Teiserver.Game.MatchmakingQueue
@@ -98,7 +99,10 @@ defmodule Teiserver.Game.Match do
host: Teiserver.Account.User.t(),
type_id: Teiserver.Game.MatchType.id(),
type: Teiserver.Game.MatchType.t(),
- members: list
+
+ members: list,
+ settings: list,
+ choices: list
}
@doc """
diff --git a/lib/teiserver/game/schemas/user_choice.ex b/lib/teiserver/game/schemas/user_choice.ex
new file mode 100644
index 000000000..801a73652
--- /dev/null
+++ b/lib/teiserver/game/schemas/user_choice.ex
@@ -0,0 +1,41 @@
+defmodule Teiserver.Game.UserChoice do
+ @moduledoc """
+ # UserChoice
+ Choices made by users at the onset of a match. Not to be confused with `Teiserver.Settings.UserSetting` which is a general preference.
+
+ ### Attributes
+ * `:type_id`/`:type` - The type of choice
+ * `:match_id`/`:match` - The match the choice was made in
+ * `:user_id`/`:user` - The user the choice was made by
+ * `:value` - The value of the choice
+ """
+ use TeiserverMacros, :schema
+
+ @primary_key false
+ schema "game_user_choices" do
+ belongs_to(:type, Teiserver.Game.UserChoiceType, primary_key: true)
+ belongs_to(:match, Teiserver.Game.Match, primary_key: true, type: Ecto.UUID)
+ belongs_to(:user, Teiserver.Account.User, primary_key: true, type: Ecto.UUID)
+
+ field(:value, :string)
+ end
+
+ @type t :: %__MODULE__{
+ type_id: Teiserver.Game.UserChoiceType.id(),
+ match_id: Teiserver.match_id(),
+ user_id: Teiserver.user_id(),
+ value: String.t()
+ }
+
+ @doc """
+ Builds a changeset based on the `struct` and `params`.
+ """
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, params \\ %{}) do
+ struct
+ |> cast(params, ~w(type_id match_id user_id value)a)
+ |> validate_required(~w(type_id match_id user_id value)a)
+ |> unique_constraint(~w(type_id match_id user_id)a)
+ end
+end
diff --git a/lib/teiserver/game/schemas/user_choice_type.ex b/lib/teiserver/game/schemas/user_choice_type.ex
new file mode 100644
index 000000000..eb7ff5ad7
--- /dev/null
+++ b/lib/teiserver/game/schemas/user_choice_type.ex
@@ -0,0 +1,33 @@
+defmodule Teiserver.Game.UserChoiceType do
+ @moduledoc """
+ # UserChoiceType
+ Type information regarding a choice made by a user prior to the start of a match
+
+ ### Attributes
+ * `:name` - The name of the setting
+ """
+ use TeiserverMacros, :schema
+
+ schema "game_user_choice_types" do
+ field(:name, :string)
+ end
+
+ @type id :: non_neg_integer()
+
+ @type t :: %__MODULE__{
+ id: id(),
+ name: String.t()
+ }
+
+ @doc """
+ Builds a changeset based on the `struct` and `params`.
+ """
+ @spec changeset(map()) :: Ecto.Changeset.t()
+ @spec changeset(map(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, params \\ %{}) do
+ struct
+ |> cast(params, ~w(name)a)
+ |> validate_required(~w(name)a)
+ |> unique_constraint(~w(name)a)
+ end
+end
diff --git a/lib/teiserver/helpers/query_helper.ex b/lib/teiserver/helpers/query_helper.ex
index 857f333b1..a87e4b84a 100644
--- a/lib/teiserver/helpers/query_helper.ex
+++ b/lib/teiserver/helpers/query_helper.ex
@@ -2,14 +2,6 @@ defmodule Teiserver.Helpers.QueryHelper do
@moduledoc false
import Ecto.Query, warn: false
- @spec offset_query(Ecto.Query.t(), nil | non_neg_integer()) :: Ecto.Query.t()
- def offset_query(query, nil), do: query
-
- def offset_query(query, amount) do
- query
- |> offset(^amount)
- end
-
@spec limit_query(Ecto.Query.t(), non_neg_integer() | :infinity) :: Ecto.Query.t()
def limit_query(query, :infinity), do: query
def limit_query(query, nil), do: query
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index 705fe3875..8c61a3344 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -123,7 +123,7 @@ defmodule Teiserver.Migrations.Postgres.V01 do
add(:win?, :boolean, default: nil, null: true)
add(:left_after_seconds, :integer)
- add(:party_id, :string)
+ add(:party_id, :uuid)
end
create_if_not_exists(index(:game_match_memberships, [:match_id], prefix: prefix))
@@ -145,6 +145,29 @@ defmodule Teiserver.Migrations.Postgres.V01 do
create_if_not_exists(index(:game_match_settings, [:match_id], prefix: prefix))
+ create_if_not_exists table(:game_user_choice_types) do
+ add(:name, :string)
+ end
+
+ create_if_not_exists table(:game_user_choices, primary_key: false) do
+ add(:type_id, references(:game_user_choice_types, on_delete: :nothing), primary_key: true)
+
+ add(:user_id, references(:account_users, on_delete: :nothing, type: :uuid),
+ primary_key: true,
+ type: :uuid
+ )
+
+ add(:match_id, references(:game_matches, on_delete: :nothing, type: :uuid),
+ primary_key: true,
+ type: :uuid
+ )
+
+ add(:value, :string)
+ end
+
+ create_if_not_exists(index(:game_user_choices, [:match_id], prefix: prefix))
+ create_if_not_exists(index(:game_user_choices, [:user_id], prefix: prefix))
+
# Communications
create_if_not_exists table(:communication_rooms, prefix: prefix) do
add(:name, :string)
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index f237c3865..43df14b7d 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -150,8 +150,8 @@ defmodule Teiserver.Settings.ServerSettingLib do
"""
@spec value_is_valid?(ServerSettingType.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok | {:error, String.t()}
- def value_is_valid?(%{validation: nil}, _), do: :ok
- def value_is_valid?(%{validation: validator_function}, value) do
+ def value_is_valid?(%{validator: nil}, _), do: :ok
+ def value_is_valid?(%{validator: validator_function}, value) do
validator_function.(value)
end
diff --git a/lib/teiserver/settings/schemas/user_setting.ex b/lib/teiserver/settings/schemas/user_setting.ex
index 9fd375750..2e78c56d8 100644
--- a/lib/teiserver/settings/schemas/user_setting.ex
+++ b/lib/teiserver/settings/schemas/user_setting.ex
@@ -5,6 +5,8 @@ defmodule Teiserver.Settings.UserSetting do
The intended use case for User settings is anything where you want to store a key-value store against the user.
+ Not to be confused with `Teiserver.Game.UserChoice` which is a per-game "setting".
+
### Attributes
* `:user_id` - A reference to the User in question
diff --git a/mix.exs b/mix.exs
index f30209b48..c0951755e 100644
--- a/mix.exs
+++ b/mix.exs
@@ -263,7 +263,7 @@ defmodule Teiserver.MixProject do
licenses: ["Apache-2.0"],
files: ~w(lib .formatter.exs mix.exs README* CHANGELOG* LICENSE*),
links: %{
- "Changelog" => "#{@source_url}/blob/master/CHANGELOG.md",
+ "Changelog" => "#{@source_url}/blob/main/CHANGELOG.md",
"GitHub" => @source_url,
"Discord" => "https://discord.gg/NmrSt9zw2p"
}
diff --git a/test/game/libs/match_membership_lib_test.exs b/test/game/libs/match_membership_lib_test.exs
index 43f774a5e..435fc92c5 100644
--- a/test/game/libs/match_membership_lib_test.exs
+++ b/test/game/libs/match_membership_lib_test.exs
@@ -12,7 +12,7 @@ defmodule Teiserver.MatchMembershipLibTest do
user_id: AccountFixtures.user_fixture().id,
team_number: 123,
win?: true,
- party_id: "some party_id",
+ party_id: "f3d93d6b-cf27-4d64-9882-ca42d220cd6b",
left_after_seconds: 123
}
end
@@ -23,7 +23,7 @@ defmodule Teiserver.MatchMembershipLibTest do
user_id: AccountFixtures.user_fixture().id,
team_number: 1234,
win?: true,
- party_id: "some updated party_id",
+ party_id: "17b33fb6-89fe-4d70-b299-b1ad27a1a852",
left_after_seconds: 1234
}
end
@@ -70,7 +70,7 @@ defmodule Teiserver.MatchMembershipLibTest do
assert {:ok, %MatchMembership{} = match_membership} =
Game.create_match_membership(valid_attrs())
- assert match_membership.party_id == "some party_id"
+ assert match_membership.party_id == "f3d93d6b-cf27-4d64-9882-ca42d220cd6b"
end
test "create_match_membership/1 with invalid data returns error changeset" do
@@ -113,8 +113,7 @@ defmodule Teiserver.MatchMembershipLibTest do
assert {:ok, %MatchMembership{} = match_membership} =
Game.update_match_membership(match_membership, update_attrs())
- assert match_membership.party_id == "some updated party_id"
- assert match_membership.party_id == "some updated party_id"
+ assert match_membership.party_id == "17b33fb6-89fe-4d70-b299-b1ad27a1a852"
end
test "update_match_membership/2 with invalid data returns error changeset" do
diff --git a/test/game/libs/user_choice_lib_test.exs b/test/game/libs/user_choice_lib_test.exs
new file mode 100644
index 000000000..0d79f82dc
--- /dev/null
+++ b/test/game/libs/user_choice_lib_test.exs
@@ -0,0 +1,158 @@
+defmodule Teiserver.UserChoiceLibTest do
+ @moduledoc false
+ alias Teiserver.Game.UserChoice
+ alias Teiserver.Game
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Fixtures.{AccountFixtures, GameFixtures}
+
+ defp valid_attrs do
+ %{
+ match_id: GameFixtures.completed_match_fixture().id,
+ type_id: GameFixtures.user_choice_type_fixture().id,
+ user_id: AccountFixtures.user_fixture().id,
+ value: "some value"
+ }
+ end
+
+ defp update_attrs do
+ %{
+ match_id: GameFixtures.completed_match_fixture().id,
+ type_id: GameFixtures.user_choice_type_fixture().id,
+ user_id: AccountFixtures.user_fixture().id,
+ value: "some updated value"
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ match_id: nil,
+ type_id: nil,
+ user_id: nil,
+ value: nil
+ }
+ end
+
+ describe "user_choice" do
+ alias Teiserver.Game.UserChoice
+
+ test "user_choice_query/0 returns a query" do
+ q = Game.user_choice_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_user_choice/0 returns user_choice" do
+ # No user_choice yet
+ assert Game.list_user_choices([]) == []
+
+ # Add a user_choice
+ GameFixtures.user_choice_fixture()
+ assert Game.list_user_choices([]) != []
+ end
+
+ test "get_user_choice!/1 and get_user_choice/1 returns the user_choice with given id" do
+ user_choice = GameFixtures.user_choice_fixture()
+
+ assert Game.get_user_choice!(user_choice.match_id, user_choice.user_id, user_choice.type_id) ==
+ user_choice
+
+ assert Game.get_user_choice(user_choice.match_id, user_choice.user_id, user_choice.type_id) ==
+ user_choice
+ end
+
+ test "get_user_choices_map/2" do
+ user = AccountFixtures.user_fixture()
+ match = GameFixtures.incomplete_match_fixture()
+
+ user_choice1 = GameFixtures.user_choice_fixture(%{user_id: user.id, match_id: match.id})
+ user_choice2 = GameFixtures.user_choice_fixture(%{user_id: user.id, match_id: match.id})
+ user_choice3 = GameFixtures.user_choice_fixture(%{match_id: match.id})
+ user_choice4 = GameFixtures.user_choice_fixture(%{user_id: user.id})
+
+ values = Game.get_user_choices_map(match.id, user.id) |> Map.values
+
+ assert Enum.member?(values, user_choice1.value)
+ assert Enum.member?(values, user_choice2.value)
+ refute Enum.member?(values, user_choice3.value)
+ refute Enum.member?(values, user_choice4.value)
+ end
+
+ test "create_user_choice/1 with valid data creates a user_choice" do
+ assert {:ok, %UserChoice{} = user_choice} =
+ Game.create_user_choice(valid_attrs())
+
+ assert user_choice.value == "some value"
+ end
+
+ test "create_user_choice/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Game.create_user_choice(invalid_attrs())
+ end
+
+ test "create_many_user_choices/1 with valid data creates a user_choice" do
+ match = GameFixtures.incomplete_match_fixture()
+ user = AccountFixtures.user_fixture()
+ assert Enum.empty?(Game.list_user_choices(where: [match_id: match.id, user_id: user.id]))
+
+ attr_list = [
+ %{match_id: match.id, type_id: GameFixtures.user_choice_type_fixture().id, user_id: user.id},
+ %{match_id: match.id, type_id: GameFixtures.user_choice_type_fixture().id, user_id: user.id},
+ %{match_id: match.id, type_id: GameFixtures.user_choice_type_fixture().id, user_id: user.id}
+ ]
+
+ # Now insert them
+ assert {:ok, %{insert_all: {3, nil}}} = Game.create_many_user_choices(attr_list)
+ assert Enum.count(Game.list_user_choices(where: [match_id: match.id, user_id: user.id])) == 3
+ end
+
+ test "create_many_user_choices/1 with invalid data returns error" do
+ match = GameFixtures.incomplete_match_fixture()
+ user = AccountFixtures.user_fixture()
+ assert Enum.empty?(Game.list_user_choices(where: [match_id: match.id, user_id: user.id]))
+
+ attr_list = [
+ %{match_id: nil, type_id: GameFixtures.user_choice_type_fixture().id, user_id: AccountFixtures.user_fixture().id},
+ %{match_id: nil, type_id: GameFixtures.user_choice_type_fixture().id, user_id: AccountFixtures.user_fixture().id},
+ %{match_id: nil, type_id: GameFixtures.user_choice_type_fixture().id, user_id: AccountFixtures.user_fixture().id}
+ ]
+
+ # Now insert them
+ assert_raise Postgrex.Error, fn -> Game.create_many_user_choices(attr_list) end
+ assert Enum.empty?(Game.list_user_choices(where: [match_id: match.id, user_id: user.id]))
+ end
+
+ test "update_user_choice/2 with valid data updates the user_choice" do
+ user_choice = GameFixtures.user_choice_fixture()
+
+ assert {:ok, %UserChoice{} = user_choice} =
+ Game.update_user_choice(user_choice, update_attrs())
+
+ assert user_choice.value == "some updated value"
+ end
+
+ test "update_user_choice/2 with invalid data returns error changeset" do
+ user_choice = GameFixtures.user_choice_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Game.update_user_choice(user_choice, invalid_attrs())
+
+ assert user_choice ==
+ Game.get_user_choice!(user_choice.match_id, user_choice.user_id, user_choice.type_id)
+ end
+
+ test "delete_user_choice/1 deletes the user_choice" do
+ user_choice = GameFixtures.user_choice_fixture()
+ assert {:ok, %UserChoice{}} = Game.delete_user_choice(user_choice)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Game.get_user_choice!(user_choice.match_id, user_choice.user_id, user_choice.type_id)
+ end
+
+ assert Game.get_user_choice(user_choice.match_id, user_choice.user_id, user_choice.type_id) == nil
+ end
+
+ test "change_user_choice/1 returns a user_choice changeset" do
+ user_choice = GameFixtures.user_choice_fixture()
+ assert %Ecto.Changeset{} = Game.change_user_choice(user_choice)
+ end
+ end
+end
diff --git a/test/game/libs/user_choice_type_lib_test.exs b/test/game/libs/user_choice_type_lib_test.exs
new file mode 100644
index 000000000..3e8fbb3c7
--- /dev/null
+++ b/test/game/libs/user_choice_type_lib_test.exs
@@ -0,0 +1,109 @@
+defmodule Teiserver.UserChoiceTypeLibTest do
+ @moduledoc false
+ alias Teiserver.Game.UserChoiceType
+ alias Teiserver.Game
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Fixtures.{GameFixtures}
+
+ defp valid_attrs do
+ %{
+ name: "some name"
+ }
+ end
+
+ defp update_attrs do
+ %{
+ name: "some updated name"
+ }
+ end
+
+ defp invalid_attrs do
+ %{
+ name: nil
+ }
+ end
+
+ describe "user_choice_type" do
+ alias Teiserver.Game.UserChoiceType
+
+ test "user_choice_type_query/0 returns a query" do
+ q = Game.user_choice_type_query([])
+ assert %Ecto.Query{} = q
+ end
+
+ test "list_user_choice_type/0 returns user_choice_type" do
+ # No user_choice_type yet
+ assert Game.list_user_choice_types([]) == []
+
+ # Add a user_choice_type
+ GameFixtures.user_choice_type_fixture()
+ assert Game.list_user_choice_types([]) != []
+ end
+
+ test "get_or_create_user_choice_type_id/1 returns an id" do
+ # No user_choice_type yet
+ assert Game.list_user_choice_types([]) == []
+
+ # Add a user_choice_type
+ type_id = Game.get_or_create_user_choice_type_id("test-name")
+ assert is_integer(type_id)
+ [the_type] = Game.list_user_choice_types([])
+
+ assert the_type.id == type_id
+ assert the_type.name == "test-name"
+ end
+
+ test "get_user_choice_type!/1 and get_user_choice_type/1 returns the user_choice_type with given id" do
+ user_choice_type = GameFixtures.user_choice_type_fixture()
+ assert Game.get_user_choice_type!(user_choice_type.id) == user_choice_type
+ assert Game.get_user_choice_type(user_choice_type.id) == user_choice_type
+ end
+
+ test "create_user_choice_type/1 with valid data creates a user_choice_type" do
+ assert {:ok, %UserChoiceType{} = user_choice_type} =
+ Game.create_user_choice_type(valid_attrs())
+
+ assert user_choice_type.name == "some name"
+ end
+
+ test "create_user_choice_type/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Game.create_user_choice_type(invalid_attrs())
+ end
+
+ test "update_user_choice_type/2 with valid data updates the user_choice_type" do
+ user_choice_type = GameFixtures.user_choice_type_fixture()
+
+ assert {:ok, %UserChoiceType{} = user_choice_type} =
+ Game.update_user_choice_type(user_choice_type, update_attrs())
+
+ assert user_choice_type.name == "some updated name"
+ assert user_choice_type.name == "some updated name"
+ end
+
+ test "update_user_choice_type/2 with invalid data returns error changeset" do
+ user_choice_type = GameFixtures.user_choice_type_fixture()
+
+ assert {:error, %Ecto.Changeset{}} =
+ Game.update_user_choice_type(user_choice_type, invalid_attrs())
+
+ assert user_choice_type == Game.get_user_choice_type!(user_choice_type.id)
+ end
+
+ test "delete_user_choice_type/1 deletes the user_choice_type" do
+ user_choice_type = GameFixtures.user_choice_type_fixture()
+ assert {:ok, %UserChoiceType{}} = Game.delete_user_choice_type(user_choice_type)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Game.get_user_choice_type!(user_choice_type.id)
+ end
+
+ assert Game.get_user_choice_type(user_choice_type.id) == nil
+ end
+
+ test "change_user_choice_type/1 returns a user_choice_type changeset" do
+ user_choice_type = GameFixtures.user_choice_type_fixture()
+ assert %Ecto.Changeset{} = Game.change_user_choice_type(user_choice_type)
+ end
+ end
+end
diff --git a/test/game/queries/match_queries_test.exs b/test/game/queries/match_queries_test.exs
index 10b171bda..06f5a7818 100644
--- a/test/game/queries/match_queries_test.exs
+++ b/test/game/queries/match_queries_test.exs
@@ -32,6 +32,14 @@ defmodule Teiserver.MatchQueriesTest do
id: [Teiserver.uuid(), Teiserver.uuid()],
id: Teiserver.uuid(),
name: "Some name",
+ ended_normally?: true,
+ processed?: true,
+ duration_gt: 100,
+ duration_lt: 999,
+ started_after: Timex.now(),
+ started_before: Timex.now(),
+ ended_after: Timex.now(),
+ ended_before: Timex.now(),
inserted_after: Timex.now(),
inserted_before: Timex.now()
],
@@ -41,7 +49,8 @@ defmodule Teiserver.MatchQueriesTest do
"Newest first",
"Oldest first"
],
- preload: []
+ preload: [],
+ limit: 10
)
assert all_values != @empty_query
diff --git a/test/game/queries/match_type_queries_test.exs b/test/game/queries/match_type_queries_test.exs
index e581a071e..a019b9240 100644
--- a/test/game/queries/match_type_queries_test.exs
+++ b/test/game/queries/match_type_queries_test.exs
@@ -38,7 +38,8 @@ defmodule Teiserver.MatchTypeQueriesTest do
"Name (A-Z)",
"Name (Z-A)"
],
- preload: []
+ preload: [],
+ limit: :infinity
)
assert all_values != @empty_query
diff --git a/test/game/queries/user_choice_queries_test.exs b/test/game/queries/user_choice_queries_test.exs
new file mode 100644
index 000000000..089a49e94
--- /dev/null
+++ b/test/game/queries/user_choice_queries_test.exs
@@ -0,0 +1,56 @@
+defmodule Teiserver.UserChoiceQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Game.UserChoiceQueries
+
+ describe "queries" do
+ @empty_query UserChoiceQueries.user_choice_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ UserChoiceQueries.user_choice_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ UserChoiceQueries.user_choice_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ UserChoiceQueries.user_choice_query(
+ where: [
+ type_id: [1, 2],
+ type_id: 1,
+ match_id: [Teiserver.uuid(), Teiserver.uuid()],
+ match_id: Teiserver.uuid(),
+ user_id: [Teiserver.uuid(), Teiserver.uuid()],
+ user_id: Teiserver.uuid(),
+ value: ["abc", "def"],
+ value: "abc"
+ ],
+ order_by: [
+ "Value (A-Z)",
+ "Value (Z-A)"
+ ],
+ preload: [
+ :match,
+ :type
+ ],
+ limit: nil
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/game/queries/user_choice_type_queries_test.exs b/test/game/queries/user_choice_type_queries_test.exs
new file mode 100644
index 000000000..80a624043
--- /dev/null
+++ b/test/game/queries/user_choice_type_queries_test.exs
@@ -0,0 +1,48 @@
+defmodule Teiserver.UserChoiceTypeQueriesTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Game.UserChoiceTypeQueries
+
+ describe "queries" do
+ @empty_query UserChoiceTypeQueries.user_choice_type_query([])
+
+ test "clauses" do
+ # Null values, shouldn't error but shouldn't generate a query
+ null_values =
+ UserChoiceTypeQueries.user_choice_type_query(
+ where: [
+ key1: "",
+ key2: nil
+ ]
+ )
+
+ assert null_values == @empty_query
+ Repo.all(null_values)
+
+ # If a key is not present in the query library it should error
+ assert_raise(FunctionClauseError, fn ->
+ UserChoiceTypeQueries.user_choice_type_query(where: [not_a_key: 1])
+ end)
+
+ # we expect the query to run though it won't produce meaningful results
+ all_values =
+ UserChoiceTypeQueries.user_choice_type_query(
+ where: [
+ id: [1, 2],
+ id: 1,
+ name: ["abc", "def"],
+ name: "Some name"
+ ],
+ order_by: [
+ "Name (A-Z)",
+ "Name (Z-A)"
+ ],
+ preload: []
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+ end
+ end
+end
diff --git a/test/support/fixtures/game_fixtures.ex b/test/support/fixtures/game_fixtures.ex
index 8b9367226..d9f171c8e 100644
--- a/test/support/fixtures/game_fixtures.ex
+++ b/test/support/fixtures/game_fixtures.ex
@@ -1,11 +1,11 @@
defmodule Teiserver.Fixtures.GameFixtures do
@moduledoc false
+ alias Teiserver.Fixtures.AccountFixtures
alias Teiserver.Game
- alias Teiserver.Game.{Lobby, Match, MatchType, MatchMembership, MatchSettingType, MatchSetting}
+ alias Teiserver.Game.{Lobby, Match, MatchType, MatchMembership, MatchSettingType, MatchSetting, UserChoice, UserChoiceType}
import Teiserver.Fixtures.AccountFixtures, only: [user_fixture: 0]
import Teiserver.Fixtures.ConnectionFixtures, only: [client_fixture: 0]
- @spec lobby_fixture() :: Lobby.t()
@spec lobby_fixture(map) :: Lobby.t()
def lobby_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
@@ -47,7 +47,6 @@ defmodule Teiserver.Fixtures.GameFixtures do
{host_conn, host_user, lobby_id}
end
- @spec match_type_fixture() :: MatchType.t()
@spec match_type_fixture(map) :: MatchType.t()
def match_type_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
@@ -61,7 +60,6 @@ defmodule Teiserver.Fixtures.GameFixtures do
|> Teiserver.Repo.insert!()
end
- @spec unstarted_match_fixture() :: Match.t()
@spec unstarted_match_fixture(map) :: Match.t()
def unstarted_match_fixture(data \\ %{}) do
Match.changeset(
@@ -77,7 +75,6 @@ defmodule Teiserver.Fixtures.GameFixtures do
|> Teiserver.Repo.insert!()
end
- @spec incomplete_match_fixture() :: Match.t()
@spec incomplete_match_fixture(map) :: Match.t()
def incomplete_match_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
@@ -106,7 +103,6 @@ defmodule Teiserver.Fixtures.GameFixtures do
|> Teiserver.Repo.insert!()
end
- @spec completed_match_fixture() :: Match.t()
@spec completed_match_fixture(map) :: Match.t()
def completed_match_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
@@ -139,11 +135,8 @@ defmodule Teiserver.Fixtures.GameFixtures do
|> Teiserver.Repo.insert!()
end
- @spec match_membership_fixture() :: Match.t()
@spec match_membership_fixture(map) :: Match.t()
def match_membership_fixture(data \\ %{}) do
- r = :rand.uniform(999_999_999)
-
MatchMembership.changeset(
%MatchMembership{},
%{
@@ -151,14 +144,13 @@ defmodule Teiserver.Fixtures.GameFixtures do
match_id: data["match_id"] || completed_match_fixture().id,
team_number: data["team_number"] || 1,
win?: data["win?"] || false,
- party_id: data["party_id"] || "party_id_#{r}",
+ party_id: data["party_id"] || nil,
left_after_seconds: data[""] || 123
}
)
|> Teiserver.Repo.insert!()
end
- @spec match_setting_type_fixture() :: Match.t()
@spec match_setting_type_fixture(map) :: Match.t()
def match_setting_type_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
@@ -187,4 +179,34 @@ defmodule Teiserver.Fixtures.GameFixtures do
)
|> Teiserver.Repo.insert!()
end
+
+ @spec user_choice_type_fixture(map) :: Match.t()
+ def user_choice_type_fixture(data \\ %{}) do
+ r = :rand.uniform(999_999_999)
+
+ UserChoiceType.changeset(
+ %UserChoiceType{},
+ %{
+ name: data["name"] || "user_choice_type_#{r}"
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
+
+ @spec user_choice_fixture() :: Match.t()
+ @spec user_choice_fixture(map) :: Match.t()
+ def user_choice_fixture(data \\ %{}) do
+ r = :rand.uniform(999_999_999)
+
+ UserChoice.changeset(
+ %UserChoice{},
+ %{
+ type_id: data[:type_id] || user_choice_type_fixture().id,
+ match_id: data[:match_id] || completed_match_fixture().id,
+ user_id: data[:user_id] || AccountFixtures.user_fixture().id,
+ value: data[:value] || "value_#{r}"
+ }
+ )
+ |> Teiserver.Repo.insert!()
+ end
end
diff --git a/test/support/fixtures/settings_fixtures.ex b/test/support/fixtures/settings_fixtures.ex
index 66a8d870a..dedaf5f99 100644
--- a/test/support/fixtures/settings_fixtures.ex
+++ b/test/support/fixtures/settings_fixtures.ex
@@ -18,7 +18,8 @@ defmodule Teiserver.Fixtures.SettingsFixtures do
permissions: data["permissions"] || nil,
choices: data["choices"] || nil,
default: data["default"] || nil,
- description: data["description"] || nil
+ description: data["description"] || nil,
+ validator: data["validator"] || nil
})
type
diff --git a/test/support/postgres/migrations/20240110214150_add_teiserver_tables.exs b/test/support/postgres/migrations/20240110214150_add_teiserver_tables.exs
index 4cafe2951..9f01de050 100644
--- a/test/support/postgres/migrations/20240110214150_add_teiserver_tables.exs
+++ b/test/support/postgres/migrations/20240110214150_add_teiserver_tables.exs
@@ -1,4 +1,4 @@
-defmodule Teiserver.Test.Repo.Postgres.Migrations.AddTeiseverTables do
+defmodule Teiserver.Test.Repo.Postgres.Migrations.AddTeiserverTables do
@moduledoc false
use Ecto.Migration
From 5c38559ea3d4eedd96758ba257639fddf35b4ccd Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 15 Jul 2024 21:09:14 +0100
Subject: [PATCH 43/64] Expanded readme
---
README.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/README.md b/README.md
index 6dfb4630f..495abf66c 100644
--- a/README.md
+++ b/README.md
@@ -56,3 +56,9 @@ defmodule MyApp.Repo.Migrations.AddTeiserverTables do
end
end
```
+
+Finally, update your config to link the repo:
+```
+config :teiserver,
+ repo: MyApp.Repo
+```
From 9a4da2b5fad17f5e509bdaba3dabde4787eebfc1 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 15 Jul 2024 22:06:28 +0100
Subject: [PATCH 44/64] Removed clustering code
---
CHANGELOG.md | 1 +
config/config.exs | 2 -
config/test.exs | 3 +-
documentation/guides/config.md | 8 -
lib/teiserver/application.ex | 5 -
lib/teiserver/migrations/postgres/v01.ex | 11 --
.../system/libs/cluster_member_lib.ex | 138 ---------------
.../system/queries/cluster_member_queries.ex | 98 -----------
.../system/schemas/cluster_member.ex | 37 ----
.../system/servers/cluster_member_server.ex | 158 ------------------
.../servers/cluster_member_supervisor.ex | 57 -------
11 files changed, 2 insertions(+), 516 deletions(-)
delete mode 100644 lib/teiserver/system/libs/cluster_member_lib.ex
delete mode 100644 lib/teiserver/system/queries/cluster_member_queries.ex
delete mode 100644 lib/teiserver/system/schemas/cluster_member.ex
delete mode 100644 lib/teiserver/system/servers/cluster_member_server.ex
delete mode 100644 lib/teiserver/system/servers/cluster_member_supervisor.ex
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ffc280231..06c426773 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@
- Changed server settings to use `text` type behind the scenes and added ability to validate themz
- Added `player_count` as a property to matches
- Added concept of user choices to represent pre-game choices made by users (e.g. in-game faction)
+- Removed clustering code so it can be handled by the application using Teiserver as a library
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/config/config.exs b/config/config.exs
index 3cbf1bbea..008939407 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -19,8 +19,6 @@ config :teiserver,
# Overridden by application
client_destroy_timeout_seconds: 300,
lobby_join_method: :simple,
- teiserver_clustering: true,
- teiserver_clustering_post_join_functions: [],
# User defaults
default_behaviour_score: 10_000,
diff --git a/config/test.exs b/config/test.exs
index e502e50eb..87a790f7a 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -10,5 +10,4 @@ config :teiserver, Teiserver.Test.Repo,
hostname: "localhost"
config :teiserver,
- repo: Teiserver.Test.Repo,
- teiserver_clustering: false
+ repo: Teiserver.Test.Repo
diff --git a/documentation/guides/config.md b/documentation/guides/config.md
index 5e827ec6c..f42ca81eb 100644
--- a/documentation/guides/config.md
+++ b/documentation/guides/config.md
@@ -33,13 +33,6 @@ The `social_score` given to users registered using `Teiserver.Account.UserLib.re
## default_min_user_password_length - Default: 6
The minimum length for a user password.
-# Clustering
-## `teiserver_clustering` - Default: true
-When enabled Teiserver will attempt to handle the clustering of nodes using a database table. Turning it off will mean this behaves like any other application and you can either not cluster it or use things like `libcluster` as you desire. See `Teiserver.System.ClusterManager` for more details.
-
-## `teiserver_clustering_post_join_functions` - Default: []
-When teiserver_clustering is enabled, this will be a list of functions called by the genserver handling the join once it has joined the cluster. See `Teiserver.System.ClusterManager` for more details.
-
# Function overrides
Teiserver implements some defaults you may want to overwrite.
@@ -67,7 +60,6 @@ config :teiserver,
repo: HelloWorldServer.Repo,
client_destroy_timeout_seconds: 300,
lobby_join_method: :simple,
- teiserver_clustering: true,
# Users
default_behaviour_score: 10_000,
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index 4279f1863..c048f8c95 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -7,7 +7,6 @@ defmodule Teiserver.Application do
def start(_type, _args) do
children = [
{Phoenix.PubSub, name: Teiserver.PubSub},
- # Teiserver.System.ClusterManagerSupervisor,
Teiserver.System.CacheClusterServer,
# Servers not part of the general slew of things
@@ -47,10 +46,6 @@ defmodule Teiserver.Application do
opts = [strategy: :one_for_one, name: __MODULE__]
start_result = Supervisor.start_link(children, opts)
- # if Application.get_env(:teiserver, :teiserver_clustering, true) do
- # Teiserver.System.ClusterManagerSupervisor.start_cluster_manager_supervisor_children()
- # end
-
Teiserver.System.StartupLib.perform()
start_result
diff --git a/lib/teiserver/migrations/postgres/v01.ex b/lib/teiserver/migrations/postgres/v01.ex
index 8c61a3344..a0a26b4ed 100644
--- a/lib/teiserver/migrations/postgres/v01.ex
+++ b/lib/teiserver/migrations/postgres/v01.ex
@@ -12,14 +12,6 @@ defmodule Teiserver.Migrations.Postgres.V01 do
execute("CREATE EXTENSION IF NOT EXISTS citext")
- # Clustering
- create table(:teiserver_cluster_members, primary_key: false, prefix: prefix) do
- add(:id, :uuid, primary_key: true, null: false)
- add(:host, :string, null: false)
-
- timestamps(type: :utc_datetime)
- end
-
# Accounts
create_if_not_exists table(:account_users, primary_key: false, prefix: prefix) do
add(:id, :uuid, primary_key: true, null: false)
@@ -250,9 +242,6 @@ defmodule Teiserver.Migrations.Postgres.V01 do
drop_if_exists(table(:account_extra_user_data, prefix: prefix))
drop_if_exists(table(:account_users, prefix: prefix))
- # System
- drop_if_exists(table(:teiserver_cluster_members, prefix: prefix))
-
execute("DROP EXTENSION IF EXISTS citext")
end
end
diff --git a/lib/teiserver/system/libs/cluster_member_lib.ex b/lib/teiserver/system/libs/cluster_member_lib.ex
deleted file mode 100644
index f95dbe4f8..000000000
--- a/lib/teiserver/system/libs/cluster_member_lib.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule Teiserver.System.ClusterMemberLib do
- @moduledoc """
- Library of cluster_member related functions.
- """
- use TeiserverMacros, :library
- alias Teiserver.System.{ClusterMember, ClusterMemberQueries}
-
- @doc """
- Returns the list of cluster_members.
-
- ## Examples
-
- iex> list_cluster_members()
- [%ClusterMember{}, ...]
-
- """
- @spec list_cluster_members(Teiserver.query_args()) :: [ClusterMember.t()]
- def list_cluster_members(query_args \\ []) do
- query_args
- |> ClusterMemberQueries.cluster_member_query()
- |> Repo.all()
- end
-
- @doc """
- Gets a single cluster_member.
-
- Raises `Ecto.NoResultsError` if the ClusterMember does not exist.
-
- ## Examples
-
- iex> get_cluster_member!(123)
- %ClusterMember{}
-
- iex> get_cluster_member!(456)
- ** (Ecto.NoResultsError)
-
- """
- @spec get_cluster_member!(ClusterMember.id()) :: ClusterMember.t()
- @spec get_cluster_member!(ClusterMember.id(), Teiserver.query_args()) :: ClusterMember.t()
- def get_cluster_member!(cluster_member_id, query_args \\ []) do
- (query_args ++ [id: cluster_member_id])
- |> ClusterMemberQueries.cluster_member_query()
- |> Repo.one!()
- end
-
- @doc """
- Gets a single cluster_member.
-
- Returns nil if the ClusterMember does not exist.
-
- ## Examples
-
- iex> get_cluster_member(123)
- %ClusterMember{}
-
- iex> get_cluster_member(456)
- nil
-
- """
- @spec get_cluster_member(ClusterMember.id()) :: ClusterMember.t() | nil
- @spec get_cluster_member(ClusterMember.id(), Teiserver.query_args()) :: ClusterMember.t() | nil
- def get_cluster_member(cluster_member_id, query_args \\ []) do
- (query_args ++ [id: cluster_member_id])
- |> ClusterMemberQueries.cluster_member_query()
- |> Repo.one()
- end
-
- @doc """
- Creates a cluster_member.
-
- ## Examples
-
- iex> create_cluster_member(%{field: value})
- {:ok, %ClusterMember{}}
-
- iex> create_cluster_member(%{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec create_cluster_member(map) :: {:ok, ClusterMember.t()} | {:error, Ecto.Changeset.t()}
- def create_cluster_member(attrs \\ %{}) do
- %ClusterMember{}
- |> ClusterMember.changeset(attrs)
- |> Repo.insert()
- end
-
- @doc """
- Updates a cluster_member.
-
- ## Examples
-
- iex> update_cluster_member(cluster_member, %{field: new_value})
- {:ok, %ClusterMember{}}
-
- iex> update_cluster_member(cluster_member, %{field: bad_value})
- {:error, %Ecto.Changeset{}}
-
- """
- @spec update_cluster_member(ClusterMember.t(), map) ::
- {:ok, ClusterMember.t()} | {:error, Ecto.Changeset.t()}
- def update_cluster_member(%ClusterMember{} = cluster_member, attrs) do
- cluster_member
- |> ClusterMember.changeset(attrs)
- |> Repo.update()
- end
-
- @doc """
- Deletes a cluster_member.
-
- ## Examples
-
- iex> delete_cluster_member(cluster_member)
- {:ok, %ClusterMember{}}
-
- iex> delete_cluster_member(cluster_member)
- {:error, %Ecto.Changeset{}}
-
- """
- @spec delete_cluster_member(ClusterMember.t()) ::
- {:ok, ClusterMember.t()} | {:error, Ecto.Changeset.t()}
- def delete_cluster_member(%ClusterMember{} = cluster_member) do
- Repo.delete(cluster_member)
- end
-
- @doc """
- Returns an `%Ecto.Changeset{}` for tracking cluster_member changes.
-
- ## Examples
-
- iex> change_cluster_member(cluster_member)
- %Ecto.Changeset{data: %ClusterMember{}}
-
- """
- @spec change_cluster_member(ClusterMember.t(), map) :: Ecto.Changeset.t()
- def change_cluster_member(%ClusterMember{} = cluster_member, attrs \\ %{}) do
- ClusterMember.changeset(cluster_member, attrs)
- end
-end
diff --git a/lib/teiserver/system/queries/cluster_member_queries.ex b/lib/teiserver/system/queries/cluster_member_queries.ex
deleted file mode 100644
index 5192f12f5..000000000
--- a/lib/teiserver/system/queries/cluster_member_queries.ex
+++ /dev/null
@@ -1,98 +0,0 @@
-defmodule Teiserver.System.ClusterMemberQueries do
- @moduledoc false
- use TeiserverMacros, :queries
- alias Teiserver.System.ClusterMember
- require Logger
-
- @spec cluster_member_query(Teiserver.query_args()) :: Ecto.Query.t()
- def cluster_member_query(args) do
- query = from(cluster_members in ClusterMember)
-
- query
- |> do_where(id: args[:id])
- |> do_where(args[:where])
- |> do_order_by(args[:order_by])
- |> QueryHelper.query_select(args[:select])
- |> QueryHelper.limit_query(args[:limit] || 50)
- end
-
- @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t()
- def do_where(query, nil), do: query
-
- def do_where(query, params) do
- params
- |> Enum.reduce(query, fn {key, value}, query_acc ->
- _where(query_acc, key, value)
- end)
- end
-
- @spec _where(Ecto.Query.t(), atom, any()) :: Ecto.Query.t()
- def _where(query, _, ""), do: query
- def _where(query, _, nil), do: query
-
- def _where(query, :id, id_list) when is_list(id_list) do
- from(cluster_members in query,
- where: cluster_members.id in ^id_list
- )
- end
-
- def _where(query, :id, id) do
- from(cluster_members in query,
- where: cluster_members.id == ^id
- )
- end
-
- def _where(query, :host, host_list) when is_list(host_list) do
- from(cluster_members in query,
- where: cluster_members.host in ^host_list
- )
- end
-
- def _where(query, :host, host) do
- from(cluster_members in query,
- where: cluster_members.host == ^host
- )
- end
-
- def _where(query, :host_not, host) do
- from(cluster_members in query,
- where: cluster_members.host != ^host
- )
- end
-
- @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
- defp do_order_by(query, nil), do: query
-
- defp do_order_by(query, params) do
- params
- |> List.wrap()
- |> Enum.reduce(query, fn key, query_acc ->
- _order_by(query_acc, key)
- end)
- end
-
- @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t()
- def _order_by(query, "Host (A-Z)") do
- from(cluster_members in query,
- order_by: [asc: cluster_members.host]
- )
- end
-
- def _order_by(query, "Host (Z-A)") do
- from(cluster_members in query,
- order_by: [desc: cluster_members.host]
- )
- end
-
- def _order_by(query, "Newest first") do
- from(cluster_members in query,
- order_by: [desc: cluster_members.inserted_at]
- )
- end
-
- def _order_by(query, "Oldest first") do
- from(cluster_members in query,
- order_by: [asc: cluster_members.inserted_at]
- )
- end
-end
diff --git a/lib/teiserver/system/schemas/cluster_member.ex b/lib/teiserver/system/schemas/cluster_member.ex
deleted file mode 100644
index dfabdbb5d..000000000
--- a/lib/teiserver/system/schemas/cluster_member.ex
+++ /dev/null
@@ -1,37 +0,0 @@
-defmodule Teiserver.System.ClusterMember do
- @moduledoc """
- # Match
- A clustering method making use of a database to setup and update the cluster.
-
- ### Attributes
-
- * `:host` - The host name, e.g. "server1.host.co.uk"
-
- """
- use TeiserverMacros, :schema
-
- @primary_key {:id, Ecto.UUID, autogenerate: true}
- schema "teiserver_cluster_members" do
- field(:host, :string)
-
- timestamps(type: :utc_datetime)
- end
-
- @type id :: Ecto.UUID.t()
-
- @type t :: %__MODULE__{
- id: id(),
- host: String.t()
- }
-
- @doc """
- Builds a changeset based on the `struct` and `params`.
- """
- @spec changeset(map()) :: Ecto.Changeset.t()
- @spec changeset(map(), map()) :: Ecto.Changeset.t()
- def changeset(struct, attrs \\ %{}) do
- struct
- |> cast(attrs, ~w(host)a)
- |> validate_required(~w(host)a)
- end
-end
diff --git a/lib/teiserver/system/servers/cluster_member_server.ex b/lib/teiserver/system/servers/cluster_member_server.ex
deleted file mode 100644
index a7a362a73..000000000
--- a/lib/teiserver/system/servers/cluster_member_server.ex
+++ /dev/null
@@ -1,158 +0,0 @@
-defmodule Teiserver.System.ClusterMemberServer do
- @moduledoc """
- The cluster manager for handling adding nodes to a cluster.
-
- You can disable this process with the config:
- ```
- config :teiserver,
- teiserver_clustering: false
- ```
- """
- use GenServer
- require Logger
- alias Teiserver.System.{ClusterMember, ClusterMemberLib}
-
- @startup_delay 500
-
- # GenServer behaviour
- def start_link(params, _opts \\ []) do
- GenServer.start_link(
- __MODULE__,
- params,
- name: __MODULE__
- )
- end
-
- @impl GenServer
- def init(_params) do
- # Make sure we are told about any nodes joining or leaving the cluster
- :net_kernel.monitor_nodes(true)
- Process.send_after(self(), {:startup, 1}, @startup_delay)
-
- {:ok, :pending}
- end
-
- @impl GenServer
- def handle_call(other, from, state) do
- Logger.warning(
- "unhandled call to ClusterMemberServer: #{inspect(other)}. From: #{inspect(from)}"
- )
-
- {:reply, :not_implemented, state}
- end
-
- @impl GenServer
- def handle_cast(other, state) do
- Logger.warning("unhandled cast to ClusterMemberServer: #{inspect(other)}.")
- {:noreply, state}
- end
-
- @impl GenServer
- def handle_info({:startup, start_count}, _state) do
- if repo_ready?() do
- host_name = Node.self() |> Atom.to_string()
-
- # If we are running one node or something goes wrong the database will have
- # a vestigial row for this node, in that case we can just leave it as is
- case ClusterMemberLib.get_cluster_member(nil, where: [host: host_name]) do
- nil ->
- ClusterMemberLib.create_cluster_member(%{
- host: host_name
- })
-
- _existing ->
- # Do nothing
- :ok
- end
-
- # Attempt to join the cluster, if there are any other Nodes "out there"....
- case attempt_to_join_cluster() do
- false ->
- :ok
-
- true ->
- Application.get_env(:teiserver, :teiserver_clustering_post_join_functions, [])
- |> Enum.each(fn post_join_function ->
- apply(post_join_function, [])
- end)
- end
-
- {:noreply, :running}
- else
- Process.send_after(self(), {:startup, start_count + 1}, @startup_delay * start_count)
- {:noreply, :pending}
- end
- end
-
- def handle_info({:nodeup, node_name}, state) do
- Logger.info("nodeup message to ClusterMemberServer: #{inspect(node_name)}.")
- {:noreply, state}
- end
-
- @impl GenServer
- def handle_info({:nodedown, node_name}, state) do
- node_to_remove = Atom.to_string(node_name)
- ClusterMemberLib.delete_cluster_member(node_to_remove)
- Logger.warning("nodedown message to ClusterMemberServer: #{inspect(node_name)}.")
- {:noreply, state}
- end
-
- @impl GenServer
- def handle_info(other, state) do
- Logger.warning("unhandled message to ClusterMemberServer: #{inspect(other)}.")
- {:noreply, state}
- end
-
- @spec attempt_to_join_cluster() :: boolean()
- defp attempt_to_join_cluster() do
- host_name = Node.self() |> Atom.to_string()
-
- case ClusterMemberLib.list_cluster_members(where: [host_not: host_name], limit: :infinity) do
- [] ->
- Logger.info("Empty cluster, no join has taken place: #{inspect(Node.self())}")
- false
-
- members ->
- members
- |> Enum.reduce_while(false, &attempt_connection/2)
- |> case do
- true ->
- Logger.info("Node successfully joined the cluster: #{inspect(Node.self())}")
- true
-
- false ->
- names =
- members
- |> Enum.map_join(", ", fn m -> m.host end)
-
- Logger.error(
- "Node #{inspect(Node.self())} failed to successfully join the cluster, tried: #{names}"
- )
-
- false
- end
- end
- end
-
- @spec attempt_connection(ClusterMember.t(), boolean()) :: {:halt | :cont, boolean()}
- defp attempt_connection(%ClusterMember{host: host}, acc) do
- case Node.connect(String.to_atom(host)) do
- true ->
- {:halt, true}
-
- false ->
- {:cont, acc}
-
- :ignored ->
- {:cont, acc}
- end
- end
-
- @spec repo_ready?() :: boolean
- defp repo_ready?() do
- case Ecto.Repo.all_running() do
- [] -> false
- _ready -> true
- end
- end
-end
diff --git a/lib/teiserver/system/servers/cluster_member_supervisor.ex b/lib/teiserver/system/servers/cluster_member_supervisor.ex
deleted file mode 100644
index c3efd3c84..000000000
--- a/lib/teiserver/system/servers/cluster_member_supervisor.ex
+++ /dev/null
@@ -1,57 +0,0 @@
-defmodule Teiserver.System.ClusterManagerSupervisor do
- @moduledoc """
- The dynamic supervisor for the ClusterManager
- """
- use DynamicSupervisor
- require Logger
-
- def start_link(init_arg) do
- DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
- end
-
- @impl true
- def init(_init_arg) do
- DynamicSupervisor.init(
- strategy: :one_for_one,
- max_restarts: 10000,
- max_seconds: 1
- )
- end
-
- @spec start_cluster_manager_supervisor_children() ::
- :ok | {:error, :start_failure}
- def start_cluster_manager_supervisor_children() do
- # Start up the Cluster Manager
- result = start_cluster_manager()
-
- children_count =
- DynamicSupervisor.count_children(Teiserver.System.ClusterManagerSupervisor)
-
- Logger.info(
- "#{__MODULE__} Supervisor startup completed. Child data:#{inspect(children_count)}"
- )
-
- result
- end
-
- @spec start_cluster_manager() :: :ok | {:error, :start_failure}
- defp start_cluster_manager() do
- case DynamicSupervisor.start_child(
- __MODULE__,
- {Teiserver.System.ClusterMemberServer, []}
- ) do
- {:ok, _pid} ->
- :ok
-
- {:ok, _pid, _info} ->
- :ok
-
- {:error, {:already_started, _pid}} ->
- :ok
-
- error ->
- Logger.error("Failed to start Cluster Manager, error:#{inspect(error)}.")
- {:error, :start_failure}
- end
- end
-end
From 3e24bf0f28d7daf6400a6e364255194f9235b76a Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 15 Jul 2024 22:34:29 +0100
Subject: [PATCH 45/64] Improved some tests
---
test/api_test.exs | 10 ++++++----
test/connections/client_lib_test.exs | 17 +++++++++++++++++
test/support/fixtures/account_fixtures.ex | 1 -
3 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/test/api_test.exs b/test/api_test.exs
index b717e7195..c8b159bc3 100644
--- a/test/api_test.exs
+++ b/test/api_test.exs
@@ -4,7 +4,7 @@ defmodule ApiTest do
use Teiserver.Case, async: true
alias Phoenix.PubSub
- alias Teiserver.Api
+ alias Teiserver.{Api, Connections}
alias Teiserver.Fixtures.AccountFixtures
alias Teiserver.Account.User
@@ -104,7 +104,7 @@ defmodule ApiTest do
user = AccountFixtures.user_fixture()
conn = TestConn.new()
- client_ids = Teiserver.Connections.list_client_ids()
+ client_ids = Connections.list_client_ids()
refute Enum.member?(client_ids, user.id)
assert TestConn.get(conn) == []
@@ -113,7 +113,7 @@ defmodule ApiTest do
# Check we're subbed to the right stuff
PubSub.broadcast(
Teiserver.PubSub,
- Teiserver.Connections.client_topic(user.id),
+ Connections.client_topic(user.id),
"client_topic"
)
@@ -126,8 +126,10 @@ defmodule ApiTest do
assert TestConn.get(conn) == ["client_topic", "user_messaging_topic"]
# Check we're counted as logged in
- client_ids = Teiserver.Connections.list_client_ids()
+ client_ids = Connections.list_client_ids()
assert Enum.member?(client_ids, user.id)
+
+ assert Connections.list_client_ids() == Connections.list_local_client_ids()
end
end
diff --git a/test/connections/client_lib_test.exs b/test/connections/client_lib_test.exs
index 687aedfd4..b2abe50f6 100644
--- a/test/connections/client_lib_test.exs
+++ b/test/connections/client_lib_test.exs
@@ -6,6 +6,14 @@ defmodule Connections.ClientLibTest do
alias Teiserver.Fixtures.ConnectionFixtures
describe "ClientLib" do
+ test "topic" do
+ {_conn, user} = ConnectionFixtures.client_fixture()
+ client = Connections.get_client(user.id)
+
+ assert Connections.client_topic(user.id) == Connections.client_topic(user)
+ assert Connections.client_topic(user.id) == Connections.client_topic(client)
+ end
+
test "server lifecycle" do
{_conn, user} = ConnectionFixtures.client_fixture()
@@ -115,5 +123,14 @@ defmodule Connections.ClientLibTest do
msgs = TestConn.get(conn)
assert msgs == []
end
+
+ test "disconnect_user" do
+ {_conn1, user} = ConnectionFixtures.client_fixture()
+ {_conn2, _user} = ConnectionFixtures.client_fixture(user)
+ assert Connections.client_exists?(user.id)
+
+ Connections.disconnect_user(user.id)
+ refute Connections.client_exists?(user.id)
+ end
end
end
diff --git a/test/support/fixtures/account_fixtures.ex b/test/support/fixtures/account_fixtures.ex
index 1d8cbf307..a008f9941 100644
--- a/test/support/fixtures/account_fixtures.ex
+++ b/test/support/fixtures/account_fixtures.ex
@@ -2,7 +2,6 @@ defmodule Teiserver.Fixtures.AccountFixtures do
@moduledoc false
alias Teiserver.Account.{User, ExtraUserData}
- @spec user_fixture() :: User.t()
@spec user_fixture(map) :: User.t()
def user_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
From e5a49e6557cec813e88848eec509c78228f84090 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 16 Jul 2024 00:00:56 +0100
Subject: [PATCH 46/64] mix format
---
lib/teiserver/application.ex | 2 +-
lib/teiserver/caches/type_lookup_cache.ex | 2 +-
lib/teiserver/contexts/game.ex | 24 +++++++--
.../game/libs/match_setting_type_lib.ex | 1 -
lib/teiserver/game/libs/user_choice_lib.ex | 18 +++++--
.../game/libs/user_choice_type_lib.ex | 1 -
lib/teiserver/game/schemas/match.ex | 1 -
.../settings/libs/server_setting_lib.ex | 17 +++++--
test/game/libs/user_choice_lib_test.exs | 51 +++++++++++++++----
test/support/fixtures/game_fixtures.ex | 13 ++++-
10 files changed, 102 insertions(+), 28 deletions(-)
diff --git a/lib/teiserver/application.ex b/lib/teiserver/application.ex
index c048f8c95..8268e1eba 100644
--- a/lib/teiserver/application.ex
+++ b/lib/teiserver/application.ex
@@ -40,7 +40,7 @@ defmodule Teiserver.Application do
Teiserver.Caches.UserSettingCache,
Teiserver.Caches.ServerSettingCache,
Teiserver.Caches.LoginCountCache,
- Teiserver.Caches.TypeLookupCache,
+ Teiserver.Caches.TypeLookupCache
]
opts = [strategy: :one_for_one, name: __MODULE__]
diff --git a/lib/teiserver/caches/type_lookup_cache.ex b/lib/teiserver/caches/type_lookup_cache.ex
index ec26c73d5..c250d19d1 100644
--- a/lib/teiserver/caches/type_lookup_cache.ex
+++ b/lib/teiserver/caches/type_lookup_cache.ex
@@ -15,7 +15,7 @@ defmodule Teiserver.Caches.TypeLookupCache do
children = [
add_cache(:ts_match_type_lookup, ttl: :timer.minutes(5)),
add_cache(:ts_match_setting_type_lookup, ttl: :timer.minutes(5)),
- add_cache(:ts_user_choice_type_lookup, ttl: :timer.minutes(5)),
+ add_cache(:ts_user_choice_type_lookup, ttl: :timer.minutes(5))
]
Supervisor.init(children, strategy: :one_for_all)
diff --git a/lib/teiserver/contexts/game.ex b/lib/teiserver/contexts/game.ex
index 843db7f95..416e30c29 100644
--- a/lib/teiserver/contexts/game.ex
+++ b/lib/teiserver/contexts/game.ex
@@ -423,18 +423,32 @@ defmodule Teiserver.Game do
defdelegate list_user_choices(args), to: UserChoiceLib
@doc section: :user_choice
- @spec get_user_choices_map(Teiserver.match_id(), Teiserver.user_id()) :: %{String.t() => String.t()}
+ @spec get_user_choices_map(Teiserver.match_id(), Teiserver.user_id()) :: %{
+ String.t() => String.t()
+ }
defdelegate get_user_choices_map(match_id, user_id), to: UserChoiceLib
@doc section: :user_choice
- @spec get_user_choice!(Teiserver.match_id(), Teiserver.user_id(), UserChoiceType.id(), Teiserver.query_args()) ::
+ @spec get_user_choice!(
+ Teiserver.match_id(),
+ Teiserver.user_id(),
+ UserChoiceType.id(),
+ Teiserver.query_args()
+ ) ::
UserChoice.t()
- defdelegate get_user_choice!(match_id, user_id, setting_type_id, query_args \\ []), to: UserChoiceLib
+ defdelegate get_user_choice!(match_id, user_id, setting_type_id, query_args \\ []),
+ to: UserChoiceLib
@doc section: :user_choice
- @spec get_user_choice(Teiserver.match_id(), Teiserver.user_id(), UserChoiceType.id(), Teiserver.query_args()) ::
+ @spec get_user_choice(
+ Teiserver.match_id(),
+ Teiserver.user_id(),
+ UserChoiceType.id(),
+ Teiserver.query_args()
+ ) ::
UserChoice.t() | nil
- defdelegate get_user_choice(match_id, user_id, setting_type_id, query_args \\ []), to: UserChoiceLib
+ defdelegate get_user_choice(match_id, user_id, setting_type_id, query_args \\ []),
+ to: UserChoiceLib
@doc section: :user_choice
@spec create_user_choice(map) :: {:ok, UserChoice.t()} | {:error, Ecto.Changeset.t()}
diff --git a/lib/teiserver/game/libs/match_setting_type_lib.ex b/lib/teiserver/game/libs/match_setting_type_lib.ex
index fcb055c71..7afc9f4bd 100644
--- a/lib/teiserver/game/libs/match_setting_type_lib.ex
+++ b/lib/teiserver/game/libs/match_setting_type_lib.ex
@@ -111,7 +111,6 @@ defmodule Teiserver.Game.MatchSettingTypeLib do
{:ok, value} ->
value
end
-
end
@spec do_get_or_create_match_setting_type_id(String.t()) :: MatchSettingType.id()
diff --git a/lib/teiserver/game/libs/user_choice_lib.ex b/lib/teiserver/game/libs/user_choice_lib.ex
index 865eda8ab..0dc625d7b 100644
--- a/lib/teiserver/game/libs/user_choice_lib.ex
+++ b/lib/teiserver/game/libs/user_choice_lib.ex
@@ -33,7 +33,9 @@ defmodule Teiserver.Game.UserChoiceLib do
%{}
"""
- @spec get_user_choices_map(Teiserver.match_id(), Teiserver.user_id()) :: %{String.t() => String.t()}
+ @spec get_user_choices_map(Teiserver.match_id(), Teiserver.user_id()) :: %{
+ String.t() => String.t()
+ }
def get_user_choices_map(match_id, user_id) do
list_user_choices(where: [match_id: match_id, user_id: user_id], preload: [:type])
|> Map.new(fn ms ->
@@ -55,7 +57,12 @@ defmodule Teiserver.Game.UserChoiceLib do
** (Ecto.NoResultsError)
"""
- @spec get_user_choice!(Teiserver.match_id(), Teiserver.user_id(),UserChoiceType.id(), Teiserver.query_args()) ::
+ @spec get_user_choice!(
+ Teiserver.match_id(),
+ Teiserver.user_id(),
+ UserChoiceType.id(),
+ Teiserver.query_args()
+ ) ::
UserChoice.t()
def get_user_choice!(match_id, user_id, choice_type_id, query_args \\ []) do
(query_args ++ [match_id: match_id, user_id: user_id, choice_type_id: choice_type_id])
@@ -77,7 +84,12 @@ defmodule Teiserver.Game.UserChoiceLib do
nil
"""
- @spec get_user_choice(Teiserver.match_id(), Teiserver.user_id(), UserChoiceType.id(), Teiserver.query_args()) ::
+ @spec get_user_choice(
+ Teiserver.match_id(),
+ Teiserver.user_id(),
+ UserChoiceType.id(),
+ Teiserver.query_args()
+ ) ::
UserChoice.t() | nil
def get_user_choice(match_id, user_id, choice_type_id, query_args \\ []) do
(query_args ++ [match_id: match_id, user_id: user_id, choice_type_id: choice_type_id])
diff --git a/lib/teiserver/game/libs/user_choice_type_lib.ex b/lib/teiserver/game/libs/user_choice_type_lib.ex
index 0e6dbdeac..3e7dde92c 100644
--- a/lib/teiserver/game/libs/user_choice_type_lib.ex
+++ b/lib/teiserver/game/libs/user_choice_type_lib.ex
@@ -109,7 +109,6 @@ defmodule Teiserver.Game.UserChoiceTypeLib do
{:ok, value} ->
value
end
-
end
@spec do_get_or_create_user_choice_type_id(String.t()) :: UserChoiceType.id()
diff --git a/lib/teiserver/game/schemas/match.ex b/lib/teiserver/game/schemas/match.ex
index 025e3d719..1e329a665 100644
--- a/lib/teiserver/game/schemas/match.ex
+++ b/lib/teiserver/game/schemas/match.ex
@@ -99,7 +99,6 @@ defmodule Teiserver.Game.Match do
host: Teiserver.Account.User.t(),
type_id: Teiserver.Game.MatchType.id(),
type: Teiserver.Game.MatchType.t(),
-
members: list,
settings: list,
choices: list
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index 43df14b7d..def1cf369 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -3,7 +3,13 @@ defmodule Teiserver.Settings.ServerSettingLib do
A library of functions for working with `Teiserver.Settings.ServerSetting`
"""
use TeiserverMacros, :library
- alias Teiserver.Settings.{ServerSetting, ServerSettingQueries, ServerSettingTypeLib, ServerSettingType}
+
+ alias Teiserver.Settings.{
+ ServerSetting,
+ ServerSettingQueries,
+ ServerSettingTypeLib,
+ ServerSettingType
+ }
@doc """
Returns the list of server_settings.
@@ -141,16 +147,19 @@ defmodule Teiserver.Settings.ServerSettingLib do
Teiserver.invalidate_cache(:ts_server_setting_cache, key)
:ok
end
- {:error, reason} ->
- {:error, reason}
+
+ {:error, reason} ->
+ {:error, reason}
end
end
@doc """
"""
- @spec value_is_valid?(ServerSettingType.t(), String.t() | non_neg_integer() | boolean() | nil) :: :ok | {:error, String.t()}
+ @spec value_is_valid?(ServerSettingType.t(), String.t() | non_neg_integer() | boolean() | nil) ::
+ :ok | {:error, String.t()}
def value_is_valid?(%{validator: nil}, _), do: :ok
+
def value_is_valid?(%{validator: validator_function}, value) do
validator_function.(value)
end
diff --git a/test/game/libs/user_choice_lib_test.exs b/test/game/libs/user_choice_lib_test.exs
index 0d79f82dc..a21b665c7 100644
--- a/test/game/libs/user_choice_lib_test.exs
+++ b/test/game/libs/user_choice_lib_test.exs
@@ -69,7 +69,7 @@ defmodule Teiserver.UserChoiceLibTest do
user_choice3 = GameFixtures.user_choice_fixture(%{match_id: match.id})
user_choice4 = GameFixtures.user_choice_fixture(%{user_id: user.id})
- values = Game.get_user_choices_map(match.id, user.id) |> Map.values
+ values = Game.get_user_choices_map(match.id, user.id) |> Map.values()
assert Enum.member?(values, user_choice1.value)
assert Enum.member?(values, user_choice2.value)
@@ -94,14 +94,28 @@ defmodule Teiserver.UserChoiceLibTest do
assert Enum.empty?(Game.list_user_choices(where: [match_id: match.id, user_id: user.id]))
attr_list = [
- %{match_id: match.id, type_id: GameFixtures.user_choice_type_fixture().id, user_id: user.id},
- %{match_id: match.id, type_id: GameFixtures.user_choice_type_fixture().id, user_id: user.id},
- %{match_id: match.id, type_id: GameFixtures.user_choice_type_fixture().id, user_id: user.id}
+ %{
+ match_id: match.id,
+ type_id: GameFixtures.user_choice_type_fixture().id,
+ user_id: user.id
+ },
+ %{
+ match_id: match.id,
+ type_id: GameFixtures.user_choice_type_fixture().id,
+ user_id: user.id
+ },
+ %{
+ match_id: match.id,
+ type_id: GameFixtures.user_choice_type_fixture().id,
+ user_id: user.id
+ }
]
# Now insert them
assert {:ok, %{insert_all: {3, nil}}} = Game.create_many_user_choices(attr_list)
- assert Enum.count(Game.list_user_choices(where: [match_id: match.id, user_id: user.id])) == 3
+
+ assert Enum.count(Game.list_user_choices(where: [match_id: match.id, user_id: user.id])) ==
+ 3
end
test "create_many_user_choices/1 with invalid data returns error" do
@@ -110,9 +124,21 @@ defmodule Teiserver.UserChoiceLibTest do
assert Enum.empty?(Game.list_user_choices(where: [match_id: match.id, user_id: user.id]))
attr_list = [
- %{match_id: nil, type_id: GameFixtures.user_choice_type_fixture().id, user_id: AccountFixtures.user_fixture().id},
- %{match_id: nil, type_id: GameFixtures.user_choice_type_fixture().id, user_id: AccountFixtures.user_fixture().id},
- %{match_id: nil, type_id: GameFixtures.user_choice_type_fixture().id, user_id: AccountFixtures.user_fixture().id}
+ %{
+ match_id: nil,
+ type_id: GameFixtures.user_choice_type_fixture().id,
+ user_id: AccountFixtures.user_fixture().id
+ },
+ %{
+ match_id: nil,
+ type_id: GameFixtures.user_choice_type_fixture().id,
+ user_id: AccountFixtures.user_fixture().id
+ },
+ %{
+ match_id: nil,
+ type_id: GameFixtures.user_choice_type_fixture().id,
+ user_id: AccountFixtures.user_fixture().id
+ }
]
# Now insert them
@@ -136,7 +162,11 @@ defmodule Teiserver.UserChoiceLibTest do
Game.update_user_choice(user_choice, invalid_attrs())
assert user_choice ==
- Game.get_user_choice!(user_choice.match_id, user_choice.user_id, user_choice.type_id)
+ Game.get_user_choice!(
+ user_choice.match_id,
+ user_choice.user_id,
+ user_choice.type_id
+ )
end
test "delete_user_choice/1 deletes the user_choice" do
@@ -147,7 +177,8 @@ defmodule Teiserver.UserChoiceLibTest do
Game.get_user_choice!(user_choice.match_id, user_choice.user_id, user_choice.type_id)
end
- assert Game.get_user_choice(user_choice.match_id, user_choice.user_id, user_choice.type_id) == nil
+ assert Game.get_user_choice(user_choice.match_id, user_choice.user_id, user_choice.type_id) ==
+ nil
end
test "change_user_choice/1 returns a user_choice changeset" do
diff --git a/test/support/fixtures/game_fixtures.ex b/test/support/fixtures/game_fixtures.ex
index d9f171c8e..b42f8c366 100644
--- a/test/support/fixtures/game_fixtures.ex
+++ b/test/support/fixtures/game_fixtures.ex
@@ -2,7 +2,18 @@ defmodule Teiserver.Fixtures.GameFixtures do
@moduledoc false
alias Teiserver.Fixtures.AccountFixtures
alias Teiserver.Game
- alias Teiserver.Game.{Lobby, Match, MatchType, MatchMembership, MatchSettingType, MatchSetting, UserChoice, UserChoiceType}
+
+ alias Teiserver.Game.{
+ Lobby,
+ Match,
+ MatchType,
+ MatchMembership,
+ MatchSettingType,
+ MatchSetting,
+ UserChoice,
+ UserChoiceType
+ }
+
import Teiserver.Fixtures.AccountFixtures, only: [user_fixture: 0]
import Teiserver.Fixtures.ConnectionFixtures, only: [client_fixture: 0]
From 72af724e7ee084825cc022b549d961a7a031f3cf Mon Sep 17 00:00:00 2001
From: Teifion
Date: Wed, 24 Jul 2024 19:03:22 +0100
Subject: [PATCH 47/64] Fixed a bug with a test
---
mix.exs | 1 +
test/api_test.exs | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/mix.exs b/mix.exs
index c0951755e..40bc415a9 100644
--- a/mix.exs
+++ b/mix.exs
@@ -276,6 +276,7 @@ defmodule Teiserver.MixProject do
# Oban has these and seems to do a really nice job so we're going to use them too
# bench: "run bench/bench_helper.exs",
release: [
+ "format --check-formatted",
"cmd git tag v#{@version}",
"cmd git push",
"cmd git push --tags",
diff --git a/test/api_test.exs b/test/api_test.exs
index c8b159bc3..439a0cab6 100644
--- a/test/api_test.exs
+++ b/test/api_test.exs
@@ -129,7 +129,7 @@ defmodule ApiTest do
client_ids = Connections.list_client_ids()
assert Enum.member?(client_ids, user.id)
- assert Connections.list_client_ids() == Connections.list_local_client_ids()
+ assert Enum.sort(Connections.list_client_ids()) == Enum.sort(Connections.list_local_client_ids())
end
end
From c9ca19b8f5ca579eb9eff534a57400f3cc44ae7f Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 6 Aug 2024 10:45:14 +0100
Subject: [PATCH 48/64] Added defdelegate for some settings to Teiserver
directly
---
lib/teiserver.ex | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 51188a2fe..881c78f77 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -84,6 +84,14 @@ defmodule Teiserver do
to_string(Application.get_env(:teiserver, :node_name) || Node.self())
end
+ # Server settings
+ @spec get_server_setting_value(String.t()) :: String.t() | integer() | boolean() | nil
+ defdelegate get_server_setting_value(key), to: Teiserver.Settings.ServerSettingLib
+
+ @spec get_user_setting_value(user_id(), String.t()) ::
+ String.t() | integer() | boolean() | nil
+ defdelegate get_user_setting_value(user_id, key), to: Teiserver.Settings.UserSettingLib
+
# PubSub delegation
@doc false
@spec broadcast(String.t(), map()) :: :ok
From 8acd3a939189add378bc7015b0d71b575cd7b7f6 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 6 Aug 2024 12:59:22 +0100
Subject: [PATCH 49/64] Deprecated Teiserver.Api
---
CHANGELOG.md | 3 +-
lib/teiserver.ex | 355 +++++++++++++++++++++++++++++++++++++++-
lib/teiserver/api.ex | 382 -------------------------------------------
mix.exs | 1 -
4 files changed, 349 insertions(+), 392 deletions(-)
delete mode 100644 lib/teiserver/api.ex
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 06c426773..4a99ea3e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,10 +9,11 @@
- Added more options for connecting clients (currently just `bot?`)
- Added support for Angen to provide guest accounts
- Added caching for some db calls
-- Changed server settings to use `text` type behind the scenes and added ability to validate themz
+- Changed server settings to use `text` type behind the scenes and added ability to validate them
- Added `player_count` as a property to matches
- Added concept of user choices to represent pre-game choices made by users (e.g. in-game faction)
- Removed clustering code so it can be handled by the application using Teiserver as a library
+- Moved everything from `Teiserver.Api` to `Teiserver`
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 881c78f77..2edf0a984 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -71,11 +71,6 @@ defmodule Teiserver do
f.()
end
- @spec deterministic_uuid(String.t()) :: String.t()
- def deterministic_uuid(base) do
- UUID.uuid5(nil, base)
- end
-
@doc """
Gets the custom node name as set in the config `:teiserver, :node_name`
"""
@@ -84,13 +79,357 @@ defmodule Teiserver do
to_string(Application.get_env(:teiserver, :node_name) || Node.self())
end
- # Server settings
+
+ alias Teiserver.{Account, Communication, Connections, Game}
+
+ alias Account.{
+ User,
+ UserLib
+ }
+
+ alias Connections.ClientLib
+
+ alias Communication.{
+ Room,
+ RoomLib,
+ RoomMessage,
+ RoomMessageLib,
+ DirectMessage,
+ DirectMessageLib,
+ MatchMessage,
+ MatchMessageLib
+ }
+
+ alias Game.{
+ Lobby,
+ LobbySummary,
+ LobbyLib,
+ Match,
+ MatchLib
+ }
+
+ @doc """
+ Takes a email and password, tries to authenticate the user.
+
+ Optionally accepts an IP for rate limiting purposes.
+
+ ## Examples
+
+ iex> maybe_authenticate_user_by_email("alice@domain", "password1", "127.0.0.1")
+ {:ok, %User{}}
+
+ iex> maybe_authenticate_user_by_email("bob@domain", "bad password", "127.0.0.1")
+ {:error, :bad_password}
+
+ iex> maybe_authenticate_user_by_email("chris@domain", "password1", "127.0.0.1")
+ {:error, :no_user}
+ """
+ @doc section: :user
+ @spec maybe_authenticate_user_by_email(String.t(), String.t(), String.t() | nil) ::
+ {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
+ def maybe_authenticate_user_by_email(email, password, ip \\ nil) do
+ case Account.get_user_by_email(email) do
+ nil ->
+ {:error, :no_user}
+
+ user ->
+ do_maybe_authenticate_user(user, password, ip)
+ end
+ end
+
+ @doc """
+ Takes a id and password, tries to authenticate the user.
+
+ Optionally accepts an IP for rate limiting purposes.
+
+ ## Examples
+
+ iex> maybe_authenticate_user_by_id("a5f2e06b-a89b-45b2-aeae-87e45d02f8f8", "password1", "127.0.0.1")
+ {:ok, %User{}}
+
+ iex> maybe_authenticate_user_by_id("7f50a62b-1e7c-440a-b851-5dc076f1a6cc", "bad password", "127.0.0.1")
+ {:error, :bad_password}
+
+ iex> maybe_authenticate_user_by_id("f8cfc144-eb45-4b09-b738-07705baae6c8", "password1", "127.0.0.1")
+ {:error, :no_user}
+ """
+ @doc section: :user
+ @spec maybe_authenticate_user_by_id(String.t(), String.t(), String.t() | nil) ::
+ {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
+ def maybe_authenticate_user_by_id(id, password, ip \\ nil) do
+ case Account.get_user_by_id(id) do
+ nil ->
+ {:error, :no_user}
+
+ user ->
+ do_maybe_authenticate_user(user, password, ip)
+ end
+ end
+
+ @spec do_maybe_authenticate_user(Account.User.t(), String.t(), String.t() | nil) ::
+ {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
+ defp do_maybe_authenticate_user(user, password, ip) do
+ rate_limit_allow? = UserLib.allow_login_attempt?(user.id, ip)
+
+ result =
+ if rate_limit_allow? do
+ if Account.valid_password?(user, password) do
+ {:ok, user}
+ else
+ {:error, :bad_password}
+ end
+ else
+ {:error, :rate_limit}
+ end
+
+ # We might want to register the failed login attempt
+ case result do
+ {:error, reason} ->
+ UserLib.register_failed_login(user.id, ip, reason)
+
+ _ ->
+ :ok
+ end
+
+ result
+ end
+
+ @doc """
+ Makes use of `Teiserver.Connections.ClientLib.connect_user/1` to connect
+ and then also subscribes you to the following pubsubs:
+ - [Teiserver.Connections.Client](documentation/pubsubs/client.md#teiserver-connections-client-user_id)
+ - [Teiserver.Communication.User](documentation/pubsubs/communication.md#teiserver-communication-user-user_id)
+
+ Always returns `:ok`
+ """
+ @doc section: :client
+ @spec connect_user(user_id(), list) :: Connections.Client.t() | nil
+ def connect_user(user_id, opts \\ []) when is_binary(user_id) do
+ client = Connections.connect_user(user_id, opts)
+
+ if client != nil do
+ # Sleep to prevent this current process getting the messages related to the connection
+ :timer.sleep(100)
+ subscribe(Connections.client_topic(user_id))
+ subscribe(Communication.user_messaging_topic(user_id))
+ end
+
+ # Return the client
+ client
+ end
+
+ @doc """
+ Takes a name, email and password. Creates a user with them.
+
+ ## Examples
+
+ iex> register_user("Alice", "alice@alice", "password1")
+ {:ok, %User{}}
+
+ iex> register_user("Bob", "bob@bob", "1")
+ {:error, %Ecto.Changeset{}}
+ """
+ @doc section: :user
+ @spec register_user(String.t(), String.t(), String.t()) ::
+ {:ok, User.t()} | {:error, Ecto.Changeset.t()}
+ def register_user(name, email, password) do
+ Account.register_user(%{
+ "name" => name,
+ "password" => password,
+ "email" => email
+ })
+ end
+
+ ### Account
+ @doc section: :user
+ @spec get_user_by_id(user_id()) :: User.t() | nil
+ defdelegate get_user_by_id(user_id), to: UserLib
+
+ @doc section: :user
+ @spec get_user_by_name(String.t()) :: User.t() | nil
+ defdelegate get_user_by_name(name), to: UserLib
+
+ ### Connections
+ # Client
+ @doc section: :client
+ @spec get_client(user_id()) :: Client.t() | nil
+ defdelegate get_client(user_id), to: ClientLib
+
+ @doc section: :client
+ @spec update_client(user_id(), map, String.t()) :: Client.t() | nil
+ defdelegate update_client(user_id, updates, reason), to: ClientLib
+
+ @doc section: :client
+ @spec update_client_in_lobby(user_id(), map, String.t()) :: Client.t() | nil
+ defdelegate update_client_in_lobby(user_id, updates, reason), to: ClientLib
+
+ ### Game
+ # Lobby
+ @doc section: :lobby
+ @spec subscribe_to_lobby(Lobby.id() | Lobby.t()) :: :ok
+ defdelegate subscribe_to_lobby(lobby_or_lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec unsubscribe_from_lobby(Lobby.id() | Lobby.t()) :: :ok
+ defdelegate unsubscribe_from_lobby(lobby_or_lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec lobby_exists?(Lobby.id()) :: boolean
+ defdelegate lobby_exists?(lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec get_lobby(Lobby.id()) :: Lobby.t() | nil
+ defdelegate get_lobby(lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec get_lobby_summary(Lobby.id()) :: LobbySummary.t() | nil
+ defdelegate get_lobby_summary(lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec update_lobby(Lobby.id(), map) :: :ok | nil
+ defdelegate update_lobby(lobby_id, value_map), to: LobbyLib
+
+ @doc section: :lobby
+ @spec list_lobby_ids() :: [Lobby.id()]
+ defdelegate list_lobby_ids, to: LobbyLib
+
+ @doc section: :lobby
+ @spec stream_lobby_summaries() :: Enumerable.t(LobbySummary.t())
+ defdelegate stream_lobby_summaries(), to: LobbyLib
+
+ @doc section: :lobby
+ @spec stream_lobby_summaries(map) :: Enumerable.t(LobbySummary.t())
+ defdelegate stream_lobby_summaries(filters), to: LobbyLib
+
+ @doc section: :lobby
+ @spec open_lobby(user_id(), Lobby.name()) :: {:ok, Lobby.id()} | {:error, String.t()}
+ defdelegate open_lobby(host_id, name), to: LobbyLib
+
+ @doc section: :lobby
+ @spec cycle_lobby(Lobby.id()) :: :ok
+ defdelegate cycle_lobby(lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec close_lobby(Lobby.id()) :: :ok
+ defdelegate close_lobby(lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec can_add_client_to_lobby(user_id(), Lobby.id()) :: {boolean(), String.t() | nil}
+ defdelegate can_add_client_to_lobby(user_id, lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec can_add_client_to_lobby(user_id(), Lobby.id(), String.t()) ::
+ {boolean(), String.t() | nil}
+ defdelegate can_add_client_to_lobby(user_id, lobby_id, password), to: LobbyLib
+
+ @doc section: :lobby
+ @spec add_client_to_lobby(user_id(), Lobby.id()) :: :ok | {:error, String.t()}
+ defdelegate add_client_to_lobby(user_id, lobby_id), to: LobbyLib
+
+ @doc section: :lobby
+ @spec remove_client_from_lobby(user_id(), Lobby.id()) :: :ok | nil
+ defdelegate remove_client_from_lobby(user_id, lobby_id), to: LobbyLib
+
+ # Match
+ @doc section: :match
+ @spec start_match(Teiserver.lobby_id()) :: Match.t()
+ defdelegate start_match(lobby_id), to: MatchLib
+
+ @doc section: :match
+ @spec end_match(Match.id(), map()) :: Match.t()
+ defdelegate end_match(match_id, outcome), to: MatchLib
+
+ ### Communication
+ # MatchMessage
+ @doc section: :match_message
+ @spec subscribe_to_match_messages(Match.id() | Match.t()) :: :ok
+ defdelegate subscribe_to_match_messages(match_or_match_id), to: MatchMessageLib
+
+ @doc section: :match_message
+ @spec unsubscribe_from_match_messages(Match.id() | Match.t()) :: :ok
+ defdelegate unsubscribe_from_match_messages(match_or_match_id), to: MatchMessageLib
+
+ @doc section: :match_message
+ @spec send_match_message(user_id(), Match.id(), String.t()) ::
+ {:ok, MatchMessage.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate send_match_message(sender_id, match_id, content), to: MatchMessageLib
+
+ @doc section: :match_message
+ @spec send_lobby_message(user_id(), Lobby.id(), String.t()) ::
+ {:ok, MatchMessage.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate send_lobby_message(sender_id, lobby_id, content), to: MatchMessageLib
+
+ # Room and RoomMessage
+ @doc section: :room_message
+ @spec subscribe_to_room_messages(Room.id() | Room.t()) :: :ok
+ defdelegate subscribe_to_room_messages(room_or_room_id), to: RoomMessageLib
+
+ @doc section: :room_message
+ @spec unsubscribe_from_room_messages(Room.id() | Room.t()) :: :ok
+ defdelegate unsubscribe_from_room_messages(room_or_room_id), to: RoomMessageLib
+
+ @doc section: :room_message
+ @spec get_room_by_name_or_id(Room.name_or_id()) :: Room.t() | nil
+ defdelegate get_room_by_name_or_id(room_name_or_id), to: RoomLib
+
+ @doc section: :room_message
+ @spec list_recent_room_messages(Room.id()) :: [RoomMessage.t()]
+ defdelegate list_recent_room_messages(room_name_or_id), to: RoomMessageLib
+
+ @doc section: :room_message
+ @spec send_room_message(user_id(), Room.id(), String.t()) ::
+ {:ok, RoomMessage.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate send_room_message(sender_id, room_id, content), to: RoomMessageLib
+
+ # DirectMessage
+ @doc section: :direct_message
+ @spec send_direct_message(user_id(), user_id(), String.t()) ::
+ {:ok, DirectMessage.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate send_direct_message(sender_id, to_id, content), to: DirectMessageLib
+
+ @doc section: :direct_message
+ @spec subscribe_to_user_messaging(User.id() | User.t()) :: :ok
+ defdelegate subscribe_to_user_messaging(user_or_user_id), to: DirectMessageLib
+
+ @doc section: :direct_message
+ @spec unsubscribe_from_user_messaging(User.id() | User.t()) :: :ok
+ defdelegate unsubscribe_from_user_messaging(user_or_user_id), to: DirectMessageLib
+
+ # Settings
+ alias Teiserver.Settings.{ServerSettingLib, UserSettingLib}
+
+ @doc section: :server_setting
@spec get_server_setting_value(String.t()) :: String.t() | integer() | boolean() | nil
- defdelegate get_server_setting_value(key), to: Teiserver.Settings.ServerSettingLib
+ defdelegate get_server_setting_value(key), to: ServerSettingLib
+ @doc section: :server_setting
+ @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) ::
+ :ok
+ defdelegate set_server_setting_value(key, value), to: ServerSettingLib
+
+ @doc section: :user_setting
@spec get_user_setting_value(user_id(), String.t()) ::
String.t() | integer() | boolean() | nil
- defdelegate get_user_setting_value(user_id, key), to: Teiserver.Settings.UserSettingLib
+ defdelegate get_user_setting_value(user_id, key), to: UserSettingLib
+
+ @doc section: :user_setting
+ @spec set_user_setting_value(
+ user_id(),
+ String.t(),
+ String.t() | non_neg_integer() | boolean() | nil
+ ) :: :ok
+ defdelegate set_user_setting_value(user_id, key, value), to: UserSettingLib
+
+ # Logging
+ alias Teiserver.Logging.{AuditLog, AuditLogLib}
+
+ @spec create_audit_log(user_id(), String.t(), String.t(), map()) ::
+ {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate create_audit_log(user_id, ip, action, details), to: AuditLogLib
+
+ @spec create_anonymous_audit_log(String.t(), String.t(), map()) ::
+ {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
+ defdelegate create_anonymous_audit_log(ip, action, details), to: AuditLogLib
# PubSub delegation
@doc false
diff --git a/lib/teiserver/api.ex b/lib/teiserver/api.ex
deleted file mode 100644
index c865742fa..000000000
--- a/lib/teiserver/api.ex
+++ /dev/null
@@ -1,382 +0,0 @@
-defmodule Teiserver.Api do
- @moduledoc """
- A set of functions for a basic usage of Teiserver. The purpose is
- to allow you to start with importing only this module and then
- import others as your needs grow more complex.
- """
-
- alias Teiserver.{Account, Communication, Connections}
- alias Account.UserLib
-
- alias Connections.ClientLib
-
- alias Communication.{
- Room,
- RoomLib,
- RoomMessage,
- RoomMessageLib,
- DirectMessage,
- DirectMessageLib,
- MatchMessage,
- MatchMessageLib
- }
-
- alias Teiserver.Game.{
- Lobby,
- LobbyLib,
- Match,
- MatchLib
- }
-
- @doc """
- Takes a name and password, tries to authenticate the user.
-
- Optionally accepts an IP for rate limiting purposes.
-
- ## Examples
-
- iex> maybe_authenticate_user_by_name("Alice", "password1", "127.0.0.1")
- {:ok, %User{}}
-
- iex> maybe_authenticate_user_by_name("Bob", "bad password", "127.0.0.1")
- {:error, :bad_password}
-
- iex> maybe_authenticate_user_by_name("Chris", "password1", "127.0.0.1")
- {:error, :no_user}
- """
- @doc section: :user
- @spec maybe_authenticate_user_by_name(String.t(), String.t(), String.t() | nil) ::
- {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
- def maybe_authenticate_user_by_name(name, password, ip \\ nil) do
- case Account.get_user_by_name(name) do
- nil ->
- {:error, :no_user}
-
- user ->
- do_maybe_authenticate_user(user, password, ip)
- end
- end
-
- @doc """
- Takes a email and password, tries to authenticate the user.
-
- Optionally accepts an IP for rate limiting purposes.
-
- ## Examples
-
- iex> maybe_authenticate_user_by_email("alice@domain", "password1", "127.0.0.1")
- {:ok, %User{}}
-
- iex> maybe_authenticate_user_by_email("bob@domain", "bad password", "127.0.0.1")
- {:error, :bad_password}
-
- iex> maybe_authenticate_user_by_email("chris@domain", "password1", "127.0.0.1")
- {:error, :no_user}
- """
- @doc section: :user
- @spec maybe_authenticate_user_by_email(String.t(), String.t(), String.t() | nil) ::
- {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
- def maybe_authenticate_user_by_email(email, password, ip \\ nil) do
- case Account.get_user_by_email(email) do
- nil ->
- {:error, :no_user}
-
- user ->
- do_maybe_authenticate_user(user, password, ip)
- end
- end
-
- @doc """
- Takes a id and password, tries to authenticate the user.
-
- Optionally accepts an IP for rate limiting purposes.
-
- ## Examples
-
- iex> maybe_authenticate_user_by_id("a5f2e06b-a89b-45b2-aeae-87e45d02f8f8", "password1", "127.0.0.1")
- {:ok, %User{}}
-
- iex> maybe_authenticate_user_by_id("7f50a62b-1e7c-440a-b851-5dc076f1a6cc", "bad password", "127.0.0.1")
- {:error, :bad_password}
-
- iex> maybe_authenticate_user_by_id("f8cfc144-eb45-4b09-b738-07705baae6c8", "password1", "127.0.0.1")
- {:error, :no_user}
- """
- @doc section: :user
- @spec maybe_authenticate_user_by_id(String.t(), String.t(), String.t() | nil) ::
- {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
- def maybe_authenticate_user_by_id(id, password, ip \\ nil) do
- case Account.get_user_by_id(id) do
- nil ->
- {:error, :no_user}
-
- user ->
- do_maybe_authenticate_user(user, password, ip)
- end
- end
-
- @spec do_maybe_authenticate_user(Account.User.t(), String.t(), String.t() | nil) ::
- {:ok, Account.User.t()} | {:error, :no_user | :bad_password | :rate_limit}
- defp do_maybe_authenticate_user(user, password, ip) do
- rate_limit_allow? = UserLib.allow_login_attempt?(user.id, ip)
-
- result =
- if rate_limit_allow? do
- if Teiserver.Account.valid_password?(user, password) do
- {:ok, user}
- else
- {:error, :bad_password}
- end
- else
- {:error, :rate_limit}
- end
-
- # We might want to register the failed login attempt
- case result do
- {:error, reason} ->
- UserLib.register_failed_login(user.id, ip, reason)
-
- _ ->
- :ok
- end
-
- result
- end
-
- @doc """
- Makes use of `Teiserver.Connections.ClientLib.connect_user/1` to connect
- and then also subscribes you to the following pubsubs:
- - [Teiserver.Connections.Client](documentation/pubsubs/client.md#teiserver-connections-client-user_id)
- - [Teiserver.Communication.User](documentation/pubsubs/communication.md#teiserver-communication-user-user_id)
-
- Always returns `:ok`
- """
- @doc section: :client
- @spec connect_user(Teiserver.user_id(), list) :: Connections.Client.t() | nil
- def connect_user(user_id, opts \\ []) when is_binary(user_id) do
- client = Connections.connect_user(user_id, opts)
-
- if client do
- # Sleep to prevent this current process getting the messages related to the connection
- :timer.sleep(100)
- Teiserver.subscribe(Connections.client_topic(user_id))
- Teiserver.subscribe(Communication.user_messaging_topic(user_id))
- end
-
- # Return the client
- client
- end
-
- @doc """
- Takes a name, email and password. Creates a user with them.
-
- ## Examples
-
- iex> register_user("Alice", "alice@alice", "password1")
- {:ok, %User{}}
-
- iex> register_user("Bob", "bob@bob", "1")
- {:error, %Ecto.Changeset{}}
- """
- @doc section: :user
- @spec register_user(String.t(), String.t(), String.t()) ::
- {:ok, User.t()} | {:error, Ecto.Changeset.t()}
- def register_user(name, email, password) do
- Teiserver.Account.register_user(%{
- "name" => name,
- "password" => password,
- "email" => email
- })
- end
-
- ### Account
- @doc section: :user
- @spec get_user_by_id(Teiserver.user_id()) :: User.t() | nil
- defdelegate get_user_by_id(user_id), to: UserLib
-
- @doc section: :user
- @spec get_user_by_name(String.t()) :: User.t() | nil
- defdelegate get_user_by_name(name), to: UserLib
-
- ### Connections
- # Client
- @doc section: :client
- @spec get_client(Teiserver.user_id()) :: Client.t() | nil
- defdelegate get_client(user_id), to: ClientLib
-
- @doc section: :client
- @spec update_client(Teiserver.user_id(), map, String.t()) :: Client.t() | nil
- defdelegate update_client(user_id, updates, reason), to: ClientLib
-
- @doc section: :client
- @spec update_client_in_lobby(Teiserver.user_id(), map, String.t()) :: Client.t() | nil
- defdelegate update_client_in_lobby(user_id, updates, reason), to: ClientLib
-
- ### Game
- # Lobby
- @doc section: :lobby
- @spec subscribe_to_lobby(Lobby.id() | Lobby.t()) :: :ok
- defdelegate subscribe_to_lobby(lobby_or_lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec unsubscribe_from_lobby(Lobby.id() | Lobby.t()) :: :ok
- defdelegate unsubscribe_from_lobby(lobby_or_lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec lobby_exists?(Lobby.id()) :: boolean
- defdelegate lobby_exists?(lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec get_lobby(Lobby.id()) :: Lobby.t() | nil
- defdelegate get_lobby(lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec get_lobby_summary(Lobby.id()) :: LobbySummary.t() | nil
- defdelegate get_lobby_summary(lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec update_lobby(Lobby.id(), map) :: :ok | nil
- defdelegate update_lobby(lobby_id, value_map), to: LobbyLib
-
- @doc section: :lobby
- @spec list_lobby_ids() :: [Lobby.id()]
- defdelegate list_lobby_ids, to: LobbyLib
-
- @doc section: :lobby
- @spec stream_lobby_summaries() :: Enumerable.t(LobbySummary.t())
- defdelegate stream_lobby_summaries(), to: LobbyLib
-
- @doc section: :lobby
- @spec stream_lobby_summaries(map) :: Enumerable.t(LobbySummary.t())
- defdelegate stream_lobby_summaries(filters), to: LobbyLib
-
- @doc section: :lobby
- @spec open_lobby(Teiserver.user_id(), Lobby.name()) :: {:ok, Lobby.id()} | {:error, String.t()}
- defdelegate open_lobby(host_id, name), to: LobbyLib
-
- @doc section: :lobby
- @spec cycle_lobby(Lobby.id()) :: :ok
- defdelegate cycle_lobby(lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec close_lobby(Lobby.id()) :: :ok
- defdelegate close_lobby(lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id()) :: {boolean(), String.t() | nil}
- defdelegate can_add_client_to_lobby(user_id, lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) ::
- {boolean(), String.t() | nil}
- defdelegate can_add_client_to_lobby(user_id, lobby_id, password), to: LobbyLib
-
- @doc section: :lobby
- @spec add_client_to_lobby(Teiserver.user_id(), Lobby.id()) :: :ok | {:error, String.t()}
- defdelegate add_client_to_lobby(user_id, lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec remove_client_from_lobby(Teiserver.user_id(), Lobby.id()) :: :ok | nil
- defdelegate remove_client_from_lobby(user_id, lobby_id), to: LobbyLib
-
- # Match
- @doc section: :match
- @spec start_match(Teiserver.lobby_id()) :: Match.t()
- defdelegate start_match(lobby_id), to: MatchLib
-
- @doc section: :match
- @spec end_match(Match.id(), map()) :: Match.t()
- defdelegate end_match(match_id, outcome), to: MatchLib
-
- ### Communication
- # MatchMessage
- @doc section: :match_message
- @spec subscribe_to_match_messages(Match.id() | Match.t()) :: :ok
- defdelegate subscribe_to_match_messages(match_or_match_id), to: MatchMessageLib
-
- @doc section: :match_message
- @spec unsubscribe_from_match_messages(Match.id() | Match.t()) :: :ok
- defdelegate unsubscribe_from_match_messages(match_or_match_id), to: MatchMessageLib
-
- @doc section: :match_message
- @spec send_match_message(Teiserver.user_id(), Match.id(), String.t()) ::
- {:ok, MatchMessage.t()} | {:error, Ecto.Changeset.t()}
- defdelegate send_match_message(sender_id, match_id, content), to: MatchMessageLib
-
- @doc section: :match_message
- @spec send_lobby_message(Teiserver.user_id(), Lobby.id(), String.t()) ::
- {:ok, MatchMessage.t()} | {:error, Ecto.Changeset.t()}
- defdelegate send_lobby_message(sender_id, lobby_id, content), to: MatchMessageLib
-
- # Room and RoomMessage
- @doc section: :room_message
- @spec subscribe_to_room_messages(Room.id() | Room.t()) :: :ok
- defdelegate subscribe_to_room_messages(room_or_room_id), to: RoomMessageLib
-
- @doc section: :room_message
- @spec unsubscribe_from_room_messages(Room.id() | Room.t()) :: :ok
- defdelegate unsubscribe_from_room_messages(room_or_room_id), to: RoomMessageLib
-
- @doc section: :room_message
- @spec get_room_by_name_or_id(Room.name_or_id()) :: Room.t() | nil
- defdelegate get_room_by_name_or_id(room_name_or_id), to: RoomLib
-
- @doc section: :room_message
- @spec list_recent_room_messages(Room.id()) :: [RoomMessage.t()]
- defdelegate list_recent_room_messages(room_name_or_id), to: RoomMessageLib
-
- @doc section: :room_message
- @spec send_room_message(Teiserver.user_id(), Room.id(), String.t()) ::
- {:ok, RoomMessage.t()} | {:error, Ecto.Changeset.t()}
- defdelegate send_room_message(sender_id, room_id, content), to: RoomMessageLib
-
- # DirectMessage
- @doc section: :direct_message
- @spec send_direct_message(Teiserver.user_id(), Teiserver.user_id(), String.t()) ::
- {:ok, DirectMessage.t()} | {:error, Ecto.Changeset.t()}
- defdelegate send_direct_message(sender_id, to_id, content), to: DirectMessageLib
-
- @doc section: :direct_message
- @spec subscribe_to_user_messaging(User.id() | User.t()) :: :ok
- defdelegate subscribe_to_user_messaging(user_or_user_id), to: DirectMessageLib
-
- @doc section: :direct_message
- @spec unsubscribe_from_user_messaging(User.id() | User.t()) :: :ok
- defdelegate unsubscribe_from_user_messaging(user_or_user_id), to: DirectMessageLib
-
- # Settings
- alias Teiserver.Settings.{ServerSettingLib, UserSettingLib}
-
- @doc section: :server_setting
- @spec get_server_setting_value(String.t()) :: String.t() | integer() | boolean() | nil
- defdelegate get_server_setting_value(key), to: ServerSettingLib
-
- @doc section: :server_setting
- @spec set_server_setting_value(String.t(), String.t() | non_neg_integer() | boolean() | nil) ::
- :ok
- defdelegate set_server_setting_value(key, value), to: ServerSettingLib
-
- @doc section: :user_setting
- @spec get_user_setting_value(Teiserver.user_id(), String.t()) ::
- String.t() | integer() | boolean() | nil
- defdelegate get_user_setting_value(user_id, key), to: UserSettingLib
-
- @doc section: :user_setting
- @spec set_user_setting_value(
- Teiserver.user_id(),
- String.t(),
- String.t() | non_neg_integer() | boolean() | nil
- ) :: :ok
- defdelegate set_user_setting_value(user_id, key, value), to: UserSettingLib
-
- # Logging
- alias Teiserver.Logging.AuditLogLib
-
- @spec create_audit_log(Teiserver.user_id(), String.t(), String.t(), map()) ::
- {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_audit_log(user_id, ip, action, details), to: AuditLogLib
-
- @spec create_anonymous_audit_log(String.t(), String.t(), map()) ::
- {:ok, AuditLog.t()} | {:error, Ecto.Changeset.t()}
- defdelegate create_anonymous_audit_log(ip, action, details), to: AuditLogLib
-end
diff --git a/mix.exs b/mix.exs
index 40bc415a9..7bd41c22c 100644
--- a/mix.exs
+++ b/mix.exs
@@ -246,7 +246,6 @@ defmodule Teiserver.MixProject do
{:timex, "~> 3.7.5"},
{:typedstruct, "~> 0.5.2", runtime: false},
{:horde, "~> 0.9"},
- {:uuid, "~> 1.1"},
{:cachex, "~> 3.6"},
# Dev and Test stuff
From aea428415127e9b50f7042aa56f7181f8ad87c8d Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 6 Aug 2024 16:26:13 +0100
Subject: [PATCH 50/64] Fixed tests
---
lib/teiserver.ex | 1 -
test/api_test.exs | 65 ++++++++++++++++++++++-------------------------
2 files changed, 30 insertions(+), 36 deletions(-)
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 2edf0a984..01e387513 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -79,7 +79,6 @@ defmodule Teiserver do
to_string(Application.get_env(:teiserver, :node_name) || Node.self())
end
-
alias Teiserver.{Account, Communication, Connections, Game}
alias Account.{
diff --git a/test/api_test.exs b/test/api_test.exs
index 439a0cab6..a835ca63e 100644
--- a/test/api_test.exs
+++ b/test/api_test.exs
@@ -4,43 +4,36 @@ defmodule ApiTest do
use Teiserver.Case, async: true
alias Phoenix.PubSub
- alias Teiserver.{Api, Connections}
+ alias Teiserver.Connections
alias Teiserver.Fixtures.AccountFixtures
alias Teiserver.Account.User
describe "API functionality" do
- test "maybe_authenticate_user_by_name/2" do
- user = AccountFixtures.user_fixture()
-
- assert Api.maybe_authenticate_user_by_name("--- no name ---", "password") ==
- {:error, :no_user}
-
- assert Api.maybe_authenticate_user_by_name(user.name, "bad_password") ==
- {:error, :bad_password}
-
- assert Api.maybe_authenticate_user_by_name(user.name, "password") == {:ok, user}
- end
-
test "maybe_authenticate_user_by_email/2" do
user = AccountFixtures.user_fixture()
- assert Api.maybe_authenticate_user_by_email("--- no email ---", "password") ==
+ assert Teiserver.maybe_authenticate_user_by_email("--- no email ---", "password") ==
{:error, :no_user}
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password") ==
+ assert Teiserver.maybe_authenticate_user_by_email(user.email, "bad_password") ==
{:error, :bad_password}
- assert Api.maybe_authenticate_user_by_email(user.email, "password") == {:ok, user}
+ assert Teiserver.maybe_authenticate_user_by_email(user.email, "password") == {:ok, user}
end
test "maybe_authenticate_user_by_id/2" do
user = AccountFixtures.user_fixture()
- assert Api.maybe_authenticate_user_by_id("e986ed95-b46f-4ad5-8168-fdb575a623f6", "password") ==
+ assert Teiserver.maybe_authenticate_user_by_id(
+ "e986ed95-b46f-4ad5-8168-fdb575a623f6",
+ "password"
+ ) ==
{:error, :no_user}
- assert Api.maybe_authenticate_user_by_id(user.id, "bad_password") == {:error, :bad_password}
- assert Api.maybe_authenticate_user_by_id(user.id, "password") == {:ok, user}
+ assert Teiserver.maybe_authenticate_user_by_id(user.id, "bad_password") ==
+ {:error, :bad_password}
+
+ assert Teiserver.maybe_authenticate_user_by_id(user.id, "password") == {:ok, user}
end
test "maybe_authenticate_user rate limit/2" do
@@ -57,7 +50,7 @@ defmodule ApiTest do
assert Enum.empty?(logs)
# Bad login
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ assert Teiserver.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
{:error, :bad_password}
# Ensure it was logged
@@ -74,30 +67,31 @@ defmodule ApiTest do
assert log.user_id == user.id
# Now do it a few more times to trip the breaker
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ assert Teiserver.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
{:error, :bad_password}
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ assert Teiserver.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
{:error, :bad_password}
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ assert Teiserver.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
{:error, :bad_password}
- assert Api.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
+ assert Teiserver.maybe_authenticate_user_by_email(user.email, "bad_password", "my-ip") ==
{:error, :rate_limit}
end
test "register_user/3" do
# Incorrectly
- assert {:error, %Ecto.Changeset{} = _} = Api.register_user("alice", "email", "")
+ assert {:error, %Ecto.Changeset{} = _} = Teiserver.register_user("alice", "email", "")
# Correctly
- assert {:ok, %User{} = user} = Api.register_user("alice", "email", "password")
+ assert {:ok, %User{} = user} = Teiserver.register_user("alice", "email", "password")
assert user.permissions == []
assert user.name == "alice"
# Now dupe the email
- assert {:error, %Ecto.Changeset{} = _} = Api.register_user("alice", "email", "password")
+ assert {:error, %Ecto.Changeset{} = _} =
+ Teiserver.register_user("alice", "email", "password")
end
test "connect_user/1" do
@@ -108,7 +102,7 @@ defmodule ApiTest do
refute Enum.member?(client_ids, user.id)
assert TestConn.get(conn) == []
- TestConn.run(conn, fn -> Api.connect_user(user.id) end)
+ TestConn.run(conn, fn -> Teiserver.connect_user(user.id) end)
# Check we're subbed to the right stuff
PubSub.broadcast(
@@ -129,7 +123,8 @@ defmodule ApiTest do
client_ids = Connections.list_client_ids()
assert Enum.member?(client_ids, user.id)
- assert Enum.sort(Connections.list_client_ids()) == Enum.sort(Connections.list_local_client_ids())
+ assert Enum.sort(Connections.list_client_ids()) ==
+ Enum.sort(Connections.list_local_client_ids())
end
end
@@ -140,15 +135,15 @@ defmodule ApiTest do
user1 = AccountFixtures.user_fixture()
user2 = AccountFixtures.user_fixture()
- assert room == Api.get_room_by_name_or_id(room.name)
+ assert room == Teiserver.get_room_by_name_or_id(room.name)
- Api.subscribe_to_room_messages(room)
- Api.unsubscribe_from_room_messages(room)
+ Teiserver.subscribe_to_room_messages(room)
+ Teiserver.unsubscribe_from_room_messages(room)
- assert Api.list_recent_room_messages(room.id) == []
+ assert Teiserver.list_recent_room_messages(room.id) == []
- {:ok, _} = Api.send_room_message(user1.id, room.id, "Content")
- {:ok, _} = Api.send_direct_message(user1.id, user2.id, "Content")
+ {:ok, _} = Teiserver.send_room_message(user1.id, room.id, "Content")
+ {:ok, _} = Teiserver.send_direct_message(user1.id, user2.id, "Content")
end
end
end
From 9850412950c8f7589f6e7cc12c418fe9dea58e76 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 6 Aug 2024 19:26:09 +0100
Subject: [PATCH 51/64] Added missing client pubsub doc entry
---
documentation/pubsubs/client.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/documentation/pubsubs/client.md b/documentation/pubsubs/client.md
index 079636471..aa29ad9a4 100644
--- a/documentation/pubsubs/client.md
+++ b/documentation/pubsubs/client.md
@@ -47,6 +47,20 @@ Sent whenever the client leaves a lobby; if you are subscribed to this topic you
}
```
+### Disconnected client - `:client_connected`
+Sent when the client connects when previously having had no connections
+
+- `:client` - A `Teiserver.Connections.Client` of the client values
+- `:user_id` - The ID of the user (which should also be present in the topic)
+
+```elixir
+%{
+ event: :client_connected,
+ client: Client.t(),
+ user_id: User.id()
+}
+```
+
### Disconnected client - `:client_disconnected`
Sent when the client has no more connections
From dc2a960878b4b9263682550bfcb05f544b875b6e Mon Sep 17 00:00:00 2001
From: Teifion
Date: Thu, 8 Aug 2024 09:52:15 +0100
Subject: [PATCH 52/64] Minor fixes
---
lib/teiserver.ex | 4 ++++
lib/teiserver/account/queries/user_queries.ex | 7 +++++++
lib/teiserver/game/schemas/match.ex | 10 ++++++----
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 01e387513..5834c9087 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -248,6 +248,10 @@ defmodule Teiserver do
@spec get_user_by_name(String.t()) :: User.t() | nil
defdelegate get_user_by_name(name), to: UserLib
+ @doc section: :user
+ @spec get_user_by_email(String.t()) :: User.t() | nil
+ defdelegate get_user_by_email(email), to: UserLib
+
### Connections
# Client
@doc section: :client
diff --git a/lib/teiserver/account/queries/user_queries.ex b/lib/teiserver/account/queries/user_queries.ex
index fb3635104..6172016b1 100644
--- a/lib/teiserver/account/queries/user_queries.ex
+++ b/lib/teiserver/account/queries/user_queries.ex
@@ -265,4 +265,11 @@ defmodule Teiserver.Account.UserQueries do
preload: [extra_data: extra_datas]
)
end
+
+ def _preload(query, :smurf_of) do
+ from(user in query,
+ left_join: smurf_ofs in assoc(user, :smurf_of),
+ preload: [smurf_of: smurf_ofs]
+ )
+ end
end
diff --git a/lib/teiserver/game/schemas/match.ex b/lib/teiserver/game/schemas/match.ex
index 1e329a665..cd7cd96bd 100644
--- a/lib/teiserver/game/schemas/match.ex
+++ b/lib/teiserver/game/schemas/match.ex
@@ -34,11 +34,12 @@ defmodule Teiserver.Game.Match do
field(:game_name, :string)
field(:game_version, :string)
+ field(:team_count, :integer)
+ field(:team_size, :integer)
+ field(:player_count, :integer)
# Outcome
field(:winning_team, :integer)
- field(:team_count, :integer)
- field(:team_size, :integer)
field(:processed?, :boolean, default: false)
field(:ended_normally?, :boolean)
@@ -47,8 +48,9 @@ defmodule Teiserver.Game.Match do
field(:match_ended_at, :utc_datetime)
# These will be something queried enough it's worth storing as it's own value
+ # it is also possible we will want to count the duration as something other than
+ # time passed between start and end, e.g. ignoring time spent paused
field(:match_duration_seconds, :integer)
- field(:player_count, :integer)
# Memberships
field(:lobby_id, Ecto.UUID)
@@ -113,7 +115,7 @@ defmodule Teiserver.Game.Match do
struct
|> cast(
attrs,
- ~w(name tags public? rated? game_name game_version winning_team team_count team_size processed? lobby_opened_at match_started_at match_ended_at ended_normally? match_duration_seconds player_count host_id type_id lobby_id)a
+ ~w(id name tags public? rated? game_name game_version winning_team team_count team_size processed? lobby_opened_at match_started_at match_ended_at ended_normally? match_duration_seconds player_count host_id type_id lobby_id)a
)
|> validate_required(~w(public? rated? host_id)a)
end
From 6fc5cb5889fd623a629832e271c95f3fdb6acbcb Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sat, 10 Aug 2024 12:07:08 +0100
Subject: [PATCH 53/64] Extended some query options
---
lib/teiserver/game/queries/match_queries.ex | 56 ++++++++++++++++++---
1 file changed, 48 insertions(+), 8 deletions(-)
diff --git a/lib/teiserver/game/queries/match_queries.ex b/lib/teiserver/game/queries/match_queries.ex
index a81e57555..38a381130 100644
--- a/lib/teiserver/game/queries/match_queries.ex
+++ b/lib/teiserver/game/queries/match_queries.ex
@@ -104,6 +104,14 @@ defmodule Teiserver.Game.MatchQueries do
)
end
+ def _where(query, :name_like, name) do
+ uname = "%" <> name <> "%"
+
+ from(users in query,
+ where: ilike(users.name, ^uname)
+ )
+ end
+
@spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t()
defp do_order_by(query, nil), do: query
@@ -152,31 +160,63 @@ defmodule Teiserver.Game.MatchQueries do
end
@spec _preload(Ecto.Query.t(), any) :: Ecto.Query.t()
+ def _preload(query, :host) do
+ from(matches in query,
+ left_join: hosts in assoc(matches, :host),
+ preload: [host: hosts]
+ )
+ end
+
def _preload(query, :type) do
- from(match in query,
- left_join: types in assoc(match, :type),
+ from(matches in query,
+ left_join: types in assoc(matches, :type),
preload: [type: types]
)
end
def _preload(query, :members) do
- from(match in query,
- left_join: members in assoc(match, :members),
+ from(matches in query,
+ left_join: members in assoc(matches, :members),
preload: [members: members]
)
end
+ def _preload(query, :members_with_users) do
+ from(matches in query,
+ left_join: memberships in assoc(matches, :members),
+ left_join: users in assoc(memberships, :user),
+ preload: [members: {memberships, user: users}]
+ )
+ end
+
def _preload(query, :settings) do
- from(match in query,
- left_join: settings in assoc(match, :settings),
+ from(matches in query,
+ left_join: settings in assoc(matches, :settings),
preload: [settings: settings]
)
end
+ def _preload(query, :settings_with_types) do
+ from(matches in query,
+ left_join: settings in assoc(matches, :settings),
+ left_join: types in assoc(settings, :type),
+ preload: [settings: {settings, type: types}]
+ )
+ end
+
def _preload(query, :choices) do
- from(match in query,
- left_join: choices in assoc(match, :choices),
+ from(matches in query,
+ left_join: choices in assoc(matches, :choices),
preload: [choices: choices]
)
end
+
+ def _preload(query, :choices_with_users_and_types) do
+ from(matches in query,
+ left_join: choices in assoc(matches, :choices),
+ left_join: types in assoc(choices, :type),
+ left_join: users in assoc(choices, :user),
+ preload: [choices: {choices, type: types, user: users}]
+ )
+ end
end
From 429a7cb196d5654ee042223cb4a21104632181c0 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 11 Aug 2024 01:09:23 +0100
Subject: [PATCH 54/64] Undid allowing match_id to be cast in the changeset
---
lib/teiserver/game/schemas/match.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/teiserver/game/schemas/match.ex b/lib/teiserver/game/schemas/match.ex
index cd7cd96bd..962174ad8 100644
--- a/lib/teiserver/game/schemas/match.ex
+++ b/lib/teiserver/game/schemas/match.ex
@@ -115,7 +115,7 @@ defmodule Teiserver.Game.Match do
struct
|> cast(
attrs,
- ~w(id name tags public? rated? game_name game_version winning_team team_count team_size processed? lobby_opened_at match_started_at match_ended_at ended_normally? match_duration_seconds player_count host_id type_id lobby_id)a
+ ~w(name tags public? rated? game_name game_version winning_team team_count team_size processed? lobby_opened_at match_started_at match_ended_at ended_normally? match_duration_seconds player_count host_id type_id lobby_id)a
)
|> validate_required(~w(public? rated? host_id)a)
end
From fdad6252c403323839b0cb76676cb58fc9368443 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 25 Aug 2024 17:36:12 +0100
Subject: [PATCH 55/64] Added helper functions related to user restrictions
---
lib/teiserver/account/libs/user_lib.ex | 45 ++++++++++++++++++++++++++
test/account/user_lib_test.exs | 24 ++++++++++++++
2 files changed, 69 insertions(+)
diff --git a/lib/teiserver/account/libs/user_lib.ex b/lib/teiserver/account/libs/user_lib.ex
index 277e54f0b..5e153b508 100644
--- a/lib/teiserver/account/libs/user_lib.ex
+++ b/lib/teiserver/account/libs/user_lib.ex
@@ -192,6 +192,51 @@ defmodule Teiserver.Account.UserLib do
|> maybe_decache_user()
end
+ @doc """
+ Removes one or more restrictions from a user.
+
+ ## Examples
+
+ iex> unrestrict_user(user_or_user_id, ["r1", "r2"])
+ {:ok, %User{}}
+
+ """
+ @spec unrestrict_user(User.t() | User.id(), [String.t()] | String.t()) ::
+ {:ok, User.t()} | {:error, Ecto.Changeset.t()}
+ def unrestrict_user(user_or_user_id, restrictions) when is_binary(user_or_user_id),
+ do: unrestrict_user(get_user_by_id(user_or_user_id), restrictions)
+
+ def unrestrict_user(%User{} = user, restrictions_to_remove) do
+ restrictions_to_remove = List.wrap(restrictions_to_remove)
+
+ new_restrictions =
+ user.restrictions
+ |> Enum.filter(fn existing_restriction ->
+ not Enum.member?(restrictions_to_remove, existing_restriction)
+ end)
+
+ update_user(user, %{restrictions: new_restrictions})
+ end
+
+ @doc """
+ Adds one or more restrictions to a user
+
+ ## Examples
+
+ iex> remove_restrictions(user_or_user_id, ["r1", "r2"])
+ {:ok, %User{}}
+
+ """
+ @spec restrict_user(User.t() | User.id(), [String.t()] | String.t()) ::
+ {:ok, User.t()} | {:error, Ecto.Changeset.t()}
+ def restrict_user(user_or_user_id, restrictions) when is_binary(user_or_user_id),
+ do: restrict_user(get_user_by_id(user_or_user_id), restrictions)
+
+ def restrict_user(%User{} = user, restrictions) do
+ new_restrictions = Enum.uniq(user.restrictions ++ List.wrap(restrictions))
+ update_user(user, %{restrictions: new_restrictions})
+ end
+
# Clears the cache for a user after a successful database option
@spec maybe_decache_user(any()) :: any()
defp maybe_decache_user({:ok, user}) do
diff --git a/test/account/user_lib_test.exs b/test/account/user_lib_test.exs
index 98c3795a1..ce059f770 100644
--- a/test/account/user_lib_test.exs
+++ b/test/account/user_lib_test.exs
@@ -106,6 +106,30 @@ defmodule Teiserver.UserLibTest do
refute Account.valid_password?(user, "bad_password")
end
+ test "restrict_user/2 and unrestrict_user/2" do
+ user = AccountFixtures.user_fixture()
+
+ # As a string
+ Account.UserLib.restrict_user(user, "OneRestriction")
+ user = Account.get_user!(user.id)
+ assert user.restrictions == ["OneRestriction"]
+
+ # As a list
+ Account.UserLib.restrict_user(user, ["TwoRestriction"])
+ user = Account.get_user!(user.id)
+ assert user.restrictions == ["OneRestriction", "TwoRestriction"]
+
+ # Two at once, one is an overlap
+ Account.UserLib.restrict_user(user, ["TwoRestriction", "ThreeRestriction"])
+ user = Account.get_user!(user.id)
+ assert user.restrictions == ["OneRestriction", "TwoRestriction", "ThreeRestriction"]
+
+ # Now remove
+ Account.UserLib.unrestrict_user(user, ["TwoRestriction", "ThreeRestriction"])
+ user = Account.get_user!(user.id)
+ assert user.restrictions == ["OneRestriction"]
+ end
+
test "allow?/2" do
# User must have all of the required permissions
user = AccountFixtures.user_fixture(%{groups: ["perm1", "perm2"]})
From a5c4f7b59c273a55cd20c253d499ff85f72f2b84 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 26 Aug 2024 23:23:31 +0100
Subject: [PATCH 56/64] Bugfixes and test coverage
---
CHANGELOG.md | 3 +-
coveralls.json | 2 +
documentation/guides/hello_world.md | 12 ++-
documentation/guides/match_lifecycle.md | 10 +--
lib/teiserver/account/schemas/user.ex | 25 ++++--
lib/teiserver/connections/libs/client_lib.ex | 14 ++-
lib/teiserver/contexts/connections.ex | 4 +
lib/teiserver/contexts/game.ex | 4 +
lib/teiserver/game/libs/lobby_lib.ex | 20 +----
lib/teiserver/game/libs/match_lib.ex | 3 +-
lib/teiserver/game/servers/lobby_server.ex | 83 ++++++++++++------
.../settings/libs/server_setting_lib.ex | 3 +-
.../settings/libs/server_setting_type_lib.ex | 1 +
.../settings/libs/user_setting_lib.ex | 47 ++++++----
.../settings/libs/user_setting_type_lib.ex | 32 ++++++-
.../settings/schemas/user_setting_type.ex | 2 +
lib/teiserver/system/libs/startup_lib.ex | 26 ++++++
test/account/user_lib_test.exs | 85 +++++++++++++++++-
test/account/user_test.exs | 6 +-
test/api_test.exs | 2 +-
.../libs/match_message_lib_test.exs | 8 ++
test/connections/client_lib_test.exs | 36 +++++++-
test/connections/client_server_test.exs | 7 ++
test/game/libs/lobby_lib_async_test.exs | 25 ++++++
...y_lib_test.exs => lobby_lib_sync_test.exs} | 87 +++++++++++++++++--
test/game/libs/match_lib_test.exs | 9 +-
test/game/queries/match_queries_test.exs | 17 +++-
test/settings/server_setting_test.exs | 27 ++++++
test/settings/server_setting_type_test.exs | 8 ++
test/settings/user_setting_test.exs | 34 ++++++++
test/settings/user_setting_type_test.exs | 8 ++
test/support/fixtures/settings_fixtures.ex | 3 +-
32 files changed, 555 insertions(+), 98 deletions(-)
create mode 100644 test/game/libs/lobby_lib_async_test.exs
rename test/game/libs/{lobby_lib_test.exs => lobby_lib_sync_test.exs} (56%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a99ea3e3..4d23752bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,9 +7,8 @@
- Added Telemetry events
- Added rate limiting of login attempts
- Added more options for connecting clients (currently just `bot?`)
-- Added support for Angen to provide guest accounts
+- Added support for guest accounts
- Added caching for some db calls
-- Changed server settings to use `text` type behind the scenes and added ability to validate them
- Added `player_count` as a property to matches
- Added concept of user choices to represent pre-game choices made by users (e.g. in-game faction)
- Removed clustering code so it can be handled by the application using Teiserver as a library
diff --git a/coveralls.json b/coveralls.json
index 686f7f373..9c4b0ee43 100644
--- a/coveralls.json
+++ b/coveralls.json
@@ -1,6 +1,8 @@
{
"skip_files": [
"^test/.*",
+ "lib/teiserver.ex",
+ "lib/teiserver/contexts/telemetry.ex",
"lib/teiserver/migrations/*",
"lib/teiserver/helpers/file_macros.ex",
"lib/teiserver/game/servers/lobby_id_server.ex"
diff --git a/documentation/guides/hello_world.md b/documentation/guides/hello_world.md
index e13f41eb7..cdaa35c90 100644
--- a/documentation/guides/hello_world.md
+++ b/documentation/guides/hello_world.md
@@ -116,20 +116,18 @@ end
```
## Data in
-Place in `lib/hellow_world_server/tcp_in.ex`, this will handle all the commands coming in.
+Place in `lib/hello_world_server/tcp_in.ex`, this will handle all the commands coming in.
```elixir
defmodule HelloWorldServer.TcpIn do
- alias Teiserver.Api
-
def data_in("ping" <> _data, state) do
{state, "pong"}
end
def data_in("login " <> data, state) do
[name, password] = String.split(data, " ")
- case Api.maybe_authenticate_user_by_name(name, password) do
+ case Teiserver.maybe_authenticate_user_by_name(name, password) do
{:ok, user} ->
- Api.connect_user(user)
+ Teiserver.connect_user(user)
{%{state | user_id: user.id}, "You are now logged in as '#{user.name}'"}
{:error, :no_user} ->
{state, "Login failed (no user)"}
@@ -145,7 +143,7 @@ defmodule HelloWorldServer.TcpIn do
# this will do for the purposes of this example
email = to_string(:rand.uniform())
- case Api.register_user(name, email, password) do
+ case Teiserver.register_user(name, email, password) do
{:ok, _user} ->
{state, "User created, you can now login with 'login name password'"}
{:error, _} ->
@@ -192,7 +190,7 @@ end
```
## Data out
-Place in `lib/hellow_world_server/tcp_out.ex`, this will handle sending data back to our users.
+Place in `lib/hello_world_server/tcp_out.ex`, this will handle sending data back to our users.
```elixir
defmodule HelloWorldServer.TcpOut do
def data_out(msg, state) do
diff --git a/documentation/guides/match_lifecycle.md b/documentation/guides/match_lifecycle.md
index 40e28ce79..96c248fc6 100644
--- a/documentation/guides/match_lifecycle.md
+++ b/documentation/guides/match_lifecycle.md
@@ -1,8 +1,6 @@
# Match lifecycle
The main purpose of Teiserver is to facilitate running a game; as a result the Lobby and Match systems are one of the core features and have a lot of customisation and flexibility.
-In every case where the `Game` context is used there is a similar or identical function in `Api`.
-
### Overview
There are multiple stages to a match taking place, they will typically follow the below diagram.
```mermaid
@@ -48,7 +46,7 @@ The standard `update_client` only contacts the ClientServer to update values but
Lobbies have a key `:game_settings` which holds key-value map of the settings chosen for the upcoming match. These can be changed at any time prior to the match starting.
## Match start
-When the match is started and the users move into playing the game itself (which does not take place on the middleware server) a call needs to be made to `Api` or `Game` `start_match/1` (delegated to `Teiserver.Game.MatchLib.start_match/1`).
+When the match is started and the users move into playing the game itself (which does not take place on the middleware server) a call needs to be made to `Teiserver` or `Game` `start_match/1` (delegated to `Teiserver.Game.MatchLib.start_match/1`).
This will update the previously added Match object with the relevant information from the Lobby. It will create `Teiserver.Game.MatchMembership` objects for each player, create the relevant `Teiserver.Game.MatchSetting` objects (along with types) and update the Lobby to show the match as ongoing.
@@ -56,13 +54,13 @@ This will update the previously added Match object with the relevant information
While the game is ongoing the server is not directly involved except for anything the host wishes to relay to the server such as public chat or game telemetry events.
## Match end
-At the conclusion of the match players should be returned to the lobby interface and the `Api` or `Game` `end_match/2` (delegated to `Teiserver.Game.MatchLib.end_match/2`) should be called.
+At the conclusion of the match players should be returned to the lobby interface, you end it with and the `Teiserver` or `Game` `end_match/2` (delegated to `Teiserver.Game.MatchLib.end_match/2`) should be called.
This will update both the Match object and MatchMembership objects with the relevant data.
## Post game
### Close
-In some cases you will want the lobby to close in which case `Api` or `Game` `close_lobby/1` (delegated to `Teiserver.Game.LobbyLib.close_lobby/1`) should be called. This will remove everybody from the lobby and stop the lobby process.
+In some cases you will want the lobby to close in which case `Teiserver` or `Game` `close_lobby/1` (delegated to `Teiserver.Game.LobbyLib.close_lobby/1`) should be called. This will remove everybody from the lobby and stop the lobby process.
### Cycle
-If you wish to keep the lobby in existence you should call `Api` or `Game` `cycle_lobby/1` (delegated to `Teiserver.Game.LobbyLib.cycle_lobby/1`) which will create a new empty Match object for the new upcoming match.
+If you wish to keep the lobby in existence you should call `Teiserver` or `Game` `cycle_lobby/1` (delegated to `Teiserver.Game.LobbyLib.cycle_lobby/1`) which will create a new empty Match object for the new upcoming match.
diff --git a/lib/teiserver/account/schemas/user.ex b/lib/teiserver/account/schemas/user.ex
index a861d28e1..9c5c8474b 100644
--- a/lib/teiserver/account/schemas/user.ex
+++ b/lib/teiserver/account/schemas/user.ex
@@ -95,7 +95,9 @@ defmodule Teiserver.Account.User do
|> SchemaHelper.uniq_lists(~w(groups)a)
# If password isn't included we won't be doing anything with it
- if attrs["password"] == "" do
+ attr_password = Map.get(attrs, "password", Map.get(attrs, :password))
+
+ if attr_password == "" do
user
|> cast(
attrs,
@@ -166,8 +168,10 @@ defmodule Teiserver.Account.User do
attrs
|> SchemaHelper.trim_strings([:email])
+ attr_password = Map.get(attrs, "password", Map.get(attrs, :password))
+
cond do
- attrs["password"] == nil or attrs["password"] == "" ->
+ attr_password == nil or attr_password == "" ->
user
|> cast(attrs, [:name, :email])
|> validate_required([:name, :email])
@@ -176,7 +180,7 @@ defmodule Teiserver.Account.User do
"Please enter your password to change your account details."
)
- valid_password?(attrs["password"], user.password) == false ->
+ valid_password?(attr_password, user.password) == false ->
user
|> cast(attrs, [:name, :email])
|> validate_required([:name, :email])
@@ -194,8 +198,11 @@ defmodule Teiserver.Account.User do
# we ask for the existing password to be submitted as a test
# they have not left the computer unlocked or similar
def changeset(user, attrs, :change_password) do
+ attr_existing = Map.get(attrs, "existing", Map.get(attrs, :existing))
+ attr_password = Map.get(attrs, "password", Map.get(attrs, :password))
+
cond do
- attrs["existing"] == nil or attrs["existing"] == "" ->
+ attr_existing == nil or attr_existing == "" ->
user
|> change_password(attrs)
|> add_error(
@@ -203,7 +210,15 @@ defmodule Teiserver.Account.User do
"Please enter your existing password to change your password."
)
- valid_password?(attrs["existing"], user.password) == false ->
+ attr_password != attrs["password_confirmation"] ->
+ user
+ |> change_password(attrs)
+ |> add_error(
+ :password_confirmation,
+ "Password and Confirmation password do not match."
+ )
+
+ valid_password?(attr_existing, user.password) == false ->
user
|> change_password(attrs)
|> add_error(:existing, "Incorrect password")
diff --git a/lib/teiserver/connections/libs/client_lib.ex b/lib/teiserver/connections/libs/client_lib.ex
index c7b65ce26..2d0797db4 100644
--- a/lib/teiserver/connections/libs/client_lib.ex
+++ b/lib/teiserver/connections/libs/client_lib.ex
@@ -183,9 +183,17 @@ defmodule Teiserver.Connections.ClientLib do
will stop itself rather than going into a disconnected state.
"""
@spec disconnect_single_connection(Teiserver.user_id()) :: :ok
- def disconnect_single_connection(user_id) do
- cast_client(user_id, {:purposeful_disconnect, self()})
- send(self(), :disconnect)
+ def disconnect_single_connection(user_id) when is_binary(user_id) do
+ disconnect_single_connection(user_id, self())
+ end
+
+ @doc """
+ Same as `disconnect_single_connection/1` except you can define the pid which is disconnected
+ """
+ @spec disconnect_single_connection(Teiserver.user_id(), pid()) :: :ok
+ def disconnect_single_connection(user_id, pid) when is_binary(user_id) do
+ cast_client(user_id, {:purposeful_disconnect, pid})
+ send(pid, :disconnect)
end
# Process stuff
diff --git a/lib/teiserver/contexts/connections.ex b/lib/teiserver/contexts/connections.ex
index f12db9ce8..d0cfbc4ae 100644
--- a/lib/teiserver/contexts/connections.ex
+++ b/lib/teiserver/contexts/connections.ex
@@ -63,6 +63,10 @@ defmodule Teiserver.Connections do
@spec disconnect_single_connection(Teiserver.user_id()) :: :ok
defdelegate disconnect_single_connection(user_id), to: ClientLib
+ @doc section: :client
+ @spec disconnect_single_connection(Teiserver.user_id(), pid) :: :ok
+ defdelegate disconnect_single_connection(user_id, pid), to: ClientLib
+
@doc false
@spec client_exists?(Teiserver.user_id()) :: pid() | boolean
defdelegate client_exists?(user_id), to: ClientLib
diff --git a/lib/teiserver/contexts/game.ex b/lib/teiserver/contexts/game.ex
index 416e30c29..2802c41cd 100644
--- a/lib/teiserver/contexts/game.ex
+++ b/lib/teiserver/contexts/game.ex
@@ -69,6 +69,10 @@ defmodule Teiserver.Game do
@spec lobby_start_match(Lobby.id()) :: :ok
defdelegate lobby_start_match(lobby_id), to: LobbyLib
+ @doc section: :lobby
+ @spec lobby_end_match(Lobby.id(), String.t()) :: :ok
+ defdelegate lobby_end_match(lobby_id, reason \\ "normal"), to: LobbyLib
+
@doc section: :lobby
@spec close_lobby(Lobby.id()) :: :ok
defdelegate close_lobby(lobby_id), to: LobbyLib
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index 50e50b0ae..ad2bbe534 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -202,9 +202,6 @@ defmodule Teiserver.Game.LobbyLib do
client = Connections.get_client(host_id)
cond do
- host_id == nil ->
- {:error, "No host_id provided"}
-
client == nil ->
{:error, "Client is not connected"}
@@ -243,7 +240,8 @@ defmodule Teiserver.Game.LobbyLib do
end
@doc """
- Used to cycle a lobby after a match has concluded.
+ Used to cycle a lobby to a new match; typically at the end of the match you would call `lobby_end_match/1`, this function allows you to cycle a lobby for a different reason
+ should you need to.
## Examples
@@ -255,19 +253,7 @@ defmodule Teiserver.Game.LobbyLib do
"""
@spec cycle_lobby(Lobby.id()) :: :ok
def cycle_lobby(lobby_id) when is_binary(lobby_id) do
- host_id = get_lobby_attribute(lobby_id, :host_id)
-
- {:ok, match} =
- Teiserver.Game.create_match(%{
- public?: true,
- rated?: true,
- host_id: host_id,
- processed?: false,
- lobby_opened_at: Timex.now(),
- lobby_id: lobby_id
- })
-
- cast_lobby(lobby_id, {:cycle_lobby, match.id})
+ cast_lobby(lobby_id, :cycle_lobby)
end
@doc """
diff --git a/lib/teiserver/game/libs/match_lib.ex b/lib/teiserver/game/libs/match_lib.ex
index 898234246..87821443b 100644
--- a/lib/teiserver/game/libs/match_lib.ex
+++ b/lib/teiserver/game/libs/match_lib.ex
@@ -129,7 +129,8 @@ defmodule Teiserver.Game.MatchLib do
end)
# Tell the lobby server the match has ended
- Game.cycle_lobby(match.lobby_id)
+ ending_reason = if outcome.ended_normally?, do: "normal", else: "abnormal"
+ Game.lobby_end_match(match.lobby_id, ending_reason)
# Finally return the updated match
updated_match
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index 7d6d3ff46..494c22227 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -5,7 +5,7 @@ defmodule Teiserver.Game.LobbyServer do
"""
use GenServer
require Logger
- alias Teiserver.{Connections, Account}
+ alias Teiserver.{Connections, Account, Game}
alias Teiserver.Game.{Lobby, LobbyLib, LobbySummary}
alias Teiserver.Connections.{Client, ClientLib}
alias Teiserver.Helpers.MapHelper
@@ -83,36 +83,37 @@ defmodule Teiserver.Game.LobbyServer do
end
end
- def handle_cast({:cycle_lobby, match_id}, state) do
+ def handle_cast(:cycle_lobby, state) do
+ new_state = do_cycle_lobby(state)
+
+ {:noreply, new_state}
+ end
+
+ def handle_cast(:lobby_start_match, state) do
new_state =
update_lobby(state, %{
- match_id: match_id,
- match_ongoing?: false,
- match_type: nil
+ match_ongoing?: true
})
+ Teiserver.broadcast(
+ state.lobby_topic,
+ %{
+ event: :match_start,
+ match_id: state.match_id,
+ lobby_id: state.lobby_id
+ }
+ )
+
:telemetry.execute(
- [:teiserver, :lobby, :cycle],
+ [:teiserver, :lobby, :start_match],
%{},
- %{match_id: match_id, lobby_id: state.lobby_id}
+ %{match_id: state.match_id, lobby_id: state.lobby_id}
)
- # We specifically reference the original state here
- if state.match_id != nil and state.lobby.match_ongoing? do
- Teiserver.broadcast(
- state.lobby_topic,
- %{
- event: :match_end,
- match_id: state.match_id,
- lobby_id: state.lobby_id
- }
- )
- end
-
- {:noreply, %{new_state | match_id: match_id}}
+ {:noreply, new_state}
end
- def handle_cast(:lobby_start_match, state) do
+ def handle_cast({:lobby_end_match, reason}, state) do
new_state =
update_lobby(state, %{
match_ongoing?: true
@@ -121,18 +122,22 @@ defmodule Teiserver.Game.LobbyServer do
Teiserver.broadcast(
state.lobby_topic,
%{
- event: :match_start,
+ event: :match_end,
match_id: state.match_id,
- lobby_id: state.lobby_id
+ lobby_id: state.lobby_id,
+ reason: reason
}
)
:telemetry.execute(
- [:teiserver, :lobby, :start_match],
- %{},
+ [:teiserver, :lobby, :end_match],
+ %{reason: reason},
%{match_id: state.match_id, lobby_id: state.lobby_id}
)
+ # Cycle at the end of the match
+ new_state = do_cycle_lobby(new_state)
+
{:noreply, new_state}
end
@@ -209,6 +214,34 @@ defmodule Teiserver.Game.LobbyServer do
GenServer.start_link(__MODULE__, opts[:data], [])
end
+ @spec do_cycle_lobby(State.t()) :: State.t()
+ defp do_cycle_lobby(state) do
+ {:ok, match} =
+ Game.create_match(%{
+ public?: true,
+ rated?: true,
+ host_id: state.host_id,
+ processed?: false,
+ lobby_opened_at: Timex.now(),
+ lobby_id: state.lobby_id
+ })
+
+ new_state =
+ update_lobby(state, %{
+ match_id: match.id,
+ match_ongoing?: false,
+ match_type: nil
+ })
+
+ :telemetry.execute(
+ [:teiserver, :lobby, :cycle],
+ %{},
+ %{match_id: match.id, lobby_id: new_state.lobby_id}
+ )
+
+ %{new_state | match_id: match.id}
+ end
+
@spec can_add_client({Teiserver.user_id(), String.t()}, State.t()) ::
{boolean(), String.t() | nil}
defp can_add_client({user_id, password}, %{lobby: lobby} = _state) do
diff --git a/lib/teiserver/settings/libs/server_setting_lib.ex b/lib/teiserver/settings/libs/server_setting_lib.ex
index def1cf369..658ce32b3 100644
--- a/lib/teiserver/settings/libs/server_setting_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_lib.ex
@@ -3,6 +3,7 @@ defmodule Teiserver.Settings.ServerSettingLib do
A library of functions for working with `Teiserver.Settings.ServerSetting`
"""
use TeiserverMacros, :library
+ require Logger
alias Teiserver.Settings.{
ServerSetting,
@@ -118,8 +119,6 @@ defmodule Teiserver.Settings.ServerSettingLib do
defp convert_from_raw_value(raw_value, "string"), do: raw_value
defp convert_from_raw_value(raw_value, "integer") when is_integer(raw_value), do: raw_value
defp convert_from_raw_value(raw_value, "integer"), do: String.to_integer(raw_value)
- defp convert_from_raw_value(true, "boolean"), do: true
- defp convert_from_raw_value(false, "boolean"), do: false
defp convert_from_raw_value(raw_value, "boolean"), do: raw_value == "t"
defp convert_from_raw_value(_, _), do: nil
diff --git a/lib/teiserver/settings/libs/server_setting_type_lib.ex b/lib/teiserver/settings/libs/server_setting_type_lib.ex
index 02f6294ad..5430670a4 100644
--- a/lib/teiserver/settings/libs/server_setting_type_lib.ex
+++ b/lib/teiserver/settings/libs/server_setting_type_lib.ex
@@ -11,6 +11,7 @@ defmodule Teiserver.Settings.ServerSettingTypeLib do
def list_server_setting_types(keys) do
keys
|> Enum.map(&get_server_setting_type/1)
+ |> Enum.reject(&(&1 == nil))
end
@spec list_server_setting_type_keys() :: [String.t()]
diff --git a/lib/teiserver/settings/libs/user_setting_lib.ex b/lib/teiserver/settings/libs/user_setting_lib.ex
index dff91bf12..22352a436 100644
--- a/lib/teiserver/settings/libs/user_setting_lib.ex
+++ b/lib/teiserver/settings/libs/user_setting_lib.ex
@@ -124,24 +124,41 @@ defmodule Teiserver.Settings.UserSettingLib do
type = UserSettingTypeLib.get_user_setting_type(key)
raw_value = convert_to_raw_value(value, type.type)
- case get_user_setting(user_id, key) do
- nil ->
- {:ok, _} =
- create_user_setting(%{
- user_id: user_id,
- key: key,
- value: raw_value
- })
-
- :ok
-
- user_setting ->
- {:ok, _} = update_user_setting(user_setting, %{"value" => raw_value})
- Teiserver.invalidate_cache(:ts_user_setting_cache, lookup)
- :ok
+ case value_is_valid?(type, value) do
+ :ok ->
+ case get_user_setting(user_id, key) do
+ nil ->
+ {:ok, _} =
+ create_user_setting(%{
+ user_id: user_id,
+ key: key,
+ value: raw_value
+ })
+
+ :ok
+
+ user_setting ->
+ {:ok, _} = update_user_setting(user_setting, %{"value" => raw_value})
+ Teiserver.invalidate_cache(:ts_user_setting_cache, lookup)
+ :ok
+ end
+
+ {:error, reason} ->
+ {:error, reason}
end
end
+ @doc """
+
+ """
+ @spec value_is_valid?(ServerSettingType.t(), String.t() | non_neg_integer() | boolean() | nil) ::
+ :ok | {:error, String.t()}
+ def value_is_valid?(%{validator: nil}, _), do: :ok
+
+ def value_is_valid?(%{validator: validator_function}, value) do
+ validator_function.(value)
+ end
+
@spec convert_to_raw_value(String.t(), String.t()) :: String.t() | integer() | boolean() | nil
defp convert_to_raw_value(value, "string"), do: value
defp convert_to_raw_value(value, "integer"), do: to_string(value)
diff --git a/lib/teiserver/settings/libs/user_setting_type_lib.ex b/lib/teiserver/settings/libs/user_setting_type_lib.ex
index f36ab1a1d..f4c01ffdb 100644
--- a/lib/teiserver/settings/libs/user_setting_type_lib.ex
+++ b/lib/teiserver/settings/libs/user_setting_type_lib.ex
@@ -11,6 +11,7 @@ defmodule Teiserver.Settings.UserSettingTypeLib do
def list_user_setting_types(keys) do
keys
|> Enum.map(&get_user_setting_type/1)
+ |> Enum.reject(&(&1 == nil))
end
@spec list_user_setting_type_keys() :: [String.t()]
@@ -25,6 +26,34 @@ defmodule Teiserver.Settings.UserSettingTypeLib do
v
end
+ @doc """
+ ### Required keys
+ * `:key` - The string key of the setting, this is the internal name used for the setting
+ * `:label` - The user-facing label used for the setting
+ * `:section` - A string referencing how the setting should be grouped
+ * `:type` - The type of value which should be parsed out, can be one of: `string`, `boolean`, `integer`
+
+ ### Optional attributes
+ * `:permissions` - A permission set (string or list of strings) used to check if a given user can edit this setting
+ * `:choices` - A list of acceptable choices for `string` based types
+ * `:default` - The default value for a setting if one is not set, defaults to `nil`
+ * `:description` - A longer description which can be used to provide more information to users
+ * `:validator` - A function taking a single value and returning `:ok | {:error, String.t()}` of if the value given is acceptable for the setting type
+
+ ## Examples
+ ```
+ add_user_setting_type(%{
+ key: "timezone",
+ label: "Timezone",
+ section: "interface",
+ type: "integer",
+ permissions: nil,
+ default: 0,
+ description: "The timezone to convert all Times to.",
+ validator: (fn v -> if -12 <= v and v <= 14, do: :ok, else: {:error, "Timezone must be within -12 and +14 hours of UTC"} end)
+ })
+ ```
+ """
@spec add_user_setting_type(map()) :: {:ok, UserSettingType.t()} | {:error, String.t()}
def add_user_setting_type(args) do
if not Enum.member?(~w(string integer boolean), args.type) do
@@ -45,7 +74,8 @@ defmodule Teiserver.Settings.UserSettingTypeLib do
permissions: Map.get(args, :permissions),
choices: Map.get(args, :choices),
default: Map.get(args, :default),
- description: Map.get(args, :description)
+ description: Map.get(args, :description),
+ validator: Map.get(args, :validator)
}
# Update our list of all keys
diff --git a/lib/teiserver/settings/schemas/user_setting_type.ex b/lib/teiserver/settings/schemas/user_setting_type.ex
index 9ae9e6239..f79520272 100644
--- a/lib/teiserver/settings/schemas/user_setting_type.ex
+++ b/lib/teiserver/settings/schemas/user_setting_type.ex
@@ -15,6 +15,7 @@ defmodule Teiserver.Settings.UserSettingType do
* `:choices` - A list of acceptable choices for `string` based types
* `:default` - The default value for a setting if one is not set, defaults to `nil`
* `:description` - A longer description which can be used to provide more information to users
+ * `:validator` - A function taking a single value and returning a `:ok | {:error, String.t()}` of if the value given is acceptable for the setting type
"""
use TypedStruct
@@ -34,5 +35,6 @@ defmodule Teiserver.Settings.UserSettingType do
field(:choices, [String.t()] | nil, default: nil)
field(:default, String.t() | integer() | boolean | nil, default: nil)
field(:description, String.t() | nil, default: nil)
+ field(:validator, function() | nil, default: nil)
end
end
diff --git a/lib/teiserver/system/libs/startup_lib.ex b/lib/teiserver/system/libs/startup_lib.ex
index accef3b32..389f55616 100644
--- a/lib/teiserver/system/libs/startup_lib.ex
+++ b/lib/teiserver/system/libs/startup_lib.ex
@@ -27,5 +27,31 @@ defmodule Teiserver.System.StartupLib do
description:
"The upper bound on how many failed attempts a given user can have before their logins are blocked."
})
+
+ Settings.add_user_setting_type(%{
+ key: "language",
+ label: "Language",
+ section: "interface",
+ type: "string",
+ permissions: nil,
+ choices: ["English", "American", "Spanish", "Lojban", "Bork bork"],
+ default: "English",
+ description: "The language used in the interface"
+ })
+
+ Settings.add_user_setting_type(%{
+ key: "timezone",
+ label: "Timezone",
+ section: "interface",
+ type: "integer",
+ permissions: nil,
+ default: 0,
+ description: "The timezone to convert all Times to.",
+ validator: fn v ->
+ if -12 <= v and v <= 14,
+ do: :ok,
+ else: {:error, "Timezone must be within -12 and +14 hours of UTC"}
+ end
+ })
end
end
diff --git a/test/account/user_lib_test.exs b/test/account/user_lib_test.exs
index ce059f770..cf30ea22f 100644
--- a/test/account/user_lib_test.exs
+++ b/test/account/user_lib_test.exs
@@ -88,6 +88,72 @@ defmodule Teiserver.UserLibTest do
assert user == Account.get_user!(user.id)
end
+ test "update_limited_user/2 with valid data updates the user" do
+ user = AccountFixtures.user_fixture()
+
+ assert {:ok, %User{} = user} =
+ Account.update_limited_user(user, Map.put(@update_attrs, :password, "password"))
+
+ assert user.name == "some updated name"
+ assert user.permissions == []
+ assert user.name == "some updated name"
+ end
+
+ test "update_limited_user/2 requires password" do
+ user = AccountFixtures.user_fixture()
+ assert {:error, %Ecto.Changeset{}} = Account.update_limited_user(user, @update_attrs)
+ end
+
+ test "update_limited_user/2 with invalid data returns error changeset" do
+ user = AccountFixtures.user_fixture()
+ assert {:error, %Ecto.Changeset{}} = Account.update_limited_user(user, @invalid_attrs)
+ assert user == Account.get_user!(user.id)
+ end
+
+ test "update_password/2 with valid data updates the user" do
+ user = AccountFixtures.user_fixture()
+
+ assert Account.User.valid_password?("password", user.password)
+ refute Account.User.valid_password?("pleaseword123", user.password)
+
+ assert {:ok, %User{} = user} =
+ Account.update_password(user, %{
+ "password" => "pleaseword123",
+ "password_confirmation" => "pleaseword123",
+ "existing" => "password"
+ })
+
+ refute Account.User.valid_password?("password", user.password)
+ assert Account.User.valid_password?("pleaseword123", user.password)
+ end
+
+ test "update_password/2 with invalid data returns error changeset" do
+ user = AccountFixtures.user_fixture()
+ assert Account.User.valid_password?("password", user.password)
+
+ # No existing
+ assert {:error, %Ecto.Changeset{}} =
+ Account.update_password(user, %{
+ "password" => "pleaseword123",
+ "password_confirmation" => "pleaseword123"
+ })
+
+ # No confirm
+ assert {:error, %Ecto.Changeset{}} =
+ Account.update_password(user, %{
+ "password" => "pleaseword123",
+ "existing" => "password"
+ })
+
+ # Bad confirm
+ assert {:error, %Ecto.Changeset{}} =
+ Account.update_password(user, %{
+ "password" => "pleaseword123",
+ "password_confirmation" => "please",
+ "existing" => "password"
+ })
+ end
+
test "delete_user/1 deletes the user" do
user = AccountFixtures.user_fixture()
assert {:ok, %User{}} = Account.delete_user(user)
@@ -180,9 +246,26 @@ defmodule Teiserver.UserLibTest do
end
describe "user related functions" do
- test "generate password" do
+ test "generate_password/0" do
p = Account.generate_password()
assert String.length(p) > 30
end
+
+ test "generate_guest_name/0" do
+ n = Account.generate_guest_name()
+ assert String.length(n) > 6
+ assert String.contains?(n, " ")
+ end
+
+ test "user_name_acceptable?/1" do
+ assert Account.user_name_acceptable?("test name")
+ assert Account.user_name_acceptable?("a bad word here")
+
+ acceptable_test = fn n -> not String.contains?(n, "bad word") end
+ Application.put_env(:teiserver, :fn_user_name_acceptor, acceptable_test)
+
+ assert Account.user_name_acceptable?("test name")
+ refute Account.user_name_acceptable?("a bad word here")
+ end
end
end
diff --git a/test/account/user_test.exs b/test/account/user_test.exs
index cc23a9f17..134c5d3f6 100644
--- a/test/account/user_test.exs
+++ b/test/account/user_test.exs
@@ -74,7 +74,11 @@ defmodule Account.UserTest do
good_existing =
User.changeset(
user,
- %{"existing" => "password", "password" => "password1"},
+ %{
+ "existing" => "password",
+ "password" => "password1",
+ "password_confirmation" => "password1"
+ },
:change_password
)
diff --git a/test/api_test.exs b/test/api_test.exs
index a835ca63e..965ea2846 100644
--- a/test/api_test.exs
+++ b/test/api_test.exs
@@ -8,7 +8,7 @@ defmodule ApiTest do
alias Teiserver.Fixtures.AccountFixtures
alias Teiserver.Account.User
- describe "API functionality" do
+ describe "Teiserver API functionality" do
test "maybe_authenticate_user_by_email/2" do
user = AccountFixtures.user_fixture()
diff --git a/test/communication/libs/match_message_lib_test.exs b/test/communication/libs/match_message_lib_test.exs
index a0605e710..85e24d9eb 100644
--- a/test/communication/libs/match_message_lib_test.exs
+++ b/test/communication/libs/match_message_lib_test.exs
@@ -1,5 +1,6 @@
defmodule Teiserver.MatchMessageLibTest do
@moduledoc false
+ alias Teiserver.Communication.MatchMessageLib
alias Teiserver.Communication.MatchMessage
use Teiserver.Case, async: true
@@ -42,6 +43,13 @@ defmodule Teiserver.MatchMessageLibTest do
describe "match_message" do
alias Teiserver.Communication.MatchMessage
+ test "topic" do
+ match = GameFixtures.incomplete_match_fixture()
+ topic = MatchMessageLib.match_messaging_topic(match)
+ assert topic == "Teiserver.Communication.Match.#{match.id}"
+ assert MatchMessageLib.match_messaging_topic(match.id) == topic
+ end
+
test "match_message_query/1 returns query" do
assert Communication.match_message_query([])
end
diff --git a/test/connections/client_lib_test.exs b/test/connections/client_lib_test.exs
index b2abe50f6..99ff3e886 100644
--- a/test/connections/client_lib_test.exs
+++ b/test/connections/client_lib_test.exs
@@ -124,7 +124,7 @@ defmodule Connections.ClientLibTest do
assert msgs == []
end
- test "disconnect_user" do
+ test "disconnect_user/1" do
{_conn1, user} = ConnectionFixtures.client_fixture()
{_conn2, _user} = ConnectionFixtures.client_fixture(user)
assert Connections.client_exists?(user.id)
@@ -132,5 +132,39 @@ defmodule Connections.ClientLibTest do
Connections.disconnect_user(user.id)
refute Connections.client_exists?(user.id)
end
+
+ test "disconnect_single_connection/2" do
+ {conn1, user} = ConnectionFixtures.client_fixture()
+ {conn2, _user} = ConnectionFixtures.client_fixture(user)
+ assert Connections.client_exists?(user.id)
+
+ conn_list = Connections.call_client(user.id, :get_connections)
+ assert Enum.member?(conn_list, conn1)
+ assert Enum.member?(conn_list, conn2)
+
+ # Disconnect conn1
+ Connections.disconnect_single_connection(user.id, conn1)
+ assert Connections.client_exists?(user.id)
+
+ conn_list = Connections.call_client(user.id, :get_connections)
+ refute Enum.member?(conn_list, conn1)
+ assert Enum.member?(conn_list, conn2)
+
+ # Disconnect self, this should have no effect as we are not a connection
+ Connections.disconnect_single_connection(user.id, self())
+ assert Connections.client_exists?(user.id)
+
+ conn_list = Connections.call_client(user.id, :get_connections)
+ refute Enum.member?(conn_list, conn1)
+ assert Enum.member?(conn_list, conn2)
+
+ # Now get rid of conn2, this should result in the client destroying itself
+ Connections.disconnect_single_connection(user.id, conn2)
+
+ # Give it time to die
+ :timer.sleep(50)
+
+ refute Connections.client_exists?(user.id)
+ end
end
end
diff --git a/test/connections/client_server_test.exs b/test/connections/client_server_test.exs
index 8e35de66b..3b331ffc0 100644
--- a/test/connections/client_server_test.exs
+++ b/test/connections/client_server_test.exs
@@ -102,6 +102,13 @@ defmodule Connections.ClientServerTest do
test "heartbeat destroy process" do
{conn, user} = ConnectionFixtures.client_fixture()
+ # Ensure it's all here and is hunky-dory
+ client_pid = Connections.get_client_pid(user.id)
+ send(client_pid, :heartbeat)
+ :timer.sleep(100)
+
+ assert Connections.client_exists?(user.id)
+
# Kill the connecting process
TestConn.stop(conn)
diff --git a/test/game/libs/lobby_lib_async_test.exs b/test/game/libs/lobby_lib_async_test.exs
new file mode 100644
index 000000000..12bf570ef
--- /dev/null
+++ b/test/game/libs/lobby_lib_async_test.exs
@@ -0,0 +1,25 @@
+defmodule Teiserver.Game.LobbyLibAsyncTest do
+ @moduledoc false
+ use Teiserver.Case, async: true
+
+ alias Teiserver.Game
+
+ describe "LobbyLib" do
+ test "lobby_name_acceptable?/1" do
+ assert Game.lobby_name_acceptable?("test name")
+ assert Game.lobby_name_acceptable?("a bad word here")
+
+ acceptable_test = fn n -> not String.contains?(n, "bad word") end
+ Application.put_env(:teiserver, :fn_lobby_name_acceptor, acceptable_test)
+
+ assert Game.lobby_name_acceptable?("test name")
+ refute Game.lobby_name_acceptable?("a bad word here")
+ end
+
+ test "open_lobby" do
+ # This client won't exist, thus it should fail
+ assert Game.open_lobby(Teiserver.uuid(), "no-host-lobby") ==
+ {:error, "Client is not connected"}
+ end
+ end
+end
diff --git a/test/game/libs/lobby_lib_test.exs b/test/game/libs/lobby_lib_sync_test.exs
similarity index 56%
rename from test/game/libs/lobby_lib_test.exs
rename to test/game/libs/lobby_lib_sync_test.exs
index 4ea92f235..f35f75a36 100644
--- a/test/game/libs/lobby_lib_test.exs
+++ b/test/game/libs/lobby_lib_sync_test.exs
@@ -1,8 +1,9 @@
-defmodule Teiserver.Game.LobbyLibTest do
+defmodule Teiserver.Game.LobbyLibSyncTest do
@moduledoc false
- use Teiserver.Case, async: true
+ use Teiserver.Case, async: false
alias Teiserver.Game
+ alias Teiserver.Game.LobbyLib
alias Teiserver.Fixtures.{ConnectionFixtures, GameFixtures}
describe "LobbyLib" do
@@ -39,9 +40,6 @@ defmodule Teiserver.Game.LobbyLibTest do
refute Game.lobby_exists?(lobby_id2)
end
- test "open_lobby" do
- end
-
test "list_lobby_summaries" do
{_host_conn, _host_user, lobby1_id} = GameFixtures.lobby_fixture_with_process()
{_host_conn, _host_user, lobby2_id} = GameFixtures.lobby_fixture_with_process()
@@ -66,6 +64,16 @@ defmodule Teiserver.Game.LobbyLibTest do
assert Enum.member?(lobby_list_ids, lobby2_id)
refute Enum.member?(lobby_list_ids, lobby3_id)
+ # Now with a dud filter
+ lobby_list =
+ Game.stream_lobby_summaries(%{"dud-filter" => [lobby1_id, lobby2_id]}) |> Enum.to_list()
+
+ lobby_list_ids = Enum.map(lobby_list, fn l -> l.id end)
+
+ assert Enum.member?(lobby_list_ids, lobby1_id)
+ assert Enum.member?(lobby_list_ids, lobby2_id)
+ assert Enum.member?(lobby_list_ids, lobby3_id)
+
# Cleanup
Game.stop_lobby_server(lobby1_id)
Game.stop_lobby_server(lobby2_id)
@@ -79,6 +87,13 @@ defmodule Teiserver.Game.LobbyLibTest do
# The test is async so it's possible other lobbies are being created while this runs
lobby_ids = Game.list_lobby_ids()
+ local_lobby_ids = Game.list_local_lobby_ids()
+
+ # In theory we're not on a cluster so these _should_ be the same
+ # it is possible multiple tests running at once could create a lobby in between these
+ # two, if that starts happening we probably just want to retry it a few times
+ # Notably there is no promise they are in the same order so we sort them
+ assert Enum.sort(lobby_ids) == Enum.sort(local_lobby_ids)
assert Enum.member?(lobby_ids, lobby1_id)
assert Enum.member?(lobby_ids, lobby2_id)
@@ -116,5 +131,67 @@ defmodule Teiserver.Game.LobbyLibTest do
# Cleanup
Game.stop_lobby_server(lobby_id)
end
+
+ test "cast_lobby/2" do
+ {_host_conn, _host_user, lobby_id} = GameFixtures.lobby_fixture_with_process()
+
+ assert LobbyLib.cast_lobby(Teiserver.uuid(), :cycle_lobby) == nil
+ assert LobbyLib.cast_lobby(lobby_id, :cycle_lobby) == :ok
+ Game.stop_lobby_server(lobby_id)
+ end
+
+ test "stop_lobby_server/2" do
+ {_host_conn, _host_user, lobby_id} = GameFixtures.lobby_fixture_with_process()
+ assert Game.lobby_exists?(lobby_id)
+
+ assert Game.stop_lobby_server(Teiserver.uuid()) == nil
+ assert Game.lobby_exists?(lobby_id)
+
+ assert Game.stop_lobby_server(lobby_id) == :ok
+ refute Game.lobby_exists?(lobby_id)
+ end
+
+ test "lobby_end_match/1" do
+ {_host_conn, _host_user, lobby_id} = GameFixtures.lobby_fixture_with_process()
+ # Start the match so we can end it
+ LobbyLib.lobby_start_match(lobby_id)
+ :timer.sleep(1000)
+ started_state = Game.get_lobby(lobby_id)
+ assert started_state.match_ongoing?
+
+ LobbyLib.lobby_end_match(lobby_id)
+ :timer.sleep(500)
+ ended_state = Game.get_lobby(lobby_id)
+ refute ended_state.match_ongoing?
+
+ assert started_state.match_id != ended_state.match_id
+ end
+
+ test "subscriptions" do
+ {_host_conn, _host_user, lobby_id} = GameFixtures.lobby_fixture_with_process()
+ lobby = Game.get_lobby(lobby_id)
+
+ {conn1, _user1} = ConnectionFixtures.client_fixture()
+ {conn2, _user2} = ConnectionFixtures.client_fixture()
+
+ TestConn.run(conn1, fn -> Game.subscribe_to_lobby(lobby.id) end)
+
+ assert TestConn.get(conn1) == []
+ assert TestConn.get(conn2) == []
+
+ topic = Game.lobby_topic(lobby.id)
+ Teiserver.broadcast(topic, %{event: :test_message, msg: "test"})
+
+ assert TestConn.get(conn1) == [%{msg: "test", event: :test_message, topic: topic}]
+ assert TestConn.get(conn2) == []
+
+ TestConn.run(conn1, fn -> Game.unsubscribe_from_lobby(lobby.id) end)
+
+ Teiserver.broadcast(topic, %{event: :test_message, msg: "test2"})
+ assert TestConn.get(conn1) == []
+ assert TestConn.get(conn2) == []
+
+ Game.stop_lobby_server(lobby_id)
+ end
end
end
diff --git a/test/game/libs/match_lib_test.exs b/test/game/libs/match_lib_test.exs
index 8144966ff..a43b9d35b 100644
--- a/test/game/libs/match_lib_test.exs
+++ b/test/game/libs/match_lib_test.exs
@@ -118,6 +118,7 @@ defmodule Teiserver.MatchLibAsyncTest do
{_, u4} = ConnectionFixtures.client_fixture()
u5 = AccountFixtures.user_fixture()
+ assert Game.can_add_client_to_lobby(u1.id, Teiserver.uuid()) == {false, "No lobby"}
assert Game.can_add_client_to_lobby(u1.id, lobby_id) == {true, nil}
assert Game.can_add_client_to_lobby(u5.id, lobby_id) == {false, "Client is not connected"}
@@ -126,8 +127,13 @@ defmodule Teiserver.MatchLibAsyncTest do
Game.add_client_to_lobby(u3.id, lobby_id)
Game.add_client_to_lobby(u4.id, lobby_id)
+ # Just to check, if we try to add the now it says no
assert Game.can_add_client_to_lobby(u1.id, lobby_id) == {false, "Existing member"}
+ # And trying to add them anyway won't generate a problem
+ resp = Game.add_client_to_lobby(u1.id, lobby_id)
+ assert resp == {:error, "Existing member"}
+
lobby = Game.get_lobby(lobby_id)
# Ensure the member lists is as we expect
@@ -137,11 +143,8 @@ defmodule Teiserver.MatchLibAsyncTest do
# Update the clients by making them players and putting them on teams
Connections.update_client(u1.id, %{player_number: 1, team_number: 1, player?: true}, "test")
-
Connections.update_client(u2.id, %{player_number: 2, team_number: 1, player?: true}, "test")
-
Connections.update_client(u3.id, %{player_number: 3, team_number: 2, player?: true}, "test")
-
Connections.update_client(u4.id, %{player_number: 4, team_number: 2, player?: true}, "test")
# Give the lobby time to read and update
diff --git a/test/game/queries/match_queries_test.exs b/test/game/queries/match_queries_test.exs
index 06f5a7818..846af101f 100644
--- a/test/game/queries/match_queries_test.exs
+++ b/test/game/queries/match_queries_test.exs
@@ -36,6 +36,7 @@ defmodule Teiserver.MatchQueriesTest do
processed?: true,
duration_gt: 100,
duration_lt: 999,
+ name_like: "abc",
started_after: Timex.now(),
started_before: Timex.now(),
ended_after: Timex.now(),
@@ -49,7 +50,21 @@ defmodule Teiserver.MatchQueriesTest do
"Newest first",
"Oldest first"
],
- preload: [],
+ preload:
+ ~w(host type members_with_users settings_with_types choices_with_users_and_types)a,
+ limit: 10
+ )
+
+ assert all_values != @empty_query
+ Repo.all(all_values)
+
+ # Some preloads we missed last time because they conflict with the others
+ all_values =
+ MatchQueries.match_query(
+ where: [
+ id: Teiserver.uuid()
+ ],
+ preload: ~w(members settings choices)a,
limit: 10
)
diff --git a/test/settings/server_setting_test.exs b/test/settings/server_setting_test.exs
index e8dd3446f..d899f5d03 100644
--- a/test/settings/server_setting_test.exs
+++ b/test/settings/server_setting_test.exs
@@ -157,5 +157,32 @@ defmodule Teiserver.ServerSettingTest do
value = Settings.get_server_setting_value(type.key)
assert value == true
end
+
+ test "validator function" do
+ type =
+ SettingsFixtures.server_setting_type_fixture(%{
+ "type" => "string",
+ "validator" => fn v ->
+ if String.length(v) > 6, do: :ok, else: {:error, "string too short"}
+ end
+ })
+
+ _setting =
+ SettingsFixtures.server_setting_fixture(%{"type" => type, "value" => "123456789"})
+
+ value = Settings.get_server_setting_value(type.key)
+ assert value == "123456789"
+
+ result = Settings.set_server_setting_value(type.key, "abcdef")
+ assert result == {:error, "string too short"}
+
+ value = Settings.get_server_setting_value(type.key)
+ refute value == "abcdef"
+
+ result = Settings.set_server_setting_value(type.key, "abcdefdef")
+ assert result == :ok
+ value = Settings.get_server_setting_value(type.key)
+ assert value == "abcdefdef"
+ end
end
end
diff --git a/test/settings/server_setting_type_test.exs b/test/settings/server_setting_type_test.exs
index db153385a..4b1f98d52 100644
--- a/test/settings/server_setting_type_test.exs
+++ b/test/settings/server_setting_type_test.exs
@@ -67,5 +67,13 @@ defmodule Teiserver.ServerSettingTypeTest do
assert Settings.get_server_setting_type(key) == type
end
+
+ test "list types" do
+ result = Settings.list_server_setting_types(["login.user_rate_limit"])
+ assert Enum.count(result) == 1
+
+ result = Settings.list_server_setting_types(["not a type"])
+ assert Enum.empty?(result)
+ end
end
end
diff --git a/test/settings/user_setting_test.exs b/test/settings/user_setting_test.exs
index 372c21f61..52d5c753f 100644
--- a/test/settings/user_setting_test.exs
+++ b/test/settings/user_setting_test.exs
@@ -177,6 +177,40 @@ defmodule Teiserver.UserSettingTest do
value = Settings.get_user_setting_value(user_id, type.key)
assert value == true
+ assert Settings.get_user_setting_value(user_id, type.key) == value
+ end
+
+ test "validator function" do
+ user_id = AccountFixtures.user_fixture().id
+
+ type =
+ SettingsFixtures.user_setting_type_fixture(%{
+ "type" => "string",
+ "validator" => fn v ->
+ if String.length(v) > 6, do: :ok, else: {:error, "string too short"}
+ end
+ })
+
+ _setting =
+ SettingsFixtures.user_setting_fixture(%{
+ "user_id" => user_id,
+ "type" => type,
+ "value" => "123456789"
+ })
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == "123456789"
+
+ result = Settings.set_user_setting_value(user_id, type.key, "abcdef")
+ assert result == {:error, "string too short"}
+
+ value = Settings.get_user_setting_value(user_id, type.key)
+ refute value == "abcdef"
+
+ result = Settings.set_user_setting_value(user_id, type.key, "abcdefdef")
+ assert result == :ok
+ value = Settings.get_user_setting_value(user_id, type.key)
+ assert value == "abcdefdef"
end
end
end
diff --git a/test/settings/user_setting_type_test.exs b/test/settings/user_setting_type_test.exs
index fd8480759..ee893edec 100644
--- a/test/settings/user_setting_type_test.exs
+++ b/test/settings/user_setting_type_test.exs
@@ -67,5 +67,13 @@ defmodule Teiserver.UserSettingTypeTest do
assert Settings.get_user_setting_type(key) == type
end
+
+ test "list types" do
+ result = Settings.list_user_setting_types(["timezone"])
+ assert Enum.count(result) == 1
+
+ result = Settings.list_user_setting_types(["not a type"])
+ assert Enum.empty?(result)
+ end
end
end
diff --git a/test/support/fixtures/settings_fixtures.ex b/test/support/fixtures/settings_fixtures.ex
index dedaf5f99..3e47a6de3 100644
--- a/test/support/fixtures/settings_fixtures.ex
+++ b/test/support/fixtures/settings_fixtures.ex
@@ -63,7 +63,8 @@ defmodule Teiserver.Fixtures.SettingsFixtures do
permissions: data["permissions"] || nil,
choices: data["choices"] || nil,
default: data["default"] || nil,
- description: data["description"] || nil
+ description: data["description"] || nil,
+ validator: data["validator"] || nil
})
type
From 5e2a7dbe1ded5aa8c2d14fc336b61b694b5bcc3f Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 27 Aug 2024 23:11:08 +0100
Subject: [PATCH 57/64] Fixed some test config
---
config/config.exs | 2 +-
config/test.exs | 6 ------
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index 008939407..4e58536d0 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -13,7 +13,7 @@ config :teiserver, Teiserver.Test.Repo,
priv: "test/support/postgres",
url:
System.get_env("DATABASE_URL") ||
- "postgres://teiserver_test:123456789@localhost/teiserver_test"
+ "postgres://teiserver_test:postgres@localhost/teiserver_test"
config :teiserver,
# Overridden by application
diff --git a/config/test.exs b/config/test.exs
index 87a790f7a..3c7253bfe 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -3,11 +3,5 @@ import Config
# This makes anything in our tests involving user passwords (creating or logging in) much faster
config :argon2_elixir, t_cost: 1, m_cost: 8
-config :teiserver, Teiserver.Test.Repo,
- database: "teiserver_test",
- username: "postgres",
- password: "postgres",
- hostname: "localhost"
-
config :teiserver,
repo: Teiserver.Test.Repo
From e7446bd3356aea52bb93cf3a7f5aa72ea41f308f Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 22 Sep 2024 16:21:24 +0100
Subject: [PATCH 58/64] Removed timex
---
CHANGELOG.md | 1 +
lib/teiserver.ex | 4 ++
.../communication/libs/direct_message_lib.ex | 2 +-
.../communication/libs/match_message_lib.ex | 2 +-
.../communication/libs/room_message_lib.ex | 2 +-
lib/teiserver/connections/client_server.ex | 4 +-
lib/teiserver/contexts/game.ex | 1 -
lib/teiserver/game/libs/match_lib.ex | 41 +++++++++++--------
lib/teiserver/game/servers/lobby_server.ex | 2 +-
mix.exs | 1 -
test/account/user_queries_test.exs | 12 +++---
.../libs/direct_message_lib_test.exs | 4 +-
.../libs/match_message_lib_test.exs | 4 +-
.../libs/room_message_lib_test.exs | 4 +-
.../queries/direct_message_queries_test.exs | 4 +-
.../queries/match_message_queries_test.exs | 4 +-
.../queries/room_message_queries_test.exs | 4 +-
.../queries/room_queries_test.exs | 4 +-
test/connections/client_server_test.exs | 4 +-
test/game/libs/match_lib_test.exs | 8 ++--
test/game/queries/match_queries_test.exs | 12 +++---
.../queries/audit_log_queries_test.exs | 8 ++--
test/settings/server_setting_queries_test.exs | 8 ++--
test/settings/user_setting_queries_test.exs | 8 ++--
.../fixtures/communication_fixtures.ex | 6 +--
test/support/fixtures/game_fixtures.ex | 14 +++----
26 files changed, 88 insertions(+), 80 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d23752bc..62181dc24 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@
- Added concept of user choices to represent pre-game choices made by users (e.g. in-game faction)
- Removed clustering code so it can be handled by the application using Teiserver as a library
- Moved everything from `Teiserver.Api` to `Teiserver`
+- Dropped Timex
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 5834c9087..9407d289f 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -342,6 +342,10 @@ defmodule Teiserver do
@spec end_match(Match.id(), map()) :: Match.t()
defdelegate end_match(match_id, outcome), to: MatchLib
+ @doc section: :match
+ @spec get_match(Match.id(), Teiserver.query_args()) :: Match.t() | nil
+ defdelegate get_match(match_id, query_args \\ []), to: MatchLib
+
### Communication
# MatchMessage
@doc section: :match_message
diff --git a/lib/teiserver/communication/libs/direct_message_lib.ex b/lib/teiserver/communication/libs/direct_message_lib.ex
index 4ab6c5ce9..0160ec441 100644
--- a/lib/teiserver/communication/libs/direct_message_lib.ex
+++ b/lib/teiserver/communication/libs/direct_message_lib.ex
@@ -52,7 +52,7 @@ defmodule Teiserver.Communication.DirectMessageLib do
sender_id: sender_id,
to_id: to_id,
content: content,
- inserted_at: Timex.now()
+ inserted_at: DateTime.utc_now()
},
attrs
)
diff --git a/lib/teiserver/communication/libs/match_message_lib.ex b/lib/teiserver/communication/libs/match_message_lib.ex
index 62b960ac1..c9f709e02 100644
--- a/lib/teiserver/communication/libs/match_message_lib.ex
+++ b/lib/teiserver/communication/libs/match_message_lib.ex
@@ -112,7 +112,7 @@ defmodule Teiserver.Communication.MatchMessageLib do
sender_id: sender_id,
match_id: match_id,
content: content,
- inserted_at: Timex.now()
+ inserted_at: DateTime.utc_now()
},
attrs
)
diff --git a/lib/teiserver/communication/libs/room_message_lib.ex b/lib/teiserver/communication/libs/room_message_lib.ex
index ab8ae3ddb..c7e84d4ae 100644
--- a/lib/teiserver/communication/libs/room_message_lib.ex
+++ b/lib/teiserver/communication/libs/room_message_lib.ex
@@ -71,7 +71,7 @@ defmodule Teiserver.Communication.RoomMessageLib do
sender_id: sender_id,
room_id: room_id,
content: content,
- inserted_at: Timex.now()
+ inserted_at: DateTime.utc_now()
},
attrs
)
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index f78dade40..9896bddeb 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -127,7 +127,7 @@ defmodule Teiserver.Connections.ClientServer do
@impl true
def handle_info(:heartbeat, %State{client: %{connected?: false}} = state) do
- seconds_since_disconnect = Timex.diff(Timex.now(), state.client.last_disconnected, :second)
+ seconds_since_disconnect = DateTime.diff(DateTime.utc_now(), state.client.last_disconnected, :second)
if seconds_since_disconnect > @client_destroy_timeout_seconds do
ClientLib.stop_client_server(state.user_id)
@@ -158,7 +158,7 @@ defmodule Teiserver.Connections.ClientServer do
new_connections = List.delete(state.connections, pid)
if Enum.empty?(new_connections) do
- new_client = %{state.client | connected?: false, last_disconnected: Timex.now()}
+ new_client = %{state.client | connected?: false, last_disconnected: DateTime.utc_now()}
Teiserver.broadcast(state.client_topic, %{
event: :client_disconnected,
diff --git a/lib/teiserver/contexts/game.ex b/lib/teiserver/contexts/game.ex
index 2802c41cd..4482fe4d0 100644
--- a/lib/teiserver/contexts/game.ex
+++ b/lib/teiserver/contexts/game.ex
@@ -196,7 +196,6 @@ defmodule Teiserver.Game do
defdelegate get_match!(match_id, query_args \\ []), to: MatchLib
@doc section: :match
- @spec get_match(Match.id()) :: Match.t() | nil
@spec get_match(Match.id(), Teiserver.query_args()) :: Match.t() | nil
defdelegate get_match(match_id, query_args \\ []), to: MatchLib
diff --git a/lib/teiserver/game/libs/match_lib.ex b/lib/teiserver/game/libs/match_lib.ex
index 87821443b..fc4c1c840 100644
--- a/lib/teiserver/game/libs/match_lib.ex
+++ b/lib/teiserver/game/libs/match_lib.ex
@@ -45,7 +45,7 @@ defmodule Teiserver.Game.MatchLib do
game_version: lobby.game_version,
team_count: team_count,
team_size: team_size,
- match_started_at: Timex.now(),
+ match_started_at: DateTime.utc_now(),
player_count: Enum.count(clients),
type_id: type_id
})
@@ -82,54 +82,59 @@ defmodule Teiserver.Game.MatchLib do
@doc """
Ends an ongoing match and updates memberships accordingly.
- Second argument is a map of the outcomes for the match with the following keys:
- * `:winning_team` - The team_number of the winning team
- * `:ended_normally?` - A boolean indicating if the match ended normally
- * `:players` - A map of player data with the keys being the user_id of the player and the value being a map of their specific outcome
+ Second argument is a (string keyed) map of the outcomes for the match with the following keys:
+ * `winning_team` - The team_number of the winning team
+ * `ended_normally?` - A boolean indicating if the match ended normally
+ * `players` - A map of player data with the keys being the user_id of the player and the value being a map of their specific outcome
Player outcomes are expected to map like so:
- Required:
+ Required
Optional:
- * `:left_after_seconds` - The number of seconds after the start the player left if early. If not included it is assumed the player remained until the end.
+ * `left_after_seconds` - The number of seconds after the start the player left if early. If not included it is assumed the player remained until the end.
## Examples
- iex> end_match(123, %{winning_team: 1, ended_normally?: true, player_data: %{123: }})
- %Match{}
-
+ iex> end_match(123, %{
+ "winning_team" => 1, "ended_normally?" => true, "players" => %{
+ "c3bf3539-fcf2-4409-ad68-1a5994aaa10f": %{"left_after_seconds": 123},
+ "13739a7f-f39d-47a5-85cc-73652372dad0": %{},
+ }
+ })
+ %Match{}
"""
@spec end_match(Match.id(), map()) :: Match.t()
def end_match(match_id, outcome) when is_binary(match_id) do
match = get_match!(match_id)
- now = Timex.now()
+ now = DateTime.utc_now()
- duration_seconds = Timex.diff(match.match_started_at, now, :second)
+ duration_seconds = DateTime.diff(match.match_started_at, now, :second)
{:ok, updated_match} =
update_match(match, %{
- winning_team: outcome.winning_team,
- ended_normally?: outcome.ended_normally?,
+ winning_team: outcome["winning_team"],
+ ended_normally?: outcome["ended_normally?"],
match_ended_at: now,
match_duration_seconds: duration_seconds
})
Game.list_match_memberships(where: [match_id: match.id])
|> Enum.each(fn mm ->
- player_outcome = outcome.players[mm.user_id]
+ # If no player data is included we don't want to break anything!
+ player_outcome = Map.get(outcome["players"], mm.user_id, %{})
- win? = mm.team_number == outcome.winning_team
+ win? = mm.team_number == outcome["winning_team"]
attrs = %{
win?: win?,
- left_after_seconds: Map.get(player_outcome, :left_after_seconds)
+ left_after_seconds: Map.get(player_outcome, "left_after_seconds")
}
Game.update_match_membership(mm, attrs)
end)
# Tell the lobby server the match has ended
- ending_reason = if outcome.ended_normally?, do: "normal", else: "abnormal"
+ ending_reason = if outcome["ended_normally?"], do: "normal", else: "abnormal"
Game.lobby_end_match(match.lobby_id, ending_reason)
# Finally return the updated match
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index 494c22227..4c2f65a26 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -222,7 +222,7 @@ defmodule Teiserver.Game.LobbyServer do
rated?: true,
host_id: state.host_id,
processed?: false,
- lobby_opened_at: Timex.now(),
+ lobby_opened_at: DateTime.utc_now(),
lobby_id: state.lobby_id
})
diff --git a/mix.exs b/mix.exs
index 7bd41c22c..36b21e98f 100644
--- a/mix.exs
+++ b/mix.exs
@@ -243,7 +243,6 @@ defmodule Teiserver.MixProject do
{:gettext, "~> 0.20"},
{:jason, "~> 1.2"},
{:argon2_elixir, "~> 4.0"},
- {:timex, "~> 3.7.5"},
{:typedstruct, "~> 0.5.2", runtime: false},
{:horde, "~> 0.9"},
{:cachex, "~> 3.6"},
diff --git a/test/account/user_queries_test.exs b/test/account/user_queries_test.exs
index 0a287d53d..55447d1f7 100644
--- a/test/account/user_queries_test.exs
+++ b/test/account/user_queries_test.exs
@@ -38,8 +38,8 @@ defmodule Teiserver.UserQueriesTest do
name_or_email: "name_or_email",
name_like: "name_like",
basic_search: "basic_search",
- inserted_after: Timex.now(),
- inserted_before: Timex.now(),
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now(),
has_group: "has_group",
not_has_group: "not_has_group",
has_permission: "has_permission",
@@ -51,10 +51,10 @@ defmodule Teiserver.UserQueriesTest do
smurf_of: "Non-smurf",
behaviour_score_gt: 123,
behaviour_score_lt: 123,
- last_played_after: Timex.now(),
- last_played_before: Timex.now(),
- last_login_after: Timex.now(),
- last_login_before: Timex.now()
+ last_played_after: DateTime.utc_now(),
+ last_played_before: DateTime.utc_now(),
+ last_login_after: DateTime.utc_now(),
+ last_login_before: DateTime.utc_now()
],
order_by: [
"Name (A-Z)",
diff --git a/test/communication/libs/direct_message_lib_test.exs b/test/communication/libs/direct_message_lib_test.exs
index c2ab5cdac..ccc94b3e4 100644
--- a/test/communication/libs/direct_message_lib_test.exs
+++ b/test/communication/libs/direct_message_lib_test.exs
@@ -9,7 +9,7 @@ defmodule Teiserver.DirectMessageLibTest do
defp valid_attrs do
%{
content: "some content",
- inserted_at: Timex.now(),
+ inserted_at: DateTime.utc_now(),
sender_id: AccountFixtures.user_fixture().id,
to_id: AccountFixtures.user_fixture().id
}
@@ -18,7 +18,7 @@ defmodule Teiserver.DirectMessageLibTest do
defp update_attrs do
%{
content: "some updated content",
- inserted_at: Timex.now(),
+ inserted_at: DateTime.utc_now(),
sender_id: AccountFixtures.user_fixture().id,
to_id: AccountFixtures.user_fixture().id
}
diff --git a/test/communication/libs/match_message_lib_test.exs b/test/communication/libs/match_message_lib_test.exs
index 85e24d9eb..165e57dcf 100644
--- a/test/communication/libs/match_message_lib_test.exs
+++ b/test/communication/libs/match_message_lib_test.exs
@@ -16,7 +16,7 @@ defmodule Teiserver.MatchMessageLibTest do
defp valid_attrs do
%{
content: "some content",
- inserted_at: Timex.now(),
+ inserted_at: DateTime.utc_now(),
sender_id: AccountFixtures.user_fixture().id,
match_id: GameFixtures.incomplete_match_fixture().id
}
@@ -25,7 +25,7 @@ defmodule Teiserver.MatchMessageLibTest do
defp update_attrs do
%{
content: "some updated content",
- inserted_at: Timex.now(),
+ inserted_at: DateTime.utc_now(),
sender_id: AccountFixtures.user_fixture().id,
match_id: GameFixtures.incomplete_match_fixture().id
}
diff --git a/test/communication/libs/room_message_lib_test.exs b/test/communication/libs/room_message_lib_test.exs
index 852fb58d2..6bfb70b98 100644
--- a/test/communication/libs/room_message_lib_test.exs
+++ b/test/communication/libs/room_message_lib_test.exs
@@ -10,7 +10,7 @@ defmodule Teiserver.RoomMessageLibTest do
defp valid_attrs do
%{
content: "some content",
- inserted_at: Timex.now(),
+ inserted_at: DateTime.utc_now(),
sender_id: AccountFixtures.user_fixture().id,
room_id: CommunicationFixtures.room_fixture().id
}
@@ -19,7 +19,7 @@ defmodule Teiserver.RoomMessageLibTest do
defp update_attrs do
%{
content: "some updated content",
- inserted_at: Timex.now(),
+ inserted_at: DateTime.utc_now(),
sender_id: AccountFixtures.user_fixture().id,
room_id: CommunicationFixtures.room_fixture().id
}
diff --git a/test/communication/queries/direct_message_queries_test.exs b/test/communication/queries/direct_message_queries_test.exs
index f72407db4..42459bd75 100644
--- a/test/communication/queries/direct_message_queries_test.exs
+++ b/test/communication/queries/direct_message_queries_test.exs
@@ -37,8 +37,8 @@ defmodule Teiserver.DirectMessageQueriesTest do
to_id: Teiserver.uuid(),
to_or_from_id: [Teiserver.uuid(), Teiserver.uuid()],
to_or_from_id: Teiserver.uuid(),
- inserted_after: Timex.now(),
- inserted_before: Timex.now()
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now()
],
order_by: [
"Newest first",
diff --git a/test/communication/queries/match_message_queries_test.exs b/test/communication/queries/match_message_queries_test.exs
index 96e3ffb7a..39523d210 100644
--- a/test/communication/queries/match_message_queries_test.exs
+++ b/test/communication/queries/match_message_queries_test.exs
@@ -35,8 +35,8 @@ defmodule Teiserver.MatchMessageQueriesTest do
sender_id: Teiserver.uuid(),
match_id: [Teiserver.uuid(), Teiserver.uuid()],
match_id: Teiserver.uuid(),
- inserted_after: Timex.now(),
- inserted_before: Timex.now()
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now()
],
order_by: [
"Newest first",
diff --git a/test/communication/queries/room_message_queries_test.exs b/test/communication/queries/room_message_queries_test.exs
index f4043c168..88f55f361 100644
--- a/test/communication/queries/room_message_queries_test.exs
+++ b/test/communication/queries/room_message_queries_test.exs
@@ -35,8 +35,8 @@ defmodule Teiserver.RoomMessageQueriesTest do
sender_id: Teiserver.uuid(),
room_id: [1, 2],
room_id: 1,
- inserted_after: Timex.now(),
- inserted_before: Timex.now()
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now()
],
order_by: [
"Newest first",
diff --git a/test/communication/queries/room_queries_test.exs b/test/communication/queries/room_queries_test.exs
index 664909e17..935c7408d 100644
--- a/test/communication/queries/room_queries_test.exs
+++ b/test/communication/queries/room_queries_test.exs
@@ -32,8 +32,8 @@ defmodule Teiserver.RoomQueriesTest do
id: [1, 2],
id: 1,
name: "Some name",
- inserted_after: Timex.now(),
- inserted_before: Timex.now()
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now()
],
order_by: [
"Name (A-Z)",
diff --git a/test/connections/client_server_test.exs b/test/connections/client_server_test.exs
index 3b331ffc0..cbf302f9b 100644
--- a/test/connections/client_server_test.exs
+++ b/test/connections/client_server_test.exs
@@ -113,7 +113,7 @@ defmodule Connections.ClientServerTest do
TestConn.stop(conn)
# Set the last_disconnected to something okay
- disconnected_at = Timex.now() |> Timex.shift(seconds: -100)
+ disconnected_at = DateTime.utc_now() |> DateTime.shift(second: -100)
Connections.update_client(user.id, %{last_disconnected: disconnected_at}, "test-heartbeat")
client = Connections.get_client(user.id)
@@ -127,7 +127,7 @@ defmodule Connections.ClientServerTest do
assert Connections.client_exists?(user.id)
# Set the last_disconnected to something much larger, it should result in the client process being destroyed
- disconnected_at = Timex.now() |> Timex.shift(seconds: -1_000_000)
+ disconnected_at = DateTime.utc_now() |> DateTime.shift(second: -1_000_000)
Connections.update_client(user.id, %{last_disconnected: disconnected_at}, "test-heartbeat2")
client = Connections.get_client(user.id)
diff --git a/test/game/libs/match_lib_test.exs b/test/game/libs/match_lib_test.exs
index a43b9d35b..aec09b494 100644
--- a/test/game/libs/match_lib_test.exs
+++ b/test/game/libs/match_lib_test.exs
@@ -189,12 +189,12 @@ defmodule Teiserver.MatchLibAsyncTest do
:timer.sleep(100)
outcome = %{
- winning_team: 1,
- ended_normally?: true,
- players: %{
+ "winning_team" => 1,
+ "ended_normally?" => true,
+ "players" => %{
u1.id => %{},
u2.id => %{},
- u3.id => %{left_after_seconds: 1},
+ u3.id => %{"left_after_seconds" => 1},
u4.id => %{}
}
}
diff --git a/test/game/queries/match_queries_test.exs b/test/game/queries/match_queries_test.exs
index 846af101f..2e2558d75 100644
--- a/test/game/queries/match_queries_test.exs
+++ b/test/game/queries/match_queries_test.exs
@@ -37,12 +37,12 @@ defmodule Teiserver.MatchQueriesTest do
duration_gt: 100,
duration_lt: 999,
name_like: "abc",
- started_after: Timex.now(),
- started_before: Timex.now(),
- ended_after: Timex.now(),
- ended_before: Timex.now(),
- inserted_after: Timex.now(),
- inserted_before: Timex.now()
+ started_after: DateTime.utc_now(),
+ started_before: DateTime.utc_now(),
+ ended_after: DateTime.utc_now(),
+ ended_before: DateTime.utc_now(),
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now()
],
order_by: [
"Name (A-Z)",
diff --git a/test/logging/queries/audit_log_queries_test.exs b/test/logging/queries/audit_log_queries_test.exs
index ea205235d..0ffbd4aad 100644
--- a/test/logging/queries/audit_log_queries_test.exs
+++ b/test/logging/queries/audit_log_queries_test.exs
@@ -42,10 +42,10 @@ defmodule Teiserver.AuditLogQueriesTest do
detail_greater_than: {"key", "value"},
detail_less_than: {"key", "value"},
detail_not: {"key", "value"},
- inserted_after: Timex.now(),
- inserted_before: Timex.now(),
- updated_after: Timex.now(),
- updated_before: Timex.now()
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now(),
+ updated_after: DateTime.utc_now(),
+ updated_before: DateTime.utc_now()
],
order_by: [
"Newest first",
diff --git a/test/settings/server_setting_queries_test.exs b/test/settings/server_setting_queries_test.exs
index 174998830..10feaa5bb 100644
--- a/test/settings/server_setting_queries_test.exs
+++ b/test/settings/server_setting_queries_test.exs
@@ -33,10 +33,10 @@ defmodule Teiserver.ServerSettingQueriesTest do
key: "key1",
value: ["value1", "value2"],
value: "value1",
- inserted_after: Timex.now(),
- inserted_before: Timex.now(),
- updated_after: Timex.now(),
- updated_before: Timex.now()
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now(),
+ updated_after: DateTime.utc_now(),
+ updated_before: DateTime.utc_now()
],
order_by: [
"Newest first",
diff --git a/test/settings/user_setting_queries_test.exs b/test/settings/user_setting_queries_test.exs
index a5b45d84d..c82f79b6c 100644
--- a/test/settings/user_setting_queries_test.exs
+++ b/test/settings/user_setting_queries_test.exs
@@ -35,10 +35,10 @@ defmodule Teiserver.UserSettingQueriesTest do
key: "key1",
value: ["value1", "value2"],
value: "value1",
- inserted_after: Timex.now(),
- inserted_before: Timex.now(),
- updated_after: Timex.now(),
- updated_before: Timex.now()
+ inserted_after: DateTime.utc_now(),
+ inserted_before: DateTime.utc_now(),
+ updated_after: DateTime.utc_now(),
+ updated_before: DateTime.utc_now()
],
order_by: [
"Newest first",
diff --git a/test/support/fixtures/communication_fixtures.ex b/test/support/fixtures/communication_fixtures.ex
index 085653db5..e62bfcf38 100644
--- a/test/support/fixtures/communication_fixtures.ex
+++ b/test/support/fixtures/communication_fixtures.ex
@@ -27,7 +27,7 @@ defmodule Teiserver.Fixtures.CommunicationFixtures do
%RoomMessage{},
%{
content: data[:content] || "room_message_content_#{r}",
- inserted_at: data[:inserted_at] || Timex.now(),
+ inserted_at: data[:inserted_at] || DateTime.utc_now(),
sender_id: data[:sender_id] || user_fixture().id,
room_id: data[:room_id] || room_fixture().id
}
@@ -44,7 +44,7 @@ defmodule Teiserver.Fixtures.CommunicationFixtures do
%DirectMessage{},
%{
content: data[:content] || "room_message_content_#{r}",
- inserted_at: data[:inserted_at] || Timex.now(),
+ inserted_at: data[:inserted_at] || DateTime.utc_now(),
delivered?: data[:delivered?] || false,
read?: data[:read?] || false,
sender_id: data[:sender_id] || user_fixture().id,
@@ -63,7 +63,7 @@ defmodule Teiserver.Fixtures.CommunicationFixtures do
%MatchMessage{},
%{
content: data[:content] || "match_message_content_#{r}",
- inserted_at: data[:inserted_at] || Timex.now(),
+ inserted_at: data[:inserted_at] || DateTime.utc_now(),
sender_id: data[:sender_id] || user_fixture().id,
match_id: data[:match_id] || incomplete_match_fixture().id
}
diff --git a/test/support/fixtures/game_fixtures.ex b/test/support/fixtures/game_fixtures.ex
index b42f8c366..d032b71e6 100644
--- a/test/support/fixtures/game_fixtures.ex
+++ b/test/support/fixtures/game_fixtures.ex
@@ -80,7 +80,7 @@ defmodule Teiserver.Fixtures.GameFixtures do
rated?: data["rated?"] || true,
host_id: data["host_id"] || user_fixture().id,
processed?: false,
- lobby_opened_at: data["lobby_opened_at"] || Timex.now() |> Timex.shift(minutes: -5)
+ lobby_opened_at: data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5)
}
)
|> Teiserver.Repo.insert!()
@@ -105,8 +105,8 @@ defmodule Teiserver.Fixtures.GameFixtures do
team_size: data["team_size"] || 2,
processed?: false,
game_type: data["game_type"] || "match_game_type_#{r}",
- lobby_opened_at: data["lobby_opened_at"] || Timex.now() |> Timex.shift(minutes: -5),
- match_started_at: data["match_started_at"] || Timex.now() |> Timex.shift(minutes: -3),
+ lobby_opened_at: data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5),
+ match_started_at: data["match_started_at"] || DateTime.utc_now() |> DateTime.shift(minute: -3),
host_id: data["host_id"] || user_fixture().id,
type_id: data["type_id"] || match_type_fixture().id
}
@@ -118,8 +118,8 @@ defmodule Teiserver.Fixtures.GameFixtures do
def completed_match_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
- match_started_at = data["match_started_at"] || Timex.now() |> Timex.shift(minutes: -3)
- match_ended_at = data["match_started_at"] || Timex.now() |> Timex.shift(minutes: -3)
+ match_started_at = data["match_started_at"] || DateTime.utc_now() |> DateTime.shift(minute: -3)
+ match_ended_at = data["match_started_at"] || DateTime.utc_now() |> DateTime.shift(minute: -3)
Match.changeset(
%Match{},
@@ -135,10 +135,10 @@ defmodule Teiserver.Fixtures.GameFixtures do
team_size: data["team_size"] || 2,
processed?: data["processed?"] || false,
game_type: data["game_type"] || "match_game_type_#{r}",
- lobby_opened_at: data["lobby_opened_at"] || Timex.now() |> Timex.shift(minutes: -5),
+ lobby_opened_at: data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5),
match_started_at: match_started_at,
match_ended_at: match_ended_at,
- match_duration_seconds: Timex.diff(match_ended_at, match_started_at, :second),
+ match_duration_seconds: DateTime.diff(match_ended_at, match_started_at, :second),
host_id: data["host_id"] || user_fixture().id,
type_id: data["type_id"] || match_type_fixture().id
}
From 6622c18b26f12528c95da0dc5f9d704bee7170d9 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Sun, 22 Sep 2024 16:23:34 +0100
Subject: [PATCH 59/64] format
---
lib/teiserver/connections/client_server.ex | 3 ++-
test/support/fixtures/game_fixtures.ex | 16 +++++++++++-----
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/lib/teiserver/connections/client_server.ex b/lib/teiserver/connections/client_server.ex
index 9896bddeb..952a9a61b 100644
--- a/lib/teiserver/connections/client_server.ex
+++ b/lib/teiserver/connections/client_server.ex
@@ -127,7 +127,8 @@ defmodule Teiserver.Connections.ClientServer do
@impl true
def handle_info(:heartbeat, %State{client: %{connected?: false}} = state) do
- seconds_since_disconnect = DateTime.diff(DateTime.utc_now(), state.client.last_disconnected, :second)
+ seconds_since_disconnect =
+ DateTime.diff(DateTime.utc_now(), state.client.last_disconnected, :second)
if seconds_since_disconnect > @client_destroy_timeout_seconds do
ClientLib.stop_client_server(state.user_id)
diff --git a/test/support/fixtures/game_fixtures.ex b/test/support/fixtures/game_fixtures.ex
index d032b71e6..f9d9177f0 100644
--- a/test/support/fixtures/game_fixtures.ex
+++ b/test/support/fixtures/game_fixtures.ex
@@ -80,7 +80,8 @@ defmodule Teiserver.Fixtures.GameFixtures do
rated?: data["rated?"] || true,
host_id: data["host_id"] || user_fixture().id,
processed?: false,
- lobby_opened_at: data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5)
+ lobby_opened_at:
+ data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5)
}
)
|> Teiserver.Repo.insert!()
@@ -105,8 +106,10 @@ defmodule Teiserver.Fixtures.GameFixtures do
team_size: data["team_size"] || 2,
processed?: false,
game_type: data["game_type"] || "match_game_type_#{r}",
- lobby_opened_at: data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5),
- match_started_at: data["match_started_at"] || DateTime.utc_now() |> DateTime.shift(minute: -3),
+ lobby_opened_at:
+ data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5),
+ match_started_at:
+ data["match_started_at"] || DateTime.utc_now() |> DateTime.shift(minute: -3),
host_id: data["host_id"] || user_fixture().id,
type_id: data["type_id"] || match_type_fixture().id
}
@@ -118,7 +121,9 @@ defmodule Teiserver.Fixtures.GameFixtures do
def completed_match_fixture(data \\ %{}) do
r = :rand.uniform(999_999_999)
- match_started_at = data["match_started_at"] || DateTime.utc_now() |> DateTime.shift(minute: -3)
+ match_started_at =
+ data["match_started_at"] || DateTime.utc_now() |> DateTime.shift(minute: -3)
+
match_ended_at = data["match_started_at"] || DateTime.utc_now() |> DateTime.shift(minute: -3)
Match.changeset(
@@ -135,7 +140,8 @@ defmodule Teiserver.Fixtures.GameFixtures do
team_size: data["team_size"] || 2,
processed?: data["processed?"] || false,
game_type: data["game_type"] || "match_game_type_#{r}",
- lobby_opened_at: data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5),
+ lobby_opened_at:
+ data["lobby_opened_at"] || DateTime.utc_now() |> DateTime.shift(minute: -5),
match_started_at: match_started_at,
match_ended_at: match_ended_at,
match_duration_seconds: DateTime.diff(match_ended_at, match_started_at, :second),
From db1c3fca00c2ac7f9abd316dc5ed758af9a51a4a Mon Sep 17 00:00:00 2001
From: Teifion
Date: Mon, 23 Sep 2024 08:28:30 +0100
Subject: [PATCH 60/64] Test DB fix
---
.github/workflows/elixir.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml
index 2dbe8cbc3..583619eb4 100644
--- a/.github/workflows/elixir.yml
+++ b/.github/workflows/elixir.yml
@@ -89,4 +89,6 @@ jobs:
# Step: Execute the tests.
- name: Run tests
+ env:
+ DATABASE_URL: postgres://teiserver_test:123456789@localhost/teiserver_test
run: mix test.ci
From cecd684b67e872b0896d861ebaa92629f3d6ef35 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 24 Sep 2024 20:49:34 +0100
Subject: [PATCH 61/64] Listing clients no longer contains nil values
---
lib/teiserver/connections/libs/client_lib.ex | 5 +++--
lib/teiserver/contexts/connections.ex | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/teiserver/connections/libs/client_lib.ex b/lib/teiserver/connections/libs/client_lib.ex
index 2d0797db4..995fa0a1f 100644
--- a/lib/teiserver/connections/libs/client_lib.ex
+++ b/lib/teiserver/connections/libs/client_lib.ex
@@ -81,16 +81,17 @@ defmodule Teiserver.Connections.ClientLib do
[%Client{}, %Client{}]
iex> get_client_list([456])
- [nil]
+ []
"""
- @spec get_client_list([Teiserver.user_id()]) :: [Client.t() | nil]
+ @spec get_client_list([Teiserver.user_id()]) :: [Client.t()]
def get_client_list(user_ids) do
user_ids
|> Enum.uniq()
|> Enum.map(fn user_id ->
call_client(user_id, :get_client_state)
end)
+ |> Enum.reject(&(&1 == nil))
end
@doc """
diff --git a/lib/teiserver/contexts/connections.ex b/lib/teiserver/contexts/connections.ex
index d0cfbc4ae..034667850 100644
--- a/lib/teiserver/contexts/connections.ex
+++ b/lib/teiserver/contexts/connections.ex
@@ -40,7 +40,7 @@ defmodule Teiserver.Connections do
defdelegate get_client(user_id), to: ClientLib
@doc section: :client
- @spec get_client_list([Teiserver.user_id()]) :: [Client.t() | nil]
+ @spec get_client_list([Teiserver.user_id()]) :: [Client.t()]
defdelegate get_client_list(user_ids), to: ClientLib
@doc section: :client
From 35e88b70b825f412e8c3e0775701e594eec373b2 Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 24 Sep 2024 20:49:45 +0100
Subject: [PATCH 62/64] Added ability for creating matches to fail
---
lib/teiserver/game/libs/match_lib.ex | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/lib/teiserver/game/libs/match_lib.ex b/lib/teiserver/game/libs/match_lib.ex
index fc4c1c840..f0d7ac4f7 100644
--- a/lib/teiserver/game/libs/match_lib.ex
+++ b/lib/teiserver/game/libs/match_lib.ex
@@ -10,17 +10,29 @@ defmodule Teiserver.Game.MatchLib do
Given a lobby_id, will update the match, memberships and settings for that lobby
and then update the Lobby itself to show the lobby is now in progress.
"""
- @spec start_match(Lobby.id()) :: Match.t()
+ @spec start_match(Lobby.id()) :: {:ok, Match.t()} | {:error, :no_players}
def start_match(lobby_id) do
lobby = Game.get_lobby(lobby_id)
- match_id = lobby.match_id
- type_id = MatchTypeLib.calculate_match_type(lobby).id
+ players =
+ lobby.members
+ |> Connections.get_client_list()
+ |> Enum.filter(fn c -> c.player? end)
+
+ if Enum.empty?(players) do
+ {:error, :no_players}
+ else
+ {:ok, do_start_match(lobby, players)}
+ end
+ end
- clients = Connections.get_client_list(lobby.members)
+ @spec do_start_match(Lobby.t(), [Teiserver.Connections.Client.t()]) :: Match.t()
+ defp do_start_match(lobby, players) do
+ match_id = lobby.match_id
+ type_id = MatchTypeLib.calculate_match_type(lobby).id
teams =
- clients
+ players
|> Enum.group_by(fn c -> c.team_number end)
team_count =
@@ -46,13 +58,13 @@ defmodule Teiserver.Game.MatchLib do
team_count: team_count,
team_size: team_size,
match_started_at: DateTime.utc_now(),
- player_count: Enum.count(clients),
+ player_count: Enum.count(players),
type_id: type_id
})
# Do members
{:ok, _memberships} =
- clients
+ players
|> Enum.map(fn client ->
%{
user_id: client.id,
@@ -73,7 +85,7 @@ defmodule Teiserver.Game.MatchLib do
|> Game.create_many_match_settings()
# Tell the lobby server the match is starting
- Game.lobby_start_match(lobby_id)
+ Game.lobby_start_match(lobby.id)
# Finally return the match itself
match
From 85639d28cee62b738ec60bbc1bc2071c4cac44eb Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 24 Sep 2024 21:05:34 +0100
Subject: [PATCH 63/64] Swapped string error messages to atom error messages
---
CHANGELOG.md | 1 +
lib/teiserver/game/libs/lobby_lib.ex | 21 ++++++++++-----------
lib/teiserver/game/servers/lobby_server.ex | 22 +++++++++++-----------
test/game/libs/lobby_lib_async_test.exs | 2 +-
test/game/libs/match_lib_test.exs | 12 ++++++------
5 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 62181dc24..3792c6385 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@
- Removed clustering code so it can be handled by the application using Teiserver as a library
- Moved everything from `Teiserver.Api` to `Teiserver`
- Dropped Timex
+- Swapped string error messages to atom error messages
## v0.0.4
- Added `Lobby`, `LobbySummary`, `MatchType`, `Match`, `MatchMembership`, `MatchSettingType`, `MatchSetting` schemas, libs and queries
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index ad2bbe534..7fbcbee01 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -195,27 +195,27 @@ defmodule Teiserver.Game.LobbyLib do
{:ok, 456}
iex> open_lobby(456, "Name")
- {:error, "Client is not connected"}
+ {:error, :client_disconnected}
"""
- @spec open_lobby(Teiserver.user_id(), Lobby.name()) :: {:ok, Lobby.id()} | {:error, String.t()}
+ @spec open_lobby(Teiserver.user_id(), Lobby.name()) :: {:ok, Lobby.id()} | {:error, :client_disconnected, :already_in_lobby, :no_name}
def open_lobby(host_id, name) when is_binary(host_id) do
client = Connections.get_client(host_id)
cond do
client == nil ->
- {:error, "Client is not connected"}
+ {:error, :client_disconnected}
client.connected? == false ->
- {:error, "Client is disconnected"}
+ {:error, :client_disconnected}
client.lobby_id != nil ->
- {:error, "Already in a lobby"}
+ {:error, :already_in_lobby}
name == nil ->
- {:error, "No name supplied"}
+ {:error, :no_name}
String.trim(name) == "" ->
- {:error, "No name supplied"}
+ {:error, :no_name}
# All checks are good, lets try to create the lobby!
true ->
@@ -333,13 +333,12 @@ defmodule Teiserver.Game.LobbyLib do
@doc """
Adds a client to the lobby
"""
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id()) :: {boolean(), String.t() | nil}
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) ::
- {boolean(), String.t() | nil}
+ @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t() | nil) ::
+ true | {false, :no_lobby | :existing_member | :client_disconnected | :already_in_a_lobby | :incorrect_password | :lobby_is_locked}
def can_add_client_to_lobby(user_id, lobby_id, password \\ nil) do
case call_lobby(lobby_id, {:can_add_client, user_id, password}) do
nil ->
- {false, "No lobby"}
+ {false, :no_lobby}
result ->
result
diff --git a/lib/teiserver/game/servers/lobby_server.ex b/lib/teiserver/game/servers/lobby_server.ex
index 4c2f65a26..b1f5273e6 100644
--- a/lib/teiserver/game/servers/lobby_server.ex
+++ b/lib/teiserver/game/servers/lobby_server.ex
@@ -40,7 +40,7 @@ defmodule Teiserver.Game.LobbyServer do
{false, reason} ->
{:reply, {:error, reason}, state}
- {true, _} ->
+ true ->
:telemetry.execute(
[:teiserver, :lobby, :add_client],
%{},
@@ -243,41 +243,41 @@ defmodule Teiserver.Game.LobbyServer do
end
@spec can_add_client({Teiserver.user_id(), String.t()}, State.t()) ::
- {boolean(), String.t() | nil}
+ true | {false, :existing_member | :client_disconnected | :already_in_a_lobby}
defp can_add_client({user_id, password}, %{lobby: lobby} = _state) do
cond do
Enum.member?(lobby.members, user_id) ->
- {false, "Existing member"}
+ {false, :existing_member}
true ->
client = Connections.get_client(user_id)
cond do
client == nil ->
- {false, "Client is not connected"}
+ {false, :client_disconnected}
client.connected? == false ->
- {false, "Client is disconnected"}
+ {false, :client_disconnected}
client.lobby_id != nil ->
- {false, "Already in a lobby"}
+ {false, :already_in_a_lobby}
# Moderator short-circuit
Account.allow?(user_id, "moderator") ->
- {true, nil}
+ true
# Approved player short-circuit
Enum.member?(lobby.approved_members, user_id) ->
- {true, nil}
+ true
lobby.password && lobby.password != password ->
- {false, "Incorrect password"}
+ {false, :incorrect_password}
lobby.locked? ->
- {false, "Lobby is locked"}
+ {false, :lobby_is_locked}
true ->
- {true, nil}
+ true
end
end
end
diff --git a/test/game/libs/lobby_lib_async_test.exs b/test/game/libs/lobby_lib_async_test.exs
index 12bf570ef..560dc96d2 100644
--- a/test/game/libs/lobby_lib_async_test.exs
+++ b/test/game/libs/lobby_lib_async_test.exs
@@ -19,7 +19,7 @@ defmodule Teiserver.Game.LobbyLibAsyncTest do
test "open_lobby" do
# This client won't exist, thus it should fail
assert Game.open_lobby(Teiserver.uuid(), "no-host-lobby") ==
- {:error, "Client is not connected"}
+ {:error, :client_disconnected}
end
end
end
diff --git a/test/game/libs/match_lib_test.exs b/test/game/libs/match_lib_test.exs
index aec09b494..aa32a378d 100644
--- a/test/game/libs/match_lib_test.exs
+++ b/test/game/libs/match_lib_test.exs
@@ -118,9 +118,9 @@ defmodule Teiserver.MatchLibAsyncTest do
{_, u4} = ConnectionFixtures.client_fixture()
u5 = AccountFixtures.user_fixture()
- assert Game.can_add_client_to_lobby(u1.id, Teiserver.uuid()) == {false, "No lobby"}
- assert Game.can_add_client_to_lobby(u1.id, lobby_id) == {true, nil}
- assert Game.can_add_client_to_lobby(u5.id, lobby_id) == {false, "Client is not connected"}
+ assert Game.can_add_client_to_lobby(u1.id, Teiserver.uuid()) == {false, :no_lobby}
+ assert Game.can_add_client_to_lobby(u1.id, lobby_id) == true
+ assert Game.can_add_client_to_lobby(u5.id, lobby_id) == {false, :client_disconnected}
Game.add_client_to_lobby(u1.id, lobby_id)
Game.add_client_to_lobby(u2.id, lobby_id)
@@ -128,11 +128,11 @@ defmodule Teiserver.MatchLibAsyncTest do
Game.add_client_to_lobby(u4.id, lobby_id)
# Just to check, if we try to add the now it says no
- assert Game.can_add_client_to_lobby(u1.id, lobby_id) == {false, "Existing member"}
+ assert Game.can_add_client_to_lobby(u1.id, lobby_id) == {false, :existing_member}
# And trying to add them anyway won't generate a problem
resp = Game.add_client_to_lobby(u1.id, lobby_id)
- assert resp == {:error, "Existing member"}
+ assert resp == {:error, :existing_member}
lobby = Game.get_lobby(lobby_id)
@@ -168,7 +168,7 @@ defmodule Teiserver.MatchLibAsyncTest do
settings = Game.get_match_settings_map(match.id)
assert settings == %{}
- started_match = Game.start_match(lobby.id)
+ {:ok, started_match} = Game.start_match(lobby.id)
refute started_match.match_started_at == nil
assert started_match.match_ended_at == nil
From b07d3c6d71396d6863815954913244f77f973e7b Mon Sep 17 00:00:00 2001
From: Teifion
Date: Tue, 24 Sep 2024 23:22:45 +0100
Subject: [PATCH 64/64] Minor cleanup
---
lib/teiserver.ex | 26 +++++++-------
lib/teiserver/contexts/game.ex | 17 +++++----
lib/teiserver/game/libs/lobby_lib.ex | 38 +++++++++++++++------
lib/teiserver/game/libs/match_lib.ex | 16 ++++++---
lib/teiserver/game/queries/match_queries.ex | 12 +++++++
5 files changed, 73 insertions(+), 36 deletions(-)
diff --git a/lib/teiserver.ex b/lib/teiserver.ex
index 9407d289f..0a143c06f 100644
--- a/lib/teiserver.ex
+++ b/lib/teiserver.ex
@@ -296,13 +296,9 @@ defmodule Teiserver do
@spec list_lobby_ids() :: [Lobby.id()]
defdelegate list_lobby_ids, to: LobbyLib
- @doc section: :lobby
- @spec stream_lobby_summaries() :: Enumerable.t(LobbySummary.t())
- defdelegate stream_lobby_summaries(), to: LobbyLib
-
@doc section: :lobby
@spec stream_lobby_summaries(map) :: Enumerable.t(LobbySummary.t())
- defdelegate stream_lobby_summaries(filters), to: LobbyLib
+ defdelegate stream_lobby_summaries(filters \\ %{}), to: LobbyLib
@doc section: :lobby
@spec open_lobby(user_id(), Lobby.name()) :: {:ok, Lobby.id()} | {:error, String.t()}
@@ -317,13 +313,16 @@ defmodule Teiserver do
defdelegate close_lobby(lobby_id), to: LobbyLib
@doc section: :lobby
- @spec can_add_client_to_lobby(user_id(), Lobby.id()) :: {boolean(), String.t() | nil}
- defdelegate can_add_client_to_lobby(user_id, lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec can_add_client_to_lobby(user_id(), Lobby.id(), String.t()) ::
- {boolean(), String.t() | nil}
- defdelegate can_add_client_to_lobby(user_id, lobby_id, password), to: LobbyLib
+ @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t() | nil) ::
+ true
+ | {false,
+ :no_lobby
+ | :existing_member
+ | :client_disconnected
+ | :already_in_a_lobby
+ | :incorrect_password
+ | :lobby_is_locked}
+ defdelegate can_add_client_to_lobby(user_id, lobby_id, password \\ nil), to: LobbyLib
@doc section: :lobby
@spec add_client_to_lobby(user_id(), Lobby.id()) :: :ok | {:error, String.t()}
@@ -335,7 +334,8 @@ defmodule Teiserver do
# Match
@doc section: :match
- @spec start_match(Teiserver.lobby_id()) :: Match.t()
+ @spec start_match(Lobby.id()) ::
+ {:ok, Match.t()} | {:error, :no_players, :match_already_started}
defdelegate start_match(lobby_id), to: MatchLib
@doc section: :match
diff --git a/lib/teiserver/contexts/game.ex b/lib/teiserver/contexts/game.ex
index 4482fe4d0..26fc1cd3d 100644
--- a/lib/teiserver/contexts/game.ex
+++ b/lib/teiserver/contexts/game.ex
@@ -78,13 +78,16 @@ defmodule Teiserver.Game do
defdelegate close_lobby(lobby_id), to: LobbyLib
@doc section: :lobby
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id()) :: {boolean(), String.t() | nil}
- defdelegate can_add_client_to_lobby(user_id, lobby_id), to: LobbyLib
-
- @doc section: :lobby
- @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t()) ::
- {boolean(), String.t() | nil}
- defdelegate can_add_client_to_lobby(user_id, lobby_id, password), to: LobbyLib
+ @spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t() | nil) ::
+ true
+ | {false,
+ :no_lobby
+ | :existing_member
+ | :client_disconnected
+ | :already_in_a_lobby
+ | :incorrect_password
+ | :lobby_is_locked}
+ defdelegate can_add_client_to_lobby(user_id, lobby_id, password \\ nil), to: LobbyLib
@doc section: :lobby
@spec add_client_to_lobby(Teiserver.user_id(), Lobby.id()) :: :ok | {:error, String.t()}
diff --git a/lib/teiserver/game/libs/lobby_lib.ex b/lib/teiserver/game/libs/lobby_lib.ex
index 7fbcbee01..559a395a9 100644
--- a/lib/teiserver/game/libs/lobby_lib.ex
+++ b/lib/teiserver/game/libs/lobby_lib.ex
@@ -83,21 +83,29 @@ defmodule Teiserver.Game.LobbyLib do
end
@doc """
-
+ Returns a stream of lobby summaries based on the filters; the filters are supplied as a string keyed map.
+
+ "match_ongoing?" => boolean
+ "require_any_tags" => [String]
+ "require_all_tags" => [String]
+ "exclude_tags" => [String]
+ "passworded?" => boolean
+ "locked?" => boolean
+ "public?" => boolean
+ TODO: "match_type" => Not implemented yet
+ "rated?" => boolean
+ "game_version" => string, equality match
+ "game_name" => string, equality match
+ "min_player_count" => integer (inclusive)
+ "max_player_count" => integer (inclusive)
"""
- @spec stream_lobby_summaries() :: Enumerable.t(LobbySummary.t())
- def stream_lobby_summaries() do
- list_lobby_ids()
- |> Stream.map(&get_lobby_summary/1)
- |> Stream.reject(&(&1 == nil))
- end
-
@spec stream_lobby_summaries(map) :: Enumerable.t(LobbySummary.t())
- def stream_lobby_summaries(filters) do
+ def stream_lobby_summaries(filters \\ %{}) do
ids = filters["ids"] || list_lobby_ids()
ids
|> Stream.map(&get_lobby_summary/1)
+ |> Stream.reject(&(&1 == nil))
|> Stream.filter(fn l -> include_lobby?(l, filters) end)
end
@@ -197,7 +205,8 @@ defmodule Teiserver.Game.LobbyLib do
iex> open_lobby(456, "Name")
{:error, :client_disconnected}
"""
- @spec open_lobby(Teiserver.user_id(), Lobby.name()) :: {:ok, Lobby.id()} | {:error, :client_disconnected, :already_in_lobby, :no_name}
+ @spec open_lobby(Teiserver.user_id(), Lobby.name()) ::
+ {:ok, Lobby.id()} | {:error, :client_disconnected, :already_in_lobby, :no_name}
def open_lobby(host_id, name) when is_binary(host_id) do
client = Connections.get_client(host_id)
@@ -334,7 +343,14 @@ defmodule Teiserver.Game.LobbyLib do
Adds a client to the lobby
"""
@spec can_add_client_to_lobby(Teiserver.user_id(), Lobby.id(), String.t() | nil) ::
- true | {false, :no_lobby | :existing_member | :client_disconnected | :already_in_a_lobby | :incorrect_password | :lobby_is_locked}
+ true
+ | {false,
+ :no_lobby
+ | :existing_member
+ | :client_disconnected
+ | :already_in_a_lobby
+ | :incorrect_password
+ | :lobby_is_locked}
def can_add_client_to_lobby(user_id, lobby_id, password \\ nil) do
case call_lobby(lobby_id, {:can_add_client, user_id, password}) do
nil ->
diff --git a/lib/teiserver/game/libs/match_lib.ex b/lib/teiserver/game/libs/match_lib.ex
index f0d7ac4f7..5166bda6f 100644
--- a/lib/teiserver/game/libs/match_lib.ex
+++ b/lib/teiserver/game/libs/match_lib.ex
@@ -10,7 +10,8 @@ defmodule Teiserver.Game.MatchLib do
Given a lobby_id, will update the match, memberships and settings for that lobby
and then update the Lobby itself to show the lobby is now in progress.
"""
- @spec start_match(Lobby.id()) :: {:ok, Match.t()} | {:error, :no_players}
+ @spec start_match(Lobby.id()) ::
+ {:ok, Match.t()} | {:error, :no_players, :match_already_started}
def start_match(lobby_id) do
lobby = Game.get_lobby(lobby_id)
@@ -19,10 +20,15 @@ defmodule Teiserver.Game.MatchLib do
|> Connections.get_client_list()
|> Enum.filter(fn c -> c.player? end)
- if Enum.empty?(players) do
- {:error, :no_players}
- else
- {:ok, do_start_match(lobby, players)}
+ cond do
+ lobby.match_ongoing? ->
+ {:error, :match_already_started}
+
+ Enum.empty?(players) ->
+ {:error, :no_players}
+
+ true ->
+ {:ok, do_start_match(lobby, players)}
end
end
diff --git a/lib/teiserver/game/queries/match_queries.ex b/lib/teiserver/game/queries/match_queries.ex
index 38a381130..747624672 100644
--- a/lib/teiserver/game/queries/match_queries.ex
+++ b/lib/teiserver/game/queries/match_queries.ex
@@ -68,6 +68,18 @@ defmodule Teiserver.Game.MatchQueries do
)
end
+ def _where(query, :started?, true) do
+ from(matches in query,
+ where: not is_nil(matches.match_started_at)
+ )
+ end
+
+ def _where(query, :started?, false) do
+ from(matches in query,
+ where: is_nil(matches.match_started_at)
+ )
+ end
+
def _where(query, :started_after, timestamp) do
from(matches in query,
where: matches.match_started_at >= ^timestamp