160 lines
4.3 KiB
Elixir
160 lines
4.3 KiB
Elixir
defmodule FrenzyWeb.PipelineController do
|
|
use FrenzyWeb, :controller
|
|
alias Frenzy.{Repo, Pipeline}
|
|
alias FrenzyWeb.Router.Helpers, as: Routes
|
|
alias FrenzyWeb.Endpoint
|
|
import Ecto.Query
|
|
|
|
plug :user_owns_pipeline
|
|
|
|
defp user_owns_pipeline(%Plug.Conn{path_params: %{"id" => pipeline_id}} = conn, _opts) do
|
|
user = conn.assigns[:user]
|
|
|
|
pipeline = Repo.get(Pipeline, pipeline_id)
|
|
|
|
if pipeline.user_id == user.id do
|
|
conn
|
|
|> assign(:pipeline, pipeline)
|
|
else
|
|
conn
|
|
|> put_flash(:error, "You do not have permission to access that resource.")
|
|
|> redirect(to: Routes.group_path(Endpoint, :index))
|
|
|> halt()
|
|
end
|
|
end
|
|
|
|
defp user_owns_pipeline(conn, _opts), do: conn
|
|
|
|
def index(conn, _params) do
|
|
user = conn.assigns[:user]
|
|
|
|
pipelines = Repo.all(from p in Pipeline, where: p.user_id == ^user.id, preload: [:feeds])
|
|
|
|
render(conn, "index.html", %{pipelines: pipelines})
|
|
end
|
|
|
|
def new(conn, _params) do
|
|
changeset =
|
|
Pipeline.changeset(%Pipeline{}, %{
|
|
name: "",
|
|
stages: "[\n]"
|
|
})
|
|
|
|
render(conn, "new.html", %{changeset: changeset})
|
|
end
|
|
|
|
def create(conn, %{"pipeline" => %{"name" => name, "stages" => stages_json}}) do
|
|
user = conn.assigns[:user]
|
|
|
|
with {:ok, stages} <- Jason.decode(stages_json),
|
|
{:ok, stages} <- validate_pipeline(stages) do
|
|
changeset = Pipeline.changeset(%Pipeline{}, %{user_id: user.id, name: name, stages: stages})
|
|
|
|
{:ok, _pipeline} = Repo.insert(changeset)
|
|
|
|
conn
|
|
|> put_flash(:info, "Pipeline created")
|
|
|> redirect(to: Routes.pipeline_path(Endpoint, :index))
|
|
else
|
|
{:error, reason} ->
|
|
error_changeset = Pipeline.changeset(%Pipeline{}, %{name: name, stages: stages_json})
|
|
|
|
conn
|
|
|> put_flash(:error, "Unable to create pipeline: #{reason}")
|
|
|> render("new.html", %{changeset: error_changeset})
|
|
end
|
|
end
|
|
|
|
def show(conn, _params) do
|
|
pipeline = conn.assigns[:pipeline]
|
|
|
|
render(conn, "show.html", %{pipeline: pipeline})
|
|
end
|
|
|
|
def delete(conn, _params) do
|
|
conn.assigns[:pipeline]
|
|
|> Repo.delete()
|
|
|
|
redirect(conn, to: Routes.pipeline_path(Endpoint, :index))
|
|
end
|
|
|
|
def edit(conn, _params) do
|
|
pipeline = conn.assigns[:pipeline]
|
|
|
|
{:ok, stages_json} = Jason.encode(pipeline.stages, pretty: true)
|
|
|
|
render(conn, "edit.html", %{
|
|
pipeline: pipeline,
|
|
name: pipeline.name,
|
|
stages_json: stages_json
|
|
})
|
|
end
|
|
|
|
def update(conn, %{"pipeline" => %{"name" => name, "stages" => stages_json}}) do
|
|
pipeline = conn.assigns[:pipeline]
|
|
|
|
with {:ok, stages} <- Jason.decode(stages_json),
|
|
{:ok, stages} <- validate_pipeline(stages) do
|
|
changeset = Pipeline.changeset(pipeline, %{name: name, stages: stages})
|
|
|
|
{:ok, _pipeline} = Repo.update(changeset)
|
|
|
|
conn
|
|
|> put_flash(:info, "Pipeline edited")
|
|
|> redirect(to: Routes.pipeline_path(Endpoint, :show, pipeline.id))
|
|
else
|
|
{:error, reason} ->
|
|
conn
|
|
|> put_flash(:error, "Unable to edit pipeline: #{inspect(reason)}")
|
|
|> render("edit.html", %{
|
|
pipeline: pipeline,
|
|
name: name,
|
|
stages_json: stages_json
|
|
})
|
|
end
|
|
end
|
|
|
|
defp validate_pipeline(stages) do
|
|
stages
|
|
|> Enum.with_index()
|
|
|> Enum.reduce_while({:ok, []}, fn {stage, index}, {:ok, new_stages} ->
|
|
case validate_stage(stage) do
|
|
{:ok, stage} ->
|
|
{:cont, {:ok, new_stages ++ [stage]}}
|
|
|
|
{:error, reason} ->
|
|
{:error, "invalid stage at #{index}: #{reason}"}
|
|
end
|
|
end)
|
|
end
|
|
|
|
defp validate_stage(%{"module_name" => module_name, "options" => options}) do
|
|
with true <- module_exists(module_name),
|
|
{:ok, options} <-
|
|
apply(String.to_existing_atom("Elixir." <> module_name), :validate_opts, [
|
|
options
|
|
]) do
|
|
{:ok, %{"module_name" => module_name, "options" => options}}
|
|
else
|
|
false ->
|
|
{:error, "module #{module_name} does not exist"}
|
|
|
|
{:error, reason} ->
|
|
{:error, "invalid options for #{module_name}: #{reason}"}
|
|
end
|
|
end
|
|
|
|
defp validate_stage(_),
|
|
do: {:error, "pipeline stage must be a map with module_name and options"}
|
|
|
|
defp module_exists(module_name) do
|
|
try do
|
|
String.to_existing_atom("Elixir." <> module_name)
|
|
true
|
|
rescue
|
|
ArgumentError ->
|
|
false
|
|
end
|
|
end
|
|
end
|