2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2025-09-07 12:02:53 +08:00

FIX: Check for group name availability should skip reserved usernames.

This commit is contained in:
Guo Xiang Tan 2018-08-01 11:08:45 +08:00
parent 129268ddc6
commit 919e8db686
9 changed files with 75 additions and 5 deletions

View file

@ -2,7 +2,7 @@ import {
default as computed, default as computed,
observes observes
} from "ember-addons/ember-computed-decorators"; } from "ember-addons/ember-computed-decorators";
import User from "discourse/models/user"; import Group from "discourse/models/group";
import InputValidation from "discourse/models/input-validation"; import InputValidation from "discourse/models/input-validation";
import debounce from "discourse/lib/debounce"; import debounce from "discourse/lib/debounce";
@ -63,7 +63,7 @@ export default Ember.Component.extend({
name = this.get("nameInput"); name = this.get("nameInput");
if (Ember.isEmpty(name)) return; if (Ember.isEmpty(name)) return;
User.checkUsername(name).then(response => { Group.checkName(name).then(response => {
const validationName = "uniqueNameValidation"; const validationName = "uniqueNameValidation";
if (response.available) { if (response.available) {

View file

@ -8,6 +8,7 @@ import RestModel from "discourse/models/rest";
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import User from "discourse/models/user"; import User from "discourse/models/user";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import { popupAjaxError } from "discourse/lib/ajax-error";
const Group = RestModel.extend({ const Group = RestModel.extend({
limit: 50, limit: 50,
@ -303,6 +304,12 @@ Group.reopenClass({
messageable(name) { messageable(name) {
return ajax(`/groups/${name}/messageable`); return ajax(`/groups/${name}/messageable`);
},
checkName(name) {
return ajax("/groups/check-name", {
data: { group_name: name }
}).catch(popupAjaxError);
} }
}); });

View file

@ -3,6 +3,7 @@ class GroupsController < ApplicationController
:set_notifications, :set_notifications,
:mentionable, :mentionable,
:messageable, :messageable,
:check_name,
:update, :update,
:histories, :histories,
:request_membership, :request_membership,
@ -314,6 +315,12 @@ class GroupsController < ApplicationController
end end
end end
def check_name
group_name = params.require(:group_name)
checker = UsernameCheckerService.new(allow_reserved_username: true)
render json: checker.check_username(group_name, nil)
end
def remove_member def remove_member
group = Group.find_by(id: params[:id]) group = Group.find_by(id: params[:id])
raise Discourse::NotFound unless group raise Discourse::NotFound unless group

View file

@ -204,9 +204,9 @@ class User < ActiveRecord::Base
SiteSetting.min_username_length.to_i..SiteSetting.max_username_length.to_i SiteSetting.min_username_length.to_i..SiteSetting.max_username_length.to_i
end end
def self.username_available?(username, email = nil) def self.username_available?(username, email = nil, allow_reserved_username: false)
lower = username.downcase lower = username.downcase
return false if reserved_username?(lower) return false if !allow_reserved_username && reserved_username?(lower)
return true if DB.exec(User::USERNAME_EXISTS_SQL, username: lower) == 0 return true if DB.exec(User::USERNAME_EXISTS_SQL, username: lower) == 0
# staged users can use the same username since they will take over the account # staged users can use the same username since they will take over the account

View file

@ -1,4 +1,7 @@
class UsernameCheckerService class UsernameCheckerService
def initialize(allow_reserved_username: false)
@allow_reserved_username = allow_reserved_username
end
def check_username(username, email) def check_username(username, email)
if username && username.length > 0 if username && username.length > 0
@ -12,7 +15,13 @@ class UsernameCheckerService
end end
def check_username_availability(username, email) def check_username_availability(username, email)
if User.username_available?(username, email) available = User.username_available?(
username,
email,
allow_reserved_username: @allow_reserved_username
)
if available
{ available: true, is_developer: is_developer?(email) } { available: true, is_developer: is_developer?(email) }
else else
{ available: false, suggestion: UserNameSuggester.suggest(username) } { available: false, suggestion: UserNameSuggester.suggest(username) }

View file

@ -482,6 +482,7 @@ Discourse::Application.routes.draw do
get 'logs' => 'groups#histories' get 'logs' => 'groups#histories'
collection do collection do
get "check-name" => 'groups#check_name'
get 'custom/new' => 'groups#new', constraints: AdminConstraint.new get 'custom/new' => 'groups#new', constraints: AdminConstraint.new
get "search" => "groups#search" get "search" => "groups#search"
end end

View file

@ -546,6 +546,16 @@ describe User do
expect(User.username_available?('tESt')).to eq(false) expect(User.username_available?('tESt')).to eq(false)
end end
it 'returns true when reserved username is explicity allowed' do
SiteSetting.reserved_usernames = 'test|donkey'
expect(User.username_available?(
'tESt',
nil,
allow_reserved_username: true)
).to eq(true)
end
it "returns true when username is associated to a staged user of the same email" do it "returns true when username is associated to a staged user of the same email" do
staged = Fabricate(:user, staged: true, email: "foo@bar.com") staged = Fabricate(:user, staged: true, email: "foo@bar.com")
expect(User.username_available?(staged.username, staged.primary_email.email)).to eq(true) expect(User.username_available?(staged.username, staged.primary_email.email)).to eq(true)

View file

@ -1320,4 +1320,22 @@ describe GroupsController do
end end
end end
end end
describe '#check_name' do
describe 'for an anon user' do
it 'should return the right response' do
get "/groups/check-name.json", params: { group_name: 'test' }
expect(response.status).to eq(403)
end
end
it 'should return the right response' do
sign_in(Fabricate(:user))
SiteSetting.reserved_usernames = 'test|donkey'
get "/groups/check-name.json", params: { group_name: 'test' }
expect(response.status).to eq(200)
expect(JSON.parse(response.body)["available"]).to eq(true)
end
end
end end

View file

@ -15,6 +15,7 @@ describe UsernameCheckerService do
result = @service.check_username('a', @nil_email) result = @service.check_username('a', @nil_email)
expect(result).to have_key(:errors) expect(result).to have_key(:errors)
end end
it 'rejects too long usernames' do it 'rejects too long usernames' do
result = @service.check_username('a123456789b123456789c123456789', @nil_email) result = @service.check_username('a123456789b123456789c123456789', @nil_email)
expect(result).to have_key(:errors) expect(result).to have_key(:errors)
@ -29,6 +30,23 @@ describe UsernameCheckerService do
result = @service.check_username('.vincent', @nil_email) result = @service.check_username('.vincent', @nil_email)
expect(result).to have_key(:errors) expect(result).to have_key(:errors)
end end
describe 'reserved usernames' do
before do
SiteSetting.reserved_usernames = 'test|donkey'
end
it 'rejects usernames that are reserved' do
result = @service.check_username("test", @nil_email)
expect(result[:available]).to eq(false)
end
it 'allows reserved username checker to be skipped' do
@service = UsernameCheckerService.new(allow_reserved_username: true)
result = @service.check_username("test", @nil_email)
expect(result[:available]).to eq(true)
end
end
end end
it 'username not available locally' do it 'username not available locally' do