Commit 9340dcda3ebbdb53a471c4a0d4fba0af33c93f44

Thomas de Grivel 2021-11-21T20:00:52

add and remove users from repo

diff --git a/lib/kmxgit/repository_manager.ex b/lib/kmxgit/repository_manager.ex
index c1f8159..5ff2673 100644
--- a/lib/kmxgit/repository_manager.ex
+++ b/lib/kmxgit/repository_manager.ex
@@ -6,6 +6,7 @@ defmodule Kmxgit.RepositoryManager do
   alias Kmxgit.Repo
   alias Kmxgit.RepositoryManager.Repository
   alias Kmxgit.SlugManager.Slug
+  alias Kmxgit.UserManager
   alias Kmxgit.UserManager.User
 
   def list_repositories do
@@ -66,7 +67,33 @@ defmodule Kmxgit.RepositoryManager do
                 user: :slug]
   end
 
-  def delete_repository(%Repository{} = repository) do
-    Repo.delete(repository)
+  def add_member(%Repository{} = repo, login) do
+    user = UserManager.get_user_by_slug(login)
+    if user do
+      members = [user | repo.members]
+      repo
+      |> Repository.changeset(%{})
+      |> Ecto.Changeset.put_assoc(:members, members)
+      |> Repo.update()
+    else
+      {:error, :not_found}
+    end
+  end
+
+  def remove_member(%Repository{} = repo, login) do
+    user = UserManager.get_user_by_slug(login)
+    if user do
+      members = Enum.reject(repo.members, &(&1.id == user.id))
+      repo
+      |> Repository.changeset(%{})
+      |> Ecto.Changeset.put_assoc(:members, members)
+      |> Repo.update()
+    else
+      {:error, :not_found}
+    end
+  end
+
+  def delete_repository(%Repository{} = repo) do
+    Repo.delete(repo)
   end
 end
diff --git a/lib/kmxgit/repository_manager/repository.ex b/lib/kmxgit/repository_manager/repository.ex
index ded6b49..cdfa9c8 100644
--- a/lib/kmxgit/repository_manager/repository.ex
+++ b/lib/kmxgit/repository_manager/repository.ex
@@ -11,7 +11,7 @@ defmodule Kmxgit.RepositoryManager.Repository do
     belongs_to :organisation, Organisation
     field :slug, :string, unique: true
     belongs_to :user, User
-    many_to_many :members, User, join_through: "users_repositories"
+    many_to_many :members, User, join_through: "users_repositories", on_replace: :delete
     timestamps()
   end
 
diff --git a/lib/kmxgit/user_manager.ex b/lib/kmxgit/user_manager.ex
index fdc3228..ab8321a 100644
--- a/lib/kmxgit/user_manager.ex
+++ b/lib/kmxgit/user_manager.ex
@@ -36,12 +36,13 @@ defmodule Kmxgit.UserManager do
   def get_user_by_slug(slug) do
     Repo.one from u in User,
       join: s in Slug,
-      on: s.id == u.slug_id,
+      on: s.user_id == u.id,
       where: fragment("lower(?)", s.slug) == ^String.downcase(slug),
       limit: 1,
       preload: [:slug,
                 organisations: :slug,
-                owned_repositories: [organisation: :slug, user: :slug]]
+                owned_repositories: [organisation: :slug,
+                                     user: :slug]]
   end
 
   def create_user(attrs \\ %{}) do
diff --git a/lib/kmxgit_web/controllers/repository_controller.ex b/lib/kmxgit_web/controllers/repository_controller.ex
index 306405e..8aa674b 100644
--- a/lib/kmxgit_web/controllers/repository_controller.ex
+++ b/lib/kmxgit_web/controllers/repository_controller.ex
@@ -97,11 +97,13 @@ defmodule KmxgitWeb.RepositoryController do
     repo = RepositoryManager.get_repository_by_owner_and_slug(params["owner"], slug)
     if repo do
       org = repo.organisation
+      user = repo.user
       conn
       |> assign_current_organisation(org)
       |> assign(:current_repository, repo)
       |> assign(:repo, repo)
       |> assign(:members, Repository.members(repo))
+      |> assign(:owner, org || user)
       |> render("show.html")
     else
       not_found(conn)
