Skip to content

Commit 2ca9871

Browse files
authored
Merge pull request #6 from openjournals/editing
Admin: editing user data
2 parents 0a535ad + ca3abff commit 2ca9871

8 files changed

Lines changed: 259 additions & 15 deletions

File tree

app/assets/stylesheets/application.tailwind.css

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,13 @@
4646
}
4747

4848
.btn-primary {
49-
@apply py-2 px-4 bg-indigo-600 hover:bg-indigo-700 focus:bg-indigo-500 text-white font-semibold rounded-md shadow focus:outline-none cursor-pointer;
49+
@apply py-2 px-4 bg-indigo-600 hover:bg-indigo-700 focus:bg-indigo-500 text-white font-semibold rounded-md shadow focus:outline-none cursor-pointer whitespace-nowrap;
50+
}
51+
.btn-action {
52+
@apply py-2 px-4 bg-amber-500 hover:bg-amber-700 focus:bg-amber-600 text-white font-semibold rounded-md shadow focus:outline-none cursor-pointer whitespace-nowrap;
5053
}
5154
.btn-danger {
52-
@apply py-2 px-4 bg-red-600 hover:bg-red-700 focus:bg-red-500 text-white font-semibold rounded-md shadow focus:outline-none cursor-pointer;
55+
@apply py-2 px-4 bg-red-600 hover:bg-red-700 focus:bg-red-500 text-white font-semibold rounded-md shadow focus:outline-none cursor-pointer whitespace-nowrap;
5356
}
5457

