Skip to content

Commit

Permalink
User.inEU and utils.ageOfConsent utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
differentmatt committed May 20, 2018
1 parent 0a5596f commit c107d23
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 30 deletions.
63 changes: 38 additions & 25 deletions app/core/utils.coffee
@@ -1,3 +1,5 @@
slugify = _.str?.slugify ? _.string?.slugify # TODO: why _.string on client and _.str on server?

clone = (obj) ->
return obj if obj is null or typeof (obj) isnt 'object'
temp = obj.constructor()
Expand All @@ -24,69 +26,78 @@ countries = [
{country: 'brazil', countryCode: 'BR'}

# Loosely ordered by decreasing traffic as measured 2016-09-01 - 2016-11-07
{country: 'united-kingdom', countryCode: 'GB'}
# TODO: switch to alphabetical ordering
{country: 'united-kingdom', countryCode: 'GB', inEU: true, ageOfConsent: 13}
{country: 'russia', countryCode: 'RU'}
{country: 'australia', countryCode: 'AU'}
{country: 'canada', countryCode: 'CA'}
{country: 'france', countryCode: 'FR'}
{country: 'france', countryCode: 'FR', inEU: true, ageOfConsent: 16}
{country: 'taiwan', countryCode: 'TW'}
{country: 'ukraine', countryCode: 'UA'}
{country: 'poland', countryCode: 'PL'}
{country: 'spain', countryCode: 'ES'}
{country: 'germany', countryCode: 'DE'}
{country: 'netherlands', countryCode: 'NL'}
{country: 'hungary', countryCode: 'HU'}
{country: 'poland', countryCode: 'PL', inEU: true, ageOfConsent: 13}
{country: 'spain', countryCode: 'ES', inEU: true, ageOfConsent: 13}
{country: 'germany', countryCode: 'DE', inEU: true, ageOfConsent: 16}
{country: 'netherlands', countryCode: 'NL', inEU: true, ageOfConsent: 16}
{country: 'hungary', countryCode: 'HU', inEU: true, ageOfConsent: 16}
{country: 'japan', countryCode: 'JP'}
{country: 'turkey', countryCode: 'TR'}
{country: 'south-africa', countryCode: 'ZA'}
{country: 'indonesia', countryCode: 'ID'}
{country: 'new-zealand', countryCode: 'NZ'}
{country: 'finland', countryCode: 'FI'}
{country: 'finland', countryCode: 'FI', inEU: true, ageOfConsent: 13}
{country: 'south-korea', countryCode: 'KR'}
{country: 'mexico', countryCode: 'MX'}
{country: 'vietnam', countryCode: 'VN'}
{country: 'singapore', countryCode: 'SG'}
{country: 'colombia', countryCode: 'CO'}
{country: 'india', countryCode: 'IN'}
{country: 'thailand', countryCode: 'TH'}
{country: 'belgium', countryCode: 'BE'}
{country: 'sweden', countryCode: 'SE'}
{country: 'denmark', countryCode: 'DK'}
{country: 'czech-republic', countryCode: 'CZ'}
{country: 'belgium', countryCode: 'BE', inEU: true}
{country: 'sweden', countryCode: 'SE', inEU: true, ageOfConsent: 13}
{country: 'denmark', countryCode: 'DK', inEU: true, ageOfConsent: 13}
{country: 'czech-republic', countryCode: 'CZ', inEU: true, ageOfConsent: 13}
{country: 'hong-kong', countryCode: 'HK'}
{country: 'italy', countryCode: 'IT'}
{country: 'romania', countryCode: 'RO'}
{country: 'italy', countryCode: 'IT', inEU: true}
{country: 'romania', countryCode: 'RO', inEU: true}
{country: 'belarus', countryCode: 'BY'}
{country: 'norway', countryCode: 'NO'}
{country: 'philippines', countryCode: 'PH'}
{country: 'lithuania', countryCode: 'LT'}
{country: 'lithuania', countryCode: 'LT', inEU: true, ageOfConsent: 16}
{country: 'argentina', countryCode: 'AR'}
{country: 'malaysia', countryCode: 'MY'}
{country: 'pakistan', countryCode: 'PK'}
{country: 'serbia', countryCode: 'RS'}
{country: 'greece', countryCode: 'GR'}
{country: 'israel', countryCode: 'IL'}
{country: 'portugal', countryCode: 'PT'}
{country: 'slovakia', countryCode: 'SK'}
{country: 'ireland', countryCode: 'IE'}
{country: 'greece', countryCode: 'GR', inEU: true, ageOfConsent: 15}
{country: 'israel', countryCode: 'IL', inEU: true}
{country: 'portugal', countryCode: 'PT', inEU: true}
{country: 'slovakia', countryCode: 'SK', inEU: true, ageOfConsent: 16}
{country: 'ireland', countryCode: 'IE', inEU: true, ageOfConsent: 13}
{country: 'switzerland', countryCode: 'CH'}
{country: 'peru', countryCode: 'PE'}
{country: 'bulgaria', countryCode: 'BG'}
{country: 'bulgaria', countryCode: 'BG', inEU: true}
{country: 'venezuela', countryCode: 'VE'}
{country: 'austria', countryCode: 'AT'}
{country: 'croatia', countryCode: 'HR'}
{country: 'austria', countryCode: 'AT', inEU: true, ageOfConsent: 14}
{country: 'croatia', countryCode: 'HR', inEU: true}
{country: 'saudia-arabia', countryCode: 'SA'}
{country: 'chile', countryCode: 'CL'}
{country: 'united-arab-emirates', countryCode: 'AE'}
{country: 'kazakhstan', countryCode: 'KZ'}
{country: 'estonia', countryCode: 'EE'}
{country: 'estonia', countryCode: 'EE', inEU: true}
{country: 'iran', countryCode: 'IR'}
{country: 'egypt', countryCode: 'EG'}
{country: 'ecuador', countryCode: 'EC'}
{country: 'slovenia', countryCode: 'SI'}
{country: 'slovenia', countryCode: 'SI', inEU: true}
{country: 'macedonia', countryCode: 'MK'}
{country: 'cyprus', countryCode: 'CY', inEU: true}
{country: 'latvia', countryCode: 'LV', inEU: true, ageOfConsent: 13}
{country: 'luxembourg', countryCode: 'LU', inEU: true, ageOfConsent: 16}
{country: 'malta', countryCode: 'MT', inEU: true}
]

