diff --git a/config/prod.exs b/config/prod.exs
index fb0f61d..f62d6ec 100644
--- a/config/prod.exs
+++ b/config/prod.exs
@@ -10,7 +10,8 @@ import Config
# which you should run after static files are built and
# before starting your production server.
config :kmxgit, KmxgitWeb.Endpoint,
- url: [host: "example.com", port: 80],
+ http: [ip: {127, 0, 0, 1}, port: 15008],
+ url: [host: "git.kmx.io", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json"
# Do not print debug messages in production
diff --git a/lib/kmxgit/git_manager.ex b/lib/kmxgit/git_manager.ex
index 41e55b3..9cef533 100644
--- a/lib/kmxgit/git_manager.ex
+++ b/lib/kmxgit/git_manager.ex
@@ -87,14 +87,34 @@ defmodule Kmxgit.GitManager do
end
end
+ def rename(from, to) do
+ dir_from = git_dir(from)
+ dir_to = git_dir(to)
+ dir = Path.dirname(dir_to)
+ :ok = File.mkdir_p(dir)
+ {out, status} = System.cmd("mv", [dir_from, dir_to], stderr_to_stdout: true)
+ case status do
+ 0 -> {:ok, out}
+ _ -> {:error, out}
+ end
+ end
+
def create(repo) do
dir = "#{@git_root}/#{Path.dirname(repo)}"
name = "#{Path.basename(repo)}.git"
:ok = File.mkdir_p(dir)
- {out, status} = System.cmd("git", ["-C", dir, "init", "--bare", name])
+ {out, status} = System.cmd("git", ["-C", dir, "init", "--bare", name], stderr_to_stdout: true)
case status do
0 -> {:ok, out}
_ -> {:error, out}
end
end
+
+ def delete(repo) do
+ dir = git_dir(repo)
+ case System.cmd("rm", ["-rf", dir], stderr_to_stdout: true) do
+ {"", 0} -> :ok
+ {err, _} -> {:error, err}
+ end
+ end
end
diff --git a/lib/kmxgit/repository_manager/repository.ex b/lib/kmxgit/repository_manager/repository.ex
index a065901..e4b85a5 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", on_replace: :delete
+ many_to_many :members, User, join_through: "users_repositories", on_replace: :delete, on_delete: :delete_all
timestamps()
end
diff --git a/lib/kmxgit/user_manager/user.ex b/lib/kmxgit/user_manager/user.ex
index 69683d1..1fdff72 100644
--- a/lib/kmxgit/user_manager/user.ex
+++ b/lib/kmxgit/user_manager/user.ex
@@ -88,4 +88,17 @@ defmodule Kmxgit.UserManager.User do
def display_name(user) do
user.name || user.login
end
+
+ def ssh_keys_with_env(user) do
+ (user.ssh_keys || "")
+ |> String.split("\n")
+ |> Enum.map(fn line ->
+ if Regex.match?(~r/^[ \t]*ssh-/, line) do
+ "environment=\"GIT_AUTH_ID=#{user.slug.slug}\" #{line}"
+ else
+ line
+ end
+ end)
+ |> Enum.join("\n")
+ end
end
diff --git a/lib/kmxgit_web/controllers/admin/repository_controller.ex b/lib/kmxgit_web/controllers/admin/repository_controller.ex
index d621455..01e2d32 100644
--- a/lib/kmxgit_web/controllers/admin/repository_controller.ex
+++ b/lib/kmxgit_web/controllers/admin/repository_controller.ex
@@ -1,6 +1,7 @@
defmodule KmxgitWeb.Admin.RepositoryController do
use KmxgitWeb, :controller
+ alias Kmxgit.GitManager
alias Kmxgit.RepositoryManager
alias Kmxgit.RepositoryManager.Repository
alias Kmxgit.Repo
@@ -92,10 +93,21 @@ defmodule KmxgitWeb.Admin.RepositoryController do
def update(conn, params) do
repo = RepositoryManager.get_repository!(params["id"])
- case RepositoryManager.update_repository(repo, params["repository"]) do
- {:ok, repo} ->
+ case Repo.transaction(fn ->
+ case RepositoryManager.update_repository(repo, params["repository"]) do
+ {:ok, repo1} ->
+ s = Repository.full_slug(repo)
+ s1 = Repository.full_slug(repo1)
+ if s != s1 do
+ GitManager.rename(s, s1)
+ end
+ repo1
+ {:error, changeset} -> Repo.rollback changeset
+ end
+ end) do
+ {:ok, repo1} ->
conn
- |> redirect(to: Routes.admin_repository_path(conn, :show, repo))
+ |> redirect(to: Routes.admin_repository_path(conn, :show, repo1))
{:error, changeset} ->
conn
|> assign(:action, Routes.admin_repository__path(conn, :update, repo))
@@ -151,11 +163,24 @@ defmodule KmxgitWeb.Admin.RepositoryController do
end
def delete(conn, params) do
- repository = RepositoryManager.get_repository(params["id"])
- if repository do
- {:ok, _} = RepositoryManager.delete_repository(repository)
- conn
- |> redirect(to: Routes.admin_repository_path(conn, :index))
+ repo = RepositoryManager.get_repository(params["id"])
+ if repo do
+ case Repo.transaction(fn ->
+ case RepositoryManager.delete_repository(repo) do
+ {:ok, _} -> GitManager.delete(Repository.full_slug(repo))
+ {:error, changeset} -> Repo.rollback(changeset)
+ end
+ end) do
+ {:ok, _} ->
+ conn
+ |> redirect(to: Routes.admin_repository_path(conn, :index))
+ {:error, changeset} ->
+ conn
+ |> assign(:action, Routes.admin_repository_path(conn, :update, repo))
+ |> assign(:changeset, changeset)
+ |> assign(:repo, repo)
+ |> render("edit.html")
+ end
else
not_found(conn)
end
diff --git a/lib/kmxgit_web/controllers/page_controller.ex b/lib/kmxgit_web/controllers/page_controller.ex
index 18e791f..a338d4c 100644
--- a/lib/kmxgit_web/controllers/page_controller.ex
+++ b/lib/kmxgit_web/controllers/page_controller.ex
@@ -47,4 +47,13 @@ defmodule KmxgitWeb.PageController do
redirect(conn, to: "/")
end
end
+
+ def keys(conn, params) do
+ k = UserManager.list_users
+ |> Enum.map(fn user -> User.ssh_keys_with_env(user) end)
+ |> Enum.join("\n")
+ conn
+ |> put_resp_content_type("text/text")
+ |> resp(200, k)
+ end
end
diff --git a/lib/kmxgit_web/controllers/repository_controller.ex b/lib/kmxgit_web/controllers/repository_controller.ex
index a8473c3..e7d73a5 100644
--- a/lib/kmxgit_web/controllers/repository_controller.ex
+++ b/lib/kmxgit_web/controllers/repository_controller.ex
@@ -112,7 +112,7 @@ defmodule KmxgitWeb.RepositoryController do
|> Enum.map(&Enum.reverse/1)
end
def chunk_path([first | rest], acc = [acc_first | acc_rest]) do
- if Regex.match?(~r/_/, first) do
+ if Regex.match?(~r/^_/, first) do
chunk_path(rest, [[first] | acc])
else
chunk_path(rest, [[first | acc_first] | acc_rest])
@@ -262,7 +262,18 @@ defmodule KmxgitWeb.RepositoryController do
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.update_repository(repo, params["repository"]) do
+ case Repo.transaction(fn ->
+ case RepositoryManager.update_repository(repo, params["repository"]) do
+ {:ok, repo1} ->
+ s = Repository.full_slug(repo)
+ s1 = Repository.full_slug(repo1)
+ if s != s1 do
+ GitManager.rename(s, s1)
+ end
+ repo1
+ {:error, changeset} -> Repo.rollback(changeset)
+ end
+ end) do
{:ok, repo} ->
conn
|> redirect(to: Routes.repository_path(conn, :show, params["owner"], Repository.splat(repo)))
@@ -382,9 +393,19 @@ defmodule KmxgitWeb.RepositoryController do
if repo do
org = repo.organisation
if org && Enum.find(org.users, &(&1.id == current_user.id)) || repo.user_id == current_user.id do
- {:ok, _} = RepositoryManager.delete_repository(repo)
- conn
- |> redirect(to: Routes.slug_path(conn, :show, params["owner"]))
+ case Repo.transaction(fn ->
+ case RepositoryManager.delete_repository(repo) do
+ {:ok, _} -> :ok
+ {:error, changeset} -> Repo.rollback changeset
+ end
+ end) do
+ {:ok, _} ->
+ conn
+ |> redirect(to: Routes.slug_path(conn, :show, params["owner"]))
+ {:error, changeset} ->
+ conn
+ |> redirect(to: Routes.slug_path(conn, :edit, params["owner"]))
+ end
else
not_found(conn)
end
diff --git a/lib/kmxgit_web/router.ex b/lib/kmxgit_web/router.ex
index 67243cb..133fc0f 100644
--- a/lib/kmxgit_web/router.ex
+++ b/lib/kmxgit_web/router.ex
@@ -33,7 +33,8 @@ defmodule KmxgitWeb.Router do
scope "/", KmxgitWeb do
pipe_through [:browser, :auth]
- get "/", PageController, :index
+ get "/", PageController, :index
+ get "/_keys", PageController, :keys
get "/_new_admin", PageController, :new_admin
post "/_new_admin", PageController, :new_admin_post
diff --git a/lib/kmxgit_web/templates/admin/user/form.html.heex b/lib/kmxgit_web/templates/admin/user/form.html.heex
index eec8af5..9687c73 100644
--- a/lib/kmxgit_web/templates/admin/user/form.html.heex
+++ b/lib/kmxgit_web/templates/admin/user/form.html.heex
@@ -6,6 +6,12 @@
<%= error_tag f, :name %>
</div>
+ <div class="mb-3">
+ <%= label f, :email, class: "form-label" %>
+ <%= text_input f, :email, class: "form-control" %>
+ <%= error_tag f, :email %>
+ </div>
+
<%= inputs_for f, :slug, fn ff -> %>
<div class="mb-3">
<%= label ff, :slug, gettext("Login"), class: "form-label" %>
@@ -15,9 +21,15 @@
<% end %>
<div class="mb-3">
- <%= label f, :email, class: "form-label" %>
- <%= text_input f, :email, class: "form-control" %>
- <%= error_tag f, :email %>
+ <%= label f, :description, class: "form-label" %>
+ <%= textarea f, :description, class: "form-control" %>
+ <%= error_tag f, :description %>
+ </div>
+
+ <div class="mb-3">
+ <%= label f, :ssh_keys, gettext("SSH keys"), class: "form-label" %>
+ <%= textarea f, :ssh_keys, class: "form-control" %>
+ <%= error_tag f, :ssh_keys %>
</div>
<div class="mb-3">
diff --git a/lib/kmxgit_web/templates/admin/user/show.html.heex b/lib/kmxgit_web/templates/admin/user/show.html.heex
index f056547..8f81b6c 100644
--- a/lib/kmxgit_web/templates/admin/user/show.html.heex
+++ b/lib/kmxgit_web/templates/admin/user/show.html.heex
@@ -44,6 +44,14 @@
<th><%= gettext "Deploy only" %></th>
<td><%= @user.deploy_only %></td>
</tr>
+ <tr>
+ <th><%= gettext "SSH keys" %></th>
+ <td class="scroll-x">
+ <pre class="ssh_keys">
+ <%= @user.ssh_keys %>
+ </pre>
+ </td>
+ </tr>
</table>
<%= link gettext("Delete user"),
diff --git a/lib/kmxgit_web/templates/organisation/show.html.heex b/lib/kmxgit_web/templates/organisation/show.html.heex
index 6288719..a70a157 100644
--- a/lib/kmxgit_web/templates/organisation/show.html.heex
+++ b/lib/kmxgit_web/templates/organisation/show.html.heex
@@ -18,9 +18,13 @@
<div class="col col-12 col-md-7">
<hr/>
<h2><%= gettext "Repositories" %></h2>
- <%= for repo <- @org.owned_repositories do %>
- <%= link Repository.full_slug(repo), to: Routes.repository_path(@conn, :show, @org.slug.slug, Repository.splat(repo)) %>
- <% end %>
+ <ul>
+ <%= for repo <- @org.owned_repositories do %>
+ <li>
+ <%= link Repository.full_slug(repo), to: Routes.repository_path(@conn, :show, @org.slug.slug, Repository.splat(repo)) %>
+ </li>
+ <% end %>
+ </ul>
</div>
<div class="col col-12 col-md-4">
<hr/>
diff --git a/lib/kmxgit_web/templates/repository/show.html.heex b/lib/kmxgit_web/templates/repository/show.html.heex
index 95854a5..c719d25 100644
--- a/lib/kmxgit_web/templates/repository/show.html.heex
+++ b/lib/kmxgit_web/templates/repository/show.html.heex
@@ -32,6 +32,8 @@
<%= link file.name, to: file.url %>
<% "tree" -> %>
<%= link "#{file.name}/", to: file.url %>
+ <% _ -> %>
+ <%= "#{file.type} #{file.name}" %>
<% end %>
</li>
<% end %>
diff --git a/lib/kmxgit_web/templates/user/show.html.heex b/lib/kmxgit_web/templates/user/show.html.heex
index 0f92445..bdc8ba7 100644
--- a/lib/kmxgit_web/templates/user/show.html.heex
+++ b/lib/kmxgit_web/templates/user/show.html.heex
@@ -17,9 +17,13 @@
<div class="col col-12 col-md-7">
<hr/>
<h2><%= gettext "Repositories" %></h2>
- <%= for repo <- @user.owned_repositories do %>
- <%= link Repository.full_slug(repo), to: Routes.repository_path(@conn, :show, @user.slug.slug, Repository.splat(repo)) %>
- <% end %>
+ <ul>
+ <%= for repo <- @user.owned_repositories do %>
+ <li>
+ <%= link Repository.full_slug(repo), to: Routes.repository_path(@conn, :show, @user.slug.slug, Repository.splat(repo)) %>
+ </li>
+ <% end %>
+ </ul>
</div>
<div class="col col-12 col-md-4">
<hr/>