251 lines
5.0 KiB
Elixir
251 lines
5.0 KiB
Elixir
defmodule Webring do
|
|
@moduledoc """
|
|
Webring keeps the contexts that define your domain
|
|
and business logic.
|
|
|
|
Contexts are also responsible for managing your data, regardless
|
|
if it comes from the database, an external API or others.
|
|
"""
|
|
import Ecto.Query, only: [from: 2]
|
|
alias Ecto.Multi
|
|
alias Webring.Repo
|
|
alias Webring.Site
|
|
alias Webring.User
|
|
alias Webring.Invite
|
|
|
|
def list_sites() do
|
|
Repo.all(Site)
|
|
end
|
|
|
|
def random_site() do
|
|
sites = list_sites
|
|
|
|
sites
|
|
|> Enum.at(:rand.uniform(Enum.count(sites)) - 1)
|
|
end
|
|
|
|
def prev_site(nil), do: {:error, "no such site"}
|
|
|
|
def prev_site(%Site{id: xid}) do
|
|
sites = list_sites
|
|
|
|
count = Enum.count(sites)
|
|
|
|
my_position =
|
|
sites
|
|
|> Enum.find_index(fn x -> x.id == xid end)
|
|
|
|
case my_position do
|
|
x when x > 0 ->
|
|
sites
|
|
|> Enum.at(x - 1)
|
|
|
|
_ ->
|
|
sites
|
|
|> Enum.at(count - 1)
|
|
end
|
|
end
|
|
|
|
def prev_site(%{from: id}) do
|
|
Repo.get(Site, id)
|
|
|> prev_site()
|
|
end
|
|
|
|
def prev_site(%{referrer: referrer}) do
|
|
me =
|
|
from(u in Site,
|
|
where: like(^referrer, u.url),
|
|
order_by: [desc: :url]
|
|
)
|
|
|> Repo.all()
|
|
|> List.first()
|
|
|
|
case me do
|
|
x when is_struct(x, Site) ->
|
|
prev_site(x)
|
|
|
|
_ ->
|
|
{:error, "referrer not recognised"}
|
|
end
|
|
end
|
|
|
|
def next_site(nil), do: {:error, "no such site"}
|
|
|
|
def next_site(%Site{id: xid}) do
|
|
sites = list_sites
|
|
|
|
count = Enum.count(sites)
|
|
|
|
my_position =
|
|
sites
|
|
|> Enum.find_index(fn x -> x.id == xid end)
|
|
|
|
case my_position do
|
|
x when x < count - 1 ->
|
|
sites
|
|
|> Enum.at(x + 1)
|
|
|
|
_ ->
|
|
sites
|
|
|> Enum.at(0)
|
|
end
|
|
end
|
|
|
|
def next_site(%{from: id}) do
|
|
Repo.get(Site, id)
|
|
|> next_site()
|
|
end
|
|
|
|
def next_site(%{referrer: referrer}) do
|
|
me =
|
|
from(u in Site,
|
|
where: like(^referrer, u.url),
|
|
order_by: [desc: :url]
|
|
)
|
|
|> Repo.all()
|
|
|> List.first()
|
|
|
|
case me do
|
|
x when is_struct(x, Site) ->
|
|
next_site(x)
|
|
|
|
_ ->
|
|
{:error, "referrer not recognised"}
|
|
end
|
|
end
|
|
|
|
def add_site(invite_code, params) do
|
|
case check_invite_code(invite_code) do
|
|
{:ok, invite} ->
|
|
remove_code = UUID.uuid1(:hex)
|
|
|
|
case Site.changeset(%Site{}, Map.put(params, :removal, remove_code)) |> Repo.insert() do
|
|
{:ok, _} ->
|
|
Invite.changeset(invite, %{uses: invite.uses + 1})
|
|
|> Repo.update()
|
|
|
|
_ ->
|
|
{:error, "database error"}
|
|
end
|
|
|
|
_ ->
|
|
{:error, "bad invite code"}
|
|
end
|
|
end
|
|
|
|
def rem_site(%{removal_code: removal_code} = _params) do
|
|
case Repo.get_by(Site, %{removal: removal_code}) do
|
|
x ->
|
|
x
|
|
|> Repo.delete()
|
|
|
|
_ ->
|
|
{:error, "no such removal_code"}
|
|
end
|
|
end
|
|
|
|
# these functions intended to be used from iex.
|
|
def create_admin(params) do
|
|
%User{}
|
|
|> User.changeset_with_password()
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def remove_admin(params) do
|
|
end
|
|
|
|
def set_password(params) do
|
|
end
|
|
|
|
###############################################
|
|
def authenticate(username, password) do
|
|
with user when not is_nil(user) <- Repo.get_by(User, %{username: username}),
|
|
true <- Webring.Password.verify(password, user.hashed_password) do
|
|
user
|
|
else
|
|
_ -> Webring.Password.dummy()
|
|
end
|
|
end
|
|
|
|
def admin_rem_site(id) do
|
|
Repo.get(Site, id)
|
|
|> Repo.delete()
|
|
end
|
|
|
|
def admin_rem_sites_by(%{owner: o} = params) do
|
|
query =
|
|
from(s in Site,
|
|
where: s.owner == ^o
|
|
)
|
|
|
|
Multi.new()
|
|
|> Multi.delete_all(:delete_all, query)
|
|
|> Repo.transaction()
|
|
end
|
|
|
|
def admin_rem_site_by(%{url: u} = params) do
|
|
Repo.get_by(Site, %{url: u})
|
|
|> Repo.delete()
|
|
end
|
|
|
|
def admin_add_site(params) do
|
|
remove_code = UUID.uuid1(:hex)
|
|
|
|
Site.changeset(%Site{}, Map.put(params, :removal, remove_code))
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def admin_change_site(id, params) do
|
|
Repo.get(Site, id)
|
|
|> Site.changeset(params)
|
|
|> Repo.update()
|
|
end
|
|
|
|
def admin_change_site_by(%{url: u}, params) do
|
|
Repo.get_by(Site, %{url: u})
|
|
|> Site.changeset(params)
|
|
|> Repo.update()
|
|
end
|
|
|
|
def admin_add_invite(params) do
|
|
invite = UUID.uuid1(:hex)
|
|
|
|
Invite.changeset(%Invite{}, Map.put(params, :code, invite))
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def admin_list_invites() do
|
|
Repo.all(Invite)
|
|
end
|
|
|
|
def admin_rem_invite(invite) do
|
|
case Repo.get_by(Invite, %{code: invite}) do
|
|
x ->
|
|
Invite.changeset(x, %{disabled: true})
|
|
|> Repo.update()
|
|
|
|
_ ->
|
|
{:error, "no valid invite"}
|
|
end
|
|
end
|
|
|
|
def check_invite_code(invite) do
|
|
case Repo.get_by(Invite, %{code: invite}) do
|
|
x = %{disabled: d} when d ->
|
|
{:error, "no valid invite"}
|
|
|
|
x = %{uses: u, max_uses: m, ends_at: e} when u < m or m == -1 ->
|
|
case DateTime.compare(DateTime.utc_now(), e) do
|
|
:lt ->
|
|
{:ok, x}
|
|
|
|
:gt ->
|
|
{:error, "no valid invite"}
|
|
end
|
|
|
|
_ ->
|
|
{:error, "no valid invite"}
|
|
end
|
|
end
|
|
end
|