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):
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
For profile change (just toggle update_flag to True)
-> *update* scholars table
see also COLS variable and doc/table_specifications.md
"""
......@@ -346,8 +349,8 @@ def save_scholar(uid, date, safe_recs, reg_db, uactive = True):
# => But currently bug in MySQLdb for binary values)
# (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) :-)
......@@ -377,19 +380,33 @@ def save_scholar(uid, date, safe_recs, reg_db, uactive = True):
db_tgtcols.append('record_status')
db_qstrvals.append('"active"')
# expected colnames "(doors_uid, last_modified_date, email, ...)"
db_tgtcols_str = ','.join(db_tgtcols)
reg_db_c = reg_db.cursor()
# fields converted to sql syntax
db_vals_str = ','.join(db_qstrvals)
if not update_flag:
# expected colnames "(doors_uid, last_modified_date, email, ...)"
db_tgtcols_str = ','.join(db_tgtcols)
reg_db_c = reg_db.cursor()
# fields converted to sql syntax
db_vals_str = ','.join(db_qstrvals)
# INSERT: full_statement with formated values
full_statmt = 'INSERT INTO scholars (%s) VALUES (%s)' % (
db_tgtcols_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)
# full_statement with formated values
full_statmt = 'INSERT INTO scholars (%s) VALUES (%s)' % (
db_tgtcols_str,
db_vals_str
)
reg_db_c.execute(full_statmt)
reg_db.commit()
......@@ -407,6 +424,16 @@ def save_pairs_sch_kw(pairings_list, comex_db):
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):
"""
kw_str -> lookup/add to *keywords* table -> kw_id
......
This diff is collapsed.
......@@ -2,6 +2,7 @@
.red { color:#910 ; }
.green { color:#161 ; }
.grey { color:#554 ; }
.orange { color:#F96 ; }
/* not used at present but could be useful for autompleted inputs */
.autocomp {
......@@ -46,6 +47,11 @@
display: none;
}
input.readonly {
font-weight: bold;
background-color: #CCC !important;
}
#cnil_warning {
/*text-align: center;*/
}
......@@ -143,10 +149,15 @@ h3.formcatfirst {
/* the main validation message (a special legend) */
#main_validation_message {
font-size: 200%;
#main_message {
color: white ;
font-size: 150%;
text-align:center;
/*color: #554 ;*/
background-color: #988 ;
border-radius: 2em;
padding: 1em 3em;
margin-bottom: 2em;
}
......@@ -154,6 +165,8 @@ ul.minilabels {
padding-top: .5em;
list-style-type: none;
font-size: 75% ;
text-align: left;
margin-left: 32%;
}
li.minilabel {
......
......@@ -14,22 +14,37 @@
*/
// initialize form controllers
cmxClt.uform.initialize("comex_profile_form", completionAsYouGo)
var isProfileComplete = false
var pleaseCompleteMessage = document.selectById("please_complete")
// main validation function
// ------------------------
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 = true
var mandatoryMissingFields = []
var optionalMissingFields = []
[ valid,
mandatoryMissingFields,
optionalMissingFields
] = cmxClt.uform.testFillField(cmxClt.uform.theForm)
var valid = diagnostic[0]
var mandatoryMissingFields = diagnostic[1]
var optionalMissingFields = diagnostic[2]
if (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/>"
}
else {
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 @@
* + prepares DB save into cmxClt.COLS
*
* @todo
* - harmonize var names (eg 'cmxClt.uauth.email' vs 'initialsInput' are both input elts)
* - package.json
*
* @version 1
......@@ -18,27 +17,26 @@
*/
// 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
cmxClt.uauth.emailIdSupposedToExist = false
var jobLookingDateStatus = false
// done when anything in the form changes
function testAsYouGo() {
// console.log("testAsYouGo Go")
cmxClt.uauth.earlyValidate()
checkJobDateStatus()
// TODO add uform.testFillField (start checking after 3-4 filled fields)
cmxClt.uform.checkJobDateStatus()
if (cmxClt.uauth.passStatus
&& cmxClt.uauth.emailStatus
&& cmxClt.uauth.captchaStatus
&& jobLookingDateStatus) {
&& cmxClt.uform.jobLookingDateStatus) {
cmxClt.uform.submitButton.disabled = false
}
else {
......@@ -50,14 +48,13 @@ function testAsYouGo() {
var regTimestamp = document.getElementById('last_modified_date')
var subPage1Style = document.getElementById('subpage_1').style
var subPage2Style = document.getElementById('subpage_2').style
var teamCityDivStyle = document.getElementById('team_city_div').style
var otherInstDivStyle = document.getElementById('other_org_div').style
var jobLookingDivStyle = document.getElementById('job_looking_div').style
function registerDoorsAndSubmit(){
......@@ -68,11 +65,11 @@ function registerDoorsAndSubmit(){
var passValue = cmxClt.uauth.pass1.value
var wholenameValue = ""
if (mName.value != "") {
wholenameValue = lName.value + ', ' + fName.value + ' ' + mName.value
if (cmxClt.uform.mName.value != "") {
wholenameValue = cmxClt.uform.lName.value + ', ' + cmxClt.uform.fName.value + ' ' + cmxClt.uform.mName.value
}
else {
wholenameValue = lName.value + ', ' + fName.value
wholenameValue = cmxClt.uform.lName.value + ', ' + cmxClt.uform.fName.value
}
......@@ -127,12 +124,14 @@ function validateAndMsg() {
cmxClt.uform.mainMessage.style.display = 'block'
cmxClt.uform.mainMessage.innerHTML = "Validating the form..."
var valid = true
var missingFields = []
// runs field-by-field validation and highlights mandatory missing fields
var diagnostic = cmxClt.uform.testFillField(cmxClt.uform.theForm)
// +++++++++++++
[valid, missingFields] = cmxClt.uform.testFillField(cmxClt.uform.theForm)
// +++++++++++++
// RESULTS
var valid = diagnostic[0]
var missingFields = diagnostic[1]
if (valid) {
// adds the captchaCheck inside the form
ccModule.uauth.collectCaptcha()
......@@ -143,14 +142,11 @@ function validateAndMsg() {
return true
}
else {
console.warn("form is not valid")
cmxClt.uform.submitButton.disabled = false
var errorMessage = ''
// TODO highlight invalid fields
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
......@@ -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
// -> local data for countries, jobtitles
// -> use ajax aggs api for the scholars, kws and labs
......@@ -912,14 +768,14 @@ $(function() {
console.log("reg controllers load OK")
// £DEBUG autofill ----------->8------
// fName.value = "Jean"
// lName.value = "Tartampion"
// initialsInput.value="JPP"
// cmxClt.uform.fName.value = "Jean"
// cmxClt.uform.lName.value = "Tartampion"
// document.getElementById('initials').value="JPP"
// document.getElementById('country').value = "France"
// document.getElementById('position').value = "atitle"
// document.getElementById('keywords').value = "Blabla"
// document.getElementById('org').value = "CNRS"
//
// cmxClt.uauth.email.value= cmxClt.makeRandomString(7)+"@om.fr"
// cmxClt.uauth.pass1.value="123456+789"
// cmxClt.uauth.pass2.value="123456+789"
......
This diff is collapsed.
......@@ -96,7 +96,7 @@ cmxClt = (function(ccModule) {
// 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)
var emailFormatOk = /^[-A-z0-9_=.+]+@[-A-z0-9_=.+]+\.[-A-z0-9_=.+]{2,4}$/.test(emailValue)
if (! emailFormatOk) {
// restore original lack of message
......@@ -149,7 +149,7 @@ cmxClt = (function(ccModule) {
ccModule.uauth.doorsMessage.style.color = ccModule.colorGreen
// label
ccModule.uauth.emailLbl.style.color = ccModule.colorGreen
ccModule.uauth.emailLbl.style.backgroundColor = ""
}
else {
var errMsg = expectExists ? "your ID isn't recognized" : "this ID is already taken"
......@@ -165,7 +165,7 @@ cmxClt = (function(ccModule) {
ccModule.uauth.doorsMessage.style.color = ccModule.colorRed
// label
ccModule.uauth.emailLbl.style.backgroundColor = ccModule.colorRed
ccModule.uauth.emailLbl.style.backgroundColor = ccModule.colorOrange
}
// to debounce re-invocations
......
......@@ -77,7 +77,7 @@
<!-- 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 -->
......@@ -93,7 +93,7 @@
<!-- normal submit button
(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"
id="formsubmit" disabled>
id="form_submit" disabled>
LOGIN
</button>
......
......@@ -18,27 +18,15 @@
<div id="intro">
<h2 class="oldstyle">Your Profile Info</h2>
<p class="mini-hero">
{% if current_user.is_authenticated %}
Welcome to your <strong>Community explorer</strong> profile,
{% if current_user.info.hon_title is not none %}
{{ current_user.info.hon_title }}
{% endif %}
{{ current_user.info.last_name }}!
{% endif %}
</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/>
The <strong>keywords</strong>, <strong>affiliations</strong> and <strong>hashtags</strong> will all count as similarities to identify network neighbours.
Welcome to your profile page,
<strong>
{% if current_user.info.hon_title is not none %}
{{ current_user.info.hon_title }}
{% endif %}
{{ current_user.info.last_name }}
</strong> !
<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.
Take the time to complete it to generate better maps of your socio-semantic network .
</p>
</div>
......@@ -48,6 +36,21 @@
<!-- 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 -->
<h3 class="formcatfirst"> Basic infos </h3>
......@@ -107,33 +110,13 @@
value="{{ current_user.info.country }}">
</div>
<!-- EMAIL & PASSWORD -->
<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 -->
<!-- JOB, INTERESTS AND ORGANIZATION -->
<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">
<label for="hon_title" class="smlabel input-group-addon"> Title </label>
<input id="hon_title" name="hon_title" maxlength="30"
......@@ -160,9 +143,6 @@
<p class="legend">Please enter at least 5 comma-separated keywords</p>
</div>
<!-- ORGANIZATION -->
<h3 class="formcat"> About your current organization </h3>
<div class="question">
<div class="input-group">
<label for="org" class="smlabel input-group-addon">* Parent Institution</label>
......@@ -223,6 +203,11 @@
<!-- OTHER PERSONAL INFO -->
<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="input-group">
<label for="gender" class="smlabel input-group-addon">Gender</label>
......@@ -321,8 +306,43 @@
</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>
<div class="cartouche" id="cnil_warning">
<p>Les informations recueillies à partir de ce formulaire font l’objet d’un traitement
......@@ -348,34 +368,6 @@
consultez vos droits sur le site de la CNIL</a>.
</p>
</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 class="spacer col-sm-2 col-md-2">&nbsp;</div>
</div>
......
......@@ -186,7 +186,8 @@
<select id="org_type" name="org_type"
class="custom-select form-control"
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 other org">Other public sector organization</option>
<option value="private org">Private sector organization</option>
......@@ -268,7 +269,7 @@
<label for="pic_file" class="smlabel input-group-addon">Picture</label>
<input type="file" id="pic_file" name="pic_file"
accept="image/png,image/jpeg" class="form-control"
onchange="checkShowPic(this)">
onchange="cmxClt.uform.checkShowPic(this)">
</div>
<p id="picture_message" class="legend red" style="font-weight:bold"></p>
</div>
......@@ -305,8 +306,7 @@
<div class="input-group">
<label for="job_bool" class="smlabel input-group-addon">Looking for a job?</label>
<select id="job_bool" name="job_bool"
class="custom-select form-control"
onchange="if(this.value=='Yes'){jobLookingDivStyle.display = 'block'} else {jobLookingDivStyle.display='none';jobDate.value=''}">
class="custom-select form-control">
<option selected value="No" onclick="jobDate.value=''">No</option>
<option value="Yes" onclick="jobLookingDivStyle.display = 'block'">Yes</option>
</select>
......@@ -382,7 +382,7 @@
<!-- 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-->
......@@ -402,7 +402,7 @@
<!-- button instead of input.submit to validate before real submit action -->
<!-- also remember stackoverflow.com/a/3315016/2489184 -->
<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()}">
Submit your form
</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