Skip to content

Commit

Permalink
Ask for programming experience on signup & profile (hedyorg#541)
Browse files Browse the repository at this point in the history
* WIP, need to rework saved structure in DynamoDB & add e2e tests.

* Update profile template.

* Reorganize DynamoDB structure; add E2E tests & fix server bugs; show programming experience in profile.

* Revert unnecessary changes.

* Add missing texts.

* Hide the language checkboxes if experience is not 'yes'; markup improvements.

* translates new signup lines in Dutch

Co-authored-by: Felienne <[email protected]>
  • Loading branch information
fpereiro and Felienne authored Jul 2, 2021
1 parent 11dda7c commit b10fd71
Show file tree
Hide file tree
Showing 21 changed files with 216 additions and 1,102 deletions.
6 changes: 6 additions & 0 deletions coursedata/texts/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ Auth:
email_reset_password_body: |-
Dein Hedy-Passwort wurde zurückgesetzt. Wenn du das veranlasst hast, ist alles in Ordnung.
Wenn du dein Passwort nicht geändert hast, nimm bitte sofort mit uns Kontakt auf, indem du auf diese E-mail antwortest.
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"

# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "Meine Programme"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/el.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ Auth:
email_reset_password_body: |-
Το Hedy συνθηματικό σου επαναφέρθηκε σε ένα νέο. Αν αυτό ήταν δική σου ενέργεια, όλα καλα.
Αν δεν άλλαξες το συνθηματικό σου, παρακαλώ επικοινώνησε μαζί μας άμεσα, απαντώντας σε αυτό το email.
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"

# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: 'Τα προγράμματά μου'
Expand Down
7 changes: 7 additions & 0 deletions coursedata/texts/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ Auth:
email_reset_password_body: |-
Your Hedy password has been reset to a new one. If you did this, all is good.
If you didn't change your password, please contact us immediately by replying to this email.
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"


# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "My programs"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/es.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ Auth:
email_reset_password_body: |-
Tu contraseña de Hedy se ha reestablecido. Si tú has hecho esto, todo marcha bien.
Si tú no has reestablecido tu contraseña, por favor contáctanos inmediataamente respondiendo a este correo electrónico.
programming_experience: "Tienes experiencia con programación?"
yes: ""
no: "no"
languages: "Cuáles de estos lenguages de programación has usado?"
other_block: "Otro lenguaje basado en bloques"
other_text: "Otro lenguaje basado en texto"

# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "Mis programas"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/fr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ Auth:
email_reset_password_body: |-
Ton mot de passe sur Hedy a été réinitialisé. Si tu as fait ce changement toi-même, tout va bien.
Si tu n'as pas changé ton mot de passe, merci de nous contacter immédiatement en répondant à cet email.
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"

# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "Mes programmes"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/hu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ Auth:
email_recover_password_body: "Erre a linkre kattintva új Hedy jelszót állíthatsz be. Ha nem te igényelted a jelszó visszaállítását, hagyd figyelmen kívül ezt az e-mailt."
email_reset_password_subject: "A Hedy jelszó vissza lett állítva "
email_reset_password_body: "Hedy jelszavadat visszaállítottad. Ha ezt te tetted, akkor minden rendben. nHa nem változtattad meg jelszavadat, kérjük, azonnal lépj kapcsolatba velünk erre az e-mailre válaszolva."
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"
# Ezeket a változókat itt adjuk hozzá a kód egyszerűbbé tételéhez, de fogalmilag az felhasználói felülethez tartoznak.
program_header: "Programjaim"
save_prompt: "A program mentéséhez fiókkal kell rendelkezned. Szeretnél most bejelentkezni?"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/it.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ Auth:
email_reset_password_body: |-
La tua password di Hedy è stata resettata con una nuova. Se ne sei a conoscenza, bene.
Se non sei statu tu a cambiare la password, per favore contattaci immediatamente rispondendo a questa email.
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"

# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "I miei programmi"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/nl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ Auth:
email_reset_password_body: |-
Je Hedy wachtwoord is veranderd in een nieuw wachtwoord. eb jij dat zelf aangevraagd? Dan is alles in orde.
Heb jij dat niet gedaan? Dan kan het zijn dat iemand probeert jouw Hedy account over te nemen. Reageer op deze mail zodat we kunnen controleren of alles in orde is.
programming_experience: "Heb jij al eens geprogrammeerd?"
yes: "Ja"
no: "Nee"
languages: "Welke programmeertaal heb je wl eens gebruikt?"
other_block: "Een andere blokkentaal"
other_text: "Een andere teksttaal"

# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "Mijn programma's"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/pt_br.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ Auth:
email_reset_password_body: |-
Your Hedy password has been reset to a new one. If you did this, all is good.
If you didn't change your password, please contact us immediately by replying to this email.
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"

# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "My programs"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/sw.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ Auth:
email_recover_password_body: "Kwa kubofya kiungo hiki, unaweza kuweka nenosiri mpya ya Hedy. Kama haujahitaji kuweka upya nenosiri, tafadhali puuza barua pepe hii."
email_reset_password_subject: "Nenosiri yako ya Hedy kimebadilishwa"
email_reset_password_body: "Nenosiri yako ya Hedy kimebadilishwa. Ikiwa umefanya hivi, yote ni mazuri.\nIkiwa haukubadilisha nenosiri yako, tafadhali wasiliana nasi mara moja kwa kujibu barua pepe hii."
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"
# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "Programu zangu"
save_prompt: "Unahitaji kuwa na akaunti kuokoa programu yako. Je! Ungependa login sasa?"
Expand Down
6 changes: 6 additions & 0 deletions coursedata/texts/zh.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ Auth:
email_reset_password_body: |-
你的Hedy账号的密码已被更改. 如果是你更改了密码, 那就没问题.
如果您没有更改密码,请立即联系我们,并回复此邮件..
programming_experience: "Do you have programming experience?"
yes: "yes"
no: "no"
languages: "Which of these programming languages have you used before?"
other_block: "Another block language"
other_text: "Another text language"

# These variables are added here to make the code simpler, but conceptually they belong to the UI.
program_header: "我的程序"
Expand Down
2 changes: 2 additions & 0 deletions doc/backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ table users:
gender: m|f|UNDEFINED
created: INTEGER (epoch milliseconds)
last_login: INTEGER|UNDEFINED (epoch milliseconds)
prog_experience: UNDEFINED|'yes'|'no',
experience_languages: UNDEFINED|['scratch'|'other_block'|'python'|'other_text']
table tokens:
id: STRING (main index; for password reset tokens, id is the username)
Expand Down
38 changes: 30 additions & 8 deletions e2e_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,17 @@ def invalidMap (tag, method, path, bodies):
counter += 1
return output

def successfulSignup (state, response, username):
if not 'token' in response ['body']:
raise Exception ('No token present')
state ['token'] = response ['body'] ['token']

# We define apres functions here because multiline lambdas are not supported by python
def setSentCookies (state, response, username):
if 'Set-Cookie' in response ['headers']:
state ['headers'] ['cookie'] = response ['headers'] ['Set-Cookie']

def successfulSignup (state, response, username):
if not 'token' in response ['body']:
raise Exception ('No token present')
state ['token'] = response ['body'] ['token']
setSentCookies (state, response, username)

def getProfile1 (state, response, username):
profile = response ['body']
if profile ['username'] != username:
Expand Down Expand Up @@ -162,6 +163,22 @@ def getProfile3 (state, response, username):
if 'verification_pending' in profile:
raise Exception ('Invalid verification_pending (getProfile3)')

def getProfile4 (state, response, username):
profile = response ['body']
if not 'verification_pending' in profile or profile ['verification_pending'] != True:
raise Exception ('Invalid verification_pending (getProfile4)')
if not 'prog_experience' in profile or profile ['prog_experience'] != 'yes':
raise Exception ('Invalid prog_experience (getProfile4)')
if not 'experience_languages' in profile or not type_check (profile ['experience_languages'], 'list') or len (profile ['experience_languages']) != 1 or profile ['experience_languages'] [0] != 'python':
raise Exception ('Invalid experience_languages (getProfile4)')

def getProfile5 (state, response, username):
profile = response ['body']
if not 'prog_experience' in profile or profile ['prog_experience'] != 'no':
raise Exception ('Invalid prog_experience (getProfile5)')
if not 'experience_languages' in profile or not type_check (profile ['experience_languages'], 'list') or len (profile ['experience_languages']) != 2 or profile ['experience_languages'] [0] not in ['scratch', 'other_text'] or profile ['experience_languages'] [1] not in ['scratch', 'other_text']:
raise Exception ('Invalid experience_languages (getProfile5)')

def emailChange (state, response, username):
if not type_check (response ['body'] ['token'], 'str'):
raise Exception ('Invalid country (emailChange)')
Expand Down Expand Up @@ -239,7 +256,7 @@ def suite (username):
['get session vars from test', 'get', '/session_test', {}, {}, 200, checkTestSessionVars],
['get session vars from main again', 'get', '/session_main', {}, {}, 200, checkMainSessionVarsAgain],
['get root', 'get', '/', {}, '', 200],
invalidMap ('signup', 'post', '/auth/signup', ['', [], {}, {'username': 1}, {'username': 'user@me', 'password': 'foobar', 'email': '[email protected]'}, {'username:': 'user: me', 'password': 'foobar', 'email': '[email protected]'}, {'username': 't'}, {'username': ' t '}, {'username': username}, {'username': username, 'password': 1}, {'username': username, 'password': 'foo'}, {'username': username, 'password': 'foobar'}, {'username': username, 'password': 'foobar', 'email': 'me@something'}]),
invalidMap ('signup', 'post', '/auth/signup', ['', [], {}, {'username': 1}, {'username': 'user@me', 'password': 'foobar', 'email': '[email protected]'}, {'username:': 'user: me', 'password': 'foobar', 'email': '[email protected]'}, {'username': 't'}, {'username': ' t '}, {'username': username}, {'username': username, 'password': 1}, {'username': username, 'password': 'foo'}, {'username': username, 'password': 'foobar'}, {'username': username, 'password': 'foobar', 'email': 'me@something'}, {'username': username, 'password': 'foobar', 'email': '[email protected]', 'prog_experience': [2]}, {'username': username, 'password': 'foobar', 'email': '[email protected]', 'prog_experience': 'foo'}, {'username': username, 'password': 'foobar', 'email': '[email protected]', 'experience_languages': 'python'}]),
['valid signup', 'post', '/auth/signup', {}, {'username': username, 'password': 'foobar', 'email': username + '@e2e-testing.com'}, 200, successfulSignup],
invalidMap ('login', 'post', '/auth/login', ['', [], {}, {'username': 1}, {'username': 'user@me'}, {'username:': 'user: me'}]),
['valid login, invalid credentials', 'post', '/auth/login', {}, {'username': username, 'password': 'password'}, 403],
Expand All @@ -257,7 +274,7 @@ def suite (username):
['login again', 'post', '/auth/login', {}, {'username': username, 'password': 'foobar2'}, 200, setSentCookies],
invalidMap ('change password', 'post', '/auth/change_password', ['', [], {}, {'foo': 'bar'}, {'old_password': 1}, {'old_password': 'foobar'}, {'old_password': 'foobar', 'new_password': 1}]),
['get profile before profile update', 'get', '/profile', {}, {}, 200, getProfile1],
invalidMap ('update profile', 'post', '/profile', ['', [], {'email': 'foobar'}, {'birth_year': 'a'}, {'birth_year': 20}, {'country': 'Netherlands'}, {'gender': 0}, {'gender': 'a'}]),
invalidMap ('update profile', 'post', '/profile', ['', [], {'email': 'foobar'}, {'birth_year': 'a'}, {'birth_year': 20}, {'country': 'Netherlands'}, {'gender': 0}, {'gender': 'a'}, {'prog_experience': 1}, {'prog_experience': 'foo'}, {'experience_languages': ['python', 'foo']}]),
['change profile with same email', 'post', '/profile', {}, {'email': username + '@e2e-testing.com', 'country': 'US'}, 200],
['change profile with different email', 'post', '/profile', {}, {'email': username + '@e2e-testing2.com', 'country': 'NL'}, 200, emailChange],
['get profile after profile update', 'get', '/profile', {}, {}, 200, getProfile2],
Expand All @@ -280,7 +297,12 @@ def suite (username):
['delete program', 'get', lambda state: '/programs/delete/' + state ['program'] ['id'], {}, {}, 302],
['retrieve programs after deleting saved program', 'get', '/programs_list', {}, {}, 200, retrieveProgramsBefore],
['destroy account', 'post', '/auth/destroy', {}, {}, 200],
['get programs without being logged in', 'get', '/programs', {}, {}, 302]
['get programs without being logged in', 'get', '/programs', {}, {}, 302],
['valid signup again', 'post', '/auth/signup', {}, {'username': username, 'password': 'foobar', 'email': username + '@e2e-testing.com', 'prog_experience': 'yes', 'experience_languages': ['python']}, 200, successfulSignup],
['get profile after recreating account', 'get', '/profile', {}, {}, 200, getProfile4],
['change profile with different programming experience', 'post', '/profile', {}, {'prog_experience': 'no', 'experience_languages': ['scratch', 'other_text']}, 200],
['get profile after updating experience', 'get', '/profile', {}, {}, 200, getProfile5],
['destroy account', 'post', '/auth/destroy', {}, {}, 200],
]