@@ -158,6 +160,104 @@ defmodule KmxgitWeb.RepositoryController do
     end
   end
 
+  def add_user(conn, params) do
+    current_user = conn.assigns.current_user
+    slug = Enum.join(params["slug"], "/")
+    repo = RepositoryManager.get_repository_by_owner_and_slug(params["owner"], slug)
+    if repo do
+      org = repo.organisation
+      if org && Enum.find(org.users, &(&1.id == current_user.id)) || repo.user_id == current_user.id do
+        changeset = RepositoryManager.change_repository(repo)
+        conn
+        |> assign(:action, Routes.repository_path(conn, :add_user_post, params["owner"], Repository.splat(repo)))
+        |> assign(:changeset, changeset)
+        |> assign_current_organisation(org)
+        |> assign(:current_repository, repo)
+        |> assign(:repo, repo)
+        |> render("add_user.html")
+      else
+        not_found(conn)
+      end
+    else
+      not_found(conn)
+    end
+  end
+
+  def add_user_post(conn, params) do
+    current_user = conn.assigns.current_user
+    login = params["repository"]["login"]
+    slug = Enum.join(params["slug"], "/")
+    repo = RepositoryManager.get_repository_by_owner_and_slug(params["owner"], slug)
+    if repo do
+      org = repo.organisation
+      if org && Enum.find(org.users, &(&1.id == current_user.id)) || repo.user_id == current_user.id do
+        case RepositoryManager.add_member(repo, login) do
+          {:ok, repo} ->
+            conn
+            |> redirect(to: Routes.repository_path(conn, :show, params["owner"], Repository.splat(repo)))
+          {:error, _} ->
+            conn
+            |> assign(:action, Routes.repository_path(conn, :add_user_post, params["owner"], Repository.splat(repo)))
+            |> assign_current_organisation(org)
+            |> assign(:current_repository, repo)
+            |> assign(:repo, repo)
+            |> render("add_user.html")
+        end
+      end
+    else
+      not_found(conn)
+    end
+  end
+
+  def remove_user(conn, params) do
+    current_user = conn.assigns.current_user
+    slug = Enum.join(params["slug"], "/")
+    repo = RepositoryManager.get_repository_by_owner_and_slug(params["owner"], slug)
+    if repo do
+      org = repo.organisation
+      if org && Enum.find(org.users, &(&1.id == current_user.id)) || repo.user_id == current_user.id do
+        changeset = RepositoryManager.change_repository(repo)
+        conn
+        |> assign(:action, Routes.repository_path(conn, :remove_user_post, params["owner"], Repository.splat(repo)))
+        |> assign(:changeset, changeset)
+        |> assign_current_organisation(org)
+        |> assign(:current_repository, repo)
+        |> assign(:repo, repo)
+        |> render("remove_user.html")
+      else
+        not_found(conn)
+      end
+    else
+      not_found(conn)
+    end
+  end
+
+  def remove_user_post(conn, params) do
+    current_user = conn.assigns.current_user
+    login = params["repository"]["login"]
+    slug = Enum.join(params["slug"], "/")
+    repo = RepositoryManager.get_repository_by_owner_and_slug(params["owner"], slug)
+    if repo do
+      org = repo.organisation
+      if org && Enum.find(org.users, &(&1.id == current_user.id)) || repo.user_id == current_user.id do
+        case RepositoryManager.remove_member(repo, login) do
+          {:ok, repo} ->
+            conn
+            |> redirect(to: Routes.repository_path(conn, :show, params["owner"], Repository.splat(repo)))
+          {:error, _} ->
+            conn
+            |> assign(:action, Routes.repository_path(conn, :remove_user_post, params["owner"], Repository.splat(repo)))
+            |> assign_current_organisation(org)
+            |> assign(:current_repository, repo)
+            |> assign(:repo, repo)
+            |> render("remove_user.html")
+        end
+      end
+    else
+      not_found(conn)
+    end
+  end
+
   def delete(conn, params) do
     current_user = conn.assigns.current_user
     slug = Enum.join(params["slug"], "/")
