Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/publish_hex.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Publish package to Hex 📦
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]*"

jobs:
publish:
Expand Down
74 changes: 73 additions & 1 deletion lib/arke_server/controllers/arke_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,49 @@ defmodule ArkeServer.ArkeController do
end
end

@doc """
Bulk Creates units
"""
def create_bulk(%Plug.Conn{body_params: params} = conn, %{"arke_id" => id}) do
# all arkes struct and gen server are on :arke_system so it won't be changed to project
project = conn.assigns[:arke_project]

arke = ArkeManager.get(String.to_atom(id), project)

# TODO handle query parameter with plugs
load_links = Map.get(conn.query_params, "load_links", "false") == "true"
load_values = Map.get(conn.query_params, "load_values", "false") == "true"
load_files = Map.get(conn.query_params, "load_files", "false") == "true"

case is_bulk_body_valid?(params) do
false ->
ResponseManager.send_resp(conn, 400, nil, "Invalid bulk body")

true ->
QueryManager.create_bulk(
project,
arke,
params["data"],
runtime_data: %{conn: conn}
)
|> case do
{:ok, inserted_count, units, errors} ->
ResponseManager.send_resp(conn, 200, %{
content:
ArkeServer.Utils.Bulk.build_response_content(conn, inserted_count, units, errors)
})

{:error, error} ->
ResponseManager.send_resp(conn, 400, nil, error)
end
end
end

defp is_bulk_body_valid?(%{"data" => data} = _params) when is_list(data),
do: Enum.all?(data, fn item -> is_map(item) end)

defp is_bulk_body_valid?(params), do: false

