Today while testing changing username via an API call, I encountered a 422 error when attempting to change the name to a name with a space in it. Digging deeper, I quickly learned that the issue was due to the username restrictions of Discourse. Currently, I’m porting a legacy custom forum to Discourse, and the previous forum has a little over 240K users with spaces in their name, and the space restriction is a bit of a show stopper. Does anyone have any experience over-riding the restriction?
AFAIK the options are:
- remove spaces from names eg “John Doe” becomes “JohnDoe”
- replace the spaces eg. “John Doe” becomes “John_Doe”
IIRC, at first periods in names was not possible, but now they are. If so you could replace the spaces so “John Doe” would become “John.Doe”
You should also be aware that duplicated names might be changed to have numeric suffixes. eg.
“somename” to “somename”
“somename” to “somename1”
“somename” to “somename2”
AFAIK, the chances of that happening depend on settings
What are you importing from? If you use an import script (or create one using an existing script as a model), usernames will be converted. If you want to do it via the API for some reason, you can look at the code in the import scripts that munges the usernames into something legal.
Thank you for your input. Specifically, I am looking for a creative solution that would work around the username restrictions when accessing Discourse via SSO. The best option so far appears to be: fork the code base, change the username restrictions, and see what happens.
Why would you need to work around the username restrictions for SSO? SSO never looks at the username, it’s OK for users to have a different username in Discourse.
This never is the best option. It’s a recipe for a painful disaster.
it may be a recipe for disaster, but at the moment it appears to be the only option. When the goal is ‘seamless integration’, it is certainly not OK for the user’s name in Discourse to be different than the name the user has been using for the past 15 years.
Please trust @fefrei (as well as all of us on the team who develop Discourse) that you do not want to fork the codebase. It is a recipe for disaster, especially in regards to security fixes which could become difficult for you to patch if they touch the code you modify to override the username rules.
It sounds like you want users to see the names (with spaces) that they’re used to. Why not prioritize full names (see site settings) and ensure that usernames are copied to that field, which allows spaces. Then SSO can manage the username field.
When it comes to customizing Discourse, you have several general options, ordered here from least to most painful and dangerous:
Level 0: “I want to change what it says”: Adjust your admin settings
/admin/customize and edit ‘Text Content’ or ‘Email Templates’, which will allow you to replace any string in Discourse or its currently installed plugins
Level 1: “I want to change how it looks”: Write (or install) a theme component
Level 2: “I want to change how it works”: Write (or install) a plugin
If your changes need to affect not just how your instance looks, but how it behaves, (including but not limited to what information it stores in the database, how the server processes information, or what restrictions exist around viewing, saving, or manipulating information), then you need a plugin. Extensive guides for installing and writing plugins are available.
^^ (NB, you are solidly in this category of functionality here, iff you really can’t find any settings which meet your use case, which I still think you may be able to)
Level 3: “I want to make a new product based on Discourse”: Fork the repo
This would generally be reserved for a person or organization who wants to take the Discourse codebase, customize it very heavily, presumably for the purposes of reselling it (which is allowed under the copyleft license).
Even in this use case, I’d probably opt for building a suite of plugins (I believe like what @angus is up to), so that I could more easily take advantage of the new security fixes, performance enhancements, and features that the Discourse team will be working on. That’s to say, there’s not a lot out there that can’t be accomplished with the first three options.
No argument here, I absolutely do not want to fork the code base. That being said, the closest I can get to my desired level of integration would be to:
- put the user’s name into the Discourse Full Name
- check “enable names” in the settings to show the user’s full name
- use CSS to hide the display of the Discourse username
Unfortunately, when creating an “@” reply, the Discourse username would be used.
Correct, however the autofill will search full names. So I can type
@james and @gdpelican will be shown as a suggestion. Not perfect, but I still feel it’s far better than trying to override username restrictions. I could be wrong (I’m not an engineer), but that would likely necessitate a DB schema level change, which will make it even harder to “revert” back to core Discourse should you choose to do so in the future.
In any case, you’re free to do what you want here, just keep in mind that we (the Discourse team) cannot support a forked install. The community may choose to continue to help, but we cannot.
I’m not sure I would refer to the guides for writing plugins as “extensive” but a plugin to over-ride the username validator as well as the method used to mung the username provided by SSO would certainly do the trick. If you have any suggestions as to where I could look for an example of over-riding a Discourse method, I would greatly appreciate it.
Have I got a topic for you!
hahaha, that is far better than the results from my search for “plugin custom validator”. My search-foo is weak.
For what it is worth, creating a plugin is a viable option for over-riding the username restrictions. Unfortunately, Discourse uses the username as an identifier for the user in various URLs, so changing the username to something containing a non-url appropriate character will break Discourse. [hella-sad-face]
Did you try using
encodeURI on the frontend and
URI.unescape on the backend?
encodeURI("dave smith") // 'dave%20smith'
URI.unescape("dave%20smith") # 'dave smith'