Commit d6e932a7 authored by Romain Loth's avatar Romain Loth

used js module pattern (cmxClt) and almost finished all client-side controllers factorization

parent 40322a00
......@@ -151,7 +151,8 @@ def user():
def login():
if request.method == 'GET':
return render_template(
"login.html"
"login.html",
doors_connect = config['DOORS_HOST']+':'+config['DOORS_PORT']
)
elif request.method == 'POST':
# TODO sanitize
......@@ -341,9 +342,8 @@ def sanitize(value):
return san_typed_val
########### MAIN ###########
# this only uses the dev server (in prod we're run by unicorn and not as main)
if __name__ == "__main__":
# our app should be bound to an ip (cf stackoverflow.com/a/30329547/2489184)
app.run(host=config['COMEX_HOST'], port=int(config['COMEX_PORT']))
/**
* @fileoverview
* Login via Doors
* @todo
* - package.json
*
* @version 1
* @copyright ISCPIF-CNRS 2016
* @author romain.loth@iscpif.fr
*
* @requires comex_user_shared
* @requires comex_user_shared_auth
*/
// initialize form controllers
cmxClt.uform.initialize("comex_login_form", loginValidate)
// initialize auth with doors
cmxClt.uauth.emailIdSupposedToExist = true
// done when anything in the form changes
function loginValidate() {
// console.log("loginValidate Go")
cmxClt.uauth.earlyValidate()
// TODO checkPassStatusSingle()
if (cmxClt.uauth.passStatus
&& cmxClt.uauth.emailStatus
&& cmxClt.uauth.captchaStatus) {
cmxClt.uform.submitButton.disabled = false
}
else {
cmxClt.uform.submitButton.disabled = true
}
}
function loginDoorsThenTestUidAndSubmit(){
cmxClt.uform.mainMessage.innerHTML = "Logging in ISCPIF Doors..."
// all values from the form have now been validated
var emailValue = cmxClt.uauth.email.value
var passValue = cmxClt.uauth.pass1.value
// KNOCKING ON THE DOORS -------------------------------------
// /!\ async
callDoors(
"user",
[emailValue, passValue],
// callback: get uid to send to server -------------------
function(doorsResp) {
console.log("login resp:", doorsResp)
testUidAndSubmit(doorsResp)
}
)
}
function testUidAndSubmit(doorsResp) {
var doorsUid = doorsResp[0]
var doorsMsg = doorsResp[1]
if (doorsUid == null) {
cmxClt.uform.mainMessage.innerHTML = "Problem with doors login..."
cmxClt.uform.mainMessage.style.color = cmxClt.colorRed
cmxClt.uform.submitButton.disabled = false
}
else {
// fill in the answer we got
// £TODO fix scope uauth and uform ?
uidInput.value = doorsUid
console.info("form was validated and registered@doors: submitting now")
//==== SEND! ====
theForm.submit()
//===============
}
}
console.log("login controllers load OK")
/**
* @fileoverview
* Profile 1/overview and 2/completing via Doors
* @todo
* - package.json
*
* @version 1
* @copyright ISCPIF-CNRS 2016
* @author romain.loth@iscpif.fr
*
* @requires comex_user_shared
* @requires comex_user_shared_auth
*/
// TODO
......@@ -6,7 +6,7 @@
* + prepares DB save into COLS
*
* @todo
* - harmonize var names (eg 'email' vs 'initialsInput' are both input elts)
* - harmonize var names (eg 'cmxClt.uauth.email' vs 'initialsInput' are both input elts)
* - package.json
*
* @version 1
......@@ -17,49 +17,32 @@
* @requires comex_user_shared_auth
*/
// common vars to user forms
// NB other vars defined in main scope but just before their respective funs
var theFormId = "comex_login_form"
var theForm = document.getElementById(theFormId)
var wholeFormData
// initialize form controllers
cmxClt.uform.initialize("comex_reg_form", testAsYouGo) // our form is now in cmxClt.uform.theForm
// cf corresponding css classes
var colorWhite = '#fff'
var colorRed = '#910'
var colorGreen = '#161'
var colorGrey = '#554'
// vars that will be used during the interaction
var submitButton = document.getElementById('formsubmit')
var mainMessage = document.getElementById('main_validation_message')
// initialize auth with doors
cmxClt.uauth.emailIdSupposedToExist = false
var jobLookingDateStatus = false
submitButton.disabled = true
theForm.onkeyup = testAsYouGo
theForm.onchange = testAsYouGo
theForm.onblur = testAsYouGo
var lastEmailValueCheckedDisplayed = null
// done when anything in the form changes
function testAsYouGo() {
// console.log("testAsYouGo Go")
if (email.value != lastEmailValueCheckedDisplayed) {
// will update the emailStatus boolean
basicEmailValidate(email.value)
}
cmxClt.uauth.earlyValidate()
captchaStatus = (captcha.value.length == realCaptchaLength)
checkPassStatus()
checkJobDateStatus()
if (passStatus && emailStatus && captchaStatus && jobLookingDateStatus) {
submitButton.disabled = false
if (cmxClt.uauth.passStatus
&& cmxClt.uauth.emailStatus
&& cmxClt.uauth.captchaStatus
&& jobLookingDateStatus) {
cmxClt.uform.submitButton.disabled = false
}
else {
submitButton.disabled = true
cmxClt.uform.submitButton.disabled = true
}
var now = new Date()
regTimestamp.value = now.toISOString()
......@@ -111,7 +94,7 @@ var jobLookingDivStyle = document.getElementById('job_looking_div').style
// case false => Ok("""{"status":"login available"}""")
function testDoorsUserExists(emailValue) {
// /!\ async
callDoors(
cmxClt.uauth.callDoors(
"userExists",
[emailValue],
function(doorsResp) {
......@@ -119,6 +102,7 @@ function testDoorsUserExists(emailValue) {
var doorsMsg = doorsResp[1]
// the global status can be true iff login is available and format ok
// £TODO fix scope (use uauth)
emailStatus = (doorsMsg == "login available")
displayDoorsStatusInRegisterBox(emailStatus, emailValue)
......@@ -131,8 +115,8 @@ function registerDoorsAndSubmit(){
mainMessage.innerHTML = "Registering with ISCPIF Doors..."
// all values from the form have now been validated
var emailValue = email.value
var passValue = pass1.value
var emailValue = cmxClt.uauth.email.value
var passValue = cmxClt.uauth.pass1.value
var wholenameValue = ""
if (mName.value != "") {
......@@ -143,7 +127,7 @@ function registerDoorsAndSubmit(){
}
// KNOCKING ON THE DOORS -------------------------------------
// REGISTERING ON THE DOORS -------------------------------------
// /!\ async
callDoors(
"register",
......@@ -151,6 +135,7 @@ function registerDoorsAndSubmit(){
// callback: send to DB -------------------
function(doorsResp) {
console.log("register resp:", doorsResp)
addUidThenSubmit(doorsResp)
}
)
......@@ -161,55 +146,21 @@ function addUidThenSubmit(doorsResp) {
var doorsMsg = doorsResp[1]
if (doorsUid == null) {
mainMessage.innerHTML = "Problem with doors registration... TODO debug"
mainMessage.style.color = colorRed
submitButton.disabled = false
cmxClt.uform.mainMessage.innerHTML = "Problem with doors registration... TODO debug"
cmxClt.uform.mainMessage.style.color = cmxClt.colorRed
cmxClt.uform.submitButton.disabled = false
}
else {
// fill in the answer we got
// £TODO fix scope uauth and uform ?
uidInput.value = doorsUid
console.info("form was validated and registered@doors: submitting now")
//==== SEND! ====
theForm.submit()
//===============
}
}
var doorsIcon = document.getElementById('doors_ret_icon')
function displayDoorsStatusInRegisterBox (available, emailValue) {
if (available) {
// icon
doorsIconMessage.title = "Ok ID available on Doors"
doorsIcon.style.color = colorGreen
doorsIcon.classList.remove('glyphicon-remove')
doorsIcon.classList.remove('glyphicon-question-sign')
doorsIcon.classList.add('glyphicon-ok')
// message in legend
doorsMessage.innerHTML = "Ok, this email ID is available on Doors!"
doorsMessage.style.color = colorGreen
//==== SEND! ==================
cmxClt.uform.theForm.submit()
//=============================
}
else {
// icon
doorsIconMessage.title = "Sorry ID already taken on Doors!"
doorsIcon.style.color = colorRed
doorsIcon.classList.remove('glyphicon-ok')
doorsIcon.classList.remove('glyphicon-question-sign')
doorsIcon.classList.add('glyphicon-remove')
// message in legend
doorsMessage.innerHTML = "Sorry this email ID is already taken on Doors!"
doorsMessage.style.color = colorRed
}
// to debounce further actions in testAsYouGo
// return to neutral is also in testAsYouGo
lastEmailValueCheckedDisplayed = emailValue
}
// validateAndMsg() : bool (validates fields before doors registration and send)
......@@ -224,20 +175,19 @@ function validateAndMsg() {
// not necessary b/c button type is set and is != "submit"
// submitEvent.preventDefault()
submitButton.disabled = true
mainMessage.style.display = 'block'
cmxClt.uform.submitButton.disabled = true
cmxClt.uform.mainMessage.style.display = 'block'
var valid = true
// TODO pass mainMessage ref as arg
mainMessage.innerHTML = "Validating the form..."
cmxClt.uform.mainMessage.innerHTML = "Validating the form..."
// also reformat the jobDate from "YYYY/MM/DD" to ISO
if (jobDate.value.length) jobDate.value = (new Date(jobDate.value)).toISOString()
// objectify the form
wholeFormData = new FormData(theForm);
cmxClt.uform.wholeFormData = new FormData(theForm);
var missingFields = []
var toolongFields = []
......@@ -255,7 +205,7 @@ function validateAndMsg() {
// skip doors_uid done afterwards if form ok
if (fieldName == 'doors_uid') continue ;
var actualValue = wholeFormData.get(fieldName)
var actualValue = cmxClt.uform.wholeFormData.get(fieldName)
// console.log("actualValue", actualValue)
......@@ -296,11 +246,11 @@ function validateAndMsg() {
// RESULTS
if (valid) {
// add the captchaCheck inside the form (jquery interference)
captchaCheck.value = $(captcha).realperson('getHash')
// add the captchaCheck inside the form (TODO should be automatic via realperson or uauth submodules)
cmxClt.uauth.captchaCheck.value = $(captcha).realperson('getHash')
mainMessage.innerHTML = "Form is valid... Will register and submit..."
mainMessage.style.display = 'block'
cmxClt.uform.mainMessage.innerHTML = "Form is valid... Will register and submit..."
cmxClt.uform.mainMessage.style.display = 'block'
return true
}
......@@ -308,11 +258,11 @@ function validateAndMsg() {
console.warn("form is not valid")
// TODO highlight invalid fields
submitButton.disabled = false
cmxClt.uform.submitButton.disabled = false
var errorMessage = ''
if (missingFields.length) {
errorMessage += "Please fill the missing fields: " + ulListFromLabelsArray(missingFields, ["red"])
errorMessage += "Please fill the missing fields: " + cmxClt.ulListFromLabelsArray(missingFields, ["red"])
}
// length is handled by each input's maxlength
......@@ -321,7 +271,7 @@ function validateAndMsg() {
if (jobDate.value.length) jobDate.value = jobDate.value.slice(0,10).replace(/-/g,"/")
// display (TODO setTimeout and fade)
mainMessage.innerHTML = errorMessage
cmxClt.uform.mainMessage.innerHTML = errorMessage
return false
}
}
......@@ -359,12 +309,12 @@ function checkShowPic() {
if (theFile.size > max_size) {
// msg pb
picMsg.innerHTML = "The picture is too big (200kB max)!"
picMsg.style.color = colorRed
picMsg.style.color = cmxClt.colorRed
}
else {
// msg ok
picMsg.innerHTML = "Picture ok"
picMsg.style.color = colorGreen
picMsg.style.color = cmxClt.colorGreen
// to show the pic when readAsDataURL
imgReader.onload = function () {
......@@ -389,7 +339,7 @@ function checkShowPic() {
boxShowPicImg.style.display = 'block'
// possible re-adjust outerbox ?
// showPicImg.style.border = "2px dashed " + colorGrey
// showPicImg.style.border = "2px dashed " + cmxClient.colorGrey
}
......@@ -456,17 +406,22 @@ jobDate.onchange = checkJobDateStatus
function checkJobDateStatus() {
jobLookingDateStatus = (jobBool.value == "No" || validDate.test(jobDate.value))
if (!jobLookingDateStatus) {
jobDateMsg.style.color = colorRed
jobDateMsg.style.color = cmxClt.colorRed
jobDateMsg.innerHTML = 'Date is not yet in the valid format YYYY/MM/DD'
}
else {
jobDateMsg.style.color = colorGreen
jobDateMsg.style.color = cmxClt.colorGreen
jobDateMsg.innerHTML = 'Ok valid date!'
}
}
// £TODO1 move autocomp data to an autocomplete module
// -> local data for countries, jobtitles
// -> ajax fetcher for the scholars, kws and labs
// £TODO2 add a fetcher API on services side
// autocomplete countries
$(function() {
var $countryInput = $('#country')
......@@ -1077,11 +1032,12 @@ console.log("reg controllers load OK")
// lName.value = "Tartampion"
// initialsInput.value="JPP"
// document.getElementById('country').value = "France"
// email.value= makeRandomString(7)+"@om.fr"
// pass1.value="123456+789"
// pass2.value="123456+789"
// document.getElementById('position').value = "atitle"
// document.getElementById('keywords').value = "Blabla"
// document.getElementById('org').value = "CNRS"
// basicEmailValidate(email.value)
// cmxClt.uauth.email.value= cmxClt.makeRandomString(7)+"@om.fr"
// cmxClt.uauth.pass1.value="123456+789"
// cmxClt.uauth.pass2.value="123456+789"
// cmxClt.uauth.testMailFormatAndExistence(email.value, false)
// --------------------------->8------
/**
* @fileoverview
* Login via Doors
* @todo
* - package.json
*
* @version 1
* @copyright ISCPIF-CNRS 2016
* @author romain.loth@iscpif.fr
*
* @requires comex_user_shared
* @requires comex_user_shared_auth
*/
// common vars to user forms
// NB other vars defined in main scope but just before their respective funs
var theFormId = "comex_login_form"
var theForm = document.getElementById(theFormId)
var wholeFormData
// cf corresponding css classes
var colorWhite = '#fff'
var colorRed = '#910'
var colorGreen = '#161'
var colorGrey = '#554'
// vars that will be used during the interaction
var submitButton = document.getElementById('formsubmit')
var mainMessage = document.getElementById('main_validation_message')
submitButton.disabled = true
theForm.onkeyup = testAsYouGo
theForm.onchange = testAsYouGo
theForm.onblur = testAsYouGo
var lastEmailValueCheckedDisplayed = null
// done when anything in the form changes
function testAsYouGo() {
// console.log("testAsYouGo Go")
if (email.value != lastEmailValueCheckedDisplayed) {
// will update the emailStatus boolean
basicEmailValidate(email.value)
}
captchaStatus = (captcha.value.length == realCaptchaLength)
checkPassStatusSingle()
if (passStatus && emailStatus && captchaStatus) {
submitButton.disabled = false
}
else {
submitButton.disabled = true
}
}
// NB using new route in doors api/userExists
// case true => Ok("""{"status":"login exists"}""")
// case false => Ok("""{"status":"login available"}""")
function testDoorsUserExists(emailValue) {
// /!\ async
callDoors(
"userExists",
[emailValue],
function(doorsResp) {
var doorsUid = doorsResp[0]
var doorsMsg = doorsResp[1]
// for login the global status can be true iff login exists
emailStatus = (doorsMsg == "login available")
displayDoorsStatusInLoginBox(emailStatus, emailValue)
}
)
}
function doorsThenTestUidAndSubmit(){
mainMessage.innerHTML = "Logging in ISCPIF Doors..."
// all values from the form have now been validated
var emailValue = email.value
var passValue = pass.value
// KNOCKING ON THE DOORS -------------------------------------
// /!\ async
callDoors(
"user",
[emailValue, passValue],
// callback: get uid to send to server -------------------
function(doorsResp) {
testUidAndSubmit(doorsResp)
}
)
}
function testUidAndSubmit(doorsResp) {
var doorsUid = doorsResp[0]
var doorsMsg = doorsResp[1]
if (doorsUid == null) {
mainMessage.innerHTML = "Problem with doors login..."
mainMessage.style.color = colorRed
submitButton.disabled = false
}
else {
// fill in the answer we got
uidInput.value = doorsUid
console.info("form was validated and registered@doors: submitting now")
//==== SEND! ====
theForm.submit()
//===============
}
}
var doorsIcon = document.getElementById('doors_ret_icon')
function displayDoorsStatusInLoginBox (available, emailValue) {
if (available) {
// icon
doorsIconMessage.title = "Sorry this ID isn't recognized on Doors!"
doorsIcon.style.color = colorRed
doorsIcon.classList.remove('glyphicon-ok')
doorsIcon.classList.remove('glyphicon-question-sign')
doorsIcon.classList.add('glyphicon-remove')
// message in legend
doorsMessage.innerHTML = "Sorry this email ID isn't recognized on Doors!"
doorsMessage.style.color = colorRed
}
else {
// icon
doorsIconMessage.title = "Ok ID exists in Doors"
doorsIcon.style.color = colorGreen
doorsIcon.classList.remove('glyphicon-remove')
doorsIcon.classList.remove('glyphicon-question-sign')
doorsIcon.classList.add('glyphicon-ok')
// message in legend
doorsMessage.innerHTML = "Ok, this email ID is recognized in Doors!"
doorsMessage.style.color = colorGreen
}
// to debounce further actions in testAsYouGo
// return to neutral is also in testAsYouGo
lastEmailValueCheckedDisplayed = emailValue
}
console.log("login controllers load OK")
/**
* @fileoverview
* Shared vars and functions for all user forms
* Comex Client Module: initialize and expose as *cmxClt* var
* -> shared vars for css
* -> shared vars and functions for all user forms in *cmxClt.uform* submodule
*
* @todo
* - package.json
......@@ -11,56 +13,73 @@
*
*/
// common vars to user forms
// NB other vars defined in main scope but just before their respective funs
var theFormId = "comex_login_form"
var theForm = document.getElementById(theFormId)
var wholeFormData
// cf corresponding css classes
var colorWhite = '#fff'
var colorRed = '#910'
var colorGreen = '#161'
var colorGrey = '#554'
// vars that will be used during the interaction
var submitButton = document.getElementById('formsubmit')
var mainMessage = document.getElementById('main_validation_message')
theForm.onkeyup = testAsYouGo
theForm.onchange = testAsYouGo
theForm.onblur = testAsYouGo
var lastEmailValueCheckedDisplayed = null
function makeRandomString(nChars) {
var rando = ""
var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
var len = possible.length
for( var i=0; i < nChars; i++ )
rando += possible.charAt(Math.floor(Math.random() * len));
return rando
}
function ulListFromLabelsArray(strArray, ulClassList) {
ulClasses=["minilabels"].concat(ulClassList).join(" ")
var resultHtml = '<ul class="'+ulClasses+'">'
for (var i in strArray) {
var label = strArray[i].replace(/_/, " ")
resultHtml += '<li class="minilabel">'+label+'</li>'
// initialize and export cmxClt module
var cmxClt = (function() {
ccModule = {}
// cf corresponding css classes
ccModule.colorWhite = '#fff'
ccModule.colorRed = '#910'
ccModule.colorGreen = '#161'
ccModule.colorGrey = '#554'
ccModule.makeRandomString = function (nChars) {
var rando = ""
var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
var len = possible.length
for( var i=0; i < nChars; i++ )
rando += possible.charAt(Math.floor(Math.random() * len));
return rando
}
ccModule.ulListFromLabelsArray = function (strArray, ulClassList) {
ulClasses=["minilabels"].concat(ulClassList).join(" ")
var resultHtml = '<ul class="'+ulClasses+'">'
for (var i in strArray) {
var label = strArray[i].replace(/_/, " ")
resultHtml += '<li class="minilabel">'+label+'</li>'
}
resultHtml += '</ul>'
return resultHtml
}
// basic inputs get normal on focus
ccModule.makeNormal = function (elt) {
elt.style.fontWeight = "normal"
}
// basic inputs get bold on blur
ccModule.makeBold = function (elt){
if (elt.value != "") elt.style.fontWeight = "bold"
}
// common vars to user forms
ccModule.uform = {}
ccModule.uform.theFormId = null
ccModule.uform.theForm = null
ccModule.uform.wholeFormData = null
// vars that will be used during the interaction
ccModule.uform.submitButton = document.getElementById('formsubmit')
ccModule.uform.mainMessage = document.getElementById('main_validation_message')
ccModule.uform.initialize = function(aFormId, aValidationFun) {
ccModule.uform.theFormId = aFormId
ccModule.uform.theForm = document.getElementById(aFormId)
ccModule.uform.theForm.onkeyup = aValidationFun
ccModule.uform.theForm.onchange = aValidationFun
ccModule.uform.theForm.onblur = aValidationFun
}
resultHtml += '</ul>'
return resultHtml
}
return ccModule
}()) ;
// basic inputs get normal on focus
function makeNormal(elt) {
elt.style.fontWeight = "normal"
}
// basic inputs get bold on blur
function makeBold(elt){
if (elt.value != "") elt.style.fontWeight = "bold"
}
console.log("shared load OK")
/**
* @fileoverview
* Validates email ID and passwords
* Validates an email ID and password(s)
* Prepares "captcha" data
* Transmits login credentials to Doors for login or register (fun callDoors)
*
* @todo
......@@ -14,246 +15,346 @@
* @requires realperson (keith-wood.name/realPerson.html)
*/
// common vars to authenticating user forms
var uidInput = document.getElementById('doors_uid')
var email = document.getElementById('email')
// str of the form: doors_hostname:doors_port
var doorsConnectParam = document.getElementById('doors_connect').value
// captchaHash should be appended by itself if normal submit,
// but we may need to do it ourselves (TODO test)
var captcha = document.getElementById('my-captcha')
var captchaCheck = document.getElementById('my-captchaHash')
// param for generation & validation
var realCaptchaLength = 5
var doorsMessage = document.getElementById('doors_ret_message')
var doorsIconMessage = document.getElementById('doors_ret_icon_msg')
var doorsIcon = document.getElementById('doors_ret_icon')
// validate as we go to even get the submitButton
var passStatus = false
var emailStatus = false
var captchaStatus = false
/* --------------- doors ajax cors function ----------------
* @args:
* apiAction: 'register' or 'user' or 'userExists' => route to doors api
* if unknown type, default action is login via doors/api/user
*
* data: 3-uple with mail, pass, name
*
* callback: function that will be called after success AND after error
* with the return couple
*
* returns couple (id, message)
* ----------------------------
* ajax success <=> doorsId should be != null except if unknown error
* ajax user infos == doorsMsg
*
* EXPECTED DOORS ANSWER FORMAT
* -----------------------------
* {
* "status": "login ok",
* "userInfo": {
* "id": {
* "id": "78407900-6f48-44b8-ab37-503901f85458"
* },
* "password": "68d23eab21abab38542184e8fca2199d",
* "name": "JPP",
* "hashAlgorithm": "PBKDF2",
* "hashParameters": {"iterations": 1000, "keyLength": 128}
* }
* }
*/
function callDoors(apiAction, data, callback) {
// console.warn("=====> CORS <=====")
// console.log("data",data)
// console.log("apiAction",apiAction)
var doorsUid = null
var doorsMsg = null
// all mandatory params for doors
var mailStr = data[0]
var passStr = data[1]
var nameStr = data[2]
// test params and set defaults
if (typeof apiAction == 'undefined'
|| (apiAction != 'register' && apiAction != 'userExists')) {
// currently forces login action unless we got 'register' or userExists
apiAction = 'user'
console.warn('DBG: forcing user route')
// cmxClt module augmentation
cmxClt = (function(ccModule) {
// common vars to authenticating/registering in user area
ccModule.uauth = {}
var bidule = "trux"
ccModule.uauth.emailIdSupposedToExist = null
ccModule.uauth.uidInput = document.getElementById('doors_uid')
ccModule.uauth.email = document.getElementById('email')
ccModule.uauth.emailLbl = document.querySelector('label[for=email]')
// str of the form: doors_hostname:doors_port
ccModule.uauth.doorsConnectParam = document.getElementById('doors_connect').value
// captchaHash should be appended by itself if normal submit,
// but we may need to do it ourselves (TODO test)
ccModule.uauth.captcha = document.getElementById('my-captcha')
ccModule.uauth.captchaCheck = document.getElementById('my-captchaHash')
// param for generation & validation
ccModule.uauth.realCaptchaLength = 5
// initialize pseudo captcha
$('#my-captcha').realperson({length: ccModule.uauth.realCaptchaLength});
// doors-related html elements
ccModule.uauth.doorsMessage = document.getElementById('doors_ret_message')
ccModule.uauth.doorsIconMessage = document.getElementById('doors_ret_icon_msg')
ccModule.uauth.doorsIcon = document.getElementById('doors_ret_icon')
// cmxClt.u.auth validators (needed to even get the submitButton)
ccModule.uauth.passStatus = false
ccModule.uauth.emailStatus = false
ccModule.uauth.captchaStatus = false
ccModule.uauth.lastEmailValueCheckedDisplayed = null
ccModule.uauth.earlyValidate = function() {
// will update the ccModule.uauth.emailStatus boolean
ccModule.uauth.testMailFormatAndExistence(ccModule.uauth.email.value, ccModule.uauth.emailIdSupposedToExist)
ccModule.uauth.captchaStatus = (ccModule.uauth.captcha.value.length == ccModule.uauth.realCaptchaLength)
}
// email validation and side-effects
// =================================
// NB for login, use --------> expectExists = true
// for registration, use -> expectExists = false
// no return value, but side effect on icon + msg + emailStatus
// wrong format ===========================> grey
// format ok, doorsStatus != expectExists => red
// format ok, doorsStatus == expectExists => green
ccModule.uauth.testMailFormatAndExistence = function (emailValue, expectExists) {
if (ccModule.uauth.email.value != ccModule.uauth.lastEmailValueCheckedDisplayed) {
// tests if email is well-formed
// TODO: better extension and allowed chars set
var emailFormatOk = /^[-A-z0-9_=.+]+@[-A-z0-9_=.+]+\.[-A-z0-9_=.+]{1,4}$/.test(emailValue)
if (! emailFormatOk) {
// restore original lack of message
ccModule.uauth.doorsMessage.title = 'The email will be checked in our DB after you finish typing'
ccModule.uauth.doorsIcon.classList.remove('glyphicon-remove')
ccModule.uauth.doorsIcon.classList.remove('glyphicon-ok')
ccModule.uauth.doorsIcon.classList.add('glyphicon-question-sign')
ccModule.uauth.doorsIcon.style.color = ccModule.colorGrey
ccModule.uauth.doorsMessage.innerHTML = ""
ccModule.uauth.emailLbl.style.color = ""
// module-wide flag
ccModule.uauth.emailStatus = false
}
else {
// additional ajax to check login availability
// => updates the emailStatus global boolean
// => displays an icon
// NB using route in doors api/userExists
// case true => Ok("""{"status":"login exists"}""")
// case false => Ok("""{"status":"login available"}""")
// /!\ async
ccModule.uauth.callDoors(
"userExists",
[emailValue],
function(doorsResp) {
var doorsUid = doorsResp[0]
var doorsMsg = doorsResp[1]
// the global status can be true iff login is as expected and format ok
if (expectExists) {
ccModule.uauth.emailStatus = (doorsMsg == "login exists")
}
else {
ccModule.uauth.emailStatus = (doorsMsg == "login available")
}
if (ccModule.uauth.emailStatus) {
// icon
ccModule.uauth.doorsIconMessage.title = "OK: "+doorsMsg+" on Doors"
ccModule.uauth.doorsIcon.style.color = ccModule.colorGreen
ccModule.uauth.doorsIcon.classList.remove('glyphicon-remove')
ccModule.uauth.doorsIcon.classList.remove('glyphicon-question-sign')
ccModule.uauth.doorsIcon.classList.add('glyphicon-ok')
// message in legend
ccModule.uauth.doorsMessage.innerHTML = "OK: "+doorsMsg+" on Doors"
ccModule.uauth.doorsMessage.style.color = ccModule.colorGreen
// label
ccModule.uauth.emailLbl.style.color = ccModule.colorGreen
}
else {
var errMsg = expectExists ? "your ID isn't recognized" : "this ID is already taken"
// icon
ccModule.uauth.doorsIconMessage.title = "Sorry "+errMsg+" on Doors!"
ccModule.uauth.doorsIcon.style.color = ccModule.colorRed
ccModule.uauth.doorsIcon.classList.remove('glyphicon-ok')
ccModule.uauth.doorsIcon.classList.remove('glyphicon-question-sign')
ccModule.uauth.doorsIcon.classList.add('glyphicon-remove')
// message in legend
ccModule.uauth.doorsMessage.innerHTML = "Sorry "+errMsg+" on Doors!"
ccModule.uauth.doorsMessage.style.color = ccModule.colorRed
// label
ccModule.uauth.emailLbl.style.backgroundColor = ccModule.colorRed
}
// to debounce further actions in testAsYouGo
// return to neutral is also in testAsYouGo
ccModule.uauth.lastEmailValueCheckedDisplayed = emailValue
}
)
}
}
}
if (typeof callback != 'function') {
callback = function(retval) { return retval }
// -----------------------------------------------------------------------
// pass 1 and pass 2 ~~~> do they match?
// TODO use a most common passwords lists
ccModule.uauth.pass1 = document.getElementById('password')
ccModule.uauth.pass2 = document.getElementById('password2')
ccModule.uauth.passMsg = document.getElementById('password_message')
ccModule.uauth.pass1.onkeyup = ccModule.uauth.checkPassStatus
ccModule.uauth.pass1.onchange = ccModule.uauth.checkPassStatus
if (ccModule.uauth.pass2) {
// could also be attached to form onchange but then called often for nothing
ccModule.uauth.pass2.onkeyup = ccModule.uauth.checkPassStatus
ccModule.uauth.pass2.onchange = ccModule.uauth.checkPassStatus
}
var ok = ((apiAction == 'userExists' && typeof mailStr != 'undefined' && mailStr)
|| (typeof mailStr != 'undefined'
&& typeof mailStr != 'undefined'
&& typeof nameStr != 'undefined'
&& mailStr && passStr)) // assumes mail and pass will nvr be == 0
if (!ok) {
doorsMsg = "Invalid parameters in input data (arg #1)"
console.warn('DEBUG callDoors() internal validation failed before ajax')
ccModule.uauth.checkPassStatus = function () {
// £TODO 2 functions:
// - check pass #X is valid (with arg pass1 or pass2) [for Login + Register]
// - check 2 passes are identical (only for Register)
if (pass1.value || pass2.value) {
var pass1v = pass1.value
var pass2v = pass2.value
if ((pass1v && pass1v.length > 7)
|| (pass2v && pass2v.length > 7)) {
// test values
if (pass1v == pass2v) {
if (pass1v.match('[^A-z0-9]')) {
passMsg.innerHTML = 'Ok valid passwords!'
passStatus = true
}
else {
passMsg.innerHTML = 'Passwords match but contain only letters and/or digits, please complexify!'
passStatus = false
}
}
else {
passMsg.innerHTML = "The passwords don't match yet."
passStatus = false
}
}
else {
passMsg.innerHTML = "The password is too short (8 chars min)."
passStatus = false
}
}
if (!passStatus) passMsg.style.color = ccModule.colorRed
else passMsg.style.color = ccModule.colorGreen
}
else {
$.ajax({
contentType: "application/json",
dataType: 'json',
url: "http://"+doorsConnectParam+"/api/" + apiAction,
data: JSON.stringify({
"login": mailStr,
"password": passStr,
"name": nameStr
}),
type: 'POST',
success: function(data) {
if (typeof data != 'undefined'
&& apiAction == 'userExists') {
// userExists success case: it's all in the message :)
doorsUid = null
doorsMsg = data.status
}
else if (typeof data != 'undefined'
&& typeof data.userInfo != undefined
&& typeof data.userInfo.id != undefined
&& typeof data.userInfo.id.id != undefined
&& typeof data.status == 'string') {
// main success case: get the id
doorsUid = data.userInfo.id.id
doorsMsg = data.status
}
else {
doorsMsg = "Unknown response for doors apiAction (" + apiAction +"):"
doorsMsg += '"' + JSON.stringify(data).substring(0,10) + '..."'
}
// start the callback
callback([doorsUid,doorsMsg])
},
error: function(result) {
console.log(result)
if (apiAction == 'user'){
if (result.responseText.match(/"User .+@.+ not found"/)) {
doorsMsg = result.responseText.replace(/^"/g, '').replace(/"$/g, '')
/* --------------- doors ajax cors function ----------------
* @args:
* apiAction: 'register' or 'user' or 'userExists' => route to doors api
* if unknown type, default action is login via doors/api/user
*
* data: 3-uple with mail, pass, name
*
* callback: function that will be called after success AND after error
* with the return couple
*
* returns couple (id, message)
* ----------------------------
* ajax success <=> doorsId should be != null except if unknown error
* ajax user infos == doorsMsg
*
* EXPECTED DOORS ANSWER FORMAT
* -----------------------------
* {
* "status": "login ok",
* "userInfo": {
* "id": {
* "id": "78407900-6f48-44b8-ab37-503901f85458"
* },
* "password": "68d23eab21abab38542184e8fca2199d",
* "name": "JPP",
* "hashAlgorithm": "PBKDF2",
* "hashParameters": {"iterations": 1000, "keyLength": 128}
* }
* }
*/
ccModule.uauth.callDoors = function(apiAction, data, callback) {
// console.warn("=====> CORS <=====")
// console.log("data",data)
// console.log("apiAction",apiAction)
var doorsUid = null
var doorsMsg = null
// all mandatory params for doors
var mailStr = data[0]
var passStr = data[1]
var nameStr = data[2]
// test params and set defaults
if (typeof apiAction == 'undefined'
|| (apiAction != 'register' && apiAction != 'userExists')) {
// currently forces login action unless we got 'register' or userExists
apiAction = 'user'
console.warn('DBG: forcing user route')
}
if (typeof callback != 'function') {
callback = function(retval) { return retval }
}
var ok = ((apiAction == 'userExists' && typeof mailStr != 'undefined' && mailStr)
|| (typeof mailStr != 'undefined'
&& typeof mailStr != 'undefined'
&& typeof nameStr != 'undefined'
&& mailStr && passStr)) // assumes mail and pass will nvr be == 0
if (!ok) {
doorsMsg = "Invalid parameters in input data (arg #1)"
console.warn('DEBUG callDoors() internal validation failed before ajax')
}
else {
$.ajax({
contentType: "application/json",
dataType: 'json',
url: "http://"+ccModule.uauth.doorsConnectParam+"/api/" + apiAction,
data: JSON.stringify({
"login": mailStr,
"password": passStr,
"name": nameStr
}),
type: 'POST',
success: function(data) {
if (typeof data != 'undefined'
&& apiAction == 'userExists') {
// userExists success case: it's all in the message :)
doorsUid = null
doorsMsg = data.status
}
else if (typeof data != 'undefined'
&& typeof data.userInfo != undefined
&& typeof data.userInfo.id != undefined
&& typeof data.userInfo.id.id != undefined
&& typeof data.status == 'string') {
// main success case: get the id
doorsUid = data.userInfo.id.id
doorsMsg = data.status
}
else {
// POSS: user message
console.warn("Unhandled error doors login (" + result.responseText +")")
doorsMsg = "Unknown response for doors apiAction (" + apiAction +"):"
doorsMsg += '"' + JSON.stringify(data).substring(0,10) + '..."'
}
// start the callback
callback([doorsUid,doorsMsg])
},
error: function(result) {
console.log(result)
if (apiAction == 'user'){
if (result.responseText.match(/"User .+@.+ not found"/)) {
doorsMsg = result.responseText.replace(/^"/g, '').replace(/"$/g, '')
}
else {
// POSS: user message
console.warn("Unhandled error doors login (" + result.responseText +")")
}
}
}
else if (apiAction == 'register'){
if (typeof result.responseJSON != 'undefined'
&& typeof result.responseJSON.status == 'string') {
doorsMsg = result.responseJSON.status
// will be useful in the future (actually doors errs don't have a status message yet)
// if doorsMsg == ''
else if (apiAction == 'register'){
if (typeof result.responseJSON != 'undefined'
&& typeof result.responseJSON.status == 'string') {
doorsMsg = result.responseJSON.status
// will be useful in the future (actually doors errs don't have a status message yet)
// if doorsMsg == ''
}
else {
// POSS: user message
doorsMsg = "Unhandled error doors register (" + result.responseText +")"
console.warn(doorsMsg)
}
}
else {
// POSS: user message
doorsMsg = "Unhandled error doors register (" + result.responseText +")"
console.warn(doorsMsg)
doorsMsg = "Unhandled error from unknown doors apiAction (" + apiAction +")"
console.error(doorsMsg)
}
}
else {
doorsMsg = "Unhandled error from unknown doors apiAction (" + apiAction +")"
console.error(doorsMsg)
}
// start the callback
callback([doorsUid,doorsMsg])
}
});
}
}
// very basic email validation TODO: better extension and allowed chars set :)
// (used in tests "as we go")
function basicEmailValidate (emailValue) {
// tests if email is well-formed
var emailFormatOk = /^[-A-z0-9_=.+]+@[-A-z0-9_=.+]+\.[-A-z0-9_=.+]{1,4}$/.test(emailValue)
if (! emailFormatOk) {
// restore original lack of message
doorsMessage.title = 'The email will be checked in our DB after you type and leave the box.'
doorsIcon.classList.remove('glyphicon-remove')
doorsIcon.classList.remove('glyphicon-ok')
doorsIcon.classList.add('glyphicon-question-sign')
doorsIcon.style.color = colorGrey
emailStatus = false
}
else {
// additional ajax to check login availability
// => updates the emailStatus global boolean
// => displays an icon
testDoorsUserExists(emailValue)
}
}
// pass 1 and pass 2 ~~~> do they match?
// TODO use a most common passwords lists
var pass1 = document.getElementById('password')
var pass2 = document.getElementById('password2')
var passMsg = document.getElementById('password_message')
var passwords = [pass1, pass2]
passwords.forEach ( function(pass) {
// could also be attached to form onchange but then called often for nothing
pass.onkeyup = checkPassStatus
pass.onchange = checkPassStatus
})
function checkPassStatus() {
if (pass1.value || pass2.value) {
var pass1v = pass1.value
var pass2v = pass2.value
if ((pass1v && pass1v.length > 7)
|| (pass2v && pass2v.length > 7)) {
// test values
if (pass1v == pass2v) {
if (pass1v.match('[^A-z0-9]')) {
passMsg.innerHTML = 'Ok valid passwords!'
passStatus = true
}
else {
passMsg.innerHTML = 'Passwords match but contain only letters and/or digits, please complexify!'
passStatus = false
}
}
else {
passMsg.innerHTML = "The passwords don't match yet."
passStatus = false
}
}
else {
passMsg.innerHTML = "The password is too short (8 chars min)."
passStatus = false
// start the callback
callback([doorsUid,doorsMsg])
}
});
}
}
}
if (!passStatus) passMsg.style.color = colorRed
else passMsg.style.color = colorGreen
}
// we return our augmented comex client module
return ccModule
})(cmxClt) ;
// pseudo captcha
$('#my-captcha').realperson({length: realCaptchaLength});
$('#my-captcha').val('')
console.log("user shared auth load OK")
......@@ -19,7 +19,7 @@
<!-- NB our js will be at the end -->
<!-- ## Piwik ## -->
<script type="text/javascript">
<!-- <script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
......@@ -31,7 +31,7 @@
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="//piwik.iscpif.fr/piwik.php?idsite=4" style="border:0;" alt="" /></p></noscript>
<noscript><p><img src="//piwik.iscpif.fr/piwik.php?idsite=4" style="border:0;" alt="" /></p></noscript> -->
<!-- End Piwik Code -->
......
......@@ -36,10 +36,7 @@
<div class="question">
<p class="legend">(It is the same login for all the ISC services.)</p>
<div class="input-group">
<!-- email validation onblur/onchange
is done by basicEmailValidate
and testDoorsUserExists
in comex_reg_form_controllers.js -->
<!-- email validation onblur/onchange is done by cmxClt.uauth in comex_user_shared_auth.js -->
<label for="email" class="smlabel input-group-addon">Email</label>
<input id="email" name="email" maxlength="255"
type="text" class="form-control" placeholder="email">
......@@ -89,7 +86,7 @@
<label for="my-captcha" class="smlabel input-group-addon">Code</label>
<input id="my-captcha" name="my-captcha" style="max-width:60%"
type="text" class="form-control input-lg" placeholder="Enter the 5 letters you see beside =>"
onblur="makeBold(this)" onfocus="makeNormal(this)">
onblur="cmxClt.makeBold(this)" onfocus="cmxClt.makeNormal(this)">
</div>
<!-- == S U B M I T == -->
......@@ -106,13 +103,10 @@
<!-- FOR DEBUG: test go-between with Doors -->
<p>
<button type=button onclick='callDoors("user", [email.value, pass1.value, initialsInput.value], console.warn)'>
<button type=button onclick='cmxClt.uauth.callDoors("user", [cmxClt.uauth.email.value, cmxClt.uauth.pass1.value, null], console.warn)'>
test doors login
</button>
<button type=button onclick='callDoors("register", [email.value, pass1.value, initialsInput.value], console.warn)'>
test doors register
</button>
<button type=button onclick='callDoors("userExists", [email.value, null, null], console.warn)'>
<button type=button onclick='cmxClt.uauth.callDoors("userExists", [cmxClt.uauth.email.value, null, null], console.warn)'>
test doors userExists
</button>
</p>
......@@ -128,5 +122,5 @@
<!-- our js -->
<script src="{{ url_for('static', filename='js/comex_user_shared.js') }}"></script>
<script src="{{ url_for('static', filename='js/comex_user_shared_auth.js') }}"></script>
<script src="{{ url_for('static', filename='js/comex_user_login_controllers.js') }}"></script>
<script src="{{ url_for('static', filename='js/comex_page_login_controllers.js') }}"></script>
{% endblock %}
......@@ -13,9 +13,22 @@
<div class="spacer col-sm-1 col-md-1">&nbsp;</div>
<div class="my_form_box col-sm-8 col-md-8">
<!-- INTRODUCTION TEXT -->
<!-- ##################### ( PROFILE OVERVIEW ) #################### -->
<div id="intro">
<h2 class="oldstyle">Profile</h2>
<h2 class="oldstyle">Your Profile Info</h2>
<p class="mini-hero">
</p>
</div>
<!-- FORM COMPLETING INTRO TEXT -->
<div id="intro">
<h2 class="oldstyle">Complete your profile</h2>
<p class="mini-hero">
Take the time to complete your <strong>Community Explorer</strong> profile to generate better maps of your own socio-semantic network .
<br/>
......@@ -27,7 +40,6 @@
</p>
</div>
<!-- ########################### ( FORM ) ########################## -->
<form id="comex_profil_form" enctype="multipart/form-data"
method="post" onsubmit="console.info('submitted')">
......@@ -94,10 +106,7 @@
<div class="question">
<p class="legend">Your email will also be your login for the ISC services.</p>
<div class="input-group">
<!-- email validation onblur/onchange
is done by basicEmailValidate
and testDoorsUserExists
in comex_reg_form_controllers.js -->
<!-- email validation onblur/onchange is done by cmxClt.uauth in comex_user_shared_auth.js -->
<label for="email" class="smlabel input-group-addon">* Email</label>
<input id="email" name="email" maxlength="255"
type="text" class="form-control" placeholder="email">
......@@ -375,5 +384,5 @@
{% block last_imports %}
<!-- our js -->
<script src="{{ url_for('static', filename='js/comex_user_shared.js') }}"></script>
<script src="{{ url_for('static', filename='js/comex_profile_form_controllers.js') }}"></script>
<script src="{{ url_for('static', filename='js/comex_page_profile_controllers.js') }}"></script>
{% endblock %}
......@@ -57,7 +57,7 @@
</label>
<input id="first_name" name="first_name" maxlength="30"
type="text" class="form-control" placeholder="prénom"
onblur="makeBold(this)" onfocus="makeNormal(this)">
onblur="cmxClt.makeBold(this)" onfocus="cmxClt.makeNormal(this)">
</div>
<!-- optionnel -->
......@@ -67,7 +67,7 @@
</label>
<input id="middle_name" name="middle_name" maxlength="30"
type="text" class="form-control" placeholder="autres prénoms"
onblur="makeBold(this)" onfocus="makeNormal(this)">
onblur="cmxClt.makeBold(this)" onfocus="cmxClt.makeNormal(this)">
</div>
<div class="question input-group">
......@@ -76,7 +76,7 @@
</label>
<input id="last_name" name="last_name" maxlength="30"
type="text" class="form-control" placeholder="nom de famille"
onblur="makeBold(this)" onfocus="makeNormal(this)">
onblur="cmxClt.makeBold(this)" onfocus="cmxClt.makeNormal(this)">
</div>
<button class="btn btn-xs btn-default operation"
......@@ -108,10 +108,7 @@
<div class="question">
<p class="legend">Your email will also be your login for the ISC services.</p>
<div class="input-group">
<!-- email validation onblur/onchange
is done by basicEmailValidate
and testDoorsUserExists
in comex_reg_form_controllers.js -->
<!-- email validation onblur/onchange is done by cmxClt.uauth in comex_user_shared_auth.js -->
<label for="email" class="smlabel input-group-addon">* Email</label>
<input id="email" name="email" maxlength="255"
type="text" class="form-control" placeholder="email">
......@@ -153,14 +150,14 @@
<label for="hon_title" class="smlabel input-group-addon"> Title </label>
<input id="hon_title" name="hon_title" maxlength="30"
type="text" class="form-control autocomp" placeholder="titre"
onblur="makeBold(this)" onfocus="makeNormal(this)">
onblur="cmxClt.makeBold(this)" onfocus="cmxClt.makeNormal(this)">
</div>
<div class="question input-group">
<label for="position" class="smlabel input-group-addon">* Job Position</label>
<input id="position" name="position" maxlength="30"
type="text" class="form-control autocomp" placeholder="titre"
onblur="makeBold(this)" onfocus="makeNormal(this)">
onblur="cmxClt.makeBold(this)" onfocus="cmxClt.makeNormal(this)">
</div>
<div class="question">
......@@ -298,7 +295,7 @@
<textarea id="interests_text" name="interests_text" maxlength="1200"
rows="7" style="resize:none"
class="form-control" placeholder="If you wish, you may describe here your personal interests."
onblur="makeBold(this)" onfocus="makeNormal(this)"
onblur="cmxClt.makeBold(this)" onfocus="cmxClt.makeNormal(this)"
></textarea>
</div>
<p class="legend">Optional, ~15 lines max (1200 chars)</p>
......@@ -398,7 +395,7 @@
<label for="my-captcha" class="smlabel input-group-addon">Code</label>
<input id="my-captcha" name="my-captcha" style="max-width:60%"
type="text" class="form-control input-lg" placeholder="Enter the 5 letters you see beside =>"
onblur="makeBold(this)" onfocus="makeNormal(this)">
onblur="cmxClt.makeBold(this)" onfocus="cmxClt.makeNormal(this)">
</div>
<!-- == S U B M I T == -->
......@@ -416,13 +413,13 @@
<!-- FOR DEBUG: test go-between with Doors -->
<!-- <p>
<button type=button onclick='callDoors("user", [email.value, pass1.value, initialsInput.value], console.warn)'>
<button type=button onclick='cmxClt.uauth.callDoors("user", [cmxClt.uauth.email.value, cmxClt.uauth.pass1.value, initialsInput.value], console.warn)'>
test doors login
</button>
<button type=button onclick='callDoors("register", [email.value, pass1.value, initialsInput.value], console.warn)'>
<button type=button onclick='cmxClt.uauth.callDoors("register", [cmxClt.uauth.email.value, cmxClt.uauth.pass1.value, initialsInput.value], console.warn)'>
test doors register
</button>
<button type=button onclick='callDoors("userExists", [email.value, null, null], console.warn)'>
<button type=button onclick='cmxClt.uauth.callDoors("userExists", [cmxClt.uauth.email.value, null, null], console.warn)'>
test doors userExists
</button>
</p> -->
......@@ -439,5 +436,5 @@
<!-- our js -->
<script src="{{ url_for('static', filename='js/comex_user_shared.js') }}"></script>
<script src="{{ url_for('static', filename='js/comex_user_shared_auth.js') }}"></script>
<script src="{{ url_for('static', filename='js/comex_user_reg_controllers.js') }}"></script>
<script src="{{ url_for('static', filename='js/comex_page_reg_controllers.js') }}"></script>
{% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment