Skip to content

Commit

Permalink
Added: dynamic regex in UI (#349)
Browse files Browse the repository at this point in the history
  • Loading branch information
signebedi committed Sep 9, 2024
1 parent 9efb7ff commit 1eaa211
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 10 deletions.
29 changes: 29 additions & 0 deletions libreforms_fastapi/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6430,6 +6430,35 @@ def build_ui_context():
kwargs["current_year"] = datetime.now().year
kwargs["render_markdown_content"] = render_markdown_content


# def convert_python_regex_to_js(python_regex: str, embed_in_js_string=True):
# js_regex = re.sub(r"\(\?P<([a-zA-Z_][a-zA-Z0-9_]*)>", r"(?<\1>", python_regex)
# js_regex = re.sub(r'\\(?![dwsDSW])', r'\\\\', js_regex) # Handle backslashes for JS
# if embed_in_js_string:
# js_regex = js_regex.replace('"', '\\"') # Escape quotes for JS strings
# return js_regex

def convert_python_regex_to_js(python_regex: str, embed_in_js_string=True):
# Replace Python-style named groups with JavaScript-style named groups
js_regex = re.sub(r"\(\?P<([a-zA-Z_][a-zA-Z0-9_]*)>", r"(?<\1>", python_regex)

# Escape only necessary backslashes for JavaScript, ignoring \d, \w, \s, etc.
# Match a backslash that is not followed by special regex characters.
js_regex = re.sub(r'\\(?![dwsDSWbB])', r'\\\\', js_regex)

# Optionally escape double quotes if embedding inside a JS string delimited by double quotes
if embed_in_js_string:
js_regex = js_regex.replace('"', '\\"')

return js_regex


# We want to render these regexes in a way that javascript can handle them, see
# https://github.com/signebedi/libreforms-fastapi/issues/349
kwargs["js_friendly_username_regex"] = convert_python_regex_to_js(_c.USERNAME_REGEX)
kwargs["js_friendly_password_regex"] = convert_python_regex_to_js(_c.PASSWORD_REGEX)


return kwargs


Expand Down
26 changes: 20 additions & 6 deletions libreforms_fastapi/app/templates/change_password.html.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

{% block content %}
<h4>Change Password</h4>
{{config['PASSWORD_REGEX']}}

<form id="changePasswordForm">


Expand All @@ -23,8 +25,7 @@
| {{config['PASSWORD_HELPER_TEXT']}}
</span>
<input type="password" id="password" name="password" class="form-control"
onchange="validateField('password', /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/, 'Invalid password. Password must be at least 8 characters long, and include at least one uppercase letter, one lowercase letter, one symbol, and one number.')" required>
{# Password must be at least 8 characters long, and include at least one uppercase letter, one lowercase letter, and one number. #}
onchange="validateField('password', 'Invalid password. {{ config['PASSWORD_HELPER_TEXT'] }}')" required>
<div class="valid-feedback" id="password-is-valid" style="display: none;">This field is valid!</div>
<div class="invalid-feedback" id="password-is-invalid" style="display: none;"></div>
</fieldset>
Expand Down Expand Up @@ -58,10 +59,22 @@ $(document).ready(function() {
var submitBtn = $('#changePasswordForm button[type="submit"]');
submitBtn.prop('disabled', true); // Initially disable the submit button
window.validateField = function(fieldId, regex, invalidMessage) {
const passwordRegex = new RegExp({{ config['PASSWORD_REGEX']|tojson }});
const usernameRegex = new RegExp({{ config['USERNAME_REGEX']|tojson }});
// console.log({{ js_friendly_password_regex }});
window.validateField = function(fieldId, invalidMessage) {
var field = $('#' + fieldId);
var value = field.val();
var isValid = regex.test(value);
if (fieldId === "password"){
var isValid = passwordRegex.test(value);
} else if (fieldId === "username") {
var isValid = usernameRegex.test(value);
} else {
console.error("Unimplemented field type");
}
var feedbackId = fieldId + '-is-' + (isValid ? 'valid' : 'invalid');
var oppositeFeedbackId = fieldId + '-is-' + (isValid ? 'invalid' : 'valid');
Expand All @@ -88,9 +101,10 @@ $(document).ready(function() {
};
function updateSubmitButton() {
var isPasswordValid = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/.test($('#password').val());
var isPasswordValid = passwordRegex.test($('#password').val());
var arePasswordsMatching = $('#password').val() === $('#confirmPassword').val();
submitBtn.prop('disabled', !(isPasswordValid && arePasswordsMatching));
}
Expand All @@ -104,7 +118,7 @@ $(document).ready(function() {
// Perform your validation checks here
// Only proceed if all validations pass
var isPasswordValid = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/.test($('#password').val());
var isPasswordValid = passwordRegex.test($('#password').val());
var arePasswordsMatching = $('#password').val() === $('#confirmPassword').val();
if (isPasswordValid && arePasswordsMatching) {
Expand Down
19 changes: 15 additions & 4 deletions libreforms_fastapi/app/templates/create_user.html.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
| {{config['USERNAME_HELPER_TEXT']}}
</span>
<input type="text" id="username" name="username" class="form-control"
onchange="validateField('username', /^[a-z0-9_]{5,15}$/, 'Invalid username. Username should be 5-15 characters long and contain only letters, numbers, and underscores.')" required>
onchange="validateField('username', 'Invalid username. {{ config['USERNAME_HELPER_TEXT'] }}')" required>
{# Username should be 3-15 characters long and contain only lowercase letters, numbers, and underscores. #}
<div class="valid-feedback" id="username-is-valid" style="display: none;">This field is valid!</div>
<div class="invalid-feedback" id="username-is-invalid" style="display: none;"></div>
Expand All @@ -37,7 +37,7 @@
| {{config['PASSWORD_HELPER_TEXT']}}
</span>
<input type="password" id="password" name="password" class="form-control"
onchange="validateField('password', /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/, 'Invalid password. Password must be at least 8 characters long, and include at least one uppercase letter, one lowercase letter, one symbol, and one number.')" required>
onchange="validateField('password', 'Invalid password. {{ config['PASSWORD_HELPER_TEXT'] }}')" required>
{# Password must be at least 8 characters long, and include at least one uppercase letter, one lowercase letter, and one number. #}
<div class="valid-feedback" id="password-is-valid" style="display: none;">This field is valid!</div>
<div class="invalid-feedback" id="password-is-invalid" style="display: none;"></div>
Expand Down Expand Up @@ -91,10 +91,21 @@ $(document).ready(function() {
var submitBtn = $('#registrationForm button[type="submit"]');
submitBtn.prop('disabled', true); // Initially disable the submit button
window.validateField = function(fieldId, regex, invalidMessage) {
const passwordRegex = new RegExp({{ config['PASSWORD_REGEX']|tojson }});
const usernameRegex = new RegExp({{ config['USERNAME_REGEX']|tojson }});
window.validateField = function(fieldId, invalidMessage) {
var field = $('#' + fieldId);
var value = field.val();
var isValid = regex.test(value);
if (fieldId === "password"){
var isValid = passwordRegex.test(value);
} else if (fieldId === "username") {
var isValid = usernameRegex.test(value);
} else {
console.error("Unimplemented field type");
}
var feedbackId = fieldId + '-is-' + (isValid ? 'valid' : 'invalid');
var oppositeFeedbackId = fieldId + '-is-' + (isValid ? 'invalid' : 'valid');
Expand Down

0 comments on commit 1eaa211

Please sign in to comment.