webring/apps/webring/lib/webring.ex

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