# delete
@doc """
Delete a unit
Expand All @@ -97,11 +140,40 @@ defmodule ArkeServer.ArkeController do

QueryManager.delete(project, conn.assigns[:unit])
|> case do
{:ok, nil} -> ResponseManager.send_resp(conn, 204)
{:ok, _} -> ResponseManager.send_resp(conn, 204)
{:error, error} -> ResponseManager.send_resp(conn, 400, nil, error)
end
end

# delete bulk
@doc """
Delete a list of units
"""
def delete_bulk(conn, %{"arke_id" => arke_id} = params) do
project = conn.assigns[:arke_project]

permission = conn.assigns[:permission_filter] || %{filter: nil}
member = ArkeAuth.Guardian.Plug.current_resource(conn)

unit_ids = Map.get(params, "id", [])

existing_units =
QueryManager.query(project: project, arke: arke_id)
|> QueryFilters.apply_query_filters(permission.filter)
|> QueryFilters.apply_member_child_only(member, Map.get(permission, :child_only, false))
|> QueryManager.where(id__in: unit_ids)
|> QueryManager.all()

QueryManager.delete_bulk(project, existing_units)
|> case do
{:ok, _, _} ->
ResponseManager.send_resp(conn, 204)

{:error, error} ->
ResponseManager.send_resp(conn, 400, nil, error)
end
end

@doc """
Get units
"""
Expand Down
186 changes: 115 additions & 71 deletions lib/arke_server/controllers/oauth_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ defmodule ArkeServer.OAuthController do
# Openapi request definition
use ArkeServer.Openapi.Spec, module: ArkeServer.Openapi.OAuthControllerSpec


alias Arke.Boundary.GroupManager

alias ArkeServer.ResponseManager
Expand All @@ -49,13 +48,18 @@ defmodule ArkeServer.OAuthController do
_params
) do
project = conn.assigns[:arke_project]
case init_oauth_flow(project,auth, provider) do
{:ok, body,oauth_member} ->

case init_oauth_flow(project, auth, provider) do
{:ok, body, oauth_member} ->
member = QueryManager.get_by(project: project, id: oauth_member.id)
handle_member_login(conn,member)
handle_member_login(conn, member)
ResponseManager.send_resp(conn, 200, %{content: body})
{:error,[%{context: "auth", message: "unauthorized"}]=msg} -> ResponseManager.send_resp(conn, 401, msg)
{:error, msg} -> ResponseManager.send_resp(conn, 400, msg)

{:error, [%{context: "auth", message: "unauthorized"}] = msg} ->
ResponseManager.send_resp(conn, 401, msg)

{:error, msg} ->
ResponseManager.send_resp(conn, 400, msg)
end
end

Expand All @@ -72,57 +76,82 @@ defmodule ArkeServer.OAuthController do
end

def handle_create_member(
%Plug.Conn{body_params: params}=conn,
%{"member" => member_id, "provider" => provider}=_all_params
%Plug.Conn{body_params: params} = conn,
%{"member" => member_id, "provider" => provider} = _all_params
) do
user_resource = ArkeAuth.SSOGuardian.Plug.current_resource(conn)
user = QueryManager.get_by(project: :arke_system, arke_id: :user,id: user_resource.id)
user = QueryManager.get_by(project: :arke_system, arke_id: :user, id: user_resource.id)
project = conn.assigns[:arke_project]
provider_arke_id = String.to_existing_atom("oauth_#{provider}")
enable_sso_group = GroupManager.get(:enable_sso,project)
enable_sso_group = GroupManager.get(:enable_sso, project)
# check if the given member_id is enable to sso login
# check if the user has any oauth link
# check if one of the oauth link has the arke_id equal to the given provider
with true <- member_id in (GroupManager.get_arke_list(enable_sso_group) |> Enum.map(fn ak -> to_string(ak.id)end)),
[_data] = link_list <- get_link(user,:child),
%Unit{}=_unit <- Enum.find(link_list, fn link_unit -> link_unit.arke_id == provider_arke_id end) do
case check_member(project,user) do
# there are no units associated with that provider or the provider does not exist
with true <-
member_id in (GroupManager.get_arke_list(enable_sso_group)
|> Enum.map(fn ak -> to_string(ak.id) end)),
[_data] = link_list <- get_link(user, :child),
%Unit{} = _unit <-
Enum.find(link_list, fn link_unit -> link_unit.arke_id == provider_arke_id end) do
case check_member(project, user) do
# member does not exists so create one
{:ok,nil} ->
case create_member(project,user,params,member_id) do
{:ok,member} ->
{:ok, resource_member, access_token, refresh_token} = Auth.create_tokens(member,"default")
content = create_response_body(resource_member,access_token,refresh_token,false)
AuthController.mailer_module().signup(conn,resource_member, mode: "oauth",member: resource_member,response_body: content)
ResponseManager.send_resp(conn, 200, content)
err -> ResponseManager.send_resp(conn, 400, err)
end
{:ok, nil} ->
case create_member(project, user, params, member_id) do
{:ok, member} ->
{:ok, resource_member, access_token, refresh_token} =
Auth.create_tokens(member, "default")

content = create_response_body(resource_member, access_token, refresh_token, false)

AuthController.mailer_module().signup(conn, resource_member,
mode: "oauth",
member: resource_member,
response_body: content
)

ResponseManager.send_resp(conn, 200, content)

err ->
ResponseManager.send_resp(conn, 400, err)
end

# member exists and it is active
{:ok, resource_member, access_token, refresh_token} ->
content = create_response_body(resource_member,access_token,refresh_token,false)
AuthController.mailer_module().signup(conn,resource_member, mode: "oauth",member: resource_member,response_body: content)
content = create_response_body(resource_member, access_token, refresh_token, false)

AuthController.mailer_module().signup(conn, resource_member,
mode: "oauth",
member: resource_member,
response_body: content
)

ResponseManager.send_resp(conn, 200, content)

{:error, reason} ->
{:error, reason}
end
else nil -> # there are no units associated with that provider or the provider does not exist
# in any of the unit sso associated with the user
else
nil ->
# in any of the unit sso associated with the user
{:error, msg} = Error.create(:sso, "invalid provider")
ResponseManager.send_resp(conn, 400, msg)
false -> {:error, msg} = Error.create(:sso, "invalid member")
ResponseManager.send_resp(conn, 400, msg) # sso not enabled for the given member

false ->
{:error, msg} = Error.create(:sso, "invalid member")
# sso not enabled for the given member
ResponseManager.send_resp(conn, 400, msg)
end
end

def handle_create_member(
conn,
conn,
_params
) do
{:error, msg} = Error.create(:auth, "invalid token/provider")
ResponseManager.send_resp(conn, 400, msg)
end


# ------- Client Side -------

# ------- Using redirects -------
Expand All @@ -135,31 +164,36 @@ defmodule ArkeServer.OAuthController do
_params
) do
project = conn.assigns[:arke_project]
case init_oauth_flow(project,auth, provider) do
{:ok, body,_member} ->

case init_oauth_flow(project, auth, provider) do
{:ok, body, _member} ->
ResponseManager.send_resp(conn, 200, %{content: body})
{:error, msg} -> ResponseManager.send_resp(conn, 400, msg)

{:error, msg} ->
ResponseManager.send_resp(conn, 400, msg)
end
end

# ------- end Using redirects -------

defp init_oauth_flow(project,auth_info, provider) do
defp init_oauth_flow(project, auth_info, provider) do
with {:ok, nil} <- check_provider(provider),
{:ok, user} <- check_oauth(auth_info) do
case check_member(project,user) do
#if member does not exists creat a SSO token
{:ok,nil} -> {:ok, user, access_token, refresh_token} = Auth.create_tokens(user,"sso")
content = create_response_body(user,access_token,refresh_token,true)
{:ok, content,user}
# if exists and is active authenticate the user
{:ok, resource_member, access_token, refresh_token} ->

content = create_response_body(resource_member,access_token,refresh_token,false)
{:ok, content,resource_member}
{:error, reason} ->
{:error, reason}
end
case check_member(project, user) do
# if member does not exists creat a SSO token
{:ok, nil} ->
{:ok, user, access_token, refresh_token} = Auth.create_tokens(user, "sso")
content = create_response_body(user, access_token, refresh_token, true)
{:ok, content, user}

# if exists and is active authenticate the user
{:ok, resource_member, access_token, refresh_token} ->
content = create_response_body(resource_member, access_token, refresh_token, false)
{:ok, content, resource_member}

{:error, reason} ->
{:error, reason}
end
else
{:error, reason} ->
{:error, reason}
Expand Down Expand Up @@ -200,31 +234,34 @@ defmodule ArkeServer.OAuthController do
check_oauth_user(oauth_user_data, provider)
end

defp create_response_body(resource,access_token,refresh_token,uncompleted_data) do
defp create_response_body(resource, access_token, refresh_token, uncompleted_data) do
Map.merge(Arke.StructManager.encode(resource, type: :json), %{
access_token: access_token,
refresh_token: refresh_token,
uncompleted_data: uncompleted_data,
uncompleted_data: uncompleted_data
})
end

defp create_member(project,user,params,member_id) do
member_model = ArkeManager.get(String.to_atom(member_id),project)
member_data = Map.put(params,"arke_system_user", to_string(user.id)) |> Map.put("email",user.data.email)
defp create_member(project, user, params, member_id) do
member_model = ArkeManager.get(String.to_atom(member_id), project)

member_data =
Map.put(params, "arke_system_user", to_string(user.id)) |> Map.put("email", user.data.email)

new_data = for {key, val} <- member_data, into: %{}, do: {String.to_atom(key), val}
QueryManager.create(project,member_model,new_data)
QueryManager.create(project, member_model, new_data)
end

defp create_user(user_data) do
user_model = ArkeManager.get(:user, :arke_system)
pwd = UUID.uuid4()
updated_data = Map.put(user_data, :password, pwd)
email = Map.get(user_data,:email)
email = Map.get(user_data, :email)

case QueryManager.get_by(project: :arke_system, arke_id: :user, email: email) do
nil -> QueryManager.create(:arke_system, user_model, updated_data)
user -> {:ok,user}
user -> {:ok, user}
end

end

defp create_link(parent_id, child_id, provider) do
Expand All @@ -233,13 +270,13 @@ defmodule ArkeServer.OAuthController do
})
end

defp get_link(unit,direction) do
defp get_link(unit, direction) do
QueryManager.query(project: :arke_system)
|> QueryManager.link(unit,
depth: 1,
direction: direction,
type: "oauth"
)
depth: 1,
direction: direction,
type: "oauth"
)
|> QueryManager.all()
end

Expand Down Expand Up @@ -269,7 +306,7 @@ defmodule ArkeServer.OAuthController do

oauth_unit ->
# check if there is a link between the given oauth_unit and an user
case get_link(oauth_unit,:parent) do
case get_link(oauth_unit, :parent) do
[] ->
# create a user and connect the two
with {:ok, user} <- create_user(oauth_user_data),
Expand All @@ -290,17 +327,24 @@ defmodule ArkeServer.OAuthController do
end
end

defp check_member(project,user) do
case Auth.get_project_member(project,user) do
{:ok , member} -> Auth.create_tokens(Auth.format_member(member),"default")
{:error, [%{context: "auth", message: "member not exists"}]} -> {:ok,nil} # if not exists return {:ok,nil}
{:error, _msg} -> Error.create(:auth, "unauthorized")
defp check_member(project, user) do
case Auth.get_project_member(project, user) do
{:ok, member} ->
Auth.create_tokens(Auth.format_member(member), "default")

# if not exists return {:ok,nil}
{:error, [%{context: "auth", message: "member not exists"}]} ->
{:ok, nil}

{:error, _msg} ->
Error.create(:auth, "unauthorized")
end
end

defp handle_member_login(_conn,nil), do: nil
defp handle_member_login(conn,member) do
defp handle_member_login(_conn, nil), do: nil

defp handle_member_login(conn, member) do
AuthController.update_member_access_time(member)
AuthController.mailer_module().signin(conn,member, mode: "oauth")
AuthController.mailer_module().signin(conn, member, mode: "oauth")
end
end
Loading
Loading