diff --git a/lib/sukaato/standard_queries.ex b/lib/sukaato/standard_queries.ex new file mode 100644 index 0000000..7b482a5 --- /dev/null +++ b/lib/sukaato/standard_queries.ex @@ -0,0 +1,173 @@ +defmodule Sukaato.StandardQueries do + alias Sukaato.{Repo, User, Post} + alias SukaatoWeb.Marker + import Ecto.Changeset + import Ecto.Query + + @rel_proj_root "../.." + @site_config_file Path.expand(@rel_proj_root <> "/site.toml", __DIR__) + @site_config Toml.decode_file(@site_config_file) + @admin_username elem(@site_config, 1)["site"]["username"] + @markdown_user_root Path.expand("../../lib/sukaato_web/controllers/page_md/users", __DIR__) + + @tables %{ + user: User, + post: Post + } + + + def add_entry(schema, type \\ :user) do + case type do + :user -> + entry = @tables.user.changeset(%User{}, schema) + result = Repo.insert(entry, on_conflict: {:replace_all_except, [:id, :slug, :inserted_at, :updated_at]}) + result + end + end + + def get_admin() do + query = from u in @tables.user, select: {u.username, u.perms} + results = Repo.all(query) + + results = Enum.filter(results, fn r -> Enum.at(elem(r, 1), length(elem(r, 1)) - 1) == 15 end) + results = Enum.map(results, fn r -> elem(r, 0) end) + results + end + + @doc """ + Gets the GPG public keys of the given user. + """ + def get_pubkeys(username \\ @admin_username, gpg_id \\ "") do + query = from u in @tables.user, select: u.pub_keys, where: u.username == ^username + pubkeys = Repo.all(query) + + if pubkeys != nil do + if length(pubkeys) > 0 do + if gpg_id != "" do + pubkeys = Enum.filter(pubkeys, fn k -> Map.has_key?(k, gpg_id) end) + + if length(pubkeys) > 0 do + pubkeys = Enum.map(pubkeys, fn k -> {gpg_id, k[gpg_id]} end) + {:ok, pubkeys} + else + {:ok, [{gpg_id, pubkeys}]} + end + else + key_choices = Enum.map(pubkeys, fn k -> Enum.random(Map.keys(k)) end) + selection = Enum.zip([key_choices, pubkeys]) + pubkeys = Enum.map(selection, fn s -> {elem(s, 0), elem(s, 1)[elem(s, 0)]} end) + {:ok, pubkeys} + end + else + {:ok, [{gpg_id, ""}]} + end + else + {:ok, [{gpg_id, ""}]} + end + # {:ok, {username, gpg_id, ""}} + end + +@doc """ +Gets and compiles a list of affiliate links or protocol addresses for the givn user. +""" + def get_inboxes(username \\ @admin_username, filter_protocols \\ [], method \\ :reject) do + query = from u in @tables.user, select: u.email, where: u.username == ^username + emails = Repo.all(query) + query = from u in @tables.user, select: u.affil, where: u.username == ^username + addresses = Repo.all(query) + + # @TODO create a database changeset schema for this in 'lib/sukaato/vschemas.ex' + emails = Enum.map(emails, fn e -> %{"name" => "EMAIL", "address" => e, "protocol" => "mailto", "scheme_postfix" => ":", "icon_uri" => "", "icon_name" => "envelope-solid"} end) + if length(filter_protocols) > 0 do + filter = filter_protocols + addresses = if method == :reject, do: Enum.filter(addresses, fn a -> !Enum.member?(filter, a.protocol) end), else: Enum.filter(addresses, fn a -> Enum.member?(filter, a.protocol) end) + inboxes = [emails | addresses] + # inboxes = Enum.map(inboxes, fn i -> for {k, v} <- i, into: %{}, do: {String.to_atom(k), v} end) + + {:ok, inboxes} + else + inboxes = [emails | addresses] + # inboxes = addresses + + {:ok, inboxes} + end + end + + def verify_login_token(token) when is_binary(token) do + token = String.split(token, ":", parts: 2) + username = Enum.at(token, 0) + query = from u in @tables.user, select: u.user_token, where: u.username == ^username + db_token = Repo.one(query) + + if is_nil(db_token) do + false + else + match_token = Enum.at(token, 1) + match_token == db_token + end + end + + def absorb_login_token(token) when is_binary(token) do + token = String.split(token, ":", parts: 2) + username = Enum.at(token, 0) + query = from u in @tables.user, where: u.username == ^username + result = Repo.one(query) + + if is_nil(result) do + {:ok, result} + else + token = Enum.at(token, 1) + demand = change(result, user_token: token) + result = Repo.update(demand) + {:ok, result} + end + end + + def dump_login_token(token) when is_binary(token) do + token = String.split(token, ":", parts: 2) + username = Enum.at(token, 0) + query = from u in @tables.user, where: u.username == ^username + result = Repo.one(query) + demand = if is_nil(result), do: result, else: change(result, user_token: nil) + result = if is_nil(demand), do: demand, else: Repo.update(demand) + result + end + + defp synchronize_posts(for_user, path \\ "") do + user_posts = if path != "", do: Path.wildcard(path), else: Path.wildcard(@markdown_user_root <> "/" <> for_user <> "/posts/*.md") + + if length(user_posts) > 0 do + # user_posts = if !is_list(user_posts), do: [user_posts], else: user_posts + user_posts = Enum.map(user_posts, fn p -> Path.basename(p) end) + user_posts = Enum.map(user_posts, fn p -> Marker.render_mark(p, :markdown_post, for_user) end) + user_posts = Enum.filter(user_posts, fn p -> elem(p, 0) == :ok end) + user_posts = Enum.map(user_posts, fn p -> Map.put(elem(p, 1), "content", elem(p, 2)) end) + user_posts = Enum.map(user_posts, fn p -> if Map.has_key?(p, "ledit"), do: Map.put(p, "ledit", Date.from_iso8601!(p["ledit"])), else: p end) + # user_posts = Enum.map(user_posts, fn p -> if Map.has_key?(p, "auth_id"), do: Map.put(p, "auth_id", elem(Integer.parse(p["auth_id"]), 0)), else: p end) + # user_posts = Enum.map(user_posts, fn p -> if Map.has_key?(p, "rev_id"), do: Map.put(p, "rev_id", elem(Integer.parse(p["auth_id"]), 0)), else: p end) + user_posts = Map.new(user_posts, fn {k, v} -> {String.to_atom(k), v} end) + # @TODO push user_posts to database + user_posts = Enum.map(user_posts, fn p -> @tables.post.changeset(%Post{}, p) end) + results = Repo.insert_all(@tables.post, user_posts, on_conflict: {:replace_all_except, [:id, :slug, :inserted_at, :updated_at]}) + + results + else + {:ok, user_posts} + end + end + + def synchronize(sync_source \\ :storage, for_user \\ @admin_username) do + if is_atom(sync_source) do + case sync_source do + :storage -> + results = synchronize_posts(for_user) + results + end + end + + if is_binary(sync_source) do + results = synchronize_posts(for_user, sync_source) + results + end + end +end