From bef5ac437aee3a506674d9e13614e9ceedccfb61 Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Sat, 2 Oct 2021 04:44:33 +0000 Subject: [PATCH] Allow users to customize their Discourse username --- .../api/management/commands/run_daily.py | 4 +-- apiserver/apiserver/api/models.py | 1 + apiserver/apiserver/api/serializers.py | 28 +++++++++++++++++++ apiserver/apiserver/api/utils.py | 3 ++ apiserver/apiserver/api/utils_auth.py | 7 +++++ webclient/src/Account.js | 5 ++++ webclient/src/AdminMembers.js | 5 ++++ webclient/src/Auth.js | 2 +- 8 files changed, 52 insertions(+), 3 deletions(-) diff --git a/apiserver/apiserver/api/management/commands/run_daily.py b/apiserver/apiserver/api/management/commands/run_daily.py index b0fbe63..4829470 100644 --- a/apiserver/apiserver/api/management/commands/run_daily.py +++ b/apiserver/apiserver/api/management/commands/run_daily.py @@ -32,8 +32,8 @@ class Command(BaseCommand): 'protospace_instructors': [], } - for user in User.objects.all(): - username = user.username + for user in User.objects.filter(member__discourse_username__isnull=False): + username = user.member.discourse_username # handle non-member vs. member if user.member.paused_date: diff --git a/apiserver/apiserver/api/models.py b/apiserver/apiserver/api/models.py index 4d987c2..120c778 100644 --- a/apiserver/apiserver/api/models.py +++ b/apiserver/apiserver/api/models.py @@ -58,6 +58,7 @@ class Member(models.Model): paused_date = models.DateField(blank=True, null=True) monthly_fees = models.IntegerField(default=55, blank=True, null=True) is_allowed_entry = models.BooleanField(default=True) + discourse_username = models.CharField(default=None, max_length=40, blank=True, null=True) history = HistoricalRecords(excluded_fields=['member_forms']) diff --git a/apiserver/apiserver/api/serializers.py b/apiserver/apiserver/api/serializers.py index bf5f43a..56f9acd 100644 --- a/apiserver/apiserver/api/serializers.py +++ b/apiserver/apiserver/api/serializers.py @@ -210,6 +210,18 @@ class MemberSerializer(serializers.ModelSerializer): instance.photo_medium = medium instance.photo_large = large + if 'discourse_username' in validated_data: + changed = validated_data['discourse_username'] != instance.discourse_username + if changed and utils_auth.discourse_is_configured(): + username = instance.discourse_username + new_username = validated_data['discourse_username'] + logger.info('Changing discourse_username from %s to %s', username, new_username) + if utils_auth.change_discourse_username(username, new_username) != 200: + msg = 'Problem connecting to Discourse Auth server: change username.' + utils.alert_tanner(msg) + logger.info(msg) + raise ValidationError(dict(discourse_username='Invalid Discourse username.')) + return super().update(instance, validated_data) # admin viewing member details @@ -599,6 +611,8 @@ class MyPasswordChangeSerializer(PasswordChangeSerializer): logger.info(msg) raise ValidationError(dict(non_field_errors=msg)) + data['username'] = self.user.member.discourse_username or self.user.username + if utils_auth.discourse_is_configured(): if request_id: utils_stats.set_progress(request_id, 'Changing Discourse password...') if utils_auth.set_discourse_password(data) != 200: @@ -606,6 +620,9 @@ class MyPasswordChangeSerializer(PasswordChangeSerializer): utils.alert_tanner(msg) logger.info(msg) raise ValidationError(dict(non_field_errors=msg)) + if not self.user.member.discourse_username: + self.user.member.discourse_username = self.user.username + self.user.member.save() if request_id: utils_stats.set_progress(request_id, 'Changing Spaceport password...') time.sleep(1) @@ -657,6 +674,8 @@ class MyPasswordResetConfirmSerializer(PasswordResetConfirmSerializer): logger.info(msg) raise ValidationError(dict(non_field_errors=msg)) + data['username'] = self.user.member.discourse_username or self.user.username + if utils_auth.discourse_is_configured(): if request_id: utils_stats.set_progress(request_id, 'Changing Discourse password...') if utils_auth.set_discourse_password(data) != 200: @@ -664,6 +683,9 @@ class MyPasswordResetConfirmSerializer(PasswordResetConfirmSerializer): utils.alert_tanner(msg) logger.info(msg) raise ValidationError(dict(non_field_errors=msg)) + if not self.user.member.discourse_username: + self.user.member.discourse_username = self.user.username + self.user.member.save() member = self.user.member logging.info('Password reset completed for: {} {} ({})'.format(member.first_name, member.last_name, member.id)) @@ -718,6 +740,12 @@ class SpaceportAuthSerializer(LoginSerializer): data['first_name'] = user.member.first_name utils_auth.set_wiki_password(data) + + data['username'] = user.member.discourse_username or user.username utils_auth.set_discourse_password(data) + if not user.member.discourse_username: + user.member.discourse_username = user.username + user.member.save() + return user diff --git a/apiserver/apiserver/api/utils.py b/apiserver/apiserver/api/utils.py index 1a42bc8..55b3cce 100644 --- a/apiserver/apiserver/api/utils.py +++ b/apiserver/apiserver/api/utils.py @@ -414,6 +414,9 @@ def register_user(data, user): msg = 'Problem connecting to Discourse Auth server: set.' utils.alert_tanner(msg) logger.info(msg) + if not user.member.discourse_username: + user.member.discourse_username = user.username + user.member.save() if utils_auth.discourse_is_configured(): if data['request_id']: utils_stats.set_progress(data['request_id'], 'Adding to Discourse group...') diff --git a/apiserver/apiserver/api/utils_auth.py b/apiserver/apiserver/api/utils_auth.py index 2e274ed..023e663 100644 --- a/apiserver/apiserver/api/utils_auth.py +++ b/apiserver/apiserver/api/utils_auth.py @@ -51,3 +51,10 @@ def remove_discourse_group_members(group_name, usernames): usernames=usernames, ) return auth_api(secrets.DISCOURSE_AUTH_API_URL + 'remove-discourse-group-members', json=json) + +def change_discourse_username(username, new_username): + data = dict( + username=username, + new_username=new_username, + ) + return auth_api(secrets.DISCOURSE_AUTH_API_URL + 'change-discourse-username', data=data) diff --git a/webclient/src/Account.js b/webclient/src/Account.js index 1a7d01b..f858b10 100644 --- a/webclient/src/Account.js +++ b/webclient/src/Account.js @@ -259,6 +259,11 @@ export function AccountForm(props) { {...makeProps('emergency_contact_phone')} /> + {member.discourse_username && } + {member.user ? 'Yes' : 'No'} + + Discourse Username: + {member.discourse_username || '?'} + + Public Bio: diff --git a/webclient/src/Auth.js b/webclient/src/Auth.js index 755c5ad..cea7436 100644 --- a/webclient/src/Auth.js +++ b/webclient/src/Auth.js @@ -137,7 +137,7 @@ export function AuthDiscourse(props) {
Success!

You can now log into the Discourse:

- Username: {user.username}
+ Username: {user.member.discourse_username || user.username}
Password: [this Spaceport password]

Protospace Discourse