Skip to content

Commit

Permalink
Allow project users to manage collections (#2898)
Browse files Browse the repository at this point in the history
* allow project users to manage collections

* remove collections from superadmin interface

* add more test cases

* Revert "remove collections from superadmin interface"

This reverts commit 44bb828.

* use Common sortable header

* split out test cases for authorized and unauthorized users

* fix failing test
  • Loading branch information
midigofrank authored Feb 6, 2025
1 parent e926588 commit 07e12cf
Show file tree
Hide file tree
Showing 10 changed files with 911 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ and this project adheres to
[#2830](https://github.com/OpenFn/lightning/issues/2830)
- Adds project name to failure alert email
[#2884](https://github.com/OpenFn/lightning/pull/2884)
- Allow project users to manage collections
[#2838](https://github.com/OpenFn/lightning/issues/2838)

### Changed

Expand Down
11 changes: 11 additions & 0 deletions lib/lightning/collections.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule Lightning.Collections do
alias Lightning.Collections.Collection
alias Lightning.Collections.Item
alias Lightning.Extensions.Message
alias Lightning.Projects.Project
alias Lightning.Repo
alias Lightning.Services.CollectionHook

Expand Down Expand Up @@ -41,6 +42,16 @@ defmodule Lightning.Collections do
Repo.all(from(c in Collection, order_by: ^order_by, preload: ^preload))
end

@spec list_project_collections(Project.t()) :: [Collection.t(), ...] | []
def list_project_collections(%Project{id: project_id}) do
query =
from c in Collection,
where: c.project_id == ^project_id,
order_by: [desc: :inserted_at]

Repo.all(query)
end

@spec get_collection(String.t()) ::
{:ok, Collection.t()} | {:error, :not_found}
def get_collection(name) do
Expand Down
29 changes: 29 additions & 0 deletions lib/lightning/collections/collection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ defmodule Lightning.Collections.Collection do
schema "collections" do
field :name, :string
field :byte_size_sum, :integer
field :raw_name, :string, virtual: true
field :delete, :boolean, virtual: true

belongs_to :project, Lightning.Projects.Project
has_many :items, Lightning.Collections.Item

Expand All @@ -42,4 +44,31 @@ defmodule Lightning.Collections.Collection do
message: "A collection with this name already exists"
)
end

defp validate_changeset(changeset) do
changeset
|> validate_format(:name, ~r/^[a-z0-9]+([\-_.][a-z0-9]+)*$/,
message: "Collection name must be URL safe"
)
|> unique_constraint([:name],
message: "A collection with this name already exists"
)
end

def form_changeset(collection, attrs) do
collection
|> cast(attrs, [:raw_name])
|> validate_required([:raw_name])
|> then(fn changeset ->
case get_change(changeset, :raw_name) do
nil ->
changeset

raw_name ->
changeset
|> put_change(:name, Lightning.Helpers.url_safe_name(raw_name))
end
end)
|> validate_changeset()
end
end
4 changes: 3 additions & 1 deletion lib/lightning/policies/project_users.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ defmodule Lightning.Policies.ProjectUsers do
| :write_webhook_auth_method
| :write_github_connection
| :initiate_github_sync
| :create_collection

@doc """
authorize/3 takes an action, a user, and a project. It checks the user's role
Expand Down Expand Up @@ -84,7 +85,8 @@ defmodule Lightning.Policies.ProjectUsers do
:run_workflow,
:provision_project,
:create_project_credential,
:initiate_github_sync
:initiate_github_sync,
:create_collection
],
do: project_user.role in [:owner, :admin, :editor]

Expand Down
22 changes: 8 additions & 14 deletions lib/lightning_web/live/collection_live/components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,10 @@ defmodule LightningWeb.CollectionLive.Components do

# TODO - replace with common table when moving to project scope!
def collections_table(assigns) do
sort_icon = %{asc: "hero-chevron-down", desc: "hero-chevron-up"}

assigns =
assign(assigns,
collections_count: Enum.count(assigns.collections),
empty?: Enum.empty?(assigns.collections),
name_sort_icon: sort_icon[assigns.name_direction]
empty?: Enum.empty?(assigns.collections)
)

~H"""
Expand All @@ -89,18 +86,15 @@ defmodule LightningWeb.CollectionLive.Components do
<div id="collections-table">
<.table>
<.tr>
# TODO - replace with common sortable header when moving to project scope!
<.th>
<div class="group inline-flex items-center">
<Common.sortable_table_header
phx-click="sort"
phx-value-by="name"
active={true}
sort_direction={to_string(@name_direction)}
>
Name
<span
phx-click="sort"
phx-value-by="name"
class="cursor-pointer align-middle ml-2 flex-none rounded text-gray-400 group-hover:visible group-focus:visible"
>
<.icon name={@name_sort_icon} />
</span>
</div>
</Common.sortable_table_header>
</.th>
<.th>Project</.th>
<.th>Used Storage (MB)</.th>
Expand Down
Loading

0 comments on commit 07e12cf

Please sign in to comment.