forked from e621ng/e621ng
add support for user name changes
This commit is contained in:
parent
f4cc6e7d99
commit
520e97485b
@ -1,9 +1,9 @@
|
||||
div#c-user-feedbacks {
|
||||
tr.feedback-category-positive {
|
||||
.feedback-category-positive {
|
||||
background: #DDFFDD !important;
|
||||
}
|
||||
|
||||
tr.feedback-category-negative {
|
||||
.feedback-category-negative {
|
||||
background: #FFDDDD !important;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
#c-user-name-change-requests {
|
||||
.feedback-category-positive {
|
||||
background: #DDFFDD !important;
|
||||
}
|
||||
|
||||
.feedback-category-negative {
|
||||
background: #FFDDDD !important;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p.author {
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
color: #AAA;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
38
app/controllers/user_name_change_requests_controller.rb
Normal file
38
app/controllers/user_name_change_requests_controller.rb
Normal file
@ -0,0 +1,38 @@
|
||||
class UserNameChangeRequestsController < ApplicationController
|
||||
before_filter :member_only, :only => [:new, :create, :show]
|
||||
before_filter :admin_only, :only => [:index, :approve, :reject]
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
@change_request = UserNameChangeRequest.create(
|
||||
:user_id => CurrentUser.user.id,
|
||||
:original_name => CurrentUser.user.name,
|
||||
:status => "pending",
|
||||
:change_reason => params[:reason],
|
||||
:desired_name => params[:desired_name]
|
||||
)
|
||||
redirect_to user_name_change_request_path(@change_request), :notice => "Your request has been submitted and is pending admin review"
|
||||
end
|
||||
|
||||
def show
|
||||
@change_request = UserNameChangeRequest.find(params[:id])
|
||||
end
|
||||
|
||||
def index
|
||||
@change_requests = UserNameChangeRequest.order("id desc").paginate(params[:page])
|
||||
end
|
||||
|
||||
def approve
|
||||
@change_request = UserNameChangeRequest.find(params[:id])
|
||||
@change_request.approve!
|
||||
redirect_to user_name_change_request_path(@change_request), :notice => "Name change request approved"
|
||||
end
|
||||
|
||||
def reject
|
||||
@change_request = UserNameChangeRequest.find(params[:id])
|
||||
@change_request.reject!(params[:reason])
|
||||
redirect_to user_name_change_request_path(@change_request), :notice => "Name change request rejected"
|
||||
end
|
||||
end
|
@ -3,6 +3,7 @@ class TagAlias < ActiveRecord::Base
|
||||
after_save :clear_all_cache
|
||||
after_destroy :clear_all_cache
|
||||
before_validation :initialize_creator, :on => :create
|
||||
before_validation :normalize_names
|
||||
validates_presence_of :creator_id, :antecedent_name, :consequent_name
|
||||
validates_uniqueness_of :antecedent_name
|
||||
validate :absence_of_transitive_relation
|
||||
@ -88,6 +89,11 @@ class TagAlias < ActiveRecord::Base
|
||||
def is_active?
|
||||
status == "active"
|
||||
end
|
||||
|
||||
def normalize_names
|
||||
self.antecedent_name = antecedent_name.mb_chars.downcase.tr(" ", "_").strip
|
||||
self.consequent_name = consequent_name.downcase.tr(" ", "_").strip
|
||||
end
|
||||
|
||||
def initialize_creator
|
||||
self.creator_id = CurrentUser.user.id
|
||||
|
@ -3,6 +3,7 @@ class TagImplication < ActiveRecord::Base
|
||||
after_save :update_descendant_names_for_parent
|
||||
belongs_to :creator, :class_name => "User"
|
||||
before_validation :initialize_creator, :on => :create
|
||||
before_validation :normalize_names
|
||||
validates_presence_of :creator_id, :antecedent_name, :consequent_name
|
||||
validates_uniqueness_of :antecedent_name, :scope => :consequent_name
|
||||
validate :absence_of_circular_relation
|
||||
@ -129,6 +130,11 @@ class TagImplication < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def normalize_names
|
||||
self.antecedent_name = antecedent_name.downcase.tr(" ", "_").strip
|
||||
self.consequent_name = consequent_name.downcase.tr(" ", "_").strip
|
||||
end
|
||||
|
||||
def is_pending?
|
||||
status == "pending"
|
||||
|
@ -531,7 +531,7 @@ class User < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def admins
|
||||
where("is_admin = TRUE")
|
||||
where("level = ?", Levels::ADMIN)
|
||||
end
|
||||
|
||||
def with_email(email)
|
||||
|
48
app/models/user_name_change_request.rb
Normal file
48
app/models/user_name_change_request.rb
Normal file
@ -0,0 +1,48 @@
|
||||
class UserNameChangeRequest < ActiveRecord::Base
|
||||
validates_presence_of :user_id, :original_name, :desired_name
|
||||
validates_inclusion_of :status, :in => %w(pending approved rejected)
|
||||
belongs_to :user
|
||||
belongs_to :approver, :class_name => "User"
|
||||
validate :uniqueness_of_desired_name
|
||||
validates_length_of :desired_name, :within => 2..100, :on => :create
|
||||
validates_format_of :desired_name, :with => /\A[^\s:]+\Z/, :on => :create, :message => "cannot have whitespace or colons"
|
||||
after_create :notify_admins
|
||||
|
||||
def self.pending
|
||||
where(:status => "pending")
|
||||
end
|
||||
|
||||
def feedback
|
||||
UserFeedback.for_user(user_id).order("id desc").all
|
||||
end
|
||||
|
||||
def notify_admins
|
||||
title = "#{original_name} is requesting a name change to #{desired_name}"
|
||||
body = title + "\n\n\"See request\":/user_name_change_requests/#{id}"
|
||||
User.admins.find_each do |user|
|
||||
Dmail.create_split(:title => title, :body => body, :to_id => user.id)
|
||||
end
|
||||
end
|
||||
|
||||
def approve!
|
||||
update_attribute(:status, "approved")
|
||||
user.update_attribute(:name, desired_name)
|
||||
body = "Your name change request has been approved. Be sure to log in with your new user name."
|
||||
Dmail.create_split(:title => "Name change request approved", :body => body, :to_id => user_id)
|
||||
end
|
||||
|
||||
def reject!(reason)
|
||||
update_attributes(:status => "rejected", :rejection_reason => reason)
|
||||
body = "Your name change request has been rejected for the following reason: #{rejection_reason}"
|
||||
Dmail.create_split(:title => "Name change request rejected", :body => body, :to_id => user_id)
|
||||
end
|
||||
|
||||
def uniqueness_of_desired_name
|
||||
if User.find_by_name(desired_name)
|
||||
errors.add(:desired_name, "already exists")
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
21
app/views/user_name_change_requests/new.html.erb
Normal file
21
app/views/user_name_change_requests/new.html.erb
Normal file
@ -0,0 +1,21 @@
|
||||
<h1>Name Change Request</h1>
|
||||
|
||||
<p>You can request a name change but it must be approved. Factors that go into consideration include your upload and update history, and your user feedback.</p>
|
||||
|
||||
<%= error_messages_for "change_request" %>
|
||||
|
||||
<%= form_tag(user_name_change_requests_path, :class => "simple_form") do %>
|
||||
<div class="input">
|
||||
<label for="desired_name">Desired Name</label>
|
||||
<%= text_field_tag "desired_name" %>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<label for="desired_name">Reason</label>
|
||||
<%= text_field_tag "reason" %>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<%= submit_tag %>
|
||||
</div>
|
||||
<% end %>
|
56
app/views/user_name_change_requests/show.html.erb
Normal file
56
app/views/user_name_change_requests/show.html.erb
Normal file
@ -0,0 +1,56 @@
|
||||
<div id="c-user-name-change-requests">
|
||||
<h1>Name Change Request</h1>
|
||||
|
||||
<section>
|
||||
<p><%= @change_request.original_name %> is requesting to change their name to <%= @change_request.desired_name %>.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Reason</h2>
|
||||
<p><%= @change_request.change_reason %></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Feedback</h2>
|
||||
<ul>
|
||||
<% @change_request.feedback.each do |feedback| %>
|
||||
<li class="feedback-category-<%= feedback.category %>">
|
||||
<p><%= feedback.body %></p>
|
||||
<p class="author">Submitted by <%= feedback.creator.name %> <%= time_ago_in_words_tagged feedback.created_at %></p>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Statistics</h2>
|
||||
<ul>
|
||||
<li>Level: <%= @change_request.user.level_string %></li>
|
||||
<li>Uploads: <%= link_to @change_request.user.post_upload_count, posts_path("user:#{@change_request.user.name}") %></li>
|
||||
<li>Updates: <%= link_to @change_request.user.post_update_count, post_versions_path(:search => {:updater_id => @change_request.user.id}) %></li>
|
||||
<li>Notes: <%= link_to @change_request.user.note_update_count, note_versions_path(:search => {:updater_id => @change_request.user.id}) %></li>
|
||||
<li>Favorites: <%= @change_request.user.favorite_count %></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<% if CurrentUser.user.is_admin? %>
|
||||
<section>
|
||||
<h2>Options</h2>
|
||||
<%= form_tag(approve_user_name_change_request_path(@change_request)) do %>
|
||||
<%= submit_tag "Approve" %>
|
||||
<% end %>
|
||||
|
||||
<%= form_tag(reject_user_name_change_request_path(@change_request), :class => "simple_form") do %>
|
||||
<div class="input">
|
||||
<label>Reason</label>
|
||||
<%= text_field_tag "reason" %>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<%= submit_tag "Reject" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -196,6 +196,12 @@ Danbooru::Application.routes.draw do
|
||||
end
|
||||
end
|
||||
resources :user_feedbacks
|
||||
resources :user_name_change_requests do
|
||||
member do
|
||||
post :approve
|
||||
post :reject
|
||||
end
|
||||
end
|
||||
resources :wiki_pages do
|
||||
member do
|
||||
put :revert
|
||||
|
@ -0,0 +1,21 @@
|
||||
class CreateUserNameChangeRequests < ActiveRecord::Migration
|
||||
def up
|
||||
create_table :user_name_change_requests do |t|
|
||||
t.string :status, :null => false, :default => "pending"
|
||||
t.integer :user_id, :null => false
|
||||
t.integer :approver_id
|
||||
t.string :original_name
|
||||
t.string :desired_name
|
||||
t.text :change_reason
|
||||
t.text :rejection_reason
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :user_name_change_requests, :user_id
|
||||
add_index :user_name_change_requests, :original_name
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :user_name_change_requests
|
||||
end
|
||||
end
|
@ -2539,6 +2539,43 @@ CREATE SEQUENCE user_feedback_id_seq
|
||||
ALTER SEQUENCE user_feedback_id_seq OWNED BY user_feedback.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_name_change_requests; Type: TABLE; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
|
||||
CREATE TABLE user_name_change_requests (
|
||||
id integer NOT NULL,
|
||||
status character varying(255) DEFAULT 'pending'::character varying NOT NULL,
|
||||
user_id integer NOT NULL,
|
||||
approver_id integer,
|
||||
original_name character varying(255),
|
||||
desired_name character varying(255),
|
||||
change_reason text,
|
||||
rejection_reason text,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_name_change_requests_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE user_name_change_requests_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MAXVALUE
|
||||
NO MINVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_name_change_requests_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE user_name_change_requests_id_seq OWNED BY user_name_change_requests.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_password_reset_nonces; Type: TABLE; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
@ -3641,6 +3678,13 @@ ALTER TABLE ONLY uploads ALTER COLUMN id SET DEFAULT nextval('uploads_id_seq'::r
|
||||
ALTER TABLE ONLY user_feedback ALTER COLUMN id SET DEFAULT nextval('user_feedback_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY user_name_change_requests ALTER COLUMN id SET DEFAULT nextval('user_name_change_requests_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
@ -3941,6 +3985,14 @@ ALTER TABLE ONLY user_feedback
|
||||
ADD CONSTRAINT user_feedback_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_name_change_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY user_name_change_requests
|
||||
ADD CONSTRAINT user_name_change_requests_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_password_reset_nonces_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
@ -6010,6 +6062,20 @@ CREATE INDEX index_user_feedback_on_creator_id ON user_feedback USING btree (cre
|
||||
CREATE INDEX index_user_feedback_on_user_id ON user_feedback USING btree (user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_user_name_change_requests_on_original_name; Type: INDEX; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
|
||||
CREATE INDEX index_user_name_change_requests_on_original_name ON user_name_change_requests USING btree (original_name);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_user_name_change_requests_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
|
||||
CREATE INDEX index_user_name_change_requests_on_user_id ON user_name_change_requests USING btree (user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_users_on_email; Type: INDEX; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
@ -6278,4 +6344,6 @@ INSERT INTO schema_migrations (version) VALUES ('20130322173202');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20130322173859');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20130323160259');
|
||||
INSERT INTO schema_migrations (version) VALUES ('20130323160259');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20130326035904');
|
89
test/unit/user_name_change_request_test.rb
Normal file
89
test/unit/user_name_change_request_test.rb
Normal file
@ -0,0 +1,89 @@
|
||||
require 'test_helper'
|
||||
|
||||
class UserNameChangeRequestTest < ActiveSupport::TestCase
|
||||
context "in all cases" do
|
||||
setup do
|
||||
@admin = FactoryGirl.create(:admin_user)
|
||||
@requester = FactoryGirl.create(:user)
|
||||
CurrentUser.user = @requester
|
||||
end
|
||||
|
||||
context "approving a request" do
|
||||
setup do
|
||||
@change_request = UserNameChangeRequest.create(
|
||||
:user_id => @requester.id,
|
||||
:original_name => @requester.name,
|
||||
:status => "pending",
|
||||
:desired_name => "abc"
|
||||
)
|
||||
CurrentUser.user = @admin
|
||||
end
|
||||
|
||||
should "create a dmail" do
|
||||
assert_difference("Dmail.count", 2) do
|
||||
@change_request.approve!
|
||||
end
|
||||
end
|
||||
|
||||
should "change the user's name" do
|
||||
@change_request.approve!
|
||||
@requester.reload
|
||||
assert_equal("abc", @requester.name)
|
||||
end
|
||||
|
||||
should "clear the user name cache" do
|
||||
@change_request.approve!
|
||||
assert_equal("abc", Cache.get("uin:#{@requester.id}"))
|
||||
end
|
||||
end
|
||||
|
||||
context "rejecting a request" do
|
||||
setup do
|
||||
@change_request = UserNameChangeRequest.create(
|
||||
:user_id => @requester.id,
|
||||
:original_name => @requester.name,
|
||||
:status => "pending",
|
||||
:desired_name => "abc"
|
||||
)
|
||||
CurrentUser.user = @admin
|
||||
end
|
||||
|
||||
should "create a dmail" do
|
||||
assert_difference("Dmail.count", 2) do
|
||||
@change_request.reject!("msg")
|
||||
end
|
||||
end
|
||||
|
||||
should "preserve the username" do
|
||||
@change_request.reject!("msg")
|
||||
@requester.reload
|
||||
assert_not_equal("abc", @requester.name)
|
||||
end
|
||||
end
|
||||
|
||||
context "creating a new request" do
|
||||
should "send dmails to the admin" do
|
||||
assert_difference("Dmail.count", 2) do
|
||||
UserNameChangeRequest.create(
|
||||
:user_id => @requester.id,
|
||||
:original_name => @requester.name,
|
||||
:status => "pending",
|
||||
:desired_name => "abc"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
should "not validate if the desired name already exists" do
|
||||
assert_difference("UserNameChangeRequest.count", 0) do
|
||||
req = UserNameChangeRequest.create(
|
||||
:user_id => @requester.id,
|
||||
:original_name => @requester.name,
|
||||
:status => "pending",
|
||||
:desired_name => @requester.name
|
||||
)
|
||||
assert_equal(["Desired name already exists"], req.errors.full_messages)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user