Skip to content

Commit

Permalink
backup. working version
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanIvanoff committed Aug 2, 2023
1 parent a0f33fd commit 5acf283
Show file tree
Hide file tree
Showing 10 changed files with 311 additions and 160 deletions.
36 changes: 18 additions & 18 deletions lib/sanbase/queries/dashboard/dashboard.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ defmodule Sanbase.Queries.Dashboard do

alias Sanbase.Repo
alias Sanbase.Accounts.User
alias Sanbase.Queries.Query

@type t :: %__MODULE__{
id: non_neg_integer(),
Expand All @@ -32,20 +33,15 @@ defmodule Sanbase.Queries.Dashboard do
optional(:name) => String.t(),
optional(:description) => String.t(),
optional(:is_public) => boolean(),
optional(:settings) => map(),
optional(:sql_query) => String.t(),
optional(:sql_parameters) => Map.t(),
optional(:origin_id) => non_neg_integer()
optional(:parameters) => map()
}

@type update_dashboard_args :: %{
optional(:name) => String.t(),
optional(:description) => String.t(),
optional(:is_public) => boolean(),
optional(:settings) => map(),
optional(:sql_query) => String.t(),
optional(:sql_parameters) => Map.t(),
optional(:origin_id) => non_neg_integer(),
optional(:parameters) => map(),
# updatable by moderators only
optional(:is_deleted) => boolean(),
optional(:is_hidden) => boolean()
}
Expand Down Expand Up @@ -74,9 +70,9 @@ defmodule Sanbase.Queries.Dashboard do
# Linked queries
many_to_many(
:queries,
Label,
Query,
join_through: "dashboard_query_mappings",
join_keys: [dashboard_id: :id, label_id: :id],
join_keys: [dashboard_id: :id, query_id: :id],
on_replace: :delete,
on_delete: :delete_all
)
Expand All @@ -100,6 +96,7 @@ defmodule Sanbase.Queries.Dashboard do

@create_fields [:name, :description, :is_public, :parameters, :user_id]
@update_fields @create_fields -- [:user_id]
@preload [:queries, :user, :featured_item]