diff --git a/lib/kmxgit_web/router.ex b/lib/kmxgit_web/router.ex
index e4b0b3e..ac9c3e9 100644
--- a/lib/kmxgit_web/router.ex
+++ b/lib/kmxgit_web/router.ex
@@ -67,6 +67,16 @@ defmodule KmxgitWeb.Router do
       put "/:owner/*slug", RepositoryController, :update
     end
 
+    scope "/_add_user/" do
+      get  "/:owner/*slug", RepositoryController, :add_user
+      post "/:owner/*slug", RepositoryController, :add_user_post
+    end
+
+    scope "/_remove_user/" do
+      get  "/:owner/*slug", RepositoryController, :remove_user
+      post "/:owner/*slug", RepositoryController, :remove_user_post
+    end
+
     scope "/admin", Admin, as: "admin" do
       pipe_through :admin
       get "/", DashboardController, :index
diff --git a/lib/kmxgit_web/templates/repository/add_user.html.heex b/lib/kmxgit_web/templates/repository/add_user.html.heex
new file mode 100644
index 0000000..557ea9d
--- /dev/null
+++ b/lib/kmxgit_web/templates/repository/add_user.html.heex
@@ -0,0 +1,17 @@
+<div class="container-fluid">
+
+  <h1><%= gettext "Add user to %{repo}", repo: Repository.full_slug(@repo) %></h1>
+
+  <%= form_for :repository, @action, fn f -> %>
+
+    <div class="mb-3">
+      <%= label f, :login, class: "form-label" %>
+      <%= text_input f, :login, class: "form=control" %>
+    </div>
+
+    <div class="mb-3">
+      <%= submit gettext("Submit"), class: "btn btn-primary" %>
+    </div>
+
+  <% end %>
+</div>
diff --git a/lib/kmxgit_web/templates/repository/remove_user.html.heex b/lib/kmxgit_web/templates/repository/remove_user.html.heex
new file mode 100644
index 0000000..6b7a494
--- /dev/null
+++ b/lib/kmxgit_web/templates/repository/remove_user.html.heex
@@ -0,0 +1,17 @@
+<div class="container-fluid">
+
+  <h1><%= gettext "Remove user from %{repo}", repo: Repository.full_slug(@repo) %></h1>
+
+  <%= form_for :repository, @action, fn f -> %>
+
+    <div class="mb-3">
+      <%= label f, :login, class: "form-label" %>
+      <%= text_input f, :login, class: "form=control" %>
+    </div>
+
+    <div class="mb-3">
+      <%= submit gettext("Submit"), class: "btn btn-primary" %>
+    </div>
+
+  <% end %>
+</div>
diff --git a/lib/kmxgit_web/templates/repository/show.html.heex b/lib/kmxgit_web/templates/repository/show.html.heex
index 5422a28..4e3f81b 100644
--- a/lib/kmxgit_web/templates/repository/show.html.heex
+++ b/lib/kmxgit_web/templates/repository/show.html.heex
@@ -33,6 +33,12 @@
             <%= for user <- @members do %>
               <%= link user.slug.slug, to: Routes.slug_path(@conn, :show, user.slug.slug) %>
             <% end %>
+            <%= link "-",
+                to: Routes.repository_path(@conn, :remove_user, @owner.slug.slug, Repository.splat(@repo)),
+                class: "btn btn-danger btn-sm" %>
+            <%= link "+",
+                to: Routes.repository_path(@conn, :add_user, @owner.slug.slug, Repository.splat(@repo)),
+                class: "btn btn-primary btn-sm" %>
           </td>
         </tr>
       </table>
diff --git a/lib/kmxgit_web/templates/user/show.html.heex b/lib/kmxgit_web/templates/user/show.html.heex
index 671846a..7d955ed 100644
--- a/lib/kmxgit_web/templates/user/show.html.heex
+++ b/lib/kmxgit_web/templates/user/show.html.heex
@@ -54,7 +54,7 @@
               <%= link(org.name || org.slug.slug, to: Routes.slug_path(@conn, :show, org.slug.slug), class: "org") %>
             <% end %>
             <%= if @user == @current_user do %>
-              <%= link("+", to: Routes.organisation_path(@conn, :new), class: "btn btn-primary") %>
+              <%= link("+", to: Routes.organisation_path(@conn, :new), class: "btn btn-primary btn-sm") %>
             <% end %>
           </td>
         </tr>