Implement room_alias_name option for client room creation
This commit is contained in:
parent
b34fd58cf7
commit
064a398a37
6 changed files with 118 additions and 68 deletions
|
@ -50,7 +50,7 @@ Here, implemented and some unimplemented features are listed.
|
||||||
- GET /_matrix/client/r0/login
|
- GET /_matrix/client/r0/login
|
||||||
- POST /_matrix/client/r0/login: Only with password flow.
|
- POST /_matrix/client/r0/login: Only with password flow.
|
||||||
- POST /_matrix/client/r0/register: Only with dummy flow.
|
- POST /_matrix/client/r0/register: Only with dummy flow.
|
||||||
- POST /_matrix/client/r0/createRoom: Except with options invite_3pid, initial_state and room_alias_name.
|
- POST /_matrix/client/r0/createRoom: Except with option invite_3pid.
|
||||||
- GET /_matrix/client/r0/joined_rooms
|
- GET /_matrix/client/r0/joined_rooms
|
||||||
- POST /_matrix/client/r0/rooms/{roomId}/invite
|
- POST /_matrix/client/r0/rooms/{roomId}/invite
|
||||||
- POST /_matrix/client/r0/rooms/{roomId}/join: Except with third party invite.
|
- POST /_matrix/client/r0/rooms/{roomId}/join: Except with third party invite.
|
||||||
|
|
|
@ -21,7 +21,8 @@ defmodule Architex.RoomServer do
|
||||||
Account,
|
Account,
|
||||||
Device,
|
Device,
|
||||||
DeviceTransaction,
|
DeviceTransaction,
|
||||||
Membership
|
Membership,
|
||||||
|
Alias
|
||||||
}
|
}
|
||||||
|
|
||||||
alias Architex.StateResolution.Authorization
|
alias Architex.StateResolution.Authorization
|
||||||
|
@ -203,19 +204,34 @@ defmodule Architex.RoomServer do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_call(
|
def handle_call(
|
||||||
{:create_room, account, request},
|
{:create_room, account, %CreateRoom{room_alias_name: room_alias_name} = request},
|
||||||
_from,
|
_from,
|
||||||
%{room: %Room{id: room_id} = room} = state
|
%{room: %Room{id: room_id} = room} = state
|
||||||
) do
|
) do
|
||||||
case Repo.transaction(create_room_insert_events(room, account, request)) do
|
create_alias_result =
|
||||||
{:ok, {state_set, room}} ->
|
if room_alias_name do
|
||||||
{:reply, {:ok, room_id}, %{state | state_set: state_set, room: room}}
|
Alias.create(room_alias_name, room_id)
|
||||||
|
else
|
||||||
|
{:ok, nil}
|
||||||
|
end
|
||||||
|
|
||||||
{:error, reason} ->
|
case create_alias_result do
|
||||||
{:reply, {:error, reason}, state}
|
{:ok, alias_} ->
|
||||||
|
events = create_room_events(room, account, request, alias_)
|
||||||
|
|
||||||
_ ->
|
case Repo.transaction(process_events(room, %{}, events)) do
|
||||||
{:reply, {:error, :unknown}, state}
|
{:ok, {state_set, room}} ->
|
||||||
|
{:reply, {:ok, room_id}, %{state | state_set: state_set, room: room}}
|
||||||
|
|
||||||
|
{:error, reason} ->
|
||||||
|
{:reply, {:error, reason}, state}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
{:reply, {:error, :unknown}, state}
|
||||||
|
end
|
||||||
|
|
||||||
|
{:error, _} ->
|
||||||
|
{:reply, {:error, :alias}, state}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -275,7 +291,7 @@ defmodule Architex.RoomServer do
|
||||||
def handle_call({:invite, account, user_id}, _from, %{room: room, state_set: state_set} = state) do
|
def handle_call({:invite, account, user_id}, _from, %{room: room, state_set: state_set} = state) do
|
||||||
invite_event = Event.Invite.new(room, account, user_id)
|
invite_event = Event.Invite.new(room, account, user_id)
|
||||||
|
|
||||||
case Repo.transaction(insert_single_event(room, state_set, invite_event)) do
|
case Repo.transaction(process_event(room, state_set, invite_event)) do
|
||||||
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
||||||
{:error, reason} -> {:reply, {:error, reason}, state}
|
{:error, reason} -> {:reply, {:error, reason}, state}
|
||||||
end
|
end
|
||||||
|
@ -288,7 +304,7 @@ defmodule Architex.RoomServer do
|
||||||
) do
|
) do
|
||||||
join_event = Event.Join.new(room, account)
|
join_event = Event.Join.new(room, account)
|
||||||
|
|
||||||
case Repo.transaction(insert_single_event(room, state_set, join_event)) do
|
case Repo.transaction(process_event(room, state_set, join_event)) do
|
||||||
{:ok, {state_set, room, _}} ->
|
{:ok, {state_set, room, _}} ->
|
||||||
{:reply, {:ok, room_id}, %{state | state_set: state_set, room: room}}
|
{:reply, {:ok, room_id}, %{state | state_set: state_set, room: room}}
|
||||||
|
|
||||||
|
@ -300,7 +316,7 @@ defmodule Architex.RoomServer do
|
||||||
def handle_call({:leave, account}, _from, %{room: room, state_set: state_set} = state) do
|
def handle_call({:leave, account}, _from, %{room: room, state_set: state_set} = state) do
|
||||||
leave_event = Event.Leave.new(room, account)
|
leave_event = Event.Leave.new(room, account)
|
||||||
|
|
||||||
case Repo.transaction(insert_single_event(room, state_set, leave_event)) do
|
case Repo.transaction(process_event(room, state_set, leave_event)) do
|
||||||
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
||||||
{:error, reason} -> {:reply, {:error, reason}, state}
|
{:error, reason} -> {:reply, {:error, reason}, state}
|
||||||
end
|
end
|
||||||
|
@ -313,7 +329,7 @@ defmodule Architex.RoomServer do
|
||||||
) do
|
) do
|
||||||
kick_event = Event.Kick.new(room, account, user_id, reason)
|
kick_event = Event.Kick.new(room, account, user_id, reason)
|
||||||
|
|
||||||
case Repo.transaction(insert_single_event(room, state_set, kick_event)) do
|
case Repo.transaction(process_event(room, state_set, kick_event)) do
|
||||||
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
||||||
{:error, reason} -> {:reply, {:error, reason}, state}
|
{:error, reason} -> {:reply, {:error, reason}, state}
|
||||||
end
|
end
|
||||||
|
@ -326,7 +342,7 @@ defmodule Architex.RoomServer do
|
||||||
) do
|
) do
|
||||||
ban_event = Event.Ban.new(room, account, user_id, reason)
|
ban_event = Event.Ban.new(room, account, user_id, reason)
|
||||||
|
|
||||||
case Repo.transaction(insert_single_event(room, state_set, ban_event)) do
|
case Repo.transaction(process_event(room, state_set, ban_event)) do
|
||||||
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
||||||
{:error, reason} -> {:reply, {:error, reason}, state}
|
{:error, reason} -> {:reply, {:error, reason}, state}
|
||||||
end
|
end
|
||||||
|
@ -335,7 +351,7 @@ defmodule Architex.RoomServer do
|
||||||
def handle_call({:unban, account, user_id}, _from, %{room: room, state_set: state_set} = state) do
|
def handle_call({:unban, account, user_id}, _from, %{room: room, state_set: state_set} = state) do
|
||||||
unban_event = Event.Unban.new(room, account, user_id)
|
unban_event = Event.Unban.new(room, account, user_id)
|
||||||
|
|
||||||
case Repo.transaction(insert_single_event(room, state_set, unban_event)) do
|
case Repo.transaction(process_event(room, state_set, unban_event)) do
|
||||||
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
{:ok, {state_set, room, _}} -> {:reply, :ok, %{state | state_set: state_set, room: room}}
|
||||||
{:error, reason} -> {:reply, {:error, reason}, state}
|
{:error, reason} -> {:reply, {:error, reason}, state}
|
||||||
end
|
end
|
||||||
|
@ -368,7 +384,7 @@ defmodule Architex.RoomServer do
|
||||||
) do
|
) do
|
||||||
message_event = Event.custom_event(room, account, event_type, content)
|
message_event = Event.custom_event(room, account, event_type, content)
|
||||||
|
|
||||||
case Repo.transaction(insert_event_with_txn(state_set, room, device, message_event, txn_id)) do
|
case Repo.transaction(process_event_with_txn(state_set, room, device, message_event, txn_id)) do
|
||||||
{:ok, {state_set, room, event_id}} ->
|
{:ok, {state_set, room, event_id}} ->
|
||||||
{:reply, {:ok, event_id}, %{state | state_set: state_set, room: room}}
|
{:reply, {:ok, event_id}, %{state | state_set: state_set, room: room}}
|
||||||
|
|
||||||
|
@ -384,7 +400,7 @@ defmodule Architex.RoomServer do
|
||||||
) do
|
) do
|
||||||
state_event = Event.custom_state_event(room, account, event_type, content, state_key)
|
state_event = Event.custom_state_event(room, account, event_type, content, state_key)
|
||||||
|
|
||||||
case Repo.transaction(insert_single_event(room, state_set, state_event)) do
|
case Repo.transaction(process_event(room, state_set, state_event)) do
|
||||||
{:ok, {state_set, room, %Event{id: event_id}}} ->
|
{:ok, {state_set, room, %Event{id: event_id}}} ->
|
||||||
{:reply, {:ok, event_id}, %{state | state_set: state_set, room: room}}
|
{:reply, {:ok, event_id}, %{state | state_set: state_set, room: room}}
|
||||||
|
|
||||||
|
@ -393,9 +409,9 @@ defmodule Architex.RoomServer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec insert_event_with_txn(t(), Room.t(), Device.t(), %Event{}, String.t()) ::
|
@spec process_event_with_txn(t(), Room.t(), Device.t(), %Event{}, String.t()) ::
|
||||||
(() -> {t(), Room.t(), String.t()} | {:error, atom()})
|
(() -> {t(), Room.t(), String.t()} | {:error, atom()})
|
||||||
defp insert_event_with_txn(
|
defp process_event_with_txn(
|
||||||
state_set,
|
state_set,
|
||||||
room,
|
room,
|
||||||
%Device{nid: device_nid} = device,
|
%Device{nid: device_nid} = device,
|
||||||
|
@ -413,7 +429,7 @@ defmodule Architex.RoomServer do
|
||||||
|
|
||||||
nil ->
|
nil ->
|
||||||
with {state_set, room, %Event{id: event_id}} <-
|
with {state_set, room, %Event{id: event_id}} <-
|
||||||
insert_single_event(room, state_set, message_event).() do
|
process_event(room, state_set, message_event).() do
|
||||||
# Mark this transaction as done.
|
# Mark this transaction as done.
|
||||||
Ecto.build_assoc(device, :device_transactions, txn_id: txn_id, event_id: event_id)
|
Ecto.build_assoc(device, :device_transactions, txn_id: txn_id, event_id: event_id)
|
||||||
|> Repo.insert!()
|
|> Repo.insert!()
|
||||||
|
@ -424,11 +440,11 @@ defmodule Architex.RoomServer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec insert_single_event(Room.t(), t(), %Event{}) ::
|
@spec process_event(Room.t(), t(), %Event{}) ::
|
||||||
(() -> {t(), Room.t(), Event.t()} | {:error, atom()})
|
(() -> {t(), Room.t(), Event.t()} | {:error, atom()})
|
||||||
defp insert_single_event(room, state_set, event) do
|
defp process_event(room, state_set, event) do
|
||||||
fn ->
|
fn ->
|
||||||
case finalize_and_insert_event(event, state_set, room) do
|
case finalize_and_process_event(event, state_set, room) do
|
||||||
{:ok, state_set, room, event} ->
|
{:ok, state_set, room, event} ->
|
||||||
_ = update_room_state_set(room, state_set)
|
_ = update_room_state_set(room, state_set)
|
||||||
{state_set, room, event}
|
{state_set, room, event}
|
||||||
|
@ -439,27 +455,53 @@ defmodule Architex.RoomServer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get a function that inserts all events for room creation.
|
@spec process_events(Room.t(), t(), [%Event{}]) ::
|
||||||
@spec create_room_insert_events(Room.t(), Account.t(), CreateRoom.t()) ::
|
(() -> {t(), Room.t()} | {:error, atom()})
|
||||||
(() -> {:ok, t(), Room.t()} | {:error, atom()})
|
defp process_events(room, state_set, events) do
|
||||||
defp create_room_insert_events(room, account, %CreateRoom{
|
fn ->
|
||||||
room_version: room_version,
|
Enum.reduce_while(events, {state_set, room}, fn event, {state_set, room} ->
|
||||||
preset: preset,
|
case finalize_and_process_event(event, state_set, room) do
|
||||||
name: name,
|
{:ok, state_set, room, _} -> {:cont, {state_set, room}}
|
||||||
topic: topic,
|
{:error, reason} -> {:halt, {:error, reason}}
|
||||||
invite: invite,
|
end
|
||||||
power_level_content_override: power_level_content_override,
|
end)
|
||||||
is_direct: is_direct,
|
|> then(fn
|
||||||
creation_content: creation_content,
|
{:error, reason} ->
|
||||||
initial_state: initial_state
|
Repo.rollback(reason)
|
||||||
}) do
|
|
||||||
|
{state_set, room} ->
|
||||||
|
_ = update_room_state_set(room, state_set)
|
||||||
|
{state_set, room}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec create_room_events(Room.t(), Account.t(), CreateRoom.t(), Alias.t() | nil) :: [%Event{}]
|
||||||
|
defp create_room_events(
|
||||||
|
room,
|
||||||
|
account,
|
||||||
|
%CreateRoom{
|
||||||
|
room_version: room_version,
|
||||||
|
preset: preset,
|
||||||
|
name: name,
|
||||||
|
topic: topic,
|
||||||
|
invite: invite,
|
||||||
|
power_level_content_override: power_level_content_override,
|
||||||
|
is_direct: is_direct,
|
||||||
|
creation_content: creation_content,
|
||||||
|
initial_state: initial_state
|
||||||
|
},
|
||||||
|
alias_
|
||||||
|
) do
|
||||||
invite_events = room_creation_invite_events(account, invite, room, is_direct)
|
invite_events = room_creation_invite_events(account, invite, room, is_direct)
|
||||||
|
|
||||||
|
# Spec doesn't specify where to insert canonical_alias event, do it after topic event.
|
||||||
name_and_topic_events =
|
name_and_topic_events =
|
||||||
Enum.reject(
|
Enum.reject(
|
||||||
[
|
[
|
||||||
if(name, do: Event.Name.new(room, account, name)),
|
if(name, do: Event.Name.new(room, account, name)),
|
||||||
if(topic, do: Event.Topic.new(room, account, topic))
|
if(topic, do: Event.Topic.new(room, account, topic)),
|
||||||
|
if(alias_, do: Event.CanonicalAlias.new(room, account, alias_.alias))
|
||||||
],
|
],
|
||||||
&Kernel.is_nil/1
|
&Kernel.is_nil/1
|
||||||
)
|
)
|
||||||
|
@ -490,28 +532,8 @@ defmodule Architex.RoomServer do
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
events =
|
basic_events ++
|
||||||
basic_events ++
|
preset_events ++ initial_state_events ++ name_and_topic_events ++ invite_events
|
||||||
preset_events ++ initial_state_events ++ name_and_topic_events ++ invite_events
|
|
||||||
|
|
||||||
fn ->
|
|
||||||
result =
|
|
||||||
Enum.reduce_while(events, {%{}, room}, fn event, {state_set, room} ->
|
|
||||||
case finalize_and_insert_event(event, state_set, room) do
|
|
||||||
{:ok, state_set, room, _} -> {:cont, {state_set, room}}
|
|
||||||
{:error, reason} -> {:halt, {:error, reason}}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
case result do
|
|
||||||
{:error, reason} ->
|
|
||||||
Repo.rollback(reason)
|
|
||||||
|
|
||||||
{state_set, room} ->
|
|
||||||
_ = update_room_state_set(room, state_set)
|
|
||||||
{state_set, room}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update the given room in the database with the given state set.
|
# Update the given room in the database with the given state set.
|
||||||
|
@ -579,9 +601,9 @@ defmodule Architex.RoomServer do
|
||||||
# - Content hash
|
# - Content hash
|
||||||
# - Event ID
|
# - Event ID
|
||||||
# - Signature
|
# - Signature
|
||||||
@spec finalize_and_insert_event(%Event{}, t(), Room.t()) ::
|
@spec finalize_and_process_event(%Event{}, t(), Room.t()) ::
|
||||||
{:ok, t(), Room.t(), Event.t()} | {:error, atom()}
|
{:ok, t(), Room.t(), Event.t()} | {:error, atom()}
|
||||||
defp finalize_and_insert_event(
|
defp finalize_and_process_event(
|
||||||
event,
|
event,
|
||||||
state_set,
|
state_set,
|
||||||
%Room{forward_extremities: forward_extremities} = room
|
%Room{forward_extremities: forward_extremities} = room
|
||||||
|
@ -593,7 +615,7 @@ defmodule Architex.RoomServer do
|
||||||
|> Map.put(:depth, get_depth(forward_extremities))
|
|> Map.put(:depth, get_depth(forward_extremities))
|
||||||
|
|
||||||
case Event.post_process(event) do
|
case Event.post_process(event) do
|
||||||
{:ok, event} -> authenticate_and_insert_event(event, state_set, room)
|
{:ok, event} -> authenticate_and_process_event(event, state_set, room)
|
||||||
_ -> {:error, :event_creation}
|
_ -> {:error, :event_creation}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -660,9 +682,9 @@ defmodule Architex.RoomServer do
|
||||||
# Authenticate and insert a new event using state resolution.
|
# Authenticate and insert a new event using state resolution.
|
||||||
# Implements the checks as described in the
|
# Implements the checks as described in the
|
||||||
# [Matrix docs](https://matrix.org/docs/spec/server_server/latest#checks-performed-on-receipt-of-a-pdu).
|
# [Matrix docs](https://matrix.org/docs/spec/server_server/latest#checks-performed-on-receipt-of-a-pdu).
|
||||||
@spec authenticate_and_insert_event(Event.t(), t(), Room.t()) ::
|
@spec authenticate_and_process_event(Event.t(), t(), Room.t()) ::
|
||||||
{:ok, t(), Room.t(), Event.t()} | {:error, atom()}
|
{:ok, t(), Room.t(), Event.t()} | {:error, atom()}
|
||||||
defp authenticate_and_insert_event(event, current_state_set, room) do
|
defp authenticate_and_process_event(event, current_state_set, room) do
|
||||||
# TODO: Correctly handle soft fails.
|
# TODO: Correctly handle soft fails.
|
||||||
# Check the following things:
|
# Check the following things:
|
||||||
# 1. TODO: Is a valid event, otherwise it is dropped.
|
# 1. TODO: Is a valid event, otherwise it is dropped.
|
||||||
|
|
|
@ -6,13 +6,18 @@ defmodule Architex.Alias do
|
||||||
alias Architex.{Repo, Alias, Room}
|
alias Architex.{Repo, Alias, Room}
|
||||||
alias Ecto.Changeset
|
alias Ecto.Changeset
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{
|
||||||
|
alias: String.t(),
|
||||||
|
room_id: String.t()
|
||||||
|
}
|
||||||
|
|
||||||
@primary_key {:alias, :string, []}
|
@primary_key {:alias, :string, []}
|
||||||
schema "aliases" do
|
schema "aliases" do
|
||||||
belongs_to :room, Room, foreign_key: :room_id, references: :id, type: :string
|
belongs_to :room, Room, foreign_key: :room_id, references: :id, type: :string
|
||||||
end
|
end
|
||||||
|
|
||||||
def create(alias, room_id) do
|
def create(alias_, room_id) do
|
||||||
change(%Alias{}, alias: alias, room_id: room_id)
|
change(%Alias{}, alias: alias_, room_id: room_id)
|
||||||
|> assoc_constraint(:room)
|
|> assoc_constraint(:room)
|
||||||
|> unique_constraint(:alias, name: :aliases_pkey)
|
|> unique_constraint(:alias, name: :aliases_pkey)
|
||||||
|> Repo.insert()
|
|> Repo.insert()
|
||||||
|
|
|
@ -282,6 +282,7 @@ end
|
||||||
|
|
||||||
defmodule Architex.Event.Unban do
|
defmodule Architex.Event.Unban do
|
||||||
alias Architex.{Event, Account, Room}
|
alias Architex.{Event, Account, Room}
|
||||||
|
|
||||||
@spec new(Room.t(), Account.t(), String.t()) :: %Event{}
|
@spec new(Room.t(), Account.t(), String.t()) :: %Event{}
|
||||||
def new(room, sender, user_id) do
|
def new(room, sender, user_id) do
|
||||||
%Event{
|
%Event{
|
||||||
|
@ -294,3 +295,21 @@ defmodule Architex.Event.Unban do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defmodule Architex.Event.CanonicalAlias do
|
||||||
|
alias Architex.{Event, Account, Room}
|
||||||
|
|
||||||
|
@spec new(Room.t(), Account.t(), String.t() | nil, [String.t()] | nil) :: %Event{}
|
||||||
|
def new(room, sender, alias_ \\ nil, alt_aliases \\ nil) do
|
||||||
|
content = %{}
|
||||||
|
content = if alias_, do: Map.put(content, "alias", alias_), else: content
|
||||||
|
content = if alt_aliases, do: Map.put(content, "alt_aliases", alt_aliases), else: content
|
||||||
|
|
||||||
|
%Event{
|
||||||
|
Event.new(room, sender)
|
||||||
|
| type: "m.room.canonical_alias",
|
||||||
|
state_key: "",
|
||||||
|
content: content
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -25,6 +25,9 @@ defmodule ArchitexWeb.Client.RoomController do
|
||||||
{:error, :authorization} ->
|
{:error, :authorization} ->
|
||||||
put_error(conn, :invalid_room_state)
|
put_error(conn, :invalid_room_state)
|
||||||
|
|
||||||
|
{:error, :alias} ->
|
||||||
|
put_error(conn, :room_in_use, "The requested alias is already in use.")
|
||||||
|
|
||||||
{:error, :unknown} ->
|
{:error, :unknown} ->
|
||||||
put_error(conn, :unknown)
|
put_error(conn, :unknown)
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,7 @@ defmodule ArchitexWeb.Error do
|
||||||
unauthorized: {400, "M_UNAUTHORIZED", "The request was unauthorized."},
|
unauthorized: {400, "M_UNAUTHORIZED", "The request was unauthorized."},
|
||||||
invalid_param: {400, "M_INVALID_PARAM", "A request parameter was invalid."},
|
invalid_param: {400, "M_INVALID_PARAM", "A request parameter was invalid."},
|
||||||
missing_param: {400, "M_MISSING_PARAM", "A request parameter is missing."},
|
missing_param: {400, "M_MISSING_PARAM", "A request parameter is missing."},
|
||||||
|
room_in_use: {400, "M_ROOM_IN_USE", "The room is already in use."},
|
||||||
unknown_token: {401, "M_UNKNOWN_TOKEN", "Invalid access token."},
|
unknown_token: {401, "M_UNKNOWN_TOKEN", "Invalid access token."},
|
||||||
missing_token: {401, "M_MISSING_TOKEN", "Access token required."},
|
missing_token: {401, "M_MISSING_TOKEN", "Access token required."},
|
||||||
not_found: {404, "M_NOT_FOUND", "The requested resource was not found."},
|
not_found: {404, "M_NOT_FOUND", "The requested resource was not found."},
|
||||||
|
|
Loading…
Reference in a new issue