inEU = (country) -> !!countries.find((c) => c.country is slugify(country))?.inEU

ageOfConsent = (country) -> countries.find((c) => c.country is slugify(country))?.ageOfConsent ? 16

courseIDs =
INTRODUCTION_TO_COMPUTER_SCIENCE: '560f1a9f22961295f9427742'
GAME_DEVELOPMENT_1: '5789587aad86a6efb573701e'
Expand Down Expand Up @@ -652,6 +663,7 @@ isValidEmail = (email) ->
emailRegex.test(email?.trim().toLowerCase())

module.exports = {
ageOfConsent
capitalLanguages
clone
combineAncestralObject
Expand Down Expand Up @@ -679,6 +691,7 @@ module.exports = {
hslToHex
i18n
injectCSS
inEU
isID
isRegionalSubscription
isSmokeTestEmail
Expand Down
2 changes: 2 additions & 0 deletions app/models/User.coffee
Expand Up @@ -35,6 +35,8 @@ module.exports = class User extends CocoModel
displayName: -> @get('name', true)
broadName: -> User.broadName(@attributes)

inEU: -> unless @get('country') then true else utils.inEU(@get('country'))

getPhotoURL: (size=80) ->
return '' if application.testing
return "/db/user/#{@id}/avatar?s=#{size}"
Expand Down
2 changes: 2 additions & 0 deletions server/models/User.coffee
Expand Up @@ -118,6 +118,8 @@ UserSchema.methods.getUserInfo = ->
id: @get('_id')
email: if @get('anonymous') then 'Unregistered User' else @get('email')

UserSchema.methods.inEU = -> unless @get('country') then true else core_utils.inEU(@get('country'))

UserSchema.methods.removeFromClassrooms = ->
userID = @get('_id')
yield Classroom.update(
Expand Down
12 changes: 11 additions & 1 deletion spec/server/unit/user.spec.coffee
Expand Up @@ -319,4 +319,14 @@ describe 'User', ->
expect(args[1]?.status).toBe('unsubscribed')
done()


describe 'inEU', ->
it 'true if in EU country', utils.wrap ->
u = yield utils.initUser({country: 'germany'})
expect(u.inEU()).toEqual(true)
it 'false if not in EU country', utils.wrap ->
u = yield utils.initUser({country: 'mexico'})
expect(u.inEU()).toEqual(false)
it 'true if not defined', utils.wrap ->
u = yield utils.initUser()
expect(u.get('country')).toBeUndefined()
expect(u.inEU()).toEqual(true)
22 changes: 21 additions & 1 deletion test/app/core/utils.spec.coffee
@@ -1,5 +1,5 @@
describe 'Utility library', ->
utils = require 'core/utils'
utils = require '../../../app/core/utils'

describe 'getQueryVariable(param, defaultValue)', ->
beforeEach ->
Expand Down Expand Up @@ -65,6 +65,26 @@ describe 'Utility library', ->
it 'i18n can fall forward if a general language is not found', ->
expect(utils.i18n(this.fixture1, 'text', 'pt')).toEqual(this.fixture1.i18n['pt-BR'].text)

describe 'inEU', ->
it 'EU countries return true', ->
euCountries = ['Austria', 'Belgium', 'Bulgaria', 'Croatia', 'Cyprus', 'Czech Republic', 'Denmark', 'Estonia', 'Finland', 'France', 'Germany', 'Greece', 'Hungary', 'Ireland', 'Italy', 'Latvia', 'Lithuania', 'Luxembourg', 'Malta', 'Netherlands', 'Poland', 'Portugal', 'Romania', 'Slovakia', 'Slovenia', 'Spain', 'Sweden', 'United Kingdom']
euCountries.forEach((c) -> expect(utils.inEU(c)).toEqual(true))
it 'non-EU countries return false', ->
nonEuCountries = ['united-states', 'peru', 'vietnam']
nonEuCountries.forEach((c) -> expect(utils.inEU(c)).toEqual(false))

describe 'ageOfConsent', ->
it 'Latvia is 13', ->
expect(utils.ageOfConsent('latvia')).toEqual(13)
it 'Austria is 14', ->
expect(utils.ageOfConsent('austria')).toEqual(14)
it 'Greece is 15', ->
expect(utils.ageOfConsent('greece')).toEqual(15)
it 'Slovakia is 16', ->
expect(utils.ageOfConsent('slovakia')).toEqual(16)
it 'default is 16', ->
expect(utils.ageOfConsent('codecombat')).toEqual(16)

describe 'createLevelNumberMap', ->
# r=required p=practice
it 'returns correct map for r', ->
Expand Down
18 changes: 15 additions & 3 deletions test/app/models/User.spec.coffee
Expand Up @@ -24,15 +24,15 @@ describe 'UserModel', ->
expect(defaultEmails.anyNotes.enabled).toBe(true)
expect(defaultEmails.generalNews.enabled).toBe(true)
expect(defaultEmails.recruitNotes.enabled).toBe(true)

it 'maintains defaults of other emails when one is explicitly set', ->
u = new User()
u.setEmailSubscription('recruitNotes', false)
defaultEmails = u.get('emails', true)
expect(defaultEmails.anyNotes?.enabled).toBe(true)
expect(defaultEmails.generalNews?.enabled).toBe(true)
expect(defaultEmails.recruitNotes.enabled).toBe(false)

it 'does not populate raw data for other emails when one is explicitly set', ->
u = new User()
u.setEmailSubscription('recruitNotes', false)
Expand All @@ -44,7 +44,7 @@ describe 'UserModel', ->
describe 'validate', ->
it 'returns undefined if the user is valid', ->
expect(new User().validate()).toBeUndefined()

it 'returns an array of errors if the user is invalid', ->
res = new User({invalidProp:'...'}).validate()
expect(_.isArray(res)).toBe(true)
Expand All @@ -56,3 +56,15 @@ describe 'UserModel', ->
expect(user.validate()).toBeUndefined()
user.set('newInvalidProp', '...')
expect(_.isArray(user.validate())).toBe(true)

describe 'inEU', ->
it 'true if in EU country', ->
u = new User({country: 'germany'})
expect(u.inEU()).toEqual(true)
it 'false if not in EU country', ->
u = new User({country: 'mexico'})
expect(u.inEU()).toEqual(false)
it 'true if not defined', ->
u = new User()
expect(u.get('country')).toBeUndefined()
expect(u.inEU()).toEqual(true)

0 comments on commit c107d23

Please sign in to comment.