Add username verification (#114)
continuous-integration/drone/push Build is passing Details

Move and add validation to Controller.get_username_from_view(). This addresses #101
+ Add tests for username validator

Reviewed-on: #114
Reviewed-by: Nathan Chung <>
Co-authored-by: o32patel <>
Co-committed-by: o32patel <>
This commit is contained in:
Ohm Patel 2024-01-15 20:01:44 -05:00 committed by Ohm Patel
parent 5332259731
commit f06ccdc3f9
3 changed files with 35 additions and 3 deletions

View File

@ -1,6 +1,7 @@
from abc import ABC
import as utils
from ...utils import validate_username
# NOTE: one controller can control multiple views,
@ -52,8 +53,9 @@ class Controller(ABC):
def get_username_from_view(self):
username = self.view.username_edit.edit_text
# TODO: share validation logic between CLI and TUI
if not username:
self.view.popup('Username must not be empty')
verification_res = validate_username(username)
if verification_res:
raise Controller.InvalidInput()
return username

View File

@ -1,9 +1,10 @@
import functools
import json
import os
from typing import List, Dict, Tuple, Callable
from typing import List, Dict, Tuple, Callable, Union
import requests
import re
from zope import component
from .StreamResponseHandler import StreamResponseHandler
@ -11,6 +12,8 @@ from ceo_common.interfaces import IHTTPClient, IConfig
from ceo_common.model import Term
from ceod.transactions.members import AddMemberTransaction
VALID_USERNAME_RE = re.compile(r"^[a-z0-9]+[a-z0-9-]+$")
def http_request(method: str, path: str, **kwargs) -> requests.Response:
client = component.getUtility(IHTTPClient)
@ -266,3 +269,11 @@ From other CSC machines you can connect using
return True
except PermissionError:
return False
def validate_username(username: str) -> Union[str, None]:
if not username:
return 'Username must not be empty'
if not VALID_USERNAME_RE.fullmatch(username):
return 'Username is invalid'
return None

tests/ceo/ Normal file
View File

@ -0,0 +1,19 @@
import ceo.utils as utils
def test_validate_username():
assert utils.validate_username('') == 'Username must not be empty'
assert utils.validate_username('-failure') == 'Username is invalid'
assert utils.validate_username('35 - joe') == 'Username is invalid'
assert utils.validate_username('35 -joe') == 'Username is invalid'
assert utils.validate_username('35- joe') == 'Username is invalid'
assert utils.validate_username('35$joe') == 'Username is invalid'
assert utils.validate_username(' 35joe') == 'Username is invalid'
assert utils.validate_username('35 joe') == 'Username is invalid'
assert utils.validate_username('35joe ') == 'Username is invalid'
assert utils.validate_username('joe!') == 'Username is invalid'
assert utils.validate_username('e45jong') is None
assert utils.validate_username('joe-35') is None
assert utils.validate_username('joe35-') is None
assert utils.validate_username('35joe-') is None
assert utils.validate_username('35-joe') is None