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:
parent
129268ddc6
commit
919e8db686
9 changed files with 75 additions and 5 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue