Skip to content

Commit 8a37b20

Browse files
authored
Merge pull request #456 from OpenGeoscience/require-usernames
Require username
2 parents fc122ae + dbf029b commit 8a37b20

7 files changed

Lines changed: 33 additions & 7 deletions

File tree

uvdat/core/rest/serializers.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@
3131
class UserSerializer(serializers.ModelSerializer):
3232
class Meta:
3333
model = User
34-
fields = ["id", "first_name", "last_name", "is_superuser"]
34+
fields = ["id", "username", "first_name", "last_name"]
35+
36+
37+
class MeSerializer(serializers.ModelSerializer):
38+
class Meta:
39+
model = User
40+
fields = ["id", "username", "first_name", "last_name", "is_superuser"]
3541

3642

3743
class BasemapSerializer(serializers.ModelSerializer):

uvdat/core/rest/user.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from rest_framework.permissions import IsAuthenticated
99
from rest_framework.viewsets import ReadOnlyModelViewSet
1010

11-
from .serializers import UserSerializer
11+
from .serializers import MeSerializer, UserSerializer
1212

1313

1414
class UserViewSet(ReadOnlyModelViewSet):
@@ -22,4 +22,4 @@ def me(self, request):
2222
"""Return the currently logged in user's information."""
2323
if request.user.is_anonymous:
2424
return HttpResponse(status=204)
25-
return HttpResponse(json.dumps(UserSerializer(request.user).data), status=200)
25+
return HttpResponse(json.dumps(MeSerializer(request.user).data), status=200)

uvdat/core/tests/factories.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class UserFactory(factory.django.DjangoModelFactory):
3636
class Meta:
3737
model = User
3838

39-
username = factory.SelfAttribute("email")
39+
username = factory.Faker("user_name")
4040
email = factory.Faker("safe_email")
4141
first_name = factory.Faker("first_name")
4242
last_name = factory.Faker("last_name")
@@ -46,7 +46,7 @@ class SuperUserFactory(UserFactory):
4646
class Meta:
4747
model = User
4848

49-
username = factory.SelfAttribute("email")
49+
username = factory.Faker("user_name")
5050
email = factory.Faker("safe_email")
5151
first_name = factory.Faker("first_name")
5252
last_name = factory.Faker("last_name")

uvdat/settings/base.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@
121121
ACCOUNT_LOGOUT_REDIRECT_URL = "/"
122122
ACCOUNT_SIGNUP_FORM_CLASS = "resonant_utils.allauth.FullNameSignupForm"
123123

124+
# Override defaults set by Resonant: https://github.com/kitware-resonant/cookiecutter-resonant/blob/master/django-resonant-settings/resonant_settings/allauth.py#L36
125+
ACCOUNT_ADAPTER = "allauth.account.adapter.DefaultAccountAdapter"
126+
ACCOUNT_SIGNUP_FIELDS = ["username*", "email*", "password1*", "password2*"]
127+
ACCOUNT_USER_MODEL_USERNAME_FIELD = "username"
128+
124129
# Use codes for email verification; links can be modified by Microsoft Safe Links
125130
ACCOUNT_EMAIL_VERIFICATION_BY_CODE_ENABLED = True
126131

web/src/components/projects/AccessControl.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ const editMode = computed(
2424
() => projectStore.permissions[props.project.id] === "owner",
2525
);
2626
27+
function userSearch(
28+
value: string,
29+
queryText: string,
30+
item: { raw: Record<string, string> } | undefined,
31+
) {
32+
if (!item) return false;
33+
const lowercaseValues = Object.entries(item.raw)
34+
.filter(([key]) => ["first_name", "last_name", "username"].includes(key))
35+
.map(([, v]) => v.toLowerCase());
36+
return lowercaseValues.some((v) => v.includes(queryText.toLowerCase()));
37+
}
38+
2739
function savePermissions() {
2840
if (!editMode.value || props.project.owner.id === undefined) return;
2941
let owner: number = props.project.owner.id;
@@ -203,6 +215,8 @@ onMounted(() => {
203215
:clearable="userSelectDialogMode === 'add'"
204216
:chips="userSelectDialogMode === 'add'"
205217
:closable-chips="userSelectDialogMode === 'add'"
218+
item-title="username"
219+
:custom-filter="userSearch"
206220
@update:model-value="
207221
(v: User | User[]) => {
208222
if (Array.isArray(v)) selectedUsers = v;

web/src/components/projects/UserProfile.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const initials = computed(() => {
2121
</script>
2222

2323
<template>
24-
<v-list-item v-if="props.user">
24+
<v-list-item v-if="props.user" :subtitle="props.user.username">
2525
<template #title>
2626
<span style="text-transform: capitalize">{{ nameLabel }}</span>
2727
</template>
@@ -37,7 +37,7 @@ const initials = computed(() => {
3737
<span v-if="initials" style="text-transform: uppercase">
3838
{{ initials }}
3939
<v-tooltip activator="parent" location="end">
40-
{{ nameLabel }}
40+
{{ props.user.username }}
4141
</v-tooltip>
4242
</span>
4343
<v-icon v-else icon="mdi-account"></v-icon>

web/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { MapGeoJSONFeature, StyleSpecification } from "maplibre-gl";
22

33
export interface User {
44
id: number | undefined; // undefined id is unauthenticated
5+
username?: string;
56
first_name?: string;
67
last_name?: string;
78
is_superuser?: boolean;

0 commit comments

Comments
 (0)