if not args.concurrent:
Expand Down
2 changes: 1 addition & 1 deletion static/css/generated.css

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions static/js/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ window.auth = {
else payload [k] = values [k];
});

payload.prog_experience = $ ('input[name=has_experience]:checked').val ();
var languages = [];
// We ignore the languages checkboxes if the section is hidden
if ($ ('#languages').is (':visible')) $ ('input[name=languages]').filter (':checked').map (function (v) {languages.push ($ (this).val ())});
if (languages.length) payload.experience_languages = languages;

$.ajax ({type: 'POST', url: '/auth/signup', data: JSON.stringify (payload), contentType: 'application/json; charset=utf-8'}).done (function () {
auth.success (auth.texts.signup_success);

Expand Down Expand Up @@ -128,6 +134,13 @@ window.auth = {
payload [k] = values [k];
});

payload.prog_experience = $ ('input[name=has_experience]:checked').val ();
var languages = [];
// We ignore the languages checkboxes if the section is hidden
if ($ ('#languages').is (':visible')) $ ('input[name=languages]').filter (':checked').map (function (v) {languages.push ($ (this).val ())});
// When updating the profile, we can remove all languages, so in this case we send the empty array. This doesn't happen on signup.
payload.experience_languages = languages;

auth.clear_error ();
$.ajax ({type: 'POST', url: '/profile', data: JSON.stringify (payload), contentType: 'application/json; charset=utf-8'}).done (function () {
auth.success (auth.texts.profile_updated);
Expand Down Expand Up @@ -243,6 +256,13 @@ $.ajax ({type: 'GET', url: '/profile'}).done (function (response) {
$ ('#birth_year').val (response.birth_year);
$ ('#gender').val (response.gender);
$ ('#country').val (response.country);
if (response.prog_experience) {
$ ('input[name=has_experience][value="' + response.prog_experience + '"]').prop ('checked', true);
if (response.prog_experience === 'yes') $ ('#languages').show ();
}
(response.experience_languages || []).map (function (lang) {
$ ('input[name=languages][value="' + lang + '"]').prop ('checked', true);
});
}
}).fail (function (response) {
if (window.location.pathname.indexOf (['/my-profile']) !== -1) auth.redirect ('login');
Expand Down
Loading

0 comments on commit b10fd71

Please sign in to comment.