Lightning.Projects (Lightning v2.15.16)
View SourceThe Projects context.
Summary
Functions
Returns an %Ecto.Changeset{} for tracking project changes.
Creates a project.
Creates a sandbox under the given parent by delegating to create_project/2.
Deletes a project and its related data, including workflows, work orders, steps, jobs, runs, triggers, project users, project credentials, and dataclips
Deletes project dataclips in batches
Deletes a project user and removes their credentials from the project.
Deletes project work orders in batches
Deletes a sandbox and all its descendant projects.
Returns a flat list of descendant project IDs for the given project IDs.
Convenience wrapper around descendants_query/1.
Returns true if child_project is a descendant of parent_project.
Returns a composable query that selects all descendant project IDs for the
given list of project IDs. Walks the parent_id tree downward using a
recursive CTE. The input IDs themselves are not included in the results.
Exports a project as yaml.
Fetches a project by id (root or sandbox) and preloads its direct :parent.
Fetches a project by id (root or sandbox) and preloads its direct :parent.
Gets the project associated with a run. Traverses Run → WorkOrder → Workflow → Project.
Gets a single project_user.
Returns the role of a user in a project. Possible roles are :admin, :viewer, :editor, and :owner
Get all project users for a given project
Gets a single project with it's members via project_users.
Fetches projects for a given user from the database.
Lists emails of users with :owner or :admin roles in the project
Returns the list of projects.
Lists all projects that have history retention
Returns the direct sandboxes (children) of a parent project, ordered by name (ASC).
Returns all projects in a workspace hierarchy.
Perform, when called with %{"type" => "purge_deleted"} will find projects that are ready for permanent deletion and purge them.
Builds a query to retrieve projects associated with a user.
Creates a new sandbox project by cloning from a parent project.
Returns the root ancestor of a project by walking up parent_id links.
Checks if a sandbox with the given name exists under the parent project.
Should input or output dataclips be saved for runs in this project?
Given a project, this function sets a scheduled deletion date based on the PURGE_DELETED_AFTER_DAYS environment variable. If no ENV is set, this date defaults to NOW but the automatic project purge cronjob will never run. (Note that subsequent logins will be blocked for projects pending deletion.)
Updates a project.
Updates a project user.
Updates a sandbox project's basic attributes (name, color, env).
Returns an %Ecto.Changeset{} for changing the project scheduled_deletion.
Functions
@spec add_project_users(Lightning.Projects.Project.t(), [map(), ...], boolean()) :: {:ok, [Lightning.Projects.ProjectUser.t(), ...]} | {:error, Ecto.Changeset.t()}
Returns an %Ecto.Changeset{} for tracking project changes.
Examples
iex> change_project(project)
%Ecto.Changeset{data: %Project{}}
Creates a project.
Examples
iex> create_project(%{field: value})
{:ok, %Project{}}
iex> create_project(%{field: bad_value})
{:error, %Ecto.Changeset{}}
@spec create_sandbox(Lightning.Projects.Project.t(), map(), boolean()) :: {:ok, Lightning.Projects.Project.t()} | {:error, Ecto.Changeset.t()}
Creates a sandbox under the given parent by delegating to create_project/2.
This is a convenience wrapper that sets :parent_id and preserves the
existing behavior around collaborator emails (off by default unless schedule_email? is true).
Notes
- Child names are scoped-unique by
(parent_id, name). Root names may repeat, but two siblings cannot share a name (enforced by theprojects_unique_child_nameindex). - This function does not clone workflows, credentials, or dataclips. It only creates
a new project row with
parent_idset. See sandbox provisioning flow for full cloning.
Returns
{:ok, %Project{}}on success{:error, %Ecto.Changeset{}}on validation/unique errors
Deletes a project and its related data, including workflows, work orders, steps, jobs, runs, triggers, project users, project credentials, and dataclips
Examples
iex> delete_project(project)
{:ok, %Project{}}
iex> delete_project(project)
{:error, %Ecto.Changeset{}}
@spec delete_project_async(Lightning.Projects.Project.t()) :: {:ok, Oban.Job.t()}
@spec delete_project_dataclips(Lightning.Projects.Project.t(), non_neg_integer()) :: :ok
Deletes project dataclips in batches
@spec delete_project_user!(Lightning.Projects.ProjectUser.t()) :: Lightning.Projects.ProjectUser.t()
Deletes a project user and removes their credentials from the project.
This function:
- Deletes the association between the user and the project
- Removes any credentials owned by the user from the project
All operations are performed within a transaction for data consistency.
Parameters
project_user: TheProjectUserstruct to be deleted
Returns
- The deleted
ProjectUserstruct
@spec delete_project_workorders(Lightning.Projects.Project.t(), non_neg_integer()) :: :ok
Deletes project work orders in batches
@spec delete_sandbox( Lightning.Projects.Project.t() | Ecto.UUID.t(), Lightning.Accounts.User.t() ) :: {:ok, Lightning.Projects.Project.t()} | {:error, :unauthorized | :not_found | term()}
Deletes a sandbox and all its descendant projects.
Warning: Permanently removes the sandbox and any nested sandboxes.
Parameters
sandbox- Sandbox to delete (project struct or ID string)actor- User performing deletion (needs:owneror:adminrole on sandbox)
Returns
{:ok, deleted_sandbox}- Successfully deleted{:error, :unauthorized}- Actor lacks permission{:error, :not_found}- Sandbox not found
@spec descendant_ids([Ecto.UUID.t()]) :: [Ecto.UUID.t()]
Returns a flat list of descendant project IDs for the given project IDs.
Convenience wrapper around descendants_query/1.
@spec descendant_of?( Lightning.Projects.Project.t(), Lightning.Projects.Project.t(), Lightning.Projects.Project.t() | nil ) :: boolean()
Returns true if child_project is a descendant of parent_project.
Walks up the parent chain using preloaded :parent associations to determine
if child_project has parent_project anywhere in its ancestry.
Parameters
child_project: The project to check (must have:parentpreloaded)parent_project: The potential parent/ancestor projectroot_project: Optional root project to use as stopping condition
Examples
iex> Projects.descendant_of?(sandbox, parent_project)
true
iex> Projects.descendant_of?(sibling, parent_project)
false
@spec descendants_query([Ecto.UUID.t()]) :: Ecto.Query.t()
Returns a composable query that selects all descendant project IDs for the
given list of project IDs. Walks the parent_id tree downward using a
recursive CTE. The input IDs themselves are not included in the results.
@spec export_project(atom(), Ecto.UUID.t(), [Ecto.UUID.t()] | nil) :: {:ok, binary()}
Exports a project as yaml.
Examples
iex> export_project(:yaml, project_id)
{:ok, string}
@spec get_project(Ecto.UUID.t()) :: Lightning.Projects.Project.t() | nil
Fetches a project by id (root or sandbox) and preloads its direct :parent.
Returns nil if no project with the given id exists.
@spec get_project!(Ecto.UUID.t()) :: Lightning.Projects.Project.t()
Fetches a project by id (root or sandbox) and preloads its direct :parent.
Raises Ecto.NoResultsError if no project with the given id exists.
@spec get_project_for_run(Lightning.Run.t()) :: Lightning.Projects.Project.t() | nil
Gets the project associated with a run. Traverses Run → WorkOrder → Workflow → Project.
Returns nil if the run is not associated with a project.
Examples
iex> get_project_for_run(run)
%Project{id: "...", env: "production", ...}
iex> get_project_for_run(orphaned_run)
nil
@spec get_project_user(Ecto.UUID.t()) :: Lightning.Projects.ProjectUser.t() | nil
@spec get_project_user( project :: Lightning.Projects.Project.t(), user :: Lightning.Accounts.User.t() ) :: Lightning.Projects.ProjectUser.t() | nil
@spec get_project_user(project_id :: binary(), user :: Lightning.Accounts.User.t()) :: Lightning.Projects.ProjectUser.t() | nil
Gets a single project_user.
Raises Ecto.NoResultsError if the ProjectUser does not exist.
Examples
iex> get_project_user!(123)
%ProjectUser{}
iex> get_project_user!(456)
** (Ecto.NoResultsError)
@spec get_project_user_role( user :: Lightning.Accounts.User.t(), project :: Lightning.Projects.Project.t() ) :: atom() | nil
Returns the role of a user in a project. Possible roles are :admin, :viewer, :editor, and :owner
Examples
iex> get_project_user_role(user, project)
:admin
iex> get_project_user_role(user, project)
:viewer
iex> get_project_user_role(user, project)
:editor
iex> get_project_user_role(user, project)
:owner
Get all project users for a given project
Gets a single project with it's members via project_users.
Raises Ecto.NoResultsError if the Project does not exist.
Examples
iex> get_project!(123)
%Project{}
iex> get_project!(456)
** (Ecto.NoResultsError)
@spec get_projects_for_user(user :: Lightning.Accounts.User.t()) :: [ Lightning.Projects.Project.t() ]
Fetches projects for a given user from the database.
Parameters
- user: The user struct for which projects are being queried.
- opts: Keyword list of options including :include for associations to preload and :order_by for sorting.
Returns
- A list of projects associated with the user.
@spec list_project_admin_emails(Ecto.UUID.t()) :: [String.t(), ...] | []
Lists emails of users with :owner or :admin roles in the project
@spec list_project_credentials(project :: Lightning.Projects.Project.t()) :: [ Lightning.Projects.ProjectCredential.t() ]
Returns the list of projects.
Examples
iex> list_projects()
[%Project{}, ...]
@spec list_projects_having_history_retention() :: [] | [Lightning.Projects.Project.t(), ...]
Lists all projects that have history retention
@spec list_sandboxes(Ecto.UUID.t()) :: [Lightning.Projects.Project.t()]
Returns the direct sandboxes (children) of a parent project, ordered by name (ASC).
This is a flat view: only rows where parent.id == child.parent_id are returned.
If we later support arbitrarily deep nesting, switch this to a recursive CTE.
@spec list_workspace_projects( Ecto.UUID.t(), keyword() ) :: %{ root: Lightning.Projects.Project.t(), descendants: [Lightning.Projects.Project.t()] }
@spec list_workspace_projects( Lightning.Projects.Project.t(), keyword() ) :: %{ root: Lightning.Projects.Project.t(), descendants: [Lightning.Projects.Project.t()] }
Returns all projects in a workspace hierarchy.
Returns a map with the root project and all its descendant sandboxes at any depth level. Uses a recursive CTE to traverse the entire project tree from root to leaves. Descendants are sorted as a flat list according to the specified options.
Options
sort_by: Field to sort by (:name,:inserted_at,:updated_at). Defaults to:name.sort_order: Sort direction (:ascor:desc). Defaults to:asc.
Examples
# Default sorting (name ascending)
Projects.list_workspace_projects(project_id)
# Sort by name descending
Projects.list_workspace_projects(project_id, sort_by: :name, sort_order: :desc)
# Sort by creation date
Projects.list_workspace_projects(project_id, sort_by: :inserted_at, sort_order: :desc)
Perform, when called with %{"type" => "purge_deleted"} will find projects that are ready for permanent deletion and purge them.
@spec project_users_query(atom() | %{:id => any(), optional(any()) => any()}) :: Ecto.Query.t()
@spec projects_for_user_query(user :: Lightning.Accounts.User.t()) :: Ecto.Queryable.t()
Builds a query to retrieve projects associated with a user.
Parameters
- user: The user struct for which projects are being queried.
- opts: Keyword list of options including :include for associations to preload and :order_by for sorting.
Returns
- An Ecto queryable struct to fetch projects.
@spec provision_sandbox( Lightning.Projects.Project.t(), Lightning.Accounts.User.t(), Lightning.Projects.Sandboxes.provision_attrs() ) :: {:ok, Lightning.Projects.Project.t()} | {:error, term()}
Creates a new sandbox project by cloning from a parent project.
Parameters
parent- Project to clone fromactor- User creating the sandbox (needs:owneror:adminrole on parent)attrs- Creation attributes (name, color, env, collaborators, dataclip_ids)
Returns
{:ok, sandbox_project}- Successfully created sandbox{:error, :unauthorized}- Actor lacks permission on parent{:error, changeset}- Validation or database error
See Lightning.Projects.Sandboxes.provision/3 for detailed behavior.
@spec root_of(Lightning.Projects.Project.t()) :: Lightning.Projects.Project.t()
Returns the root ancestor of a project by walking up parent_id links.
Supports arbitrarily deep nesting. (Assumes the parent chain is well-formed.)
Checks if a sandbox with the given name exists under the parent project.
Returns true if a sandbox exists, false otherwise.
Optionally excludes a specific sandbox by ID (useful for edit operations).
Should input or output dataclips be saved for runs in this project?
Given a project, this function sets a scheduled deletion date based on the PURGE_DELETED_AFTER_DAYS environment variable. If no ENV is set, this date defaults to NOW but the automatic project purge cronjob will never run. (Note that subsequent logins will be blocked for projects pending deletion.)
@spec select_first_project_for_user(user :: Lightning.Accounts.User.t()) :: Lightning.Projects.Project.t() | nil
Updates a project.
Examples
iex> update_project(project, %{field: new_value})
{:ok, %Project{}}
iex> update_project(project, %{field: bad_value})
{:error, %Ecto.Changeset{}}
Updates a project user.
Examples
iex> update_project_user(project_user, %{field: new_value})
{:ok, %ProjectUser{}}
iex> update_project_user(projectUser, %{field: bad_value})
{:error, %Ecto.Changeset{}}
@spec update_project_with_users(Lightning.Projects.Project.t(), map(), boolean()) :: {:ok, Lightning.Projects.Project.t()} | {:error, Ecto.Changeset.t()}
@spec update_sandbox( Lightning.Projects.Project.t() | Ecto.UUID.t(), Lightning.Accounts.User.t(), map() ) :: {:ok, Lightning.Projects.Project.t()} | {:error, :unauthorized | :not_found | Ecto.Changeset.t()}
Updates a sandbox project's basic attributes (name, color, env).
Parameters
sandbox- Sandbox to update (project struct or ID string)actor- User performing update (needs:owneror:adminrole on sandbox)attrs- Map with name, color, and/or env keys
Returns
{:ok, updated_sandbox}- Successfully updated{:error, :unauthorized}- Actor lacks permission{:error, :not_found}- Sandbox not found{:error, changeset}- Validation error
Returns an %Ecto.Changeset{} for changing the project scheduled_deletion.
Examples
iex> validate_for_deletion(project)
%Ecto.Changeset{data: %Project{}}