Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
clinicaltrials
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
david Chavalarias
clinicaltrials
Commits
dc82d799
Commit
dc82d799
authored
Jan 06, 2017
by
Romain Loth
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
more profile scenarios (WIP) + COLS validation becomes shared + minor tidying
parent
29d937f7
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
313 additions
and
196 deletions
+313
-196
db.py
services/db.py
+7
-5
main.py
services/main.py
+99
-10
tools.py
services/tools.py
+1
-1
user.py
services/user.py
+13
-7
comex_reg.css
static/css/comex_reg.css
+10
-0
comex_page_profile_controllers.js
static/js/comex_page_profile_controllers.js
+23
-3
comex_page_reg_controllers.js
static/js/comex_page_reg_controllers.js
+7
-121
comex_user_shared.js
static/js/comex_user_shared.js
+98
-4
profile.html
templates/profile.html
+55
-45
No files found.
services/db.py
View file @
dc82d799
...
@@ -65,12 +65,12 @@ def connect_db(config=REALCONFIG):
...
@@ -65,12 +65,12 @@ def connect_db(config=REALCONFIG):
"""
"""
Simple connection
Simple connection
TODO decide if we'll use one or multiple (<= atm
yes
)
TODO decide if we'll use one or multiple (<= atm
multiple
)
"""
"""
return
connect
(
return
connect
(
host
=
config
[
'SQL_HOST'
],
host
=
config
[
'SQL_HOST'
],
port
=
int
(
config
[
'SQL_PORT'
]),
port
=
int
(
config
[
'SQL_PORT'
]),
user
=
"root"
,
#
TODO
change db ownership to a comexreg user
user
=
"root"
,
#
POSS
change db ownership to a comexreg user
passwd
=
"very-safe-pass"
,
passwd
=
"very-safe-pass"
,
db
=
"comex_shared"
db
=
"comex_shared"
)
)
...
@@ -96,8 +96,7 @@ def get_field_aggs(a_field, hapax_threshold=int(REALCONFIG['HAPAX_THRESHOLD'])):
...
@@ -96,8 +96,7 @@ def get_field_aggs(a_field, hapax_threshold=int(REALCONFIG['HAPAX_THRESHOLD'])):
sql_col
=
FIELDS_FRONTEND_TO_SQL
[
a_field
]
sql_col
=
FIELDS_FRONTEND_TO_SQL
[
a_field
]
sql_tab
=
sql_col
.
split
(
'.'
)[
0
]
sql_tab
=
sql_col
.
split
(
'.'
)[
0
]
mlog
(
'DEBUG'
,
"AGG API sql_col"
,
sql_col
)
mlog
(
'INFO'
,
"AGG API sql_col"
,
sql_col
)
mlog
(
'DEBUG'
,
"AGG API sql_tab"
,
sql_tab
)
db
=
connect_db
()
db
=
connect_db
()
db_c
=
db
.
cursor
(
DictCursor
)
db_c
=
db
.
cursor
(
DictCursor
)
...
@@ -321,6 +320,8 @@ def get_full_scholar(uid):
...
@@ -321,6 +320,8 @@ def get_full_scholar(uid):
lkid_id
=
lkid_couple
[
1
]
lkid_id
=
lkid_couple
[
1
]
urow_dict
[
'linked_ids'
][
lkid_type
]
=
lkid_id
urow_dict
[
'linked_ids'
][
lkid_type
]
=
lkid_id
mlog
(
"INFO"
,
"get_full_scholar
%
s: OK"
%
uid
)
# full user info as a dict
# full user info as a dict
return
urow_dict
return
urow_dict
...
@@ -394,6 +395,7 @@ def save_scholar(uid, date, safe_recs, reg_db, uactive = True):
...
@@ -394,6 +395,7 @@ def save_scholar(uid, date, safe_recs, reg_db, uactive = True):
reg_db
.
commit
()
reg_db
.
commit
()
def
save_pairs_sch_kw
(
pairings_list
,
comex_db
):
def
save_pairs_sch_kw
(
pairings_list
,
comex_db
):
"""
"""
Simply save all pairings (uid, kwid) in the list
Simply save all pairings (uid, kwid) in the list
...
@@ -440,7 +442,7 @@ def get_or_create_keywords(kw_list, comex_db):
...
@@ -440,7 +442,7 @@ def get_or_create_keywords(kw_list, comex_db):
db_cursor
.
execute
(
'INSERT INTO keywords(kwstr) VALUES ("
%
s")'
%
kw_str
)
db_cursor
.
execute
(
'INSERT INTO keywords(kwstr) VALUES ("
%
s")'
%
kw_str
)
comex_db
.
commit
()
comex_db
.
commit
()
mlog
(
"
DEBUG
"
,
"Added keyword '
%
s'"
%
kw_str
)
mlog
(
"
INFO
"
,
"Added keyword '
%
s'"
%
kw_str
)
found_ids
.
append
(
db_cursor
.
lastrowid
)
found_ids
.
append
(
db_cursor
.
lastrowid
)
...
...
services/main.py
View file @
dc82d799
...
@@ -23,17 +23,19 @@ __version__ = "1.4"
...
@@ -23,17 +23,19 @@ __version__ = "1.4"
__email__
=
"romain.loth@iscpif.fr"
__email__
=
"romain.loth@iscpif.fr"
__status__
=
"Dev"
__status__
=
"Dev"
from
flask
import
Flask
,
render_template
,
request
,
redirect
,
url_for
from
flask
import
Flask
,
render_template
,
request
,
\
from
flask_login
import
login_required
,
current_user
,
login_user
redirect
,
url_for
,
session
from
flask_login
import
fresh_login_required
,
current_user
,
login_user
from
re
import
sub
from
re
import
sub
from
os
import
path
from
os
import
path
from
traceback
import
format_tb
from
traceback
import
format_tb
from
json
import
dumps
from
json
import
dumps
from
datetime
import
timedelta
if
__package__
==
'services'
:
if
__package__
==
'services'
:
# when we're run via import
# when we're run via import
print
(
"*** comex services ***"
)
print
(
"*** comex services ***"
)
from
services.user
import
User
,
login_manager
,
doors_login
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
,
get_or_create_affiliation
,
save_scholar
,
get_field_aggs
...
@@ -41,7 +43,7 @@ if __package__ == 'services':
...
@@ -41,7 +43,7 @@ if __package__ == 'services':
else
:
else
:
# when this script is run directly
# when this script is run directly
print
(
"*** comex services (dev server mode) ***"
)
print
(
"*** comex services (dev server mode) ***"
)
from
user
import
User
,
login_manager
,
doors_login
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
,
get_or_create_affiliation
,
save_scholar
,
get_field_aggs
...
@@ -57,6 +59,14 @@ app = Flask("services",
...
@@ -57,6 +59,14 @@ app = Flask("services",
app
.
config
[
'DEBUG'
]
=
(
config
[
'LOG_LEVEL'
]
==
"DEBUG"
)
app
.
config
[
'DEBUG'
]
=
(
config
[
'LOG_LEVEL'
]
==
"DEBUG"
)
app
.
config
[
'SECRET_KEY'
]
=
'TODO fill secret key for sessions for login'
app
.
config
[
'SECRET_KEY'
]
=
'TODO fill secret key for sessions for login'
# for flask_login
app
.
config
[
'REMEMBER_COOKIE_DURATION'
]
=
timedelta
(
seconds
=
15
)
app
.
config
[
'REMEMBER_COOKIE_NAME'
]
=
'supercookie'
app
.
config
[
'MY_VAR'
]
=
'incredible it works'
login_manager
.
login_view
=
"login"
login_manager
.
session_protection
=
"strong"
login_manager
.
init_app
(
app
)
login_manager
.
init_app
(
app
)
########### PARAMS ###########
########### PARAMS ###########
...
@@ -108,11 +118,29 @@ MIN_KW = 5
...
@@ -108,11 +118,29 @@ MIN_KW = 5
# /!\ Routes are not prefixed by nginx in prod so we do it ourselves /!\
# /!\ Routes are not prefixed by nginx in prod so we do it ourselves /!\
# -----------------------------------------------------------------------
# -----------------------------------------------------------------------
@
login_manager
.
unauthorized_handler
def
unauthorized
():
return
render_template
(
"message.html"
,
message
=
"""
Please <strong><a href="
%(login)
s">login here</a></strong>.
<br/><br/>
The page <span class='code'>
%(tgt)
s</span> is only available after login.
"""
%
{
'tgt'
:
request
.
path
,
'login'
:
url_for
(
'login'
,
next
=
request
.
path
,
_external
=
True
)}
)
# /services/
# /services/
@
app
.
route
(
config
[
'PREFIX'
]
+
'/'
,
methods
=
[
'GET'
])
@
app
.
route
(
config
[
'PREFIX'
]
+
'/'
,
methods
=
[
'GET'
])
def
services
():
def
services
():
return
redirect
(
url_for
(
'login'
,
_external
=
True
))
return
redirect
(
url_for
(
'login'
,
_external
=
True
))
# /services/test
@
app
.
route
(
config
[
'PREFIX'
]
+
'/test'
,
methods
=
[
'GET'
])
def
test_stuff
():
print
(
UCACHE
)
return
render_template
(
"message.html"
,
message
=
"UCACHE="
+
sub
(
'<|&|>'
,
'::'
,
repr
(
UCACHE
)))
# /services/api/aggs
# /services/api/aggs
@
app
.
route
(
config
[
'PREFIX'
]
+
config
[
'API_ROUTE'
]
+
'/aggs'
)
@
app
.
route
(
config
[
'PREFIX'
]
+
config
[
'API_ROUTE'
]
+
'/aggs'
)
def
aggs_api
():
def
aggs_api
():
...
@@ -166,6 +194,7 @@ def login():
...
@@ -166,6 +194,7 @@ 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
# TODO sanitize
# TODO sanitize
email
=
request
.
form
[
'email'
]
email
=
request
.
form
[
'email'
]
pwd
=
request
.
form
[
'password'
]
pwd
=
request
.
form
[
'password'
]
...
@@ -174,19 +203,72 @@ def login():
...
@@ -174,19 +203,72 @@ def login():
uid
=
doors_login
(
email
,
pwd
,
config
)
uid
=
doors_login
(
email
,
pwd
,
config
)
if
uid
:
if
uid
:
# £TODO usage ?
login_user
(
User
(
uid
))
return
redirect
(
url_for
(
'profile'
,
_external
=
True
))
login_ok
=
login_user
(
User
(
uid
))
# login_ok = login_user(User(uid), remember=True)
# -------------
# creates REMEMBER_COOKIE_NAME
# which is itself bound to session cookie
if
login_ok
:
# normal user
return
redirect
(
url_for
(
'profile'
,
_external
=
True
))
# POSS "next" request.args (useful when we'll have more pages)
# ---
else
:
# user exists in doors but has no comex profile yet
# => TODO
# => we add him
# => status = "fresh_profile"
# => empty profile
# return redirect(url_for('fresh_profile', _external=True))
return
redirect
(
url_for
(
'register'
,
_external
=
True
))
else
:
# user doesn't exist in doors nor comex_db
# (shouldn't happen since client-side blocks submit and displays same message, but still possible if user tweaks the js)
return
render_template
(
"message.html"
,
message
=
"""
We're sorry but you don't exist in our database yet!
<br/>
However you can easily <strong><a href="
%
s">register here</a></strong>.
"""
%
url_for
(
'register'
,
_external
=
True
)
)
# /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'
])
@
login_required
@
fresh_
login_required
def
profile
():
def
profile
():
"""
Entrypoint for users to load/re-save personal data
@login_required uses flask_login to relay User object current_user
"""
# login provides us current_user
if
current_user
.
empty
:
mlog
(
"INFO"
,
"PROFILE: empty current_user
%
s"
%
current_user
.
uid
)
else
:
mlog
(
"INFO"
,
"PROFILE: current_user
%
s
\n
-"
%
current_user
.
uid
+
'
\n
-'
.
join
([
current_user
.
info
[
'email'
],
current_user
.
info
[
'initials'
],
str
(
current_user
.
info
[
'keywords'
]),
current_user
.
info
[
'country'
]]
)
)
# debug session cookies
# print("[k for k in session.keys()]",[k for k in session.keys()])
mlog
(
"DEBUG"
,
"PROFILE view with flag session.new = "
,
session
.
new
)
return
render_template
(
return
render_template
(
"profile.html"
,
"profile.html"
logged_in
=
True
# NB we also got user info in {{current_user.info}}
# and {{current_user.json_info}}
)
)
...
@@ -247,12 +329,19 @@ def register():
...
@@ -247,12 +329,19 @@ def register():
# C) create record into the primary user table
# C) create record into the primary user table
# ---------------------------------------------
# ---------------------------------------------
# TODO class User method !!
save_scholar
(
duuid
,
rdate
,
clean_records
,
reg_db
)
save_scholar
(
duuid
,
rdate
,
clean_records
,
reg_db
)
# 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 !!
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
# TODO class User method !!
if
uid
in
UCACHE
:
UCACHE
.
pop
(
uid
)
# E) end connection
# E) end connection
reg_db
.
close
()
reg_db
.
close
()
...
...
services/tools.py
View file @
dc82d799
...
@@ -215,4 +215,4 @@ def mlog(loglvl, *args):
...
@@ -215,4 +215,4 @@ def mlog(loglvl, *args):
print
(
"WARNING: attempt to use mlog before read_config"
)
print
(
"WARNING: attempt to use mlog before read_config"
)
mlog
(
"
DEBUG
"
,
"conf
\n
"
+
"
\n
"
.
join
([
"
%
s=
%
s"
%
(
k
[
'var'
],
REALCONFIG
[
k
[
'var'
]])
for
k
in
CONFIGMENU
]))
mlog
(
"
INFO
"
,
"conf
\n
"
+
"
\n
"
.
join
([
"
%
s=
%
s"
%
(
k
[
'var'
],
REALCONFIG
[
k
[
'var'
]])
for
k
in
CONFIGMENU
]))
services/user.py
View file @
dc82d799
...
@@ -14,14 +14,16 @@ from flask_login import LoginManager
...
@@ -14,14 +14,16 @@ from flask_login import LoginManager
if
__package__
==
'services'
:
if
__package__
==
'services'
:
from
services.db
import
connect_db
,
get_full_scholar
from
services.db
import
connect_db
,
get_full_scholar
from
services.tools
import
mlog
else
:
else
:
from
db
import
connect_db
,
get_full_scholar
from
db
import
connect_db
,
get_full_scholar
from
tools
import
mlog
# will be exported to main for initialization with app
# will be exported to main for initialization with app
login_manager
=
LoginManager
()
login_manager
=
LoginManager
()
#
user
cache
#
scholar User objects
cache
ucache
=
{}
UCACHE
=
{}
@
login_manager
.
user_loader
@
login_manager
.
user_loader
def
load_user
(
uid
):
def
load_user
(
uid
):
...
@@ -29,12 +31,14 @@ def load_user(uid):
...
@@ -29,12 +31,14 @@ def load_user(uid):
Used by flask-login to bring back user object from uid stored in session
Used by flask-login to bring back user object from uid stored in session
"""
"""
u
=
None
u
=
None
if
uid
in
ucache
:
if
uid
in
UCACHE
:
u
=
ucache
[
uid
]
u
=
UCACHE
[
uid
]
mlog
(
"DEBUG"
,
"load_user: user re-loaded by cache"
)
else
:
else
:
try
:
try
:
u
=
User
(
uid
)
u
=
User
(
uid
)
ucache
[
uid
]
=
u
UCACHE
[
uid
]
=
u
mlog
(
"DEBUG"
,
"load_user: user re-loaded from DB"
)
except
Exception
as
err
:
except
Exception
as
err
:
print
(
"User(
%
s) init error:"
%
str
(
uid
),
err
)
print
(
"User(
%
s) init error:"
%
str
(
uid
),
err
)
return
u
return
u
...
@@ -42,7 +46,7 @@ def load_user(uid):
...
@@ -42,7 +46,7 @@ def load_user(uid):
def
doors_login
(
email
,
password
,
config
):
def
doors_login
(
email
,
password
,
config
):
"""
"""
Q
uery to Doors API to login a user
Remote q
uery to Doors API to login a user
Doors responses look like this:
Doors responses look like this:
{'status': 'login ok',
{'status': 'login ok',
...
@@ -83,10 +87,12 @@ class User(object):
...
@@ -83,10 +87,12 @@ class User(object):
if
user_info
is
None
:
if
user_info
is
None
:
# user exists in doors but has nothing in DB yet
# user exists in doors but has nothing in DB yet
self
.
info
=
{}
self
.
info
=
{}
self
.
json_info
=
"{}"
self
.
empty
=
True
self
.
empty
=
True
else
:
else
:
# normal user has a nice info dict
# normal user has a nice info dict
self
.
info
=
user_info
self
.
info
=
user_info
self
.
json_info
=
dumps
(
user_info
)
self
.
empty
=
False
self
.
empty
=
False
def
get_id
(
self
):
def
get_id
(
self
):
...
@@ -97,7 +103,7 @@ class User(object):
...
@@ -97,7 +103,7 @@ class User(object):
"""
"""
uses scholars.status
uses scholars.status
"""
"""
return
(
self
.
info
[
'record_status'
]
==
"active"
)
return
(
not
self
.
empty
and
self
.
info
[
'record_status'
]
==
"active"
)
@
property
@
property
def
is_anonymous
(
self
):
def
is_anonymous
(
self
):
...
...
static/css/comex_reg.css
View file @
dc82d799
...
@@ -73,6 +73,16 @@
...
@@ -73,6 +73,16 @@
margin
:
0
;
margin
:
0
;
}
}
/* for code blocks or urls */
.code
{
font-family
:
"Fira Mono"
,
"Droid Sans Mono"
,
monospace
;
font-weight
:
500
;
font-size
:
75%
;
background-color
:
#ACA
;
padding
:
.2em
;
border-radius
:
.2em
;
}
/* the picture preview */
/* the picture preview */
#box_show_pic
{
#box_show_pic
{
...
...
static/js/comex_page_profile_controllers.js
View file @
dc82d799
/**
/**
* @fileoverview
* @fileoverview
* Profile 1/overview and 2/completing
via Doors
* Profile 1/overview and 2/completing
* @todo
* @todo
* - package.json
* - package.json
*
*
...
@@ -9,7 +9,27 @@
...
@@ -9,7 +9,27 @@
* @author romain.loth@iscpif.fr
* @author romain.loth@iscpif.fr
*
*
* @requires comex_user_shared
* @requires comex_user_shared
* @requires comex_user_shared_auth
*
* NB The uinfo variable should be set to template's user.json_info value.
*/
*/
// TODO
// initialize form controllers
cmxClt
.
uform
.
initialize
(
"comex_profile_form"
,
completionAsYouGo
)
var
isProfileComplete
=
false
var
pleaseCompleteMessage
=
document
.
selectById
(
"please_complete"
)
var
missingColumns
=
[]
function
completionAsYouGo
()
{
var
valid
=
true
var
mandatoryMissingFields
=
[]
var
optionalMissingFields
=
[]
[
valid
,
mandatoryMissingFields
,
optionalMissingFields
]
=
cmxClt
.
uform
.
testFillField
(
cmxClt
.
uform
.
theForm
)
}
static/js/comex_page_reg_controllers.js
View file @
dc82d799
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
* Validates the comex (communityexplorer.org) registration form
* Validates the comex (communityexplorer.org) registration form
* + adds a timestamp in input#last_modified_date
* + adds a timestamp in input#last_modified_date
* + adds autocompletes
* + adds autocompletes
* + prepares DB save into COLS
* + prepares DB save into
cmxClt.
COLS
*
*
* @todo
* @todo
* - harmonize var names (eg 'cmxClt.uauth.email' vs 'initialsInput' are both input elts)
* - harmonize var names (eg 'cmxClt.uauth.email' vs 'initialsInput' are both input elts)
...
@@ -49,39 +49,10 @@ function testAsYouGo() {
...
@@ -49,39 +49,10 @@ function testAsYouGo() {
}
}
// the target columns in DB: tuple (name, mandatoryBool, maxChars (or nChars))
var
COLS
=
[
[
"doors_uid"
,
true
,
36
,
'exact'
],
[
"last_modified_date"
,
true
,
24
,
'exact'
],
[
"email"
,
true
,
255
],
[
"country"
,
true
,
60
],
[
"first_name"
,
true
,
30
],
[
"middle_name"
,
false
,
30
],
[
"last_name"
,
true
,
50
],
[
"initials"
,
true
,
7
],
[
"position"
,
false
,
30
],
[
"hon_title"
,
false
,
30
],
[
"interests_text"
,
false
,
1200
],
[
"community_hashtags"
,
false
,
350
],
[
"gender"
,
false
,
1
,
'exact'
],
[
"job_looking_date"
,
false
,
24
,
'exact'
],
[
"home_url"
,
false
,
120
],
[
"pic_url"
,
false
,
120
],
[
"pic_file"
,
false
,
null
],
// ==> *scholars* table
[
"keywords"
,
true
,
350
],
// ==> *keywords* table
[
"org"
,
true
,
120
],
[
"org_type"
,
true
,
50
],
[
"team_lab"
,
false
,
120
],
[
"org_city"
,
false
,
50
]]
// ==> *affiliations* table
var
regTimestamp
=
document
.
getElementById
(
'last_modified_date'
)
var
regTimestamp
=
document
.
getElementById
(
'last_modified_date'
)
// dates up to 2049/12/31
var
validDate
=
new
RegExp
(
/^20
[
0-4
][
0-9
]\/(?:
0
?[
1-9
]
|1
[
0-2
])\/(?:
0
?[
1-9
]
|
[
1-2
][
0-9
]
|3
[
0-1
])
$/
)
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
...
@@ -89,28 +60,6 @@ var otherInstDivStyle = document.getElementById('other_org_div').style
...
@@ -89,28 +60,6 @@ var otherInstDivStyle = document.getElementById('other_org_div').style
var
jobLookingDivStyle
=
document
.
getElementById
(
'job_looking_div'
).
style
var
jobLookingDivStyle
=
document
.
getElementById
(
'job_looking_div'
).
style
// NB using new route in doors api/userExists
// case true => Ok("""{"status":"login exists"}""")
// case false => Ok("""{"status":"login available"}""")
function
testDoorsUserExists
(
emailValue
)
{
// /!\ async
cmxClt
.
uauth
.
callDoors
(
"userExists"
,
[
emailValue
],
function
(
doorsResp
)
{
var
doorsUid
=
doorsResp
[
0
]
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
)
}
)
}
function
registerDoorsAndSubmit
(){
function
registerDoorsAndSubmit
(){
cmxClt
.
uform
.
mainMessage
.
innerHTML
=
"Registering with ISCPIF Doors..."
cmxClt
.
uform
.
mainMessage
.
innerHTML
=
"Registering with ISCPIF Doors..."
...
@@ -176,73 +125,13 @@ function validateAndMsg() {
...
@@ -176,73 +125,13 @@ function validateAndMsg() {
cmxClt
.
uform
.
submitButton
.
disabled
=
true
cmxClt
.
uform
.
submitButton
.
disabled
=
true
cmxClt
.
uform
.
mainMessage
.
style
.
display
=
'block'
cmxClt
.
uform
.
mainMessage
.
style
.
display
=
'block'
var
valid
=
true
cmxClt
.
uform
.
mainMessage
.
innerHTML
=
"Validating the form..."
cmxClt
.
uform
.
mainMessage
.
innerHTML
=
"Validating the form..."
// also reformat the jobDate from "YYYY/MM/DD" to ISO
var
valid
=
true
if
(
jobDate
.
value
.
length
)
jobDate
.
value
=
(
new
Date
(
jobDate
.
value
)).
toISOString
()
// objectify the form
cmxClt
.
uform
.
wholeFormData
=
new
FormData
(
cmxClt
.
uform
.
theForm
);
var
missingFields
=
[]
var
missingFields
=
[]
var
toolongFields
=
[]
for
(
var
i
in
COLS
)
{
// console.warn("checking COLS["+i+"]", COLS[i])
var
fieldName
=
COLS
[
i
][
0
]
var
mandatory
=
COLS
[
i
][
1
]
var
nChars
=
COLS
[
i
][
2
]
var
isExactN
=
(
COLS
[
i
][
3
]
==
'exact'
)
// skip picture already done
if
(
fieldName
==
'pic_file'
)
continue
;
// skip doors_uid done afterwards if form ok
if
(
fieldName
==
'doors_uid'
)
continue
;
var
actualValue
=
cmxClt
.
uform
.
wholeFormData
.
get
(
fieldName
)
// console.log("actualValue", actualValue)
// test mandatory -----------------
if
(
mandatory
&&
(
actualValue
==
null
||
actualValue
==
""
))
{
// todo human-readable fieldName here
missingFields
.
push
(
fieldName
)
valid
=
false
console
.
log
(
"missingField"
,
fieldName
)
}
// test length --------------------
else
if
(
mandatory
||
(
actualValue
!=
null
&&
actualValue
!=
""
))
{
if
(
isExactN
)
{
// should never happen => trigger error
if
(
actualValue
.
length
!=
nChars
)
{
console
.
error
(
"invalid value for field "
+
fieldName
+
"("
+
actualValue
+
")"
+
"should have exactly "
+
nChars
+
" chars"
)
valid
=
false
console
.
log
(
"wrong value"
)
}
}
else
{
if
(
actualValue
.
length
>
nChars
)
{
toolongFields
.
push
([
fieldName
,
nChars
])
valid
=
false
console
.
log
(
"tooShort"
)
}
}
}
// --------------------------------
}
// end for val in COLS
[
valid
,
missingFields
]
=
cmxClt
.
uform
.
testFillField
(
cmxClt
.
uform
.
theForm
)
// +++++++++++++
// RESULTS
// RESULTS
if
(
valid
)
{
if
(
valid
)
{
// adds the captchaCheck inside the form
// adds the captchaCheck inside the form
...
@@ -256,19 +145,16 @@ function validateAndMsg() {
...
@@ -256,19 +145,16 @@ function validateAndMsg() {
else
{
else
{
console
.
warn
(
"form is not valid"
)
console
.
warn
(
"form is not valid"
)
// TODO highlight invalid fields
cmxClt
.
uform
.
submitButton
.
disabled
=
false
cmxClt
.
uform
.
submitButton
.
disabled
=
false
var
errorMessage
=
''
var
errorMessage
=
''
// TODO highlight invalid fields
if
(
missingFields
.
length
)
{
if
(
missingFields
.
length
)
{
errorMessage
+=
"Please fill the missing fields: "
+
cmxClt
.
ulListFromLabelsArray
(
missingFields
,
[
"red"
])
errorMessage
+=
"Please fill the missing fields: "
+
cmxClt
.
ulListFromLabelsArray
(
missingFields
,
[
"red"
])
}
}
// length is handled by each input's maxlength
// length is handled by each input's maxlength
// re change the jobDate from ISO to YYYY/MM/DD
if
(
jobDate
.
value
.
length
)
jobDate
.
value
=
jobDate
.
value
.
slice
(
0
,
10
).
replace
(
/-/g
,
"/"
)
// display (TODO setTimeout and fade)
// display (TODO setTimeout and fade)
cmxClt
.
uform
.
mainMessage
.
innerHTML
=
errorMessage
cmxClt
.
uform
.
mainMessage
.
innerHTML
=
errorMessage
return
false
return
false
...
@@ -403,7 +289,7 @@ jobDate.onkeyup = checkJobDateStatus
...
@@ -403,7 +289,7 @@ jobDate.onkeyup = checkJobDateStatus
jobDate
.
onchange
=
checkJobDateStatus
jobDate
.
onchange
=
checkJobDateStatus
function
checkJobDateStatus
()
{
function
checkJobDateStatus
()
{
jobLookingDateStatus
=
(
jobBool
.
value
==
"No"
||
validDate
.
test
(
jobDate
.
value
))
jobLookingDateStatus
=
(
jobBool
.
value
==
"No"
||
cmxClt
.
uform
.
validDate
.
test
(
jobDate
.
value
))
if
(
!
jobLookingDateStatus
)
{
if
(
!
jobLookingDateStatus
)
{
jobDateMsg
.
style
.
color
=
cmxClt
.
colorRed
jobDateMsg
.
style
.
color
=
cmxClt
.
colorRed
jobDateMsg
.
innerHTML
=
'Date is not yet in the valid format YYYY/MM/DD'
jobDateMsg
.
innerHTML
=
'Date is not yet in the valid format YYYY/MM/DD'
...
...
static/js/comex_user_shared.js
View file @
dc82d799
...
@@ -13,7 +13,6 @@
...
@@ -13,7 +13,6 @@
*
*
*/
*/
// initialize and export cmxClt module
// initialize and export cmxClt module
var
cmxClt
=
(
function
()
{
var
cmxClt
=
(
function
()
{
...
@@ -25,6 +24,41 @@ var cmxClt = (function() {
...
@@ -25,6 +24,41 @@ var cmxClt = (function() {
ccModule
.
colorGreen
=
'#161'
ccModule
.
colorGreen
=
'#161'
ccModule
.
colorGrey
=
'#554'
ccModule
.
colorGrey
=
'#554'
// the target columns in DB: tuple (name, mandatoryBool, type)
ccModule
.
COLS
=
[
[
"doors_uid"
,
true
,
"auto"
],
[
"last_modified_date"
,
true
,
"auto"
],
[
"email"
,
true
,
"plsfill"
],
[
"country"
,
true
,
"plsfill"
],
[
"first_name"
,
true
,
"plsfill"
],
[
"middle_name"
,
false
,
"plsfill"
],
[
"last_name"
,
true
,
"plsfill"
],
[
"initials"
,
true
,
"plsfill"
],
[
"position"
,
false
,
"plsfill"
],
[
"hon_title"
,
false
,
"plsfill"
],
[
"interests_text"
,
false
,
"plsfill"
],
[
"community_hashtags"
,
false
,
"plsfill"
],
[
"gender"
,
false
,
"plsfill"
],
[
"job_looking_date"
,
false
,
"pref"
],
[
"home_url"
,
false
,
"plsfill"
],
[
"pic_url"
,
false
,
"pref"
],
[
"pic_file"
,
false
,
"pref"
],
// ==> *scholars* table
[
"keywords"
,
true
,
"plsfill"
],
// ==> *keywords* table
[
"org"
,
true
,
"plsfill"
],
[
"org_type"
,
true
,
"plsfill"
],
[
"team_lab"
,
false
,
"pref"
],
[
"org_city"
,
false
,
"pref"
]]
// ==> *affiliations* table
// "type" is a complementary information to mandatory
// --------------------------------------------------
// type "auto" === filled by controllers
// type "plsfill" === filled by user, ideally needed for a complete profile
// type "pref" === filled by user but not needed at all
ccModule
.
makeRandomString
=
function
(
nChars
)
{
ccModule
.
makeRandomString
=
function
(
nChars
)
{
var
rando
=
""
var
rando
=
""
...
@@ -61,7 +95,6 @@ var cmxClt = (function() {
...
@@ -61,7 +95,6 @@ var cmxClt = (function() {
ccModule
.
uform
=
{}
ccModule
.
uform
=
{}
ccModule
.
uform
.
theFormId
=
null
ccModule
.
uform
.
theFormId
=
null
ccModule
.
uform
.
theForm
=
null
ccModule
.
uform
.
theForm
=
null
ccModule
.
uform
.
wholeFormData
=
null
// vars that will be used during the interaction
// vars that will be used during the interaction
ccModule
.
uform
.
submitButton
=
document
.
getElementById
(
'formsubmit'
)
ccModule
.
uform
.
submitButton
=
document
.
getElementById
(
'formsubmit'
)
...
@@ -77,9 +110,70 @@ var cmxClt = (function() {
...
@@ -77,9 +110,70 @@ var cmxClt = (function() {
}
}
// 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
])
$/
)
// checks if mandatory fields are filled
// checks if other plsfill ones are filled
ccModule
.
uform
.
testFillField
=
function
(
aForm
)
{
// "private" copy
var
wholeFormData
=
new
FormData
(
aForm
)
// our return values
var
valid
=
true
var
mandatoryMissingFields
=
[]
var
otherMissingFields
=
[]
// var toolongFields = []
// let's go
for
(
var
i
in
ccModule
.
COLS
)
{
// console.warn("checking ccModule.COLS["+i+"]", ccModule.COLS[i])
var
fieldName
=
ccModule
.
COLS
[
i
][
0
]
var
mandatory
=
ccModule
.
COLS
[
i
][
1
]
var
fieldType
=
ccModule
.
COLS
[
i
][
2
]
// skip non-plsfill elements
if
(
fieldName
!=
'plsfill'
)
continue
;
var
actualValue
=
wholeFormData
.
get
(
fieldName
)
// alternative null values
if
(
actualValue
==
""
||
actualValue
==
"None"
)
{
actualValue
=
null
}
// debug
// console.log(
// "cmxClt.testEachField: field", fieldName,
// "actualValue:", actualValue
// )
// test mandatory -----------------
if
(
mandatory
&&
actualValue
==
null
)
{
// todo human-readable fieldName here
mandatoryMissingFields
.
push
(
fieldName
)
valid
=
false
console
.
log
(
"mandatoryMissingFields"
,
fieldName
)
}
// test benign --------------------
// may be missing but doesn't affect valid
else
if
(
actualValue
==
null
)
{
otherMissingFields
.
push
(
fieldName
)
console
.
log
(
"otherMissingField"
,
fieldName
)
}
// --------------------------------
}
// end for val in ccModule.COLS
// return full form diagnostic and field census
return
[
valid
,
mandatoryMissingFields
,
otherMissingFields
]
}
return
ccModule
return
ccModule
}())
;
}())
;
console
.
log
(
"shared load OK"
)
console
.
log
(
"shared load OK"
)
templates/profile.html
View file @
dc82d799
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment