forked from bors-ng/bors-ng
/
project_controller.ex
183 lines (167 loc) · 5.61 KB
/
project_controller.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
defmodule BorsNG.ProjectController do
@moduledoc """
Shows a list of repositories, a single repository,
and the repository's settings page.
n.b.
We call it a project internally, though it corresponds
to a GitHub repository. This is to avoid confusing
a GitHub repo with an Ecto repo.
"""
use BorsNG.Web, :controller
alias BorsNG.Worker.Batcher
alias BorsNG.Database.Repo
alias BorsNG.Database.LinkUserProject
alias BorsNG.Database.Project
alias BorsNG.Database.Batch
alias BorsNG.Database.Patch
alias BorsNG.Database.User
alias BorsNG.GitHub
alias BorsNG.Worker.Syncer
# Auto-grab the project and check the permissions
def action(conn, _) do
do_action(conn, action_name(conn), conn.params)
end
defp do_action(conn, action, %{"id" => id} = params) do
allow_private_repos = Application.get_env(
:bors_frontend, BorsNG)[:allow_private_repos]
project = Project
|> from(preload: [:installation])
|> Repo.get!(id)
mode = cond do
User.has_perm(Repo, conn.assigns.user, project.id) -> :rw
!allow_private_repos -> :ro
true -> raise RuntimeError, "Permission denied"
end
apply(__MODULE__, action, [conn, mode, project, params])
end
defp do_action(conn, action, params) do
apply(__MODULE__, action, [conn, params])
end
# The actual handlers
# Two-item ones have a project ID inputed
# One-item ones don't
def index(conn, _params) do
projects = Repo.all(Project.by_owner(conn.assigns.user.id))
render conn, "index.html", projects: projects
end
defp batch_info(batch) do
%{
commit: batch.commit,
patches: Repo.all(Patch.all_for_batch(batch.id)),
state: batch.state}
end
def show(conn, mode, project, _params) do
batches = project.id
|> Batch.all_for_project(:incomplete)
|> Repo.all()
|> Enum.map(&batch_info/1)
unbatched_patches = project.id
|> Patch.all_for_project(:awaiting_review)
|> Repo.all()
is_synchronizing = match?(
[{_, _}],
Registry.lookup(Syncer.Registry, project.id))
render conn, "show.html",
project: project,
batches: batches,
is_synchronizing: is_synchronizing,
unbatched_patches: unbatched_patches,
mode: mode
end
def settings(_, :ro, _, _), do: raise RuntimeError, "Permission denied"
def settings(conn, :rw, project, _params) do
reviewers = Repo.all(User.by_project(project.id))
render conn, "settings.html",
project: project,
reviewers: reviewers,
current_user_id: conn.assigns.user.id,
update_branches: Project.changeset_branches(project)
end
def cancel_all(_, :ro, _, _), do: raise RuntimeError, "Permission denied"
def cancel_all(conn, :rw, project, _params) do
project.id
|> Batcher.Registry.get()
|> Batcher.cancel_all()
conn
|> put_flash(:ok, "Canceled all running batches")
|> redirect(to: project_path(conn, :show, project))
end
def update_branches(_, :ro, _, _), do: raise RuntimeError, "Permission denied"
def update_branches(conn, :rw, project, %{"project" => pdef}) do
result = project
|> Project.changeset_branches(pdef)
|> Repo.update()
case result do
{:ok, _} ->
conn
|> put_flash(:ok, "Successfully updated branches")
|> redirect(to: project_path(conn, :settings, project))
{:error, changeset} ->
reviewers = Repo.all(User.by_project(project.id))
conn
|> put_flash(:error, "Cannot update branches")
|> render("settings.html",
project: project,
reviewers: reviewers,
current_user_id: conn.assigns.user.id,
update_branches: changeset)
end
end
def add_reviewer(_, :ro, _, _), do: raise RuntimeError, "Permission denied"
def add_reviewer(conn, :rw, project, %{"reviewer" => %{"login" => ""}}) do
conn
|> put_flash(:error, "Please enter a GitHub user's nickname")
|> redirect(to: project_path(conn, :settings, project))
end
def add_reviewer(conn, :rw, project, %{"reviewer" => %{"login" => login}}) do
user = case Repo.get_by(User, login: login) do
nil ->
{:installation, project.installation.installation_xref}
|> GitHub.get_user_by_login!(login)
|> case do
nil -> nil
gh_user ->
%User{user_xref: gh_user.id, login: gh_user.login}
|> Repo.insert!()
end
user -> user
end
{state, msg} = case user do
nil ->
{:error, "GitHub user not found; maybe you typo-ed?"}
user ->
%LinkUserProject{}
|> LinkUserProject.changeset(%{
user_id: user.id,
project_id: project.id})
|> Repo.insert()
|> case do
{:error, _} ->
{:error, "This user is already a reviewer"}
{:ok, _login} ->
{:ok, "Successfully added #{user.login} as a reviewer"}
end
end
conn
|> put_flash(state, msg)
|> redirect(to: project_path(conn, :settings, project))
end
def remove_reviewer(_, :ro, _, _), do: raise RuntimeError, "Permission denied"
def remove_reviewer(conn, :rw, project, %{"user_id" => user_id}) do
link = Repo.get_by!(
LinkUserProject,
project_id: project.id,
user_id: user_id)
Repo.delete!(link)
conn
|> put_flash(:ok, "Removed reviewer")
|> redirect(to: project_path(conn, :settings, project))
end
def synchronize(_, :ro, _, _), do: raise RuntimeError, "Permission denied"
def synchronize(conn, :rw, project, _params) do
Syncer.start_synchronize_project(project.id)
conn
|> put_flash(:ok, "Started synchronizing")
|> redirect(to: project_path(conn, :show, project))
end
end