Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds multitenancy support #180

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions lib/kaffy/resource_callbacks.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Kaffy.ResourceCallbacks do

def create_callbacks(conn, resource, changes) do
changeset = Kaffy.ResourceAdmin.create_changeset(resource, changes)
repo = Kaffy.Utils.repo()
repo = Kaffy.Utils.repo(resource)

repo.transaction(fn ->
result =
Expand All @@ -28,7 +28,7 @@ defmodule Kaffy.ResourceCallbacks do
{:ok, entry}
else
{:error, :not_found} ->
Kaffy.Utils.repo().insert(changeset)
Kaffy.Utils.repo(resource).insert(changeset)

unexpected_error ->
{:error, unexpected_error}
Expand All @@ -37,7 +37,7 @@ defmodule Kaffy.ResourceCallbacks do

def update_callbacks(conn, resource, entry, changes) do
changeset = Kaffy.ResourceAdmin.update_changeset(resource, entry, changes)
repo = Kaffy.Utils.repo()
repo = Kaffy.Utils.repo(resource)

repo.transaction(fn ->
result =
Expand All @@ -60,15 +60,15 @@ defmodule Kaffy.ResourceCallbacks do
{:ok, entry}
else
{:error, :not_found} ->
Kaffy.Utils.repo().update(changeset)
Kaffy.Utils.repo(resource).update(changeset)

unexpected_error ->
{:error, unexpected_error}
end
end

def delete_callbacks(conn, resource, entry) do
repo = Kaffy.Utils.repo()
repo = Kaffy.Utils.repo(resource)

repo.transaction(fn ->
result =
Expand Down Expand Up @@ -163,7 +163,7 @@ defmodule Kaffy.ResourceCallbacks do
{:ok, entry}
else
{:error, :not_found} ->
Kaffy.Utils.repo().delete(changeset)
Kaffy.Utils.repo(resource).delete(changeset)

unexpected_error ->
{:error, unexpected_error}
Expand Down
48 changes: 32 additions & 16 deletions lib/kaffy/resource_form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ defmodule Kaffy.ResourceForm do
)

true ->
build_html_input(resource[:schema], form, field, type, [])
build_html_input(resource, resource[:schema], form, field, type, [])
end
end

def form_field(changeset, form, field, opts \\ [])
def form_field(resource, changeset, form, field, opts \\ [])

def form_field(changeset, form, {field, options}, opts) do
def form_field(resource, changeset, form, {field, options}, opts) do
options = options || %{}

type =
Expand All @@ -50,7 +50,7 @@ defmodule Kaffy.ResourceForm do
end

permission =
case is_nil(changeset.data.id) do
case !Map.has_key?(changeset.data, :id) || is_nil(changeset.data.id) do
true -> Map.get(options, :create, :editable)
false -> Map.get(options, :update, :editable)
end
Expand All @@ -62,16 +62,24 @@ defmodule Kaffy.ResourceForm do
select(form, field, choices, class: "custom-select")

true ->
build_html_input(changeset.data, form, field, type, opts, permission == :readonly)
build_html_input(
resource,
changeset.data,
form,
field,
type,
opts,
permission == :readonly
)
end
end

def form_field(changeset, form, field, opts) do
def form_field(resource, changeset, form, field, opts) do
type = Kaffy.ResourceSchema.field_type(changeset.data.__struct__, field)
build_html_input(changeset.data, form, field, type, opts)
build_html_input(resource, changeset.data, form, field, type, opts)
end

defp build_html_input(schema, form, field, type, opts, readonly \\ false) do
defp build_html_input(resource, schema, form, field, type, opts, readonly \\ false) do
data = schema
{conn, opts} = Keyword.pop(opts, :conn)
opts = Keyword.put(opts, :readonly, readonly)
Expand All @@ -91,7 +99,7 @@ defmodule Kaffy.ResourceForm do
[
[
form_label(fp, f),
form_field(embed_changeset, fp, f, class: "form-control")
form_field(resource, embed_changeset, fp, f, class: "form-control")
]
| all
]
Expand All @@ -104,13 +112,13 @@ defmodule Kaffy.ResourceForm do
:id ->
case Kaffy.ResourceSchema.primary_key(schema) == [field] do
true -> text_input(form, field, opts)
false -> text_or_assoc(conn, schema, form, field, opts)
false -> text_or_assoc(conn, resource, form, field, opts)
end

:binary_id ->
case Kaffy.ResourceSchema.primary_key(schema) == [field] do
true -> text_input(form, field, opts)
false -> text_or_assoc(conn, schema, form, field, opts)
false -> text_or_assoc(conn, resource, form, field, opts)
end

:string ->
Expand Down Expand Up @@ -240,7 +248,9 @@ defmodule Kaffy.ResourceForm do
]
end

defp text_or_assoc(conn, schema, form, field, opts) do
defp text_or_assoc(conn, resource, form, field, opts) do
schema = resource[:schema]

actual_assoc =
Enum.filter(Kaffy.ResourceSchema.associations(schema), fn a ->
Kaffy.ResourceSchema.association(schema, a).owner_key == field
Expand All @@ -256,7 +266,8 @@ defmodule Kaffy.ResourceForm do
case field_no_id in Kaffy.ResourceSchema.associations(schema) do
true ->
assoc = Kaffy.ResourceSchema.association_schema(schema, field_no_id)
option_count = Kaffy.ResourceQuery.cached_total_count(assoc, true, assoc)
assoc_resource = Kaffy.Utils.get_resource_from_schema(conn, assoc)
option_count = Kaffy.ResourceQuery.cached_total_count(assoc_resource, true, assoc)

case option_count > 100 do
true ->
Expand Down Expand Up @@ -291,7 +302,7 @@ defmodule Kaffy.ResourceForm do
end

false ->
options = Kaffy.Utils.repo().all(assoc)
options = Kaffy.Utils.repo(resource).all(assoc)

fields = Kaffy.ResourceSchema.fields(assoc)

Expand Down Expand Up @@ -335,6 +346,11 @@ defmodule Kaffy.ResourceForm do
nil ->
{nil, ""}

errors when is_map(errors) ->
error_msg = Kaffy.ResourceAdmin.humanize_term(field) <> " has multiple errors!"

{error_msg, "is-invalid"}

messages ->
error_msg =
Kaffy.ResourceAdmin.humanize_term(field) <> " " <> Enum.join(messages, ", ") <> "!"
Expand All @@ -356,7 +372,7 @@ defmodule Kaffy.ResourceForm do

defp build_changeset_value(value), do: to_string(value)

def kaffy_input(conn, changeset, form, field, options) do
def kaffy_input(conn, resource, changeset, form, field, options) do
ft = Kaffy.ResourceSchema.field_type(changeset.data.__struct__, field)

case Kaffy.Utils.is_module(ft) && Keyword.has_key?(ft.__info__(:functions), :render_form) do
Expand All @@ -371,7 +387,7 @@ defmodule Kaffy.ResourceForm do
label_tag = if ft != :boolean, do: form_label(form, {field, options}), else: ""

field_tag =
form_field(changeset, form, {field, options},
form_field(resource, changeset, form, {field, options},
class: "form-control #{error_class}",
conn: conn
)
Expand Down
21 changes: 12 additions & 9 deletions lib/kaffy/resource_query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ defmodule Kaffy.ResourceQuery do
)

custom_query = Kaffy.ResourceAdmin.custom_index_query(conn, resource, paged)
current_page = Kaffy.Utils.repo().all(custom_query)
current_page = Kaffy.Utils.repo(resource).all(custom_query)

do_cache = if search == "" and Enum.empty?(filtered_fields), do: true, else: false
all_count = cached_total_count(schema, do_cache, all)
all_count = cached_total_count(resource, do_cache, all)
{all_count, current_page}
end

Expand All @@ -48,7 +48,7 @@ defmodule Kaffy.ResourceQuery do
schema = resource[:schema]
query = from(s in schema, where: s.id == ^id)
custom_query = Kaffy.ResourceAdmin.custom_show_query(conn, resource, query)
Kaffy.Utils.repo().one(custom_query)
Kaffy.Utils.repo(resource).one(custom_query)
end

def fetch_list(_, [""]), do: []
Expand All @@ -57,13 +57,15 @@ defmodule Kaffy.ResourceQuery do
schema = resource[:schema]

from(s in schema, where: s.id in ^ids)
|> Kaffy.Utils.repo().all()
|> Kaffy.Utils.repo(resource).all()
end

def total_count(schema, do_cache, query) do
def total_count(resource, do_cache, query) do
schema = resource[:schema]

result =
from(s in query, select: fragment("count(*)"))
|> Kaffy.Utils.repo().one()
|> Kaffy.Utils.repo(resource).one()

if do_cache and result > 100_000 do
Kaffy.Cache.Client.add_cache(schema, "count", result, 600)
Expand All @@ -72,10 +74,11 @@ defmodule Kaffy.ResourceQuery do
result
end

def cached_total_count(schema, false, query), do: total_count(schema, false, query)
def cached_total_count(resource, false, query), do: total_count(resource, false, query)

def cached_total_count(schema, do_cache, query) do
Kaffy.Cache.Client.get_cache(schema, "count") || total_count(schema, do_cache, query)
def cached_total_count(resource, do_cache, query) do
Kaffy.Cache.Client.get_cache(resource[:schema], "count") ||
total_count(resource, do_cache, query)
end

defp get_filter_fields(params, resource) do
Expand Down
51 changes: 50 additions & 1 deletion lib/kaffy/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ defmodule Kaffy.Utils do
end
end

@doc """
Returns the repo module specified by the resource
"""
@spec repo(String.t()) :: atom()
def repo(resource) do
resource[:repo] || repo()
end

@doc """
Returns the version of the provided app.

Expand Down Expand Up @@ -121,6 +129,14 @@ defmodule Kaffy.Utils do
end
end

@spec set_dynamic_repo(Plug.Conn.t()) :: atom() | pid() | nil
def set_dynamic_repo(conn) do
case env(:set_dynamic_repo) do
f when is_function(f) -> f.(conn)
_ -> nil
end
end

@doc """
Returns a list of contexts as atoms.

Expand Down Expand Up @@ -211,6 +227,31 @@ defmodule Kaffy.Utils do
get_in(full_resources(conn), [context, :resources, resource])
end

@doc """
Returns the resource entry from the schema.

Example:

iex> get_resource_from_schema(conn, MyApp.Blog.Post)
[schema: MyApp.Blog.Post, admin: MyApp.Blog.PostAdmin]
"""
@spec get_resource_from_schema(Plug.Conn.t(), module()) :: list()
def get_resource_from_schema(conn, schema) do
full_resources(conn)
|> Enum.reduce_while(nil, fn {_, props}, acc ->
props[:resources]
|> Enum.reduce(fn {_name, resource_props}, _ ->
if resource_props[:schema] == schema do
resource_props
end
end)
|> case do
nil -> {:cont, acc}
resource -> {:halt, resource}
end
end)
end

@doc """
Returns all the schemas for the given context.

Expand Down Expand Up @@ -340,7 +381,15 @@ defmodule Kaffy.Utils do
end
end)

%{stylesheets: stylesheets, javascripts: javascripts}
navigation_extras =
Enum.map(exts, fn ext ->
case function_exported?(ext, :navigation_extras, 1) do
true -> ext.navigation_extras(conn)
false -> []
end
end)

%{stylesheets: stylesheets, javascripts: javascripts, navigation_extras: navigation_extras}
end

defp env(key, default \\ nil) do
Expand Down
Loading