Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions server/mergin/auth/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,10 @@ paths:
schema:
type: object
required:
- username
- email
- password
- confirm
properties:
username:
type: string
example: john.doe
email:
type: string
format: email
Expand Down
3 changes: 2 additions & 1 deletion server/mergin/auth/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,8 @@ def register_user(): # pylint: disable=W0613,W0612
from ..celery import send_email_async

form = UserRegistrationForm()
if form.validate():
form.username.data = User.generate_username(form.email.data)
if form.validate_on_submit():
user = User.create(form.username.data, form.email.data, form.password.data)
user_created.send(user, source="admin")
token = generate_confirmation_token(
Expand Down
16 changes: 10 additions & 6 deletions server/mergin/auth/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ def username_validation(form, field):
is_reserved_word,
)

errors = [
has_valid_characters(field.data),
has_valid_first_character(field.data),
is_reserved_word(field.data),
check_filename(field.data),
]
errors = (
[
has_valid_characters(field.data),
has_valid_first_character(field.data),
is_reserved_word(field.data),
check_filename(field.data),
]
if field.data
else []
)
for error in errors:
if error:
raise ValidationError(error)
Expand Down
3 changes: 2 additions & 1 deletion server/mergin/sync/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

def project_name_validation(name: str) -> str | None:
"""Check whether project name is valid"""
if not name.strip():
name = name.strip() if name is not None else name
if not name:
return "Project name cannot be empty"
errors = [
has_valid_characters(name),
Expand Down
34 changes: 8 additions & 26 deletions server/mergin/tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,65 +88,47 @@ def test_logout(client):

# user registration tests
test_user_reg_data = [
("test", "test@test.com", "#pwd1234", 201), # success
("test@test.com", "#pwd1234", 201), # success
(
"TesTUser",
"test@test.com",
"#pwd1234",
201,
), # tests with upper case, but user does not exist
(
"TesTUser2",
"test2@test.com",
"#pwd1234",
201,
), # tests with upper case, but user does not exist
("bob", "test@test.com", "#pwd1234", 400), # invalid (short) username
("test", "test.com", "#pwd1234", 400), # invalid email
("mergin", "test@test.com", "#pwd1234", 400), # existing user
("test.com", "#pwd1234", 400), # invalid email
("admin@example.com", "#pwd1234", 400), # existing user
(
"MerGin",
"tests@test.com",
"#pwd1234",
400,
), # tests with upper case but mergin already exists
(
" mergin ",
"tests@test.com",
"#pwd1234",
400,
), # tests with blank spaces, but mergin user already exists
(
"XmerginX",
" tests@test.com ",
"#pwd1234",
201,
), # tests with blank spaces, whitespace to be removed
(
"mergin2",
" mergin@mergin.com ",
"#pwd1234",
400,
), # tests with blank spaces, but email already exists
(
"mergin3",
" merGIN@mergin.com ",
"#pwd1234",
400,
), # tests with upper case, but email already exists
("XmerginX", " mergin@mergin.com ", "#pwd123", 400), # invalid password
(" mergin@mergin.com ", "#pwd123", 400), # invalid password
]


@pytest.mark.parametrize("username,email,pwd,expected", test_user_reg_data)
def test_user_register(client, username, email, pwd, expected):
@pytest.mark.parametrize("email,pwd,expected", test_user_reg_data)
def test_user_register(client, email, pwd, expected):
login_as_admin(client)
url = url_for("/.mergin_auth_controller_register_user")
data = {"username": username, "email": email, "password": pwd, "confirm": pwd}
data = {"email": email, "password": pwd, "confirm": pwd}
resp = client.post(url, data=json.dumps(data), headers=json_headers)
assert resp.status_code == expected
if expected == 201:
user = User.query.filter_by(username=username).first()
user = User.query.filter_by(email=email.strip()).first()
assert user
assert user.active
assert not user.verified_email # awaits user confirmation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,6 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial

<template>
<form @submit.prevent="submit" class="flex flex-column pb-4">
<span class="p-input-filled">
<label for="username">First name</label>
<PInputText
id="username"
v-model="username"
data-cy="create-user-username"
:class="['w-full', errors.username ? 'p-invalid' : '']"
toggleMask
:feedback="false"
aria-describedby="username-error"
/>
<span class="p-error paragraph-p6" id="username-error">{{
errors.username?.[0] || '&nbsp;'
}}</span>
</span>

<span class="p-input-filled">
<label for="email">Email</label>
<PInputText
Expand Down Expand Up @@ -101,7 +85,6 @@ export default defineComponent({
data() {
return {
isValid: null,
username: '',
email: '',
password: '',
passwordVisible: false
Expand Down Expand Up @@ -132,11 +115,10 @@ export default defineComponent({
...mapActions(useFormStore, ['clearErrors', 'handleError']),

validateInput(data) {
return ['username', 'email', 'password'].some((k) => data[k] === '')
return ['email', 'password'].some((k) => data[k] === '')
},
submit() {
const data: CreateUserData = {
username: this.username.trim(),
email: this.email.trim(),
password: this.password,
confirm: this.password
Expand Down
1 change: 0 additions & 1 deletion web-app/packages/admin-lib/src/modules/admin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export interface UpdateUserData {
}

export interface CreateUserData {
username: string
email: string
password: string
confirm: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial
toggleMask
:feedback="false"
aria-describedby="old-password-error"
placeholder="Please enter your password"
placeholder="Must be at least 8 characters"
/>
<span class="p-error paragraph-p6" id="old-password-error">{{
errors.old_password?.[0] || '&nbsp;'
Expand All @@ -36,10 +36,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial
aria-describedby="password-error"
toggleMask
:feedback="false"
placeholder="Please enter your new password"
placeholder="Must be at least 8 characters"
/>
<span class="p-error paragraph-p6" id="password-error">{{
errors.password?.[0] || '&nbsp;'
errors.password?.[0]
? errors.password?.[0].startsWith('Password')
? 'Password must be at least 8 characters long and include at least three of the following: lowercase letters, uppercase letters, numbers or special characters.'
: errors.password[0]
: '&nbsp;'
}}</span>
</span>

Expand All @@ -56,7 +60,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial
aria-describedby="confirm-password-error"
toggleMask
:feedback="false"
placeholder="Please enter your new password"
placeholder="Must be at least 8 characters"
/>

<span class="p-error paragraph-p6" id="confirm-password-error">{{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial
placeholder="Please enter your password"
/>
<span class="p-error paragraph-p6" id="password-error">{{
errors.password?.[0] || '&nbsp;'
errors.password?.[0]
? errors.password?.[0].startsWith('Password')
? 'Password must be at least 8 characters long and include at least three of the following: lowercase letters, uppercase letters, numbers or special characters.'
: errors.password[0]
: '&nbsp;'
}}</span>
</span>

Expand Down
Loading