/* above is frontmatter for jekyll to include this file in build */ window.onload = function () { // Is the user logged in? const edxCookie = document.cookie.split('; ').find(row => row.startsWith('edxloggedin')); const isUserLoggedIn = (edxCookie === 'edxloggedin=true'); // If not logged in, remove the mask. if (! isUserLoggedIn) { document.getElementById('mask-area').outerHTML = ''; } const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\/\?\,\!\@\#\$\%\^\&\*\)\(\+\=\.\<\>\{\}\[\]\:\;\'\"\|\~\`\_\-])(?=.{8,})/; const usernameRegex = /^[A-Za-z0-9_-]+$/; const HIDDEN_CLASS = 'hidden'; const COUNTRY_USA = 'United States'; const COUNTRY_CANADA = 'Canada'; const GENERIC_ERROR_MESSAGE = "Error processing student registration."; let isProcessing = false; const isWithinBounds = (str, minLength, maxLength) => { if (! str || 'string' !== typeof(str)) { return false; } return (str.length >= minLength) && (str.length <= maxLength); }; const hideElement = (elem) => { if (elem) { elem.classList.add(HIDDEN_CLASS); } }; const showElement = (elem) => { if (elem) { elem.classList.remove(HIDDEN_CLASS); } }; const signInLink = document.getElementById('sign-in-link'); const currentPageURL = new URL(window.location.href); if (currentPageURL.search.indexOf('enrollment_action=enroll') === -1) { signInLink.href = 'https://university.redis.com/login'; } else { if (currentPageURL.searchParams.has('course_id')) { const encodedCourseId = encodeURIComponent(currentPageURL.searchParams.get('course_id')); const linkText = `https://university.redis.com/login?next=/account/finish_auth%3Fcourse_id%3D${encodedCourseId}%26enrollment_action%3Denroll%26next%3D%2Fdashboard`; // If they are logged in, just send them here as they won't need to register... if (isUserLoggedIn) { window.location = linkText; return; } // Otherwise, set the sign in link correctly. signInLink.href = linkText; } } // If we get here, drop the mask layer as we are staying on this page... // Sometimes the isLoggedIn detection isn't correct and the user can // end up on the register page with the mask up and not be redirected // so this is a safety mechanism to ensure that if this happens, they // can still interact with the registration form. if (document.getElementById('mask-area')) { document.getElementById('mask-area').outerHTML = ''; } const countrySelectField = document.getElementById('country-field'); countrySelectField.addEventListener('change', (e) => { const selected = e.target.value; const usaStatesArea = document.getElementById('usa-states-area'); const usaStateField = document.getElementById('usa-state-field'); const canadaProvincesArea = document.getElementById('canada-provinces-area'); const canadaProvinceField = document.getElementById('canada-province-field'); usaStateField.disabled = true; canadaProvinceField.disabled = true; hideElement(usaStatesArea); hideElement(canadaProvincesArea); if (selected === COUNTRY_USA) { showElement(usaStatesArea); usaStateField.disabled = false; } else if (selected === COUNTRY_CANADA) { showElement(canadaProvincesArea); canadaProvinceField.disabled = false; } }); const createAccountButton = document.getElementById('create-account-btn'); const onFormSubmit = async (e) => { try { e.preventDefault(); if (isProcessing) { return; } isProcessing = true; let errorsFound = false; const FIELD_IS_REQUIRED_MESSAGE = 'This field is required!'; const requiredTextFieldIds = [ { name: 'email-field', min: 1, max: 254, error: 'Email must be 1-254 characters!' }, { name: 'firstname-field', min: 1, max: 120, error: 'First Name must be 1-120 characters!' }, { name: 'lastname-field', min: 1, max: 120, error: 'Last Name must be 1-120 characters!' }, { name: 'job-function-field' }, { name: 'company-field' }, { name: 'username-field', min: 2, max: 30, error: 'Username must be 2-30 characters!' }, { name: 'country-field' }, { name: 'password-field', min: 8, max: 128, error: 'Password must be 8-128 characters!' }, { name: 'confirm-password-field', min: 8, max: 128, error: 'Password must be 8-128 characters!' } ]; const generalErrorArea = document.getElementById('general-error-area'); hideElement(generalErrorArea); const countryField = document.getElementById('country-field'); if (countryField.value === COUNTRY_USA) { requiredTextFieldIds.push({ name: 'usa-state-field' }); } else if (countryField.value === COUNTRY_CANADA) { requiredTextFieldIds.push({ name: 'canada-province-field' }); } requiredTextFieldIds.map((field) => { const elem = document.getElementById(field.name); const elemError = document.getElementById(`${field.name}-error`); const elemValue = elem.value.trim(); hideElement(elemError); if (elemValue.length === 0) { elemError.textContent = FIELD_IS_REQUIRED_MESSAGE; showElement(elemError); errorsFound = true; } else if (field.hasOwnProperty('min') && field.hasOwnProperty('max')) { if (elemValue.length < field.min || elemValue.length > field.max) { if (field.hasOwnProperty('error')) { elemError.textContent = field.error; showElement(elemError); } errorsFound = true; } } }); const emailField = document.getElementById('email-field'); const emailFieldError = document.getElementById('email-field-error'); const emailFieldValue = emailField.value.trim(); hideElement(emailFieldError); if (! emailRegex.test(emailFieldValue)) { emailFieldError.textContent = 'A valid email address is required!'; showElement(emailFieldError); errorsFound = true; } else if (emailFieldValue.length > 254) { emailFieldError.textContent = 'Email must be 254 characters or less!'; showElement(emailFieldError); errorsFound = true; } const usernameField = document.getElementById('username-field'); const usernameFieldError = document.getElementById('username-field-error'); const usernameFieldValue = usernameField.value.trim(); hideElement(usernameFieldError); if (! usernameRegex.test(usernameFieldValue)) { usernameFieldError.textContent = 'Username must be 2-30 characters and only contain letters, numbers, _ and - characters.'; showElement(usernameFieldError); errorsFound = true; } const passwordField = document.getElementById('password-field'); const passwordValue = passwordField.value; const passwordFieldError = document.getElementById('password-field-error'); const confirmPasswordField = document.getElementById('confirm-password-field'); const confirmPasswordFieldError = document.getElementById('confirm-password-field-error'); if (passwordValue !== confirmPasswordField.value) { passwordFieldError.textContent = 'Password fields must match!'; confirmPasswordFieldError.textContent = 'Password fields must match!'; showElement(passwordFieldError); showElement(confirmPasswordFieldError); errorsFound = true; } else { if (passwordValue.length > 0 && passwordValue === emailFieldValue) { passwordFieldError.textContent = 'Password cannot be your email!'; confirmPasswordFieldError.textContent = 'Password cannot be your email!'; showElement(passwordFieldError); showElement(confirmPasswordFieldError); errorsFound = true; } else { const userNameValue = document.getElementById('username-field').value; if (passwordValue.length > 0 && passwordValue === userNameValue) { passwordFieldError.textContent = 'Password cannot be your username!'; confirmPasswordFieldError.textContent = 'Password cannot be your username!'; showElement(passwordFieldError); showElement(confirmPasswordFieldError); errorsFound = true; } else { if (! passwordRegex.test(passwordValue)) { passwordFieldError.textContent = 'Password must be 8 or more characters, with a mix of upper and lowercase letters, numbers and special characters!'; confirmPasswordFieldError.textContent = 'Password must be 8 or more characters, with a mix of upper and lowercase letters, numbers and special characters!'; showElement(passwordFieldError); showElement(confirmPasswordFieldError); errorsFound = true; } } } } const termsOfServiceCheckBox = document.getElementById('terms-of-service-field'); const tosError = document.getElementById('terms-of-service-error'); if (! termsOfServiceCheckBox.checked) { showElement(tosError); errorsFound = true; } else { hideElement(tosError); } if (! errorsFound) { const currentPageURL = new URL(window.location.href); const userRegistration = { email: emailFieldValue.trim(), firstName: document.getElementById('firstname-field').value.trim(), lastName: document.getElementById('lastname-field').value.trim(), jobFunction: document.getElementById('job-function-field').value, company: document.getElementById('company-field').value.trim(), userName: document.getElementById('username-field').value.trim(), password: passwordValue, country: countryField.value, agreeTerms: true }; if (countryField.value === COUNTRY_USA) { userRegistration.state = document.getElementById('usa-state-field').value; } else if (countryField.value === COUNTRY_CANADA) { userRegistration.province = document.getElementById('canada-province-field').value; } if (currentPageURL.searchParams.has('course_id')) { userRegistration.courseId = currentPageURL.searchParams.get('course_id'); } const response = await fetch('https://us-central1-redislabs-university.cloudfunctions.net/register-form-processor', { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(userRegistration) }); if (response.ok) { hideElement(document.getElementById('register-form')); showElement(document.getElementById('post-register')); window.scrollTo(0, 0) } else if (response.status === 409) { // Look in the response body and see which field(s) are // in error then highlight them. const responseBody = await response.json(); const emailInError = responseBody['invalid-params'].includes('email'); const userNameInError = responseBody['invalid-params'].includes('username'); if (emailInError) { const emailError = document.getElementById('email-field-error'); emailError.textContent = 'This email address is already in use!'; showElement(emailError); } if (userNameInError) { const userNameError = document.getElementById('username-field-error'); userNameError.textContent = 'This username is already in use!'; showElement(userNameError); } } else { // 400 class error... const responseBody = await response.json(); if (responseBody) { // Look for the password being too similar to the username... // and throw a general error if something else is found... let throwGeneralError = true; if (responseBody.hasOwnProperty('user_message')) { const userMessages = responseBody['user_message']; for (let n = 0; n < userMessages.length; n++) { const msg = userMessages[n][1][0]; if (msg.indexOf('password is too similar') !== -1) { const passwordFieldError = document.getElementById('password-field-error'); const confirmPasswordFieldError = document.getElementById('confirm-password-field-error'); passwordFieldError.textContent = 'Password is too similar to your username!'; confirmPasswordFieldError.textContent = 'Password is too similar to your username!'; showElement(passwordFieldError); showElement(confirmPasswordFieldError); throwGeneralError = false; break; } } } if (throwGeneralError) { document.getElementById('general-error').textContent = GENERIC_ERROR_MESSAGE; showElement(generalErrorArea); } } else { // General error... document.getElementById('general-error').textContent = GENERIC_ERROR_MESSAGE; showElement(generalErrorArea); } } } isProcessing = false; } catch (ex) { console.log(ex); isProcessing = false; } }; createAccountButton.addEventListener('click', onFormSubmit); };