Commit 1b0fc6f9 authored by Romain Loth's avatar Romain Loth

finish fundamental login and profile scenarios

parent 008c9ab5
...@@ -326,11 +326,14 @@ def get_full_scholar(uid): ...@@ -326,11 +326,14 @@ def get_full_scholar(uid):
return urow_dict return urow_dict
def save_scholar(uid, date, safe_recs, reg_db, uactive = True): def save_scholar(uid, date, safe_recs, reg_db, uactive=True, update_flag=False):
""" """
Useful for new registration: For new registration:
-> add to *scholars* table -> add to *scholars* table
For profile change (just toggle update_flag to True)
-> *update* scholars table
see also COLS variable and doc/table_specifications.md see also COLS variable and doc/table_specifications.md
""" """
...@@ -346,7 +349,7 @@ def save_scholar(uid, date, safe_recs, reg_db, uactive = True): ...@@ -346,7 +349,7 @@ def save_scholar(uid, date, safe_recs, reg_db, uactive = True):
# => But currently bug in MySQLdb for binary values) # => But currently bug in MySQLdb for binary values)
# (see also MySQLdb.converters) # (see also MySQLdb.converters)
# => So for now we buid the values string ourselves in db_qstrvals instead # => So for now we build the values string ourselves in db_qstrvals instead
# ------------- ----------- # ------------- -----------
# and then we execute(full_statmt) :-) # and then we execute(full_statmt) :-)
...@@ -377,19 +380,33 @@ def save_scholar(uid, date, safe_recs, reg_db, uactive = True): ...@@ -377,19 +380,33 @@ def save_scholar(uid, date, safe_recs, reg_db, uactive = True):
db_tgtcols.append('record_status') db_tgtcols.append('record_status')
db_qstrvals.append('"active"') db_qstrvals.append('"active"')
reg_db_c = reg_db.cursor()
if not update_flag:
# expected colnames "(doors_uid, last_modified_date, email, ...)" # expected colnames "(doors_uid, last_modified_date, email, ...)"
db_tgtcols_str = ','.join(db_tgtcols) db_tgtcols_str = ','.join(db_tgtcols)
# fields converted to sql syntax # fields converted to sql syntax
db_vals_str = ','.join(db_qstrvals) db_vals_str = ','.join(db_qstrvals)
reg_db_c = reg_db.cursor() # INSERT: full_statement with formated values
# full_statement with formated values
full_statmt = 'INSERT INTO scholars (%s) VALUES (%s)' % ( full_statmt = 'INSERT INTO scholars (%s) VALUES (%s)' % (
db_tgtcols_str, db_tgtcols_str,
db_vals_str db_vals_str
) )
else:
# we won't change the ID now
db_tgtcols.pop(0)
db_qstrvals.pop(0)
set_full_str = ','.join([db_tgtcols[i] + '=' + db_qstrvals[i] for i in range(len(db_tgtcols))])
# UPDATE: full_statement with formated values
full_statmt = 'UPDATE scholars SET %s WHERE doors_uid = "%s"' % (
set_full_str,
uid
)
print(full_statmt)
reg_db_c.execute(full_statmt) reg_db_c.execute(full_statmt)
reg_db.commit() reg_db.commit()
...@@ -407,6 +424,16 @@ def save_pairs_sch_kw(pairings_list, comex_db): ...@@ -407,6 +424,16 @@ def save_pairs_sch_kw(pairings_list, comex_db):
mlog("DEBUG", "Keywords: saved %s pair" % str(id_pair)) mlog("DEBUG", "Keywords: saved %s pair" % str(id_pair))
def delete_pairs_sch_kw(uid, comex_db):
"""
Simply deletes all pairings (uid, *) in the table
"""
db_cursor = comex_db.cursor()
n = db_cursor.execute('DELETE FROM sch_kw WHERE uid = "%s"' % uid)
comex_db.commit()
mlog("DEBUG", "Keywords: DELETED %i pairings for %s" % (n, str(uid)))
def get_or_create_keywords(kw_list, comex_db): def get_or_create_keywords(kw_list, comex_db):
""" """
kw_str -> lookup/add to *keywords* table -> kw_id kw_str -> lookup/add to *keywords* table -> kw_id
......
...@@ -38,7 +38,7 @@ if __package__ == 'services': ...@@ -38,7 +38,7 @@ if __package__ == 'services':
from services.user import User, login_manager, doors_login, UCACHE from services.user import User, login_manager, doors_login, UCACHE
from services.text import keywords from services.text import keywords
from services.tools import restparse, mlog, re_hash, REALCONFIG from services.tools import restparse, mlog, re_hash, REALCONFIG
from services.db import connect_db, get_or_create_keywords, save_pairs_sch_kw, get_or_create_affiliation, save_scholar, get_field_aggs from services.db import connect_db, get_or_create_keywords, save_pairs_sch_kw, delete_pairs_sch_kw, get_or_create_affiliation, save_scholar, get_field_aggs
from services.db_to_tina_api.extractDataCustom import MyExtractor as MySQL from services.db_to_tina_api.extractDataCustom import MyExtractor as MySQL
else: else:
# when this script is run directly # when this script is run directly
...@@ -46,7 +46,7 @@ else: ...@@ -46,7 +46,7 @@ else:
from user import User, login_manager, doors_login, UCACHE from user import User, login_manager, doors_login, UCACHE
from text import keywords from text import keywords
from tools import restparse, mlog, re_hash, REALCONFIG from tools import restparse, mlog, re_hash, REALCONFIG
from db import connect_db, get_or_create_keywords, save_pairs_sch_kw, get_or_create_affiliation, save_scholar, get_field_aggs from db import connect_db, get_or_create_keywords, save_pairs_sch_kw, delete_pairs_sch_kw, get_or_create_affiliation, save_scholar, get_field_aggs
from db_to_tina_api.extractDataCustom import MyExtractor as MySQL from db_to_tina_api.extractDataCustom import MyExtractor as MySQL
# ============= read config ============ # ============= read config ============
...@@ -194,8 +194,27 @@ def login(): ...@@ -194,8 +194,27 @@ def login():
doors_connect = config['DOORS_HOST']+':'+config['DOORS_PORT'] doors_connect = config['DOORS_HOST']+':'+config['DOORS_PORT']
) )
elif request.method == 'POST': elif request.method == 'POST':
# TODO check captcha # testing the captcha answer
# TODO sanitize captcha_userinput = request.form['my-captcha']
captcha_userhash = re_hash(captcha_userinput)
captcha_verifhash = int(request.form['my-captchaHash'])
# dbg
mlog("DEBUG", "login captcha verif", str(captcha_verifhash))
mlog("DEBUG", "login captcha user", str(captcha_userhash))
if captcha_userhash != captcha_verifhash:
mlog("WARNING", "pb captcha rejected")
return render_template(
"message.html",
message = """
We're sorry the "captcha" information you entered was wrong!
<br/>
<strong><a href="%s">Retry login here</a></strong>.
""" % url_for('login', _external=True)
)
else:
# OK captcha accepted
email = request.form['email'] email = request.form['email']
pwd = request.form['password'] pwd = request.form['password']
...@@ -203,9 +222,9 @@ def login(): ...@@ -203,9 +222,9 @@ def login():
uid = doors_login(email, pwd, config) uid = doors_login(email, pwd, config)
if uid: if uid:
login_ok = login_user(User(uid)) login_ok = login_user(User(uid))
# TODO check cookie
# login_ok = login_user(User(uid), remember=True) # login_ok = login_user(User(uid), remember=True)
# ------------- # -------------
# creates REMEMBER_COOKIE_NAME # creates REMEMBER_COOKIE_NAME
...@@ -240,7 +259,7 @@ def login(): ...@@ -240,7 +259,7 @@ def login():
# /services/user/profile/ # /services/user/profile/
@app.route(config['PREFIX'] + config['USR_ROUTE'] + '/profile/', methods=['GET']) @app.route(config['PREFIX'] + config['USR_ROUTE'] + '/profile/', methods=['GET', 'POST'])
@fresh_login_required @fresh_login_required
def profile(): def profile():
""" """
...@@ -248,7 +267,7 @@ def profile(): ...@@ -248,7 +267,7 @@ def profile():
@login_required uses flask_login to relay User object current_user @login_required uses flask_login to relay User object current_user
""" """
if request.method == 'GET':
# login provides us current_user # login provides us current_user
if current_user.empty: if current_user.empty:
mlog("INFO", "PROFILE: empty current_user %s" % current_user.uid) mlog("INFO", "PROFILE: empty current_user %s" % current_user.uid)
...@@ -266,10 +285,36 @@ def profile(): ...@@ -266,10 +285,36 @@ def profile():
mlog("DEBUG", "PROFILE view with flag session.new = ", session.new) mlog("DEBUG", "PROFILE view with flag session.new = ", session.new)
return render_template( return render_template(
"profile.html" "profile.html",
# doors info only for link
doors_connect=config['DOORS_HOST']+':'+config['DOORS_PORT']
# NB we also got user info in {{current_user.info}} # NB we also got user info in {{current_user.info}}
# and {{current_user.json_info}} # and {{current_user.json_info}}
) )
elif request.method == 'POST':
try:
save_form(
request.form,
request.files if hasattr(request, "files") else {},
update_flag = True
)
except Exception as perr:
return render_template("thank_you.html",
form_accepted = False,
backend_error = True,
message = ("ERROR ("+str(perr.__doc__)+"):<br/>"
+ ("<br/>".join(format_tb(perr.__traceback__)+[repr(perr)]))
)
)
return render_template("thank_you.html",
debug_records = (clean_records if app.config['DEBUG'] else {}),
form_accepted = True,
backend_error = False,
message = "")
# /services/user/register/ # /services/user/register/
...@@ -305,22 +350,48 @@ def register(): ...@@ -305,22 +350,48 @@ def register():
mlog("INFO", "ok form accepted") mlog("INFO", "ok form accepted")
form_accepted = True form_accepted = True
try:
clean_records = save_form(
request.form,
request.files if hasattr(request, "files") else {}
)
except Exception as perr:
return render_template("thank_you.html",
form_accepted = False,
backend_error = True,
message = ("ERROR ("+str(perr.__doc__)+"):<br/>"
+ ("<br/>".join(format_tb(perr.__traceback__)+[repr(perr)]))
)
)
return render_template("thank_you.html",
debug_records = (clean_records if app.config['DEBUG'] else {}),
form_accepted = True,
backend_error = False,
message = "")
########### SUBS ###########
def save_form(request_form, request_files, update_flag=False):
"""
wrapper function for save profile/register form actions
"""
# only safe values # only safe values
clean_records = {} clean_records = {}
kw_array = [] kw_array = []
# 1) handles all the inputs from form, no matter what target table # 1) handles all the inputs from form, no matter what target table
(duuid, rdate, kw_array, clean_records) = read_record(request.form) (duuid, rdate, kw_array, clean_records) = read_record(request_form)
# 2) handles the pic_file if present # 2) handles the pic_file if present
if hasattr(request, "files") and 'pic_file' in request.files: if 'pic_file' in request_files:
# type: werkzeug.datastructures.FileStorage.stream # type: werkzeug.datastructures.FileStorage.stream
pic_blob = request.files['pic_file'].stream.read() pic_blob = request_files['pic_file'].stream.read()
if len(pic_blob) != 0: if len(pic_blob) != 0:
clean_records['pic_file'] = pic_blob clean_records['pic_file'] = pic_blob
# 3) save to DB # 3) save to DB
try:
# A) a new DB connection # A) a new DB connection
reg_db = connect_db(config) reg_db = connect_db(config)
...@@ -330,12 +401,16 @@ def register(): ...@@ -330,12 +401,16 @@ def register():
# C) create record into the primary user table # C) create record into the primary user table
# --------------------------------------------- # ---------------------------------------------
# TODO class User method !! # TODO class User method !!
save_scholar(duuid, rdate, clean_records, reg_db) save_scholar(duuid, rdate, clean_records, reg_db, update_flag=update_flag)
# D) read/fill each keyword and save the (uid <=> kwid) pairings # D) read/fill each keyword and save the (uid <=> kwid) pairings
kwids = get_or_create_keywords(kw_array, reg_db) kwids = get_or_create_keywords(kw_array, reg_db)
# TODO class User method !! # TODO class User method !!
# POSS selective delete ?
if update_flag:
delete_pairs_sch_kw(duuid, reg_db)
save_pairs_sch_kw([(duuid, kwid) for kwid in kwids], reg_db) save_pairs_sch_kw([(duuid, kwid) for kwid in kwids], reg_db)
# clear cache concerning this scholar # clear cache concerning this scholar
...@@ -345,24 +420,8 @@ def register(): ...@@ -345,24 +420,8 @@ def register():
# E) end connection # E) end connection
reg_db.close() reg_db.close()
except Exception as perr: return clean_records
return render_template("thank_you.html",
debug_records = clean_records,
form_accepted = False,
backend_error = True,
message = ("ERROR ("+str(perr.__doc__)+"):<br/>"
+ ("<br/>".join(format_tb(perr.__traceback__)+[repr(perr)]))
)
)
return render_template("thank_you.html",
debug_records = (clean_records if app.config['DEBUG'] else {}),
form_accepted = True,
backend_error = False,
message = "")
########### SUBS ###########
def read_record(incoming_data): def read_record(incoming_data):
""" """
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
.red { color:#910 ; } .red { color:#910 ; }
.green { color:#161 ; } .green { color:#161 ; }
.grey { color:#554 ; } .grey { color:#554 ; }
.orange { color:#F96 ; }
/* not used at present but could be useful for autompleted inputs */ /* not used at present but could be useful for autompleted inputs */
.autocomp { .autocomp {
...@@ -46,6 +47,11 @@ ...@@ -46,6 +47,11 @@
display: none; display: none;
} }
input.readonly {
font-weight: bold;
background-color: #CCC !important;
}
#cnil_warning { #cnil_warning {
/*text-align: center;*/ /*text-align: center;*/
} }
...@@ -143,10 +149,15 @@ h3.formcatfirst { ...@@ -143,10 +149,15 @@ h3.formcatfirst {
/* the main validation message (a special legend) */ /* the main validation message (a special legend) */
#main_validation_message { #main_message {
font-size: 200%; color: white ;
font-size: 150%;
text-align:center; text-align:center;
/*color: #554 ;*/
background-color: #988 ;
border-radius: 2em;
padding: 1em 3em;
margin-bottom: 2em;
} }
...@@ -154,6 +165,8 @@ ul.minilabels { ...@@ -154,6 +165,8 @@ ul.minilabels {
padding-top: .5em; padding-top: .5em;
list-style-type: none; list-style-type: none;
font-size: 75% ; font-size: 75% ;
text-align: left;
margin-left: 32%;
} }
li.minilabel { li.minilabel {
......
...@@ -14,22 +14,37 @@ ...@@ -14,22 +14,37 @@
*/ */
// initialize form controllers // initialize form controllers
cmxClt.uform.initialize("comex_profile_form", completionAsYouGo) cmxClt.uform.initialize("comex_profile_form", completionAsYouGo)
var isProfileComplete = false // main validation function
var pleaseCompleteMessage = document.selectById("please_complete") // ------------------------
function completionAsYouGo() {
cmxClt.uform.mainMessage.style.display = 'block'
cmxClt.uform.mainMessage.innerHTML = "Checking the answers..."
var missingColumns = [] var diagnostic = cmxClt.uform.testFillField(cmxClt.uform.theForm,
{'fixResidue': true})
function completionAsYouGo() { var valid = diagnostic[0]
var valid = true var mandatoryMissingFields = diagnostic[1]
var mandatoryMissingFields = [] var optionalMissingFields = diagnostic[2]
var optionalMissingFields = []
if (valid) {
[ valid, cmxClt.uform.mainMessage.innerHTML = "<span class='green glyphicon glyphicon-check' style='float:left;'></span>&nbsp;&nbsp;OK we have all the important fields!<br/>"
mandatoryMissingFields, }
optionalMissingFields else {
] = cmxClt.uform.testFillField(cmxClt.uform.theForm) cmxClt.uform.mainMessage.innerHTML = "<span class='red glyphicon glyphicon-warning-sign'></span>&nbsp;&nbsp;Sorry, there are some important missing fields<br/>"
}
// list of missing fields
cmxClt.uform.mainMessage.innerHTML += cmxClt.ulListFromLabelsArray(mandatoryMissingFields, ['red']) + cmxClt.ulListFromLabelsArray(optionalMissingFields, ['white'], "You may also want to fill:")
} }
// run first check on existing profile data pre-filled by the template
completionAsYouGo()
console.log("profile controllers load OK")
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
* + prepares DB save into cmxClt.COLS * + prepares DB save into cmxClt.COLS
* *
* @todo * @todo
* - harmonize var names (eg 'cmxClt.uauth.email' vs 'initialsInput' are both input elts)
* - package.json * - package.json
* *
* @version 1 * @version 1
...@@ -18,27 +17,26 @@ ...@@ -18,27 +17,26 @@
*/ */
// initialize form controllers // initialize form controllers
cmxClt.uform.initialize("comex_reg_form", testAsYouGo) // our form is now in cmxClt.uform.theForm cmxClt.uform.initialize("comex_reg_form", testAsYouGo)
// our form is now in cmxClt.uform.theForm
// initialize auth with doors // initialize auth with doors
cmxClt.uauth.emailIdSupposedToExist = false cmxClt.uauth.emailIdSupposedToExist = false
var jobLookingDateStatus = false
// done when anything in the form changes // done when anything in the form changes
function testAsYouGo() { function testAsYouGo() {
// console.log("testAsYouGo Go") // console.log("testAsYouGo Go")
cmxClt.uauth.earlyValidate() cmxClt.uauth.earlyValidate()
checkJobDateStatus() // TODO add uform.testFillField (start checking after 3-4 filled fields)
cmxClt.uform.checkJobDateStatus()
if (cmxClt.uauth.passStatus if (cmxClt.uauth.passStatus
&& cmxClt.uauth.emailStatus && cmxClt.uauth.emailStatus
&& cmxClt.uauth.captchaStatus && cmxClt.uauth.captchaStatus
&& jobLookingDateStatus) { && cmxClt.uform.jobLookingDateStatus) {
cmxClt.uform.submitButton.disabled = false cmxClt.uform.submitButton.disabled = false
} }
else { else {
...@@ -50,14 +48,13 @@ function testAsYouGo() { ...@@ -50,14 +48,13 @@ function testAsYouGo() {
var regTimestamp = document.getElementById('last_modified_date') var regTimestamp = document.getElementById('last_modified_date')
var subPage1Style = document.getElementById('subpage_1').style var subPage1Style = document.getElementById('subpage_1').style
var subPage2Style = document.getElementById('subpage_2').style var subPage2Style = document.getElementById('subpage_2').style
var teamCityDivStyle = document.getElementById('team_city_div').style var teamCityDivStyle = document.getElementById('team_city_div').style
var otherInstDivStyle = document.getElementById('other_org_div').style var otherInstDivStyle = document.getElementById('other_org_div').style
var jobLookingDivStyle = document.getElementById('job_looking_div').style
function registerDoorsAndSubmit(){ function registerDoorsAndSubmit(){
...@@ -68,11 +65,11 @@ function registerDoorsAndSubmit(){ ...@@ -68,11 +65,11 @@ function registerDoorsAndSubmit(){
var passValue = cmxClt.uauth.pass1.value var passValue = cmxClt.uauth.pass1.value
var wholenameValue = "" var wholenameValue = ""
if (mName.value != "") { if (cmxClt.uform.mName.value != "") {
wholenameValue = lName.value + ', ' + fName.value + ' ' + mName.value wholenameValue = cmxClt.uform.lName.value + ', ' + cmxClt.uform.fName.value + ' ' + cmxClt.uform.mName.value
} }
else { else {
wholenameValue = lName.value + ', ' + fName.value wholenameValue = cmxClt.uform.lName.value + ', ' + cmxClt.uform.fName.value
} }
...@@ -127,12 +124,14 @@ function validateAndMsg() { ...@@ -127,12 +124,14 @@ function validateAndMsg() {
cmxClt.uform.mainMessage.style.display = 'block' cmxClt.uform.mainMessage.style.display = 'block'
cmxClt.uform.mainMessage.innerHTML = "Validating the form..." cmxClt.uform.mainMessage.innerHTML = "Validating the form..."
var valid = true // runs field-by-field validation and highlights mandatory missing fields
var missingFields = [] var diagnostic = cmxClt.uform.testFillField(cmxClt.uform.theForm)
[valid, missingFields] = cmxClt.uform.testFillField(cmxClt.uform.theForm)
// +++++++++++++ // +++++++++++++
// RESULTS // RESULTS
var valid = diagnostic[0]
var missingFields = diagnostic[1]
if (valid) { if (valid) {
// adds the captchaCheck inside the form // adds the captchaCheck inside the form
ccModule.uauth.collectCaptcha() ccModule.uauth.collectCaptcha()
...@@ -143,14 +142,11 @@ function validateAndMsg() { ...@@ -143,14 +142,11 @@ function validateAndMsg() {
return true return true
} }
else { else {
console.warn("form is not valid") console.warn("form is not valid")
cmxClt.uform.submitButton.disabled = false cmxClt.uform.submitButton.disabled = false
var errorMessage = ''
// TODO highlight invalid fields
if (missingFields.length) { if (missingFields.length) {
errorMessage += "Please fill the missing fields: " + cmxClt.ulListFromLabelsArray(missingFields, ["red"]) errorMessage = cmxClt.ulListFromLabelsArray(missingFields, ["red"], "Please fill the missing fields: ")
} }
// length is handled by each input's maxlength // length is handled by each input's maxlength
...@@ -162,146 +158,6 @@ function validateAndMsg() { ...@@ -162,146 +158,6 @@ function validateAndMsg() {
} }
var fileInput = document.getElementById('pic_file')
var showPicImg = document.getElementById('show_pic')
var boxShowPicImg = document.getElementById('box_show_pic')
var picMsg = document.getElementById('picture_message')
var imgReader = new FileReader();
function checkShowPic() {
// TEMPORARY initial size already 200 kB, user has to do it himself
var max_size = 204800
// TODO max source image size before resizing
// see libs or stackoverflow.com/a/24015367
// 4 MB
// always reset style and width/height calculations
boxShowPicImg.style.display = 'none'
showPicImg.style.display = ""
showPicImg.style.width = ""
showPicImg.style.height = ""
// var max_size = 4194304
if (fileInput.files) {
var theFile = fileInput.files[0]
// debug
console.log(theFile.name, "size", theFile.size, theFile.lastModifiedDate)
if (theFile.size > max_size) {
// msg pb
picMsg.innerHTML = "The picture is too big (200kB max)!"
picMsg.style.color = cmxClt.colorRed
}
else {
// msg ok
picMsg.innerHTML = "Picture ok"
picMsg.style.color = cmxClt.colorGreen
// to show the pic when readAsDataURL
imgReader.onload = function () {
showPicImg.src = imgReader.result;
// prepare max size while preserving ratio
var imgW = window.getComputedStyle(showPicImg).getPropertyValue("width")
var imgH = window.getComputedStyle(showPicImg).getPropertyValue("height")
console.log("img wid", imgW)
console.log("img hei", imgH)
if (imgW > imgH) {
showPicImg.style.width = "100%"
showPicImg.style.height = "auto"
}
else {
showPicImg.style.width = "auto"
showPicImg.style.height = "100%"
}
// now reaadjust outer box and show
boxShowPicImg.style.display = 'block'
// possible re-adjust outerbox ?
// showPicImg.style.border = "2px dashed " + cmxClient.colorGrey
}
// create fake src url & trigger the onload
imgReader.readAsDataURL(theFile);
}
}
else {
console.warn("skipping testPictureBlob called w/o picture in fileInput")
}
}
// show middlename button binding
var mnBtn = document.getElementById('btn-midname')
mnBtn.onclick= function() {
var mnDiv = document.getElementById('group-midname')
if (mnDiv.style.display == 'none') {
mnDiv.style.display = 'table'
}
else {
mnDiv.style.display = 'none'
}
}
// first, middle & last name ~~~> initials
var fName = document.getElementById('first_name')
var mName = document.getElementById('middle_name')
var lName = document.getElementById('last_name')
var initialsInput = document.getElementById('initials')
var nameInputs = [fName, mName, lName]
nameInputs.forEach ( function(nameInput) {
nameInput.onchange = function () {
var apparentInitials = ""
nameInputs.forEach ( function(nameInput) {
var txt = nameInput.value
if (txt.length) {
if(/[A-Z]/.test(txt)) {
var capsArr = txt.match(/[A-Z]/g)
for (var i in capsArr) {
apparentInitials += capsArr[i]
}
}
else {
apparentInitials += txt.charAt(0)
}
}
}) ;
// update the displayed value
initialsInput.value = apparentInitials
}
})
// jobLookingDateStatus ~~~> is job date a valid date?
var jobBool = document.getElementById('job_bool')
var jobDate = document.getElementById('job_looking_date')
var jobDateMsg = document.getElementById('job_date_message')
jobDate.onkeyup = checkJobDateStatus
jobDate.onchange = checkJobDateStatus
function checkJobDateStatus() {
jobLookingDateStatus = (jobBool.value == "No" || cmxClt.uform.validDate.test(jobDate.value))
if (!jobLookingDateStatus) {
jobDateMsg.style.color = cmxClt.colorRed
jobDateMsg.innerHTML = 'Date is not yet in the valid format YYYY/MM/DD'
}
else {
jobDateMsg.style.color = cmxClt.colorGreen
jobDateMsg.innerHTML = 'Ok valid date!'
}
}
// £TODO move autocomp data to an autocomplete module // £TODO move autocomp data to an autocomplete module
// -> local data for countries, jobtitles // -> local data for countries, jobtitles
// -> use ajax aggs api for the scholars, kws and labs // -> use ajax aggs api for the scholars, kws and labs
...@@ -912,14 +768,14 @@ $(function() { ...@@ -912,14 +768,14 @@ $(function() {
console.log("reg controllers load OK") console.log("reg controllers load OK")
// £DEBUG autofill ----------->8------ // £DEBUG autofill ----------->8------
// fName.value = "Jean" // cmxClt.uform.fName.value = "Jean"
// lName.value = "Tartampion" // cmxClt.uform.lName.value = "Tartampion"
// initialsInput.value="JPP" // document.getElementById('initials').value="JPP"
// document.getElementById('country').value = "France" // document.getElementById('country').value = "France"
// document.getElementById('position').value = "atitle" // document.getElementById('position').value = "atitle"
// document.getElementById('keywords').value = "Blabla" // document.getElementById('keywords').value = "Blabla"
// document.getElementById('org').value = "CNRS" // document.getElementById('org').value = "CNRS"
//
// cmxClt.uauth.email.value= cmxClt.makeRandomString(7)+"@om.fr" // cmxClt.uauth.email.value= cmxClt.makeRandomString(7)+"@om.fr"
// cmxClt.uauth.pass1.value="123456+789" // cmxClt.uauth.pass1.value="123456+789"
// cmxClt.uauth.pass2.value="123456+789" // cmxClt.uauth.pass2.value="123456+789"
......
...@@ -23,42 +23,45 @@ var cmxClt = (function() { ...@@ -23,42 +23,45 @@ var cmxClt = (function() {
ccModule.colorRed = '#910' ccModule.colorRed = '#910'
ccModule.colorGreen = '#161' ccModule.colorGreen = '#161'
ccModule.colorGrey = '#554' ccModule.colorGrey = '#554'
ccModule.colorOrange = '#F96'
// the target columns in DB: tuple (name, mandatoryBool, type)
ccModule.COLS = [ ["doors_uid", true, "auto" ], // the target columns in DB: tuple (name, mandatoryBool, group, type)
["last_modified_date", true, "auto" ], ccModule.COLS = [ ["doors_uid", true, "auto" , "t"],
["email", true, "plsfill"], ["last_modified_date", true, "auto" , "d"],
["country", true, "plsfill"], ["email", true, "plsfill", "t"],
["first_name", true, "plsfill"], ["country", true, "plsfill", "t"],
["middle_name", false, "plsfill"], ["first_name", true, "plsfill", "t"],
["last_name", true, "plsfill"], ["middle_name", false, "pref", "t"],
["initials", true, "plsfill"], ["last_name", true, "plsfill", "t"],
["position", false, "plsfill"], ["initials", true, "plsfill", "t"],
["hon_title", false, "plsfill"], ["position", true, "plsfill", "t"],
["interests_text", false, "plsfill"], ["hon_title", false, "plsfill", "t"],
["community_hashtags", false, "plsfill"], ["interests_text", false, "plsfill", "t"],
["gender", false, "plsfill"], ["community_hashtags", false, "plsfill", "at"],
["job_looking_date", false, "pref" ], ["gender", false, "plsfill", "m"],
["home_url", false, "plsfill"], ["job_looking_date", false, "pref" , "d"],
["pic_url", false, "pref" ], ["home_url", false, "plsfill", "t"],
["pic_file", false, "pref" ], ["pic_url", false, "pref" , "t"],
["pic_file", false, "pref" , "f"],
// ==> *scholars* table // ==> *scholars* table
["keywords", true, "plsfill"], ["keywords", true, "plsfill", "at"],
// ==> *keywords* table // ==> *keywords* table
["org", true, "plsfill"], ["org", true, "plsfill", "t"],
["org_type", true, "plsfill"], ["org_type", true, "plsfill", "m"],
["team_lab", false, "pref" ], ["team_lab", false, "pref" , "t"],
["org_city", false, "pref" ]] ["org_city", false, "pref" , "t"]]
// ==> *affiliations* table // ==> *affiliations* table
// "type" is a complementary information to mandatory // group "auto" === filled by controllers
// -------------------------------------------------- // group "plsfill" === filled by user, ideally needed for a complete profile
// type "auto" === filled by controllers // group "pref" === filled by user but not needed at all
// type "plsfill" === filled by user, ideally needed for a complete profile
// type "pref" === filled by user but not needed at all ccModule.miniSanitize = function(aString) {
return aString.replace(/[^A-z0-9, :\(\)-]/, ' ').replace(/^ +| +$/, '')
}
ccModule.makeRandomString = function (nChars) { ccModule.makeRandomString = function (nChars) {
var rando = "" var rando = ""
...@@ -69,12 +72,17 @@ var cmxClt = (function() { ...@@ -69,12 +72,17 @@ var cmxClt = (function() {
return rando return rando
} }
ccModule.ulListFromLabelsArray = function (strArray, ulClassList) { ccModule.ulListFromLabelsArray = function (cplArray, ulClassList, message) {
ulClasses=["minilabels"].concat(ulClassList).join(" ") ulClasses=["minilabels"].concat(ulClassList).join(" ")
var resultHtml = '<ul class="'+ulClasses+'">' var resultHtml = ""
for (var i in strArray) { if (message) {
var label = strArray[i].replace(/_/, " ") resultHtml = ccModule.miniSanitize(message)
resultHtml += '<li class="minilabel">'+label+'</li>' }
resultHtml += '<ul class="'+ulClasses+'">'
for (var i in cplArray) {
var fname = cplArray[i][0]
var flabel = cplArray[i][1]
resultHtml += '<li class="minilabel">'+flabel+'</li>'
} }
resultHtml += '</ul>' resultHtml += '</ul>'
return resultHtml return resultHtml
...@@ -91,15 +99,29 @@ var cmxClt = (function() { ...@@ -91,15 +99,29 @@ var cmxClt = (function() {
} }
// common vars to user forms // ===============================
// common vars to all user forms
// ===============================
// exposed functions and vars that will be used during the interaction
ccModule.uform = {} ccModule.uform = {}
ccModule.uform.theFormId = null ccModule.uform.theFormId = null
ccModule.uform.theForm = null ccModule.uform.theForm = null
// vars that will be used during the interaction ccModule.uform.initialize
ccModule.uform.submitButton = document.getElementById('formsubmit') ccModule.uform.testFillField
ccModule.uform.mainMessage = document.getElementById('main_validation_message') ccModule.uform.mainMessage = document.getElementById('main_message')
ccModule.uform.submitButton = document.getElementById('form_submit')
// dates up to 2049/12/31
ccModule.uform.validDate = new RegExp( /^20[0-4][0-9]\/(?:0?[1-9]|1[0-2])\/(?:0?[1-9]|[1-2][0-9]|3[0-1])$/)
// function definitions
// =====================
// initialize
// -----------
ccModule.uform.initialize = function(aFormId, aValidationFun) { ccModule.uform.initialize = function(aFormId, aValidationFun) {
ccModule.uform.theFormId = aFormId ccModule.uform.theFormId = aFormId
ccModule.uform.theForm = document.getElementById(aFormId) ccModule.uform.theForm = document.getElementById(aFormId)
...@@ -107,16 +129,14 @@ var cmxClt = (function() { ...@@ -107,16 +129,14 @@ var cmxClt = (function() {
ccModule.uform.theForm.onkeyup = aValidationFun ccModule.uform.theForm.onkeyup = aValidationFun
ccModule.uform.theForm.onchange = aValidationFun ccModule.uform.theForm.onchange = aValidationFun
ccModule.uform.theForm.onblur = aValidationFun ccModule.uform.theForm.onblur = aValidationFun
} }
// dates up to 2049/12/31 // testFillField
ccModule.uform.validDate = new RegExp( /^20[0-4][0-9]\/(?:0?[1-9]|1[0-2])\/(?:0?[1-9]|[1-2][0-9]|3[0-1])$/) // --------------
// checks if mandatory fields are filled // checks if mandatory fields are filled
// checks if other plsfill ones are filled // checks if other plsfill ones are filled
ccModule.uform.testFillField = function (aForm) { // highlights labels of missing mandatory fields
ccModule.uform.testFillField = function (aForm, params) {
// "private" copy // "private" copy
var wholeFormData = new FormData(aForm) var wholeFormData = new FormData(aForm)
...@@ -124,47 +144,80 @@ var cmxClt = (function() { ...@@ -124,47 +144,80 @@ var cmxClt = (function() {
var valid = true var valid = true
var mandatoryMissingFields = [] var mandatoryMissingFields = []
var otherMissingFields = [] var otherMissingFields = []
// var toolongFields = []
// default params
if (!params) params = {}
if (params.doHighlight == undefined) params.doHighlight = true
if (params.fixResidue == undefined) params.fixResidue = false
// let's go // let's go
for (var i in ccModule.COLS) { for (var i in ccModule.COLS) {
// console.warn("checking ccModule.COLS["+i+"]", ccModule.COLS[i]) // console.info("testFillField COLS["+i+"]", ccModule.COLS[i])
var fieldName = ccModule.COLS[i][0] var fieldName = ccModule.COLS[i][0]
var mandatory = ccModule.COLS[i][1] var mandatory = ccModule.COLS[i][1]
var fieldType = ccModule.COLS[i][2] var fieldGroup = ccModule.COLS[i][2]
var fieldType = ccModule.COLS[i][3]
// skip non-plsfill elements // skip non-plsfill elements
if (fieldName != 'plsfill') continue ; if (fieldGroup != 'plsfill') continue ;
var actualValue = wholeFormData.get(fieldName) var actualValue = wholeFormData.get(fieldName)
// get a human-readable label
var labelElt = document.querySelector('label[for='+fieldName+']')
var fieldLabel = labelElt ? labelElt.innerText : fieldName
// alternative null values // alternative null values
if (actualValue == "" || actualValue == "None") { if (actualValue == "") {
actualValue = null
}
// python residue ~~~> can correct on the fly
// POSS better strategy ?
if (params.fixResidue) {
// "None" as a string
if (actualValue == "None") {
actualValue = null actualValue = null
document.getElementById(fieldName).value = ""
}
// arrays of text
if (fieldType == "at" && actualValue
&& actualValue.charAt(0) == '['
&& actualValue.charAt(1) == "'") {
actualValue = actualValue.replace(/[\[\]']/g,'')
document.getElementById(fieldName).value = actualValue
}
} }
// debug // debug
// console.log( // console.log(
// "cmxClt.testEachField: field", fieldName, // "cmxClt.testFillField: field", fieldName,
// "actualValue:", actualValue // "actualValue:", actualValue
// ) // )
// test mandatory ----------------- // test mandatory -----------------
if (mandatory && actualValue == null) { if (mandatory && actualValue == null) {
// todo human-readable fieldName here // todo human-readable fieldName here
mandatoryMissingFields.push(fieldName) mandatoryMissingFields.push([fieldName, fieldLabel])
valid = false valid = false
console.log("mandatoryMissingFields", fieldName) // console.log("mandatoryMissingFields", fieldName)
if (params.doHighlight) {
labelElt.style.backgroundColor = ccModule.colorOrange
}
} }
// test benign -------------------- // test benign
// may be missing but doesn't affect valid // may be missing but doesn't affect valid
else if (actualValue == null) { else if (actualValue == null) {
otherMissingFields.push(fieldName) otherMissingFields.push([fieldName, fieldLabel])
console.log("otherMissingField", fieldName) // console.log("otherMissingField", fieldName)
} }
// -------------------------------- else if (params.doHighlight) {
labelElt.style.backgroundColor = ""
}
} // end for val in ccModule.COLS } // end for val in ccModule.COLS
// return full form diagnostic and field census // return full form diagnostic and field census
...@@ -173,7 +226,188 @@ var cmxClt = (function() { ...@@ -173,7 +226,188 @@ var cmxClt = (function() {
otherMissingFields ] otherMissingFields ]
} }
// ===================================================================
// additional controllers for detailed forms like /register, /profile
// ===================================================================
// exposed functions and vars
ccModule.uform.checkShowPic
ccModule.uform.createInitials
ccModule.uform.checkJobDateStatus
ccModule.uform.fName = document.getElementById('first_name')
ccModule.uform.mName = document.getElementById('middle_name')
ccModule.uform.lName = document.getElementById('last_name')
ccModule.uform.jobLookingDateStatus = false
// function definitions, private vars and event handlers
// ======================================================
// image fileInput ~~~> display image
// ----------------------------------
var fileInput = document.getElementById('pic_file')
var showPicImg = document.getElementById('show_pic')
var boxShowPicImg = document.getElementById('box_show_pic')
var picMsg = document.getElementById('picture_message')
var imgReader = new FileReader();
ccModule.uform.checkShowPic = function (aForm, doHighlight) {
// TEMPORARY initial size already 200 kB, user has to do it himself
var max_size = 204800
// TODO max source image size before resizing
// see libs or stackoverflow.com/a/24015367
// 4 MB
// var max_size = 4194304
// always reset style and width/height calculations
boxShowPicImg.style.display = 'none'
showPicImg.style.display = ""
showPicImg.style.width = ""
showPicImg.style.height = ""
if (fileInput.files) {
var theFile = fileInput.files[0]
// debug
console.log(theFile.name, "size", theFile.size, theFile.lastModifiedDate)
if (theFile.size > max_size) {
// msg pb
picMsg.innerHTML = "The picture is too big (200kB max)!"
picMsg.style.color = cmxClt.colorRed
}
else {
// msg ok
picMsg.innerHTML = "Picture ok"
picMsg.style.color = cmxClt.colorGreen
// to show the pic when readAsDataURL
imgReader.onload = function () {
showPicImg.src = imgReader.result;
// prepare max size while preserving ratio
var realValues = window.getComputedStyle(showPicImg)
var imgW = realValues.getPropertyValue("width")
var imgH = realValues.getPropertyValue("height")
// debug
// console.log("img wid", imgW)
// console.log("img hei", imgH)
if (imgW > imgH) {
showPicImg.style.width = "100%"
showPicImg.style.height = "auto"
}
else {
showPicImg.style.width = "auto"
showPicImg.style.height = "100%"
}
// now show it
boxShowPicImg.style.display = 'block'
// possible re-adjust outerbox ?
}
// create fake src url & trigger the onload
imgReader.readAsDataURL(theFile);
}
}
else {
console.warn("skipping testPictureBlob called w/o picture in fileInput")
}
}
// first, middle & last name ~~~> initials
// ----------------------------------------
var nameInputs = [ccModule.uform.fName,
ccModule.uform.mName,
ccModule.uform.lName]
var initialsInput = document.getElementById('initials')
ccModule.uform.createInitials = function() {
var apparentInitials = ""
nameInputs.forEach ( function(nameInput) {
var txt = nameInput.value
if (txt.length) {
if(/[A-Z]/.test(txt)) {
var capsArr = txt.match(/[A-Z]/g)
for (var i in capsArr) {
apparentInitials += capsArr[i]
}
}
else {
apparentInitials += txt.charAt(0)
}
}
}) ;
// update the displayed value
initialsInput.value = apparentInitials
}
// handlers: names to initials
nameInputs.forEach ( function(nameInput) {
if (nameInput) {
nameInput.onkeyup = ccModule.uform.createInitials
nameInput.onchange = ccModule.uform.createInitials
}
})
// handler: show middlename button
var mnBtn = document.getElementById('btn-midname')
if(mnBtn) {
mnBtn.onclick= function() {
var mnDiv = document.getElementById('group-midname')
if (mnDiv.style.display == 'none') {
mnDiv.style.display = 'table'
}
else {
mnDiv.style.display = 'none'
}
}
}
// jobLookingDateStatus ~~~> is job date a valid date?
// ---------------------------------------------------
var jobBool = document.getElementById('job_bool')
var jobDate = document.getElementById('job_looking_date')
var jobDateMsg = document.getElementById('job_date_message')
var jobLookingDiv = document.getElementById('job_looking_div')
ccModule.uform.checkJobDateStatus = function () {
ccModule.uform.jobLookingDateStatus = (jobBool.value == "No" || ccModule.uform.validDate.test(jobDate.value))
if (!ccModule.uform.jobLookingDateStatus) {
jobDateMsg.style.color = cmxClt.colorRed
jobDateMsg.innerHTML = 'Date is not yet in the valid format YYYY/MM/DD'
}
else {
jobDateMsg.style.color = cmxClt.colorGreen
jobDateMsg.innerHTML = 'Ok valid date!'
}
}
// handler: show jobLookingDiv
if (jobBool && jobDate) {
jobBool.onchange = function() {
if(this.value=='Yes'){
jobLookingDiv.style.display = 'block'
}
else {
jobLookingDiv.style.display='none'
jobDate.value=''
}
}
jobDate.onkeyup = ccModule.uform.checkJobDateStatus
jobDate.onchange = ccModule.uform.checkJobDateStatus
}
// ========= end of advanced form controls ===========
return ccModule return ccModule
}()) ; }()) ;
console.log("shared load OK") console.log("user shared load OK")
...@@ -96,7 +96,7 @@ cmxClt = (function(ccModule) { ...@@ -96,7 +96,7 @@ cmxClt = (function(ccModule) {
// tests if email is well-formed // tests if email is well-formed
// TODO: better extension and allowed chars set // TODO: better extension and allowed chars set
var emailFormatOk = /^[-A-z0-9_=.+]+@[-A-z0-9_=.+]+\.[-A-z0-9_=.+]{1,4}$/.test(emailValue) var emailFormatOk = /^[-A-z0-9_=.+]+@[-A-z0-9_=.+]+\.[-A-z0-9_=.+]{2,4}$/.test(emailValue)
if (! emailFormatOk) { if (! emailFormatOk) {
// restore original lack of message // restore original lack of message
...@@ -149,7 +149,7 @@ cmxClt = (function(ccModule) { ...@@ -149,7 +149,7 @@ cmxClt = (function(ccModule) {
ccModule.uauth.doorsMessage.style.color = ccModule.colorGreen ccModule.uauth.doorsMessage.style.color = ccModule.colorGreen
// label // label
ccModule.uauth.emailLbl.style.color = ccModule.colorGreen ccModule.uauth.emailLbl.style.backgroundColor = ""
} }
else { else {
var errMsg = expectExists ? "your ID isn't recognized" : "this ID is already taken" var errMsg = expectExists ? "your ID isn't recognized" : "this ID is already taken"
...@@ -165,7 +165,7 @@ cmxClt = (function(ccModule) { ...@@ -165,7 +165,7 @@ cmxClt = (function(ccModule) {
ccModule.uauth.doorsMessage.style.color = ccModule.colorRed ccModule.uauth.doorsMessage.style.color = ccModule.colorRed
// label // label
ccModule.uauth.emailLbl.style.backgroundColor = ccModule.colorRed ccModule.uauth.emailLbl.style.backgroundColor = ccModule.colorOrange
} }
// to debounce re-invocations // to debounce re-invocations
......
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
<!-- main validation message --> <!-- main validation message -->
<p id="main_validation_message" class="legend" style="display:none"></p> <p id="main_message" class="legend" style="display:none"></p>
<!--pseudo captcha using realperson from http://keith-wood.name/realPerson.html --> <!--pseudo captcha using realperson from http://keith-wood.name/realPerson.html -->
...@@ -93,7 +93,7 @@ ...@@ -93,7 +93,7 @@
<!-- normal submit button <!-- normal submit button
(login to doors will happen b/w servers: no need to do it by ajax) --> (login to doors will happen b/w servers: no need to do it by ajax) -->
<button class="btn btn-lg btn-success" style="float:right" <button class="btn btn-lg btn-success" style="float:right"
id="formsubmit" disabled> id="form_submit" disabled>
LOGIN LOGIN
</button> </button>
......
...@@ -18,27 +18,15 @@ ...@@ -18,27 +18,15 @@
<div id="intro"> <div id="intro">
<h2 class="oldstyle">Your Profile Info</h2> <h2 class="oldstyle">Your Profile Info</h2>
<p class="mini-hero"> <p class="mini-hero">
{% if current_user.is_authenticated %} Welcome to your profile page,
Welcome to your <strong>Community explorer</strong> profile, <strong>
{% if current_user.info.hon_title is not none %} {% if current_user.info.hon_title is not none %}
{{ current_user.info.hon_title }} {{ current_user.info.hon_title }}
{% endif %} {% endif %}
{{ current_user.info.last_name }}! {{ current_user.info.last_name }}
{% endif %} </strong> !
</p>
</div>
<!-- FORM COMPLETING INTRO TEXT -->
<div id="intro">
<h2 id="please_complete" class="oldstyle">Please 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/> <br/>
<br/> Take the time to complete it to generate better maps of your socio-semantic network .
The <strong>keywords</strong>, <strong>affiliations</strong> and <strong>hashtags</strong> will all count as similarities to identify network neighbours.
<br/>
<br/>
The <strong>home page (url)</strong>, <strong>picture (url or file)</strong> and <strong>free description</strong> will allow your neighbours to know you a little better.
</p> </p>
</div> </div>
...@@ -48,6 +36,21 @@ ...@@ -48,6 +36,21 @@
<!-- todo onsubmit also save to cache --> <!-- todo onsubmit also save to cache -->
<!-- EMAIL & PASSWORD -->
<h3 class="formcat"> Login infos </h3>
<p class="mini-hero">
This email is your main ID. You may only change it via the <a href="http://{{ doors_connect }}/">Doors portal</a>.
</p>
<!-- readonly version for current profile -->
<div class="question input-group">
<label for="email" class="smlabel input-group-addon">* Email</label>
<input id="email" name="email" maxlength="255" readonly
type="text" class="form-control readonly" placeholder="email"
value="{{ current_user.info.email }}">
</div>
<!-- NAME & COUNTRY --> <!-- NAME & COUNTRY -->
<h3 class="formcatfirst"> Basic infos </h3> <h3 class="formcatfirst"> Basic infos </h3>
...@@ -107,33 +110,13 @@ ...@@ -107,33 +110,13 @@
value="{{ current_user.info.country }}"> value="{{ current_user.info.country }}">
</div> </div>
<!-- EMAIL & PASSWORD --> <!-- JOB, INTERESTS AND ORGANIZATION -->
<h3 class="formcat"> Login infos </h3>
<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 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"
value="{{ current_user.info.email }}">
<!-- doors return value icon -->
<div id="doors_ret_icon_msg" class="input-group-addon"
title="The email will be checked in our DB after you type and leave the box.">
<span id="doors_ret_icon"
class="glyphicon glyphicon-question-sign grey"
></span>
</div>
</div>
<!-- doors return value message -->
<p id="doors_ret_message" class="legend"></p>
</div>
<!-- JOB & INTERESTS -->
<h3 class="formcat"> About your job and research </h3> <h3 class="formcat"> About your job and research </h3>
<p class="mini-hero">
The <strong>keywords</strong> and <strong>affiliation</strong> will count as similarities to identify your network neighbours.
</p>
<div class="question input-group"> <div class="question input-group">
<label for="hon_title" class="smlabel input-group-addon"> Title </label> <label for="hon_title" class="smlabel input-group-addon"> Title </label>
<input id="hon_title" name="hon_title" maxlength="30" <input id="hon_title" name="hon_title" maxlength="30"
...@@ -160,9 +143,6 @@ ...@@ -160,9 +143,6 @@
<p class="legend">Please enter at least 5 comma-separated keywords</p> <p class="legend">Please enter at least 5 comma-separated keywords</p>
</div> </div>
<!-- ORGANIZATION -->
<h3 class="formcat"> About your current organization </h3>
<div class="question"> <div class="question">
<div class="input-group"> <div class="input-group">
<label for="org" class="smlabel input-group-addon">* Parent Institution</label> <label for="org" class="smlabel input-group-addon">* Parent Institution</label>
...@@ -223,6 +203,11 @@ ...@@ -223,6 +203,11 @@
<!-- OTHER PERSONAL INFO --> <!-- OTHER PERSONAL INFO -->
<h3 class="formcatfirst"> Complementary information </h3> <h3 class="formcatfirst"> Complementary information </h3>
<p class="mini-hero">
The <strong>home page (url)</strong>, <strong>picture (url or file)</strong> and <strong>free description</strong> will allow your neighbours to know you a little better.
Also, our <strong>interest groups</strong> are each linked to an ISCPIF mailing list that you can subscribe to.
</p>
<div class="question"> <div class="question">
<div class="input-group"> <div class="input-group">
<label for="gender" class="smlabel input-group-addon">Gender</label> <label for="gender" class="smlabel input-group-addon">Gender</label>
...@@ -321,8 +306,43 @@ ...@@ -321,8 +306,43 @@
</div> </div>
</div> </div>
<!-- CNIL WARNING --> <!-- hidden input for modification date -->
<input id="last_modified_date" name="last_modified_date" type="text" hidden>
</input>
<!-- hidden input for doors user id -->
<input id="doors_uid" name="doors_uid" type="text" hidden
value="{{ current_user.uid | safe }}">
</input>
<p> TEST UID {{ current_user.uid | safe }} </p>
<div class="row spacerrow">&nbsp;</div>
<!-- main validation message -->
<p id="main_message" class="cartouche legend" style="display:none"></p>
<!-- == S U B M I T == -->
<div style="text-align:center">
<!-- no @type => implicit @type=submit -->
<button class="btn btn-lg btn-success" id="form_submit">
Save profile
</button>
</div>
</form>
</div>
<div class="spacer col-sm-2 col-md-2">&nbsp;</div>
</div>
<!-- CNIL WARNING -->
<div class="row spacerrow">&nbsp;</div>
<div class="row spacerrow">&nbsp;</div>
<div class="row">
<div class="spacer col-sm-1 col-md-1">&nbsp;</div>
<div class="col-sm-8 col-md-8">
<h3 class="formcat"> About your data </h3> <h3 class="formcat"> About your data </h3>
<div class="cartouche" id="cnil_warning"> <div class="cartouche" id="cnil_warning">
<p>Les informations recueillies à partir de ce formulaire font l’objet d’un traitement <p>Les informations recueillies à partir de ce formulaire font l’objet d’un traitement
...@@ -348,34 +368,6 @@ ...@@ -348,34 +368,6 @@
consultez vos droits sur le site de la CNIL</a>. consultez vos droits sur le site de la CNIL</a>.
</p> </p>
</div> </div>
<!-- hidden input for modification date -->
<input id="last_modified_date" name="last_modified_date" type="text" hidden>
</input>
<!-- hidden input for doors user id -->
<input id="doors_uid" name="doors_uid" type="text" hidden>
</input>
<div class="row spacerrow">&nbsp;</div>
<!-- main validation message -->
<p id="main_validation_message" class="legend" style="display:none"></p>
<!-- == S U B M I T == -->
<h3 class="formcat">Save profile</h3>
<!-- button instead of input.submit to validate before real submit action -->
<button class="btn btn-lg btn-success" style="float:right"
id="formsubmit" type=button
onclick="if (validateAndMsg(event)) {registerDoorsAndSubmit()}">
Save profile
</button>
</form>
</div> </div>
<div class="spacer col-sm-2 col-md-2">&nbsp;</div> <div class="spacer col-sm-2 col-md-2">&nbsp;</div>
</div> </div>
......
...@@ -186,7 +186,8 @@ ...@@ -186,7 +186,8 @@
<select id="org_type" name="org_type" <select id="org_type" name="org_type"
class="custom-select form-control" class="custom-select form-control"
onchange="if(this.value=='other'){otherInstDivStyle.display = 'block'} else {otherInstDivStyle.display='none'}"> onchange="if(this.value=='other'){otherInstDivStyle.display = 'block'} else {otherInstDivStyle.display='none'}">
<option selected value="university">University</option> <option selected disabled value="">Please select</option>
<option value="university">University</option>
<option value="public R&amp;D org">Public sector R&amp;D organization</option> <option value="public R&amp;D org">Public sector R&amp;D organization</option>
<option value="public other org">Other public sector organization</option> <option value="public other org">Other public sector organization</option>
<option value="private org">Private sector organization</option> <option value="private org">Private sector organization</option>
...@@ -268,7 +269,7 @@ ...@@ -268,7 +269,7 @@
<label for="pic_file" class="smlabel input-group-addon">Picture</label> <label for="pic_file" class="smlabel input-group-addon">Picture</label>
<input type="file" id="pic_file" name="pic_file" <input type="file" id="pic_file" name="pic_file"
accept="image/png,image/jpeg" class="form-control" accept="image/png,image/jpeg" class="form-control"
onchange="checkShowPic(this)"> onchange="cmxClt.uform.checkShowPic(this)">
</div> </div>
<p id="picture_message" class="legend red" style="font-weight:bold"></p> <p id="picture_message" class="legend red" style="font-weight:bold"></p>
</div> </div>
...@@ -305,8 +306,7 @@ ...@@ -305,8 +306,7 @@
<div class="input-group"> <div class="input-group">
<label for="job_bool" class="smlabel input-group-addon">Looking for a job?</label> <label for="job_bool" class="smlabel input-group-addon">Looking for a job?</label>
<select id="job_bool" name="job_bool" <select id="job_bool" name="job_bool"
class="custom-select form-control" class="custom-select form-control">
onchange="if(this.value=='Yes'){jobLookingDivStyle.display = 'block'} else {jobLookingDivStyle.display='none';jobDate.value=''}">
<option selected value="No" onclick="jobDate.value=''">No</option> <option selected value="No" onclick="jobDate.value=''">No</option>
<option value="Yes" onclick="jobLookingDivStyle.display = 'block'">Yes</option> <option value="Yes" onclick="jobLookingDivStyle.display = 'block'">Yes</option>
</select> </select>
...@@ -382,7 +382,7 @@ ...@@ -382,7 +382,7 @@
<!-- main validation message --> <!-- main validation message -->
<p id="main_validation_message" class="legend" style="display:none"></p> <p id="main_message" class="legend" style="display:none"></p>
<!-- CAPTCHA & SUBMIT BTN + INFOS--> <!-- CAPTCHA & SUBMIT BTN + INFOS-->
...@@ -402,7 +402,7 @@ ...@@ -402,7 +402,7 @@
<!-- button instead of input.submit to validate before real submit action --> <!-- button instead of input.submit to validate before real submit action -->
<!-- also remember stackoverflow.com/a/3315016/2489184 --> <!-- also remember stackoverflow.com/a/3315016/2489184 -->
<button class="btn btn-lg btn-success" style="float:right" <button class="btn btn-lg btn-success" style="float:right"
id="formsubmit" type=button disabled id="form_submit" type=button disabled
onclick="if (validateAndMsg(event)) {registerDoorsAndSubmit()}"> onclick="if (validateAndMsg(event)) {registerDoorsAndSubmit()}">
Submit your form Submit your form
</button> </button>
......
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