defmodule StepFlow.WorkflowController do
use StepFlow, :controller
require Logger
alias StepFlow.Configuration
alias StepFlow.Controller.Helpers
alias StepFlow.Metrics.WorkflowInstrumenter
alias StepFlow.Repo
alias StepFlow.Step
alias StepFlow.Workflows
alias StepFlow.Workflows.Workflow
action_fallback(StepFlow.FallbackController)
def index(%Plug.Conn{assigns: %{current_user: user}} = conn, %{"job_id" => job_id} = params) do
mode = StepFlow.Map.get_by_key_or_atom(params, :mode, "full")
workflow =
Workflows.get_workflow_for_job!(job_id)
|> Repo.preload([:jobs, :status])
if Helpers.has_right(workflow, user, "view") do
conn
|> put_view(StepFlow.WorkflowView)
|> render("show.json", workflow: workflow, mode: mode)
else
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to view workflow with this identifier"}
)
end
end
def index(%Plug.Conn{assigns: %{current_user: user}} = conn, params) do
workflows =
params
|> Map.put("rights", user.rights)
|> Workflows.list_workflows()
conn
|> put_view(StepFlow.WorkflowView)
|> render("index.json", workflows: workflows)
end
def index(conn, _) do
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to view workflows."}
)
end
def create_workflow(%Plug.Conn{assigns: %{current_user: user}} = conn, workflow_params) do
if Map.has_key?(user, :uuid) do
workflow_params = Map.put(workflow_params, :user_uuid, user.uuid)
case Workflows.create_workflow(workflow_params) do
{:ok, %Workflow{} = workflow} ->
WorkflowInstrumenter.inc(:step_flow_workflows_created, workflow.identifier)
Workflows.Status.define_workflow_status(workflow.id, :created_workflow)
Step.start_next(workflow)
StepFlow.Notification.send("new_workflow", %{workflow_id: workflow.id})
conn
|> put_status(:created)
|> put_view(StepFlow.WorkflowView)
|> render("created.json", workflow: workflow)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> put_view(StepFlow.ChangesetView)
|> render("error.json", changeset: changeset)
end
else
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to create workflow with a user with no uuid"}
)
end
end
def locate_and_create_workflow(conn, user, workflow_definition, workflow_params) do
case workflow_definition do
nil ->
conn
|> put_status(:unprocessable_entity)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Unable to locate workflow with this identifier"}
)
workflow_definition ->
if Helpers.has_right(workflow_definition, user, "create") do
workflow_description =
workflow_definition
|> Map.put(:reference, Map.get(workflow_params, "reference"))
|> Map.put(
:parameters,
merge_parameters(
StepFlow.Map.get_by_key_or_atom(workflow_definition, :parameters),
Map.get(workflow_params, "parameters", %{})
)
)
|> Map.put(
:rights,
workflow_definition
|> Map.get(:rights)
|> Enum.map(fn right -> Map.from_struct(right) end)
)
|> Map.from_struct()
create_workflow(conn, workflow_description)
else
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to create workflow with this identifier"}
)
end
end
end
def create(
%Plug.Conn{assigns: %{current_user: user}} = conn,
%{
"workflow_identifier" => identifier,
"version_major" => version_major,
"version_minor" => version_minor,
"version_micro" => version_micro
} = workflow_params
) do
workflow_definition =
StepFlow.WorkflowDefinitions.get_workflow_definition(
identifier,
version_major,
version_minor,
version_micro
)
locate_and_create_workflow(conn, user, workflow_definition, workflow_params)
end
def create(
%Plug.Conn{assigns: %{current_user: user}} = conn,
%{"workflow_identifier" => identifier} = workflow_params
) do
workflow_definition = StepFlow.WorkflowDefinitions.get_workflow_definition(identifier)
locate_and_create_workflow(conn, user, workflow_definition, workflow_params)
end
def create(conn, _workflow_params) do
conn
|> put_status(:unprocessable_entity)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Missing Workflow identifier parameter"}
)
end
defp merge_parameters(parameters, request_parameters, result \\ [])
defp merge_parameters([], _request_parameters, result), do: result
defp merge_parameters([parameter | tail], request_parameters, result) do
result =
case Map.get(request_parameters, Map.get(parameter, "id")) do
nil ->
List.insert_at(result, -1, parameter)
parameter_value ->
List.insert_at(result, -1, Map.put(parameter, "value", parameter_value))
end
merge_parameters(tail, request_parameters, result)
end
def show(%Plug.Conn{assigns: %{current_user: user}} = conn, %{"id" => id} = params) do
mode = StepFlow.Map.get_by_key_or_atom(params, :mode, "full")
workflow =
Workflows.get_workflow!(id)
|> Repo.preload([:jobs, :status])
if Helpers.has_right(workflow, user, "view") do
conn
|> put_view(StepFlow.WorkflowView)
|> render("show.json", workflow: workflow, mode: mode)
else
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to view workflow with this identifier"}
)
end
end
def show(conn, _) do
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to show workflow with this identifier"}
)
end
def get(conn, %{"identifier" => workflow_identifier} = _params) do
workflow =
case workflow_identifier do
_ -> %{}
end
conn
|> json(workflow)
end
def get(conn, _params) do
conn
|> json(%{})
end
def statistics(
%Plug.Conn{assigns: %{current_user: user}} = conn,
params
) do
start_date =
params
|> Map.get(
"start_date",
NaiveDateTime.utc_now()
|> NaiveDateTime.add(-86_400, :second)
|> NaiveDateTime.to_string()
)
|> NaiveDateTime.from_iso8601!()
|> NaiveDateTime.truncate(:second)
end_date =
params
|> Map.get(
"end_date",
NaiveDateTime.utc_now() |> NaiveDateTime.to_string()
)
|> NaiveDateTime.from_iso8601!()
|> NaiveDateTime.truncate(:second)
time_interval =
params
|> Map.get("time_interval", define_time_interval(start_date, end_date))
|> String.to_integer()
|> Kernel.max(1)
identifiers = Map.get(params, "identifiers", [])
workflows_status =
Workflows.Status.list_workflows_status(start_date, end_date, identifiers, user.rights)
conn
|> put_view(StepFlow.WorkflowView)
|> render("statistics.json", %{
workflows_status: workflows_status,
time_interval: time_interval,
end_date: end_date
})
end
defp define_time_interval(start_date, end_date) do
with number_bins <- Configuration.get_var_value(StepFlow.Workflows, :number_bins, 60) do
NaiveDateTime.diff(end_date, start_date, :second)
|> Kernel.div(number_bins)
|> Integer.to_string()
end
end
def update(conn, _params) do
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to update workflow with this identifier"}
)
end
def delete(%Plug.Conn{assigns: %{current_user: user}} = conn, %{"id" => id}) do
workflow = Workflows.get_workflow!(id)
if Helpers.has_right(workflow, user, "delete") do
with {:ok, %Workflow{}} <- Workflows.delete_workflow(workflow) do
send_resp(conn, :no_content, "")
end
else
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to update workflow with this identifier"}
)
end
end
def delete(conn, _) do
conn
|> put_status(:forbidden)
|> put_view(StepFlow.WorkflowDefinitionView)
|> render("error.json",
errors: %{reason: "Forbidden to delete workflow with this identifier"}
)
end
end