5558
.alert-error {

app/controllers/feedbacks_controller.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
class FeedbacksController < ApplicationController
2-
before_action :require_editor
2+
before_action :require_editor, except: :admin_destroy
3+
before_action :require_admin, only: :admin_destroy
34

45
def create
56
@feedback = current_editor.given_feedbacks.build(feedback_params)
@@ -20,6 +21,12 @@ def destroy
2021
redirect_to reviewer_path(reviewer_id), notice: "Feedback deleted"
2122
end
2223

24+
def admin_destroy
25+
feedback = Feedback.find(params[:id])
26+
reviewer_id = feedback.user_id
27+
feedback.destroy
28+
redirect_to user_path(reviewer_id), notice: "Feedback deleted"
29+
end
2330

2431
private
2532

app/controllers/users_controller.rb

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
class UsersController < ApplicationController
22
before_action :require_admin
3-
before_action :load_user, only: [:update, :destroy]
3+
before_action :load_user, only: [:edit, :update, :status, :destroy]
44

55
def show
66
@user = User.includes(:languages, :areas).find(params[:id])
77
@feedbacks = @user.feedbacks.includes(:editor).page(params[:page])
88
end
99

10+
def edit
11+
end
12+
1013
def update
14+
if @user.update(user_update_params)
15+
redirect_to user_path(@user), notice: "User data updated!"
16+
else
17+
render action: :edit, status: :unprocessable_entity
18+
end
19+
end
20+
21+
def status
1122
@user.update(user_status_params)
1223
redirect_to user_path(@user), notice: "User status updated!"
1324
end
@@ -26,4 +37,8 @@ def load_user
2637
def user_status_params
2738
params.permit(:reviewer, :editor, :admin)
2839
end
40+
41+
def user_update_params
42+
params.require(:user).permit(:github, :complete_name, :citation_name, :email, :affiliation, { area_ids: [], language_ids: [] }, :domains, :url, :description)
43+
end
2944
end

app/views/users/edit.html.erb

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<div class="justify-content-lg-center px-9">
2+
<h1><%= @user.screen_name %></h1>
3+
<%= form_for(@user, url: user_path(@user)) do |f| %>
4+
<% if @user.errors.any? {|error| error.attribute == :github && error.message == "has already been taken" } %>
5+
<div id="error_explanation" class="alert-error">
6+
<p>The reviewer with the GitHub username <strong><%= @user.github %></strong> is already registered in the system.</p>
7+
If it does not appear in the <%= link_to "reviewers search", search_reviewers_path(name: @user.github), class: "underline cursor-pointer" %> they have probably mark themselves as not available for review at the moment.
8+
</div>
9+
<% elsif @user.errors.any? %>
10+
<div id="error_explanation" class="alert-error">
11+
<h3><%= pluralize(@user.errors.count, "error") %>, prohibited to create the reviewer:</h3>
12+
<ul>
13+
<% @user.errors.each do |error| %>
14+
<li><strong><%= error.attribute.to_s.humanize %></strong>: <%= error.message %></li>
15+
<% end %>
16+
</ul>
17+
</div>
18+
<% end %>
19+
20+
<div class="grid sm:grid-cols-2 gap-y-5 gap-x-16">
21+
<div>
22+
<div class="block mb-5">
23+
<%= f.label :github, "GitHub username <small><sup>*(mandatory)</sup></small>".html_safe %>
24+
<%= f.text_field :github, class: "form-input mt-1 block w-full" %>
25+
</div>
26+
27+
<div class="block mb-5">
28+
<%= f.label :complete_name %>
29+
<%= f.text_field :complete_name, class: "form-input mt-1 block w-full", placeholder: "e.g. Ada Lovelace" %>
30+
</div>
31+
32+
<div class="block mb-5">
33+
<%= f.label :citation_name %>
34+
<%= f.text_field :citation_name, class: "form-input mt-1 block w-full", placeholder: "e.g. Lovelace, A." %>
35+
</div>
36+
37+
<div class="block mb-5">
38+
<%= f.label :email %>
39+
<%= f.text_field :email, class: "form-input mt-1 block w-full" %>
40+
</div>
41+
42+
<div class="block mb-5">
43+
<%= f.label :affiliation %>
44+
<%= f.text_field :affiliation, class: "form-input mt-1 block w-full" %>
45+
</div>
46+
47+
<div class="block mb-5">
48+
<%= f.label :url, "URL" %>
49+
<%= f.text_field :url, class: "form-input mt-1 block w-full" %>
50+
</div>
51+
52+
<div class="block mb-5">
53+
<%= f.label :description, "Public description" %>
54+
<%= f.text_area :description, rows: 4, class: "form-textarea mt-1 block w-full" %>
55+
</div>
56+
57+
</div>
58+
59+
<div>
60+
<% if Area.count > 10 %>
61+
<div class="block mb-5" data-controller="autocomplete" data-autocomplete-url-value="<%= search_areas_path %>">
62+
<%= label_tag :area_search, "Area(s) of expertise" %>
63+
<%= text_field_tag :area_search, nil, class: "form-input mt-1 block w-full", data: {"autocomplete-target" => "input"}, placeholder: "Please choose at least one" %>
64+
<ul class="areas-options" data-autocomplete-target="results"></ul>
65+
</div>
66+
67+
<div class="block mb-5" data-controller="area-tags">
68+
<div id="area_tags">
69+
<% @user.areas.each do |area| %>
70+
<span id="area_tag_<%= area.id %>" class="tag">
71+
<span aria-hidden="true" class="close-tag" aria-label="Remove area" data-area-tags-area-param="<%= area.id %>" data-action="click->area-tags#removeTag">&times;</span>
72+
<%= area.name %>
73+
</span>
74+
<% end %>
75+
</div>
76+
<div id="user_area_hidden_fields">
77+
<%= hidden_field_tag "user[area_ids][]", "", {id: "user_area_ids_empty"} %>
78+
<% @user.area_ids.each do |id| %>
79+
<%= hidden_field_tag "user[area_ids][]", id, {id: "user_area_ids_#{id}"} %>
80+
<% end %>
81+
</div>
82+
</div>
83+
<% else %>
84+
<div class="block mb-5">
85+
<%= f.label :area_ids, "Area(s) of expertise" %>
86+
<div class="form-input w-full grid grid-cols-1">
87+
<%= f.collection_check_boxes(:area_ids, Area.all, :id, :name) do |b|
88+
b.label(class: " mt-1 block") { b.check_box(class: "form-checkbox mx-2") + "#{b.text}" }
89+
end %>
90+
</div>
91+
</div>
92+
<% end %>
93+
94+
<div class="block mb-5">
95+
<%= f.label :domains, "Domains/topic areas of the reviewer" %>
96+
<%= f.text_field :domains, class: "form-input mt-1 block w-full", placeholder: "e.g. Mathematics, numerical analysis, statistics, exoplanets" %>
97+
</div>
98+
99+
<div class="block mb-5">
100+
<%= f.label :language_ids, "Programming language(s) for the reviewer" %>
101+
<div class="form-input w-full grid sm:grid-cols-3">
102+
<%= f.collection_check_boxes(:language_ids, Language.all, :id, :name) do |b|
103+
b.label(class: " mt-1 block") { b.check_box(class: "form-checkbox mx-2") + "#{b.text}" }
104+
end %>
105+
</div>
106+
</div>
107+
</div>
108+
109+
</div>
110+
111+
<div class="block mb-5">
112+
<%= f.submit "Update user profile", class: "btn-primary" %>
113+
<%= link_to "Cancel", user_path(@user), class: "btn-action" %>
114+
</div>
115+
<% end %>
116+
</div>

app/views/users/show.html.erb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,27 @@
2222

2323
<div class="block mb-5 w-full">
2424
<% if @user.reviewer? %>
25-
<%= link_to "⏬ Remove reviewer status", user_path(@user, reviewer: false), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
25+
<%= link_to "⏬ Remove reviewer status", status_user_path(@user, reviewer: false), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
2626
<% else %>
27-
<%= link_to "⏫ Grant reviewer status", user_path(@user, reviewer: true), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
27+
<%= link_to "⏫ Grant reviewer status", status_user_path(@user, reviewer: true), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
2828
<% end %>
2929

3030
<% if @user.editor? %>
31-
<%= link_to "⏬ Remove editor status", user_path(@user, editor: false), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
31+
<%= link_to "⏬ Remove editor status", status_user_path(@user, editor: false), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
3232
<% else %>
33-
<%= link_to "⏫ Grant editor status", user_path(@user, editor: true), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
33+
<%= link_to "⏫ Grant editor status", status_user_path(@user, editor: true), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
3434
<% end %>
3535

3636
<% if @user != current_admin %>
3737
<% if @user.admin? %>
38-
<%= link_to "⏬ Remove admin status", user_path(@user, admin: false), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
38+
<%= link_to "⏬ Remove admin status", status_user_path(@user, admin: false), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
3939
<% else %>
40-
<%= link_to "⏫ Grant admin status", user_path(@user, admin: true), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
40+
<%= link_to "⏫ Grant admin status", status_user_path(@user, admin: true), data: { turbo_method: :put }, class: "btn-primary mb-1" %>
4141
<% end %>
4242
<% end %>
4343

4444
<% if @user != current_admin %>
45+
<%= link_to "🔠 Edit", edit_user_path(@user), class: "btn-action mb-1" %>
4546
<%= link_to "🚮 Delete user", user_path(@user), data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete this user?" }, class: "btn-danger mb-1" %>
4647
<% end %>
4748

@@ -135,6 +136,7 @@
135136
<td class="max-w-fit text-center">
136137
by: <%= github_link(feedback.editor&.github) %>
137138
<%= " | ".html_safe + link_to("Reference", feedback.link, target: "_blank", title: "Go to review") if feedback.link.present? %>
139+
<%= " | ".html_safe + link_to("Delete", admin_destroy_feedback_path(feedback), data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete this feedback?" }) %>
138140
</td>
139141
</tr>
140142
<% end %>

config/routes.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
get :find_users, on: :collection
2424
end
2525

26-
resources :users, only: [:show, :update, :destroy]
26+
resources :users, only: [:show, :edit, :update, :destroy] do
27+
put :status, on: :member
28+
end
2729

2830
resources :reviewers, only: [:show, :index, :new, :create] do
2931
get :search, on: :collection
@@ -33,7 +35,9 @@
3335
get :search, on: :collection
3436
end
3537

36-
resources :feedbacks, only: [:create, :destroy]
38+
resources :feedbacks, only: [:create, :destroy] do
39+
delete :admin_destroy, on: :member
40+
end
3741

3842
get '/join', to: 'home#reviewer_signup', as: :reviewer_signup
3943
get '/lookup', to: 'home#no_reviewer_signup', as: :no_reviewer_signup

spec/system/admin_dashboard_spec.rb

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
end
77

88
scenario "Is only available to admins" do
9+
user = create(:user)
910
visit root_path
1011
expect(page).to_not have_content("Manage users")
1112
expect {
@@ -18,19 +19,27 @@
1819
expect {
1920
visit admin_path
2021
}.to raise_exception(ActionController::RoutingError, "Not Found")
22+
expect {
23+
visit edit_user_path(user)
24+
}.to raise_exception(ActionController::RoutingError, "Not Found")
2125

2226
login_as create(:editor)
2327
visit root_path
2428
expect(page).to_not have_content("Manage users")
2529
expect {
2630
visit admin_path
2731
}.to raise_exception(ActionController::RoutingError, "Not Found")
32+
expect {
33+
visit edit_user_path(user)
34+
}.to raise_exception(ActionController::RoutingError, "Not Found")
2835

2936
login_as create(:admin)
3037
visit root_path
3138
expect(page).to have_content("Manage users")
3239
click_link("Manage users")
3340
expect(page).to have_current_path(admin_path)
41+
visit edit_user_path(user)
42+
expect(page).to have_current_path(edit_user_path(user))
3443
end
3544

3645
describe "Search users" do
@@ -115,11 +124,11 @@
115124

116125
describe "Edit user" do
117126
before do
118-
user = create(:user, complete_name: "Tester McTest", github: "test33")
127+
@user = create(:user, complete_name: "Tester McTest", github: "test33")
119128
login_as create(:admin)
120129
visit admin_path
121130
click_link "Tester McTest"
122-
expect(page).to have_current_path(user_path(user))
131+
expect(page).to have_current_path(user_path(@user))
123132
end
124133

125134
scenario "show user roles" do
@@ -212,6 +221,69 @@
212221
expect(page).to have_link("Grant editor status")
213222
expect(page).to have_link("Grant admin status")
214223
end
224+
225+
scenario "update profile data" do
226+
expect(page).to have_content("Tester McTest")
227+
expect(page).to have_content("GitHub: test33")
228+
create(:language, name: "Julia")
229+
create(:language, name: "Python")
230+
create(:area, name: "Astronomy")
231+
create(:area, name: "Plant Science")
232+
233+
click_link "Edit"
234+
expect(page).to have_current_path(edit_user_path(@user))
235+
expect(page).to have_content("Tester McTest")
236+
237+
fill_in "user_github", with: "NewHandle"
238+
fill_in "user_complete_name", with: "Tester Reviewer"
239+
fill_in "user_citation_name", with: "Reviewer., T."
240+
fill_in "user_email", with: "tester@teste.rs"
241+
fill_in "user_affiliation", with: "Reviewing University"
242+
fill_in "user_url", with: "http://testing.revs/reviewer33"
243+
fill_in "user_description", with: "Head of plant division"
244+
check("Plant Science")
245+
fill_in "user_domains", with: "Trees, Forests"
246+
check("Julia")
247+
expect {
248+
click_button "Update user profile"
249+
}.to_not change { User.count }
250+
251+
expect(page).to have_content("User data updated!")
252+
253+
visit user_path(@user)
254+
expect(page).to_not have_content("Tester McTest")
255+
expect(page).to_not have_content("GitHub: test33")
256+
257+
expect(page).to have_content("GitHub: NewHandle")
258+
expect(page).to have_content("Name: Tester Reviewer")
259+
expect(page).to have_content("Citation name: Reviewer., T.")
260+
expect(page).to have_content("Email: tester@teste.rs")
261+
expect(page).to have_content("Affiliation:\nReviewing University")
262+
expect(page).to have_content("URL:\nhttp://testing.revs/reviewer33")
263+
expect(page).to have_content("Description:\nHead of plant division")
264+
expect(page).to have_content("Area(s) of expertise:\nPlant Science")
265+
expect(page).to have_content("Domains:\nTrees, Forests")
266+
expect(page).to have_content("Programming languages:\nJulia")
267+
end
268+
269+
scenario "delete feedback" do
270+
editor = create(:editor)
271+
feedback = create(:feedback, user: @user, editor: editor, rating: "positive", comment: "A very nice comment")
272+
273+
visit user_path(@user)
274+
275+
within("#feedback-#{feedback.id}") do
276+
expect(page).to have_content("A very nice comment")
277+
expect(page).to have_content("Delete")
278+
click_link "Delete"
279+
end
280+
281+
expect(page).to have_content("Feedback deleted")
282+
expect(page).to_not have_content("A very nice comment")
283+
284+
visit user_path(@user)
285+
expect(page).to have_content("There's no feedback for this reviewer yet.")
286+
end
215287
end
216288

217289
describe "Show user page" do

0 commit comments

Comments
 (0)