def create_changeset(%__MODULE__{} = dashboard, attrs) do
dashboard
Expand All @@ -117,30 +114,33 @@ defmodule Sanbase.Queries.Dashboard do
Get a query in order to read or run it.
This can be done by owner or by anyone if the query is public.
"""
@spec get_for_read(query_id, user_id | nil) :: Ecto.Query.t()
def get_for_read(query_id, nil = _querying_user_id) do
@spec get_for_read(dashboard_id, user_id | nil) :: Ecto.Query.t()
def get_for_read(dashboard_id, nil = _querying_user_id) do
from(
q in base_query(),
where: q.id == ^query_id and q.is_public == true
where: q.id == ^dashboard_id and q.is_public == true,
preload: ^@preload
)
end

def get_for_read(query_id, querying_user_id) do
def get_for_read(dashboard_id, querying_user_id) do
from(
q in base_query(),
where: q.id == ^query_id and (q.is_public == true or q.user_id == ^querying_user_id)
where: q.id == ^dashboard_id and (q.is_public == true or q.user_id == ^querying_user_id),
preload: ^@preload
)
end

@doc ~s"""
Get a query in order to mutate it (update or delete).
Only the owner of the query can do that.
"""
@spec get_for_mutation(query_id, user_id) :: Ecto.Query.t()
def get_for_mutation(query_id, querying_user_id) when not is_nil(querying_user_id) do
@spec get_for_mutation(dashboard_id, user_id) :: Ecto.Query.t()
def get_for_mutation(dashboard_id, querying_user_id) when not is_nil(querying_user_id) do
from(
q in base_query(),
where: q.id == ^query_id and q.user_id == ^querying_user_id
where: q.id == ^dashboard_id and q.user_id == ^querying_user_id,
preload: ^@preload
)
end

Expand Down
30 changes: 20 additions & 10 deletions lib/sanbase/queries/dashboard/dashboard_query_mapping.ex
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
# defmodule Sanbase.Queries.DashboardQueryMapping do
# use Ecto.Schema
defmodule Sanbase.Queries.DashboardQueryMapping do
use Ecto.Schema

# alias Sanbase.Queries.Dashboard
# alias Sanbase.Queries.Query
import Ecto.Changeset

# schema "dashboard_query_mappings" do
# field(:settings, :map)
alias Sanbase.Queries.Dashboard
alias Sanbase.Queries.Query

# belongs_to(:query, Query)
# belongs_to(:dashboard, Dashboard)
# end
# end
schema "dashboard_query_mappings" do
field(:settings, :map)

belongs_to(:query, Query)
belongs_to(:dashboard, Dashboard)

timestamps()
end

def create_changeset(%__MODULE__{} = mapping, args) do
mapping
|> cast(args, [:dashboard_id, :query_id, :settings])
|> validate_required([:dashboard_id, :query_id])
end
end
199 changes: 124 additions & 75 deletions lib/sanbase/queries/dashboards.ex
Original file line number Diff line number Diff line change
@@ -1,54 +1,20 @@
defmodule Sanbase.Dashboards do
alias Sanbase.Repo
alias Sanbase.Queries.Dashboard
alias Sanbase.Queries.DashboardQueryMapping

def get_user_dashboards(user_id) do
query =
from(
ds in __MODULE__,
where: ds.user_id == ^user_id
)
import Sanbase.Utils.ErrorHandling, only: [changeset_errors_string: 1]

{:ok, Repo.all(query)}
end

def is_public?(%__MODULE__{is_public: is_public}), do: is_public

def user_dashboards(user_id) do
query =
from(
ds in __MODULE__,
where: ds.user_id == ^user_id
)

{:ok, Repo.all(query)}
end

def user_public_dashboards(user_id) do
query =
from(
ds in __MODULE__,
where: ds.user_id == ^user_id and ds.is_public == true
)

{:ok, Repo.all(query)}
end
# Type aliases
@type dashboard_id :: Dashboard.dashboard_id()
@type query_id :: Sanbase.Queries.Query.query_id()
@type user_id :: Dashboard.user_id()
@type create_dashboard_args :: Dashboard.create_dashboard_args()
@type update_dashboard_args :: Dashboard.update_dashboard_args()

@spec get_is_public_and_owner(non_neg_integer()) ::
{:ok, %{user_id: non_neg_integer(), is_public: boolean()}}
| {:error, String.t()}
def get_is_public_and_owner(dashboard_id) do
result =
from(d in __MODULE__,
where: d.id == ^dashboard_id,
select: %{user_id: d.user_id, is_public: d.is_public}
)
|> Repo.one()

case result do
nil -> {:error, "Dashboard does not exist"}
data -> {:ok, data}
end
def get_dashboard(dashboard_id, querying_user_id) do
Dashboard.get_for_read(dashboard_id, querying_user_id)
|> Repo.one()
end

@doc ~s"""
Expand All @@ -61,54 +27,137 @@ defmodule Sanbase.Dashboards do
- user_id: The id of the user that created the query.
TODO
"""
@spec create_dashboard(Dashboard.create_dashboard_args(), user_id) ::
{:ok, Query.t()} | {:error, String.t()} | {:error, Ecto.Changeset.t()}
@spec create_dashboard(user_id(), create_dashboard_args()) ::
{:ok, Dashboard.t()} | {:error, String.t()} | {:error, Ecto.Changeset.t()}
def create_dashboard(args, user_id) do
uuid = "query_" <> Uniq.UUID.uuid7()
args = args |> Map.merge(%{user_id: user_id, uuid: uuid})
args = args |> Map.merge(%{user_id: user_id})

changeset = Query.create_changeset(%Query{}, args)
changeset = Dashboard.create_changeset(%Dashboard{}, args)

Repo.insert(changeset)
end

@spec update(dashboard_id(), schema_args()) ::
{:ok, t()} | {:error, Changeset.t()}
def update(dashboard_id, args) do
transaction_result =
Ecto.Multi.new()
|> Ecto.Multi.run(:get_for_mutation, fn _repo, _changes ->
query = Dashboard.get_for_mutation(Dashboard_id, querying_user_id)

case Repo.one(query) do
%Dashboard{} = struct -> {:ok, struct}
nil -> {:error, "Dashboard does not exist or it belongs to another user."}
end
end)
|> Ecto.Multi.run(:update, fn _repo, %{get_for_mutation: struct} ->
Dashboard.update_changeset(struct, attrs) |> Repo.update()
end)
|> Repo.transaction()

handle_ecto_multi_result(transaction_result, :update)
@spec update_dashboard(dashboard_id(), create_dashboard_args(), user_id()) ::
{:ok, Dashboard.t()} | {:error, Changeset.t()}
def update_dashboard(dashboard_id, args, querying_user_id) do
Ecto.Multi.new()
|> Ecto.Multi.run(:get_for_mutation, fn _repo, _changes ->
get_for_mutation(dashboard_id, querying_user_id)
end)
|> Ecto.Multi.run(:update, fn _repo, %{get_for_mutation: struct} ->
Dashboard.update_changeset(struct, args) |> Repo.update()
end)
|> Repo.transaction()
|> process_transaction_result(:update)
end

@doc ~s"""
Delete a dashboard.
"""
@spec delete(dashboard_id) :: {:ok, t()} | {:error, Changeset.t()}
def delete(dashboard_id) do
Repo.get(__MODULE__, dashboard_id) |> Repo.delete()
@spec delete_dashboard(dashboard_id(), user_id()) ::
{:ok, Dashboard.t()} | {:error, Changeset.t()}
def delete_dashboard(dashboard_id, querying_user_id) do
Ecto.Multi.new()
|> Ecto.Multi.run(:get_for_mutation, fn _repo, _changes ->
get_for_mutation(dashboard_id, querying_user_id)
end)
|> Ecto.Multi.run(:delete, fn _repo, %{get_for_mutation: struct} ->
Repo.delete(struct)
end)
|> Repo.transaction()
|> process_transaction_result(:delete)
end

@doc ~s"""
TODO
"""
@spec public?(Dashboard.t()) :: boolean()
def public?(%Dashboard{is_public: is_public}), do: is_public

@doc ~s"""
TODO
"""
@spec user_dashboards(user_id()) :: {:ok, [Dashboard.t()]}
def user_dashboards(user_id) do
# query =
# from(
# ds in Dashboard,
# where: ds.user_id == ^user_id
# )

# {:ok, Repo.all(query)}
end

@doc ~s"""
TODO
"""
@spec user_public_dashboards(user_id()) :: {:ok, [Dashboard.t()]}
def user_public_dashboards(user_id) do
# query =
# from(
# ds in Dashboard,
# where: ds.user_id == ^user_id and ds.is_public == true
# )

# {:ok, Repo.all(query)}
end

@spec get_is_public_and_owner(dashboard_id()) ::
{:ok, %{user_id: user_id(), is_public: boolean()}} | {:error, String.t()}
def get_is_public_and_owner(dashboard_id) do
# result =
# from(d in Dashboard,
# where: d.id == ^dashboard_id,
# select: %{user_id: d.user_id, is_public: d.is_public}
# )
# |> Repo.one()

# case result do
# nil -> {:error, "Dashboard does not exist"}
# data -> {:ok, data}
# end
end

@spec add_query_to_dashboard(dashboard_id(), query_id(), Map.t(), user_id()) ::
{:ok, Dashboard.t()} | {:error, String.t()}
def add_query_to_dashboard(dashboard_id, query_id, settings, querying_user_id) do
Ecto.Multi.new()
|> Ecto.Multi.run(:get_for_mutation, fn _repo, _changes ->
# Only to make sure the querying user can mutate the dashboard
get_for_mutation(dashboard_id, querying_user_id)
end)
|> Ecto.Multi.run(:add_query_to_dashboard, fn _repo, %{get_for_mutation: _struct} ->
query =
DashboardQueryMapping.create_changeset(%DashboardQueryMapping{}, %{
dashboard_id: dashboard_id,
query_id: query_id,
settings: settings,
user_id: querying_user_id
})

Repo.insert(query)
end)
|> Repo.transaction()
|> process_transaction_result(:add_query_to_dashboard)
end

# Private functions

defp handle_ecto_multi_result({:ok, map}, ok_field),
defp get_for_mutation(dashboard_id, querying_user_id) do
query = Dashboard.get_for_mutation(dashboard_id, querying_user_id)

case Repo.one(query) do
%Dashboard{} = struct -> {:ok, struct}
nil -> {:error, "Dashboard does not exist or it belongs to another user."}
end
end

defp process_transaction_result({:ok, map}, ok_field),
do: {:ok, map[ok_field]}

defp handle_ecto_multi_result({:error, _, %Ecto.Changeset{} = changeset, _}, _ok_field),
defp process_transaction_result({:error, _, %Ecto.Changeset{} = changeset, _}, _ok_field),
do: {:error, changeset_errors_string(changeset)}

defp handle_ecto_multi_result({:error, _, error, _}, _ok_field),
defp process_transaction_result({:error, _, error, _}, _ok_field),
do: {:error, error}
end
Loading

0 comments on commit 5acf283

Please sign in to comment.