1
0
mirror of https://github.com/mgerb/classic-wow-forums synced 2026-01-10 17:12:48 +00:00
Files
classic-wow-forums/lib/myapp/data/user.ex

134 lines
4.2 KiB
Elixir

defmodule MyApp.Data.User do
use Ecto.Schema
import Ecto.Query
import Ecto.Changeset
alias MyApp.Repo
alias MyApp.Data
@derive {Poison.Encoder, except: [:__meta__, :__struct__]}
schema "user" do
field :battle_net_id, :integer
field :battletag, :string
field :permissions, :string, default: "user" # admin, mod, user
field :character_guild, :string
field :character_name, :string
field :character_class, :string
field :character_realm, :string
field :character_avatar, :string
# for admin purposes
field :username, :string
field :password, :string
timestamps(type: :utc_datetime)
end
defp changeset(user, params \\ %{}) do
user
|> cast(params, [:battle_net_id, :battletag])
|> validate_required([:battle_net_id, :battletag])
|> unique_constraint(:battle_net_id)
end
defp update_char_changeset(user, params \\ %{}) do
user
|> cast(params, [:character_guild, :character_name, :character_class, :character_realm, :character_avatar])
|> validate_required([:character_name, :character_class, :character_realm, :character_avatar])
end
def update_character(params) do
{:ok, data} = Repo.transaction(fn ->
user = Repo.get(__MODULE__, Map.get(params, "id"))
# remove columns from data because we need to update all of them
|> Map.drop([:character_realm, :character_name, :character_guild, :character_class, :character_avatar])
output = user
|> update_char_changeset(params)
|> Repo.update
|> Data.Util.process_insert_or_update
end)
data
end
@spec get_user(integer) :: nil | map
defp get_user(battle_net_id) do
query = from u in "user",
where: u.battle_net_id == ^battle_net_id,
select: [:id, :permissions, :battle_net_id, :battletag, :character_guild, :character_name, :character_class, :character_realm, :character_avatar]
Repo.one(query)
end
# insert user info in database - if not exists - update battletag if it has changed
@spec upsert_user(%{"battle_net_id": integer, "battletag": String.t, "access_token": String.t} | tuple) :: {:ok, map} | {:error, any}
def upsert_user(params) when is_map(params) do
# check for current user in database
user = get_user(Map.get(params, "battle_net_id"))
output = cond do
is_nil(user) ->
insert_battlenet_user(params)
true ->
if Map.get(user, :battletag) != Map.get(params, "battletag") do
update_battletag(user, params)
else
{:ok, user}
end
end
output
|> add_extra_params(params)
end
def upsert_user({:ok, params}), do: upsert_user(params)
def upsert_user({:error, error}), do: {:error, error}
# need to add token back to map because we don't store it in the database
defp add_extra_params({:error, error}, _), do: {:error, error}
defp add_extra_params({:ok, user}, params) do
{:ok, Map.merge(user, params)}
end
defp insert_battlenet_user(params) do
changeset(%Data.User{}, params)
|> Repo.insert
|> Data.Util.process_insert_or_update
|> filter_values
end
# it's possible for a user's battle tag to change - if so update it
defp update_battletag(user, params) do
changeset(Map.merge(%Data.User{}, user), %{battletag: Map.get(params, "battletag")})
|> Repo.update
|> Data.Util.process_insert_or_update
|> filter_values
end
# take certain values after insertion
defp filter_values({:error, error}), do: {:error, error}
defp filter_values({:ok, user}), do: {:ok, Map.take(user, [:id, :permissions, :battle_net_id, :battletag])}
def insert_admin_user(params) do
params = params
|> Map.put("password", Comeonin.Argon2.hashpwsalt(Map.get(params, "password")))
%Data.User{}
|> cast(params, [:username, :password, :permissions, :character_name, :character_avatar])
|> Repo.insert
end
def login(params) do
user = Repo.get_by(Data.User, username: Map.get(params, "username"))
if user do
case Comeonin.Argon2.checkpw(Map.get(params, "password"), user.password) do
false -> {:error, "invalid login"}
_ ->
user = user
|> Map.from_struct
|> Map.drop([:password, :__meta__])
{:ok, user}
end
else
{:error, "invalid login"}
end
end
end