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
87912a69
Commit
87912a69
authored
Feb 02, 2017
by
Romain Loth
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP claim profile scenario + small layout changes
parent
12813e16
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
766 additions
and
79 deletions
+766
-79
table_specifications.md
doc/table_specifications.md
+1
-1
db.py
services/db.py
+48
-11
main.py
services/main.py
+31
-19
comex.css
static/css/comex.css
+4
-3
comex_user.css
static/css/comex_user.css
+2
-0
comex_user_shared.js
static/js/comex_user_shared.js
+39
-33
claim_profile.html
templates/claim_profile.html
+623
-0
profile.html
templates/profile.html
+12
-6
registration_full_form.html
templates/registration_full_form.html
+3
-3
registration_short_form.html
templates/registration_short_form.html
+3
-3
No files found.
doc/table_specifications.md
View file @
87912a69
...
...
@@ -148,7 +148,7 @@ CREATE TABLE doors_temp_user (
-- (return tokens associated to a legacy user)
CREATE TABLE legacy_temp_rettoks (
luid int(15) not null unique primary key,
rettok
varchar(255
) not null unique,
rettok
char(36
) not null unique,
INDEX luid_index_ltempt (luid),
INDEX rettok_index_ltempt (rettok)
) ;
...
...
services/db.py
View file @
87912a69
...
...
@@ -736,29 +736,66 @@ def rm_doors_temp_user(doors_uid):
# another temp table, for the secret return tokens
# of users coming back (= with a legacy profile)
def
save_legacy_user_rettoken
(
luid
,
rettok
):
db
=
connect_db
()
db_c
=
db
.
cursor
()
stmt
=
"INSERT INTO legacy_temp_rettoks(luid, rettok) VALUES (
%
s,
%
s)"
db_c
.
execute
(
stmt
,
(
luid
,
rettok
))
db
.
commit
()
db
.
close
()
def
get_legacy_user
(
rettok
):
info_row
=
None
db
=
connect_db
()
db_c
=
db
.
cursor
(
DictCursor
)
db_c
.
execute
(
'''SELECT *
FROM legacy_temp_rettoks
WHERE
luid = "
%
s"'''
%
luid
)
WHERE
rettok = "
%
s"'''
%
rettok
)
info_row
=
db_c
.
fetchone
()
db
.
close
()
return
info_row
if
info_row
and
'luid'
in
info_row
:
return
info_row
[
'luid'
]
else
:
return
None
def
rm_legacy_user_rettoken
(
luid
):
db
=
connect_db
()
db_c
=
db
.
cursor
()
db_c
.
execute
(
'''DELETE FROM legacy_temp_rettoks
WHERE luid =
"
%
s"'''
%
luid
)
WHERE luid =
%
s'''
%
int
(
luid
)
)
db
.
commit
()
db
.
close
()
def
create_legacy_user_rettokens
(
constraints
=
[
"record_status = 'legacy'"
],
validity_months
=
3
):
"""
Run this once for a new return campaign
- creates a return token for a set of users defined by @constraints
- also sets their valid_date to CURDATE + 3 months
"""
db
=
connect_db
()
db_c
=
db
.
cursor
()
# creates the rettoks by doing a UUID() on each SELECTED luid
stmt1
=
"""
INSERT INTO legacy_temp_rettoks (luid, rettok)
SELECT luid, UUID() FROM scholars
WHERE
%
s
"""
%
" AND "
.
join
([
'(
%
s)'
%
c
for
c
in
constraints
])
db_c
.
execute
(
stmt1
)
db
.
commit
()
# creates/updates the valid_date
# same constraints <=> same set of luids
stmt2
=
"""
UPDATE scholars
SET valid_date = DATE_ADD(CURDATE(), INTERVAL
%
i MONTH)
WHERE
%
s
"""
%
(
int
(
validity_months
),
" AND "
.
join
([
'(
%
s)'
%
c
for
c
in
constraints
]))
db_c
.
execute
(
stmt2
)
db
.
commit
()
db
.
close
()
# stmt2 variant for all users from legacy_temp_rettoks
# stmt2 = """
# UPDATE scholars JOIN legacy_temp_rettoks
# ON scholars.luid = legacy_temp_rettoks.uid
# SET valid_date = DATE_ADD(CURDATE(), INTERVAL 3 MONTH);
# """
services/main.py
View file @
87912a69
...
...
@@ -467,34 +467,46 @@ def claim_profile():
For returning users (access by token as GET arg)
"""
if
request
.
method
==
'GET'
:
return_token
=
None
luid
=
None
# identify who came back from the return token
if
'token'
in
request
.
args
:
return_token
=
sanitize
(
request
.
args
[
'return_token'
])
# we don't log him in but we put his data as return_user manually
# => this way we can use templating to show benign data
if
luid
is
None
:
return
render_template
(
"message.html"
,
message
=
"""
This is not the correct link. Don't attempt to claim a profile that is not yours.
"""
)
return_user
=
User
return_token
=
sanitize
(
request
.
args
[
'token'
])
print
(
"clean token"
,
return_token
)
if
(
return_token
and
type
(
return_token
)
==
str
and
len
(
return_token
)
==
36
):
luid
=
db
.
get_legacy_user
(
return_token
)
if
luid
is
not
None
:
try
:
return_user
=
User
(
luid
)
except
ValueError
:
return_user
=
None
# claim failure cases
if
return_token
is
None
or
luid
is
None
or
return_user
is
None
:
mlog
(
'INFO'
,
'failed claim profile attempt with return_token=
%
s, luid=
%
s'
%
str
(
return_token
),
str
(
luid
))
return
render_template
(
"message.html"
,
message
=
"""
This is not the correct link. Don't attempt to claim a profile that is not yours.
"""
)
# claim success
else
:
return
redirect
(
url_for
(
'rootindex'
,
_external
=
True
)
)
# return render_template(
# "profile.html"
# # NB we also got user info in {{current_user.info}}
# # and {{current_user.json_info}}
#
)
mlog
(
'INFO'
,
"successful claim_profile attempt with luid=
%
i"
,
luid
)
# we *don't* log him in but we do put his data as return_user
# => this way we can use templating to show the data
return
render_template
(
"claim_profile.html"
,
return_user
=
return_user
)
elif
request
.
method
==
'POST'
:
return
(
'not implemented yet'
)
...
...
@@ -716,7 +728,7 @@ def sanitize(value):
str_val
=
str
(
value
)
clean_val
=
sub
(
r'^\s+'
,
''
,
str_val
)
clean_val
=
sub
(
r'\s+$'
,
''
,
clean_val
)
san_val
=
sub
(
r'[^\w@\.
-:,()#
]'
,
'_'
,
clean_val
)
san_val
=
sub
(
r'[^\w@\.
:,()# -
]'
,
'_'
,
clean_val
)
if
vtype
not
in
[
int
,
str
]:
raise
ValueError
(
"Value has an incorrect type
%
s"
%
str
(
vtype
))
...
...
static/css/comex.css
View file @
87912a69
...
...
@@ -68,7 +68,7 @@ div.my-box {
/* for intro text */
.mini-hero
{
margin-top
:
5px
;
font-size
:
1
5
px
;
font-size
:
1
6
px
;
line-height
:
20px
;
font-family
:
"Droid Sans"
,
Calibri
,
"Helvetica Neue"
,
Helvetica
,
sans-serif
;
padding-bottom
:
.3em
;
...
...
@@ -192,6 +192,7 @@ div.my-box {
/* page sections: style snippets from old bootstrap h2 */
h2
.oldstyle
{
font-size
:
26px
;
font-family
:
"Droid Sans"
,
Calibri
,
Ubuntu
,
sans-serif
;
font-weight
:
bold
;
}
...
...
@@ -199,13 +200,13 @@ h2.oldstyle {
@media
(
max-width
:
768px
){
/* sm */
h2
.oldstyle
{
font-size
:
2
4
px
!important
;
font-size
:
2
2
px
!important
;
}
}
@media
(
max-width
:
544px
){
/* xs */
h2
.oldstyle
{
font-size
:
1
8
px
!important
;
font-size
:
1
6
px
!important
;
}
}
...
...
static/css/comex_user.css
View file @
87912a69
...
...
@@ -5,6 +5,7 @@ div.uform {
padding
:
15px
30px
53px
30px
;
margin
:
38px
38px
8px
38px
;
background-color
:
#ddd
;
max-width
:
950px
;
}
/*div.uform::before {
...
...
@@ -18,6 +19,7 @@ div.uform {
/* same but to put a panel-body inside */
div
.uform-nobg
{
margin
:
38px
38px
8px
38px
;
max-width
:
900px
;
}
@media
(
max-width
:
991px
){
...
...
static/js/comex_user_shared.js
View file @
87912a69
...
...
@@ -37,34 +37,35 @@ var cmxClt = (function() {
// the target columns in DB: tuple (name, mandatory, group, type, section)
cC
.
COLS
=
[
[
"keywords"
,
true
,
"plsfill"
,
"at"
,
"map_infos"
],
// ==> *keywords* table
[
"hashtags"
,
false
,
"plsfill"
,
"at"
,
"map_infos"
],
// ==> *hashtags* table
[
"doors_uid"
,
true
,
"auto"
,
"t"
,
null
],
[
"last_modified_date"
,
true
,
"auto"
,
"d"
,
null
],
[
"hon_title"
,
false
,
"plsfill"
,
"t"
,
"basic_infos"
],
[
"email"
,
true
,
"plsfill"
,
"t"
,
"login_infos"
],
[
"first_name"
,
true
,
"plsfill"
,
"t"
,
"basic_infos"
],
[
"middle_name"
,
false
,
"pref"
,
"t"
,
"basic_infos"
],
[
"last_name"
,
true
,
"plsfill"
,
"t"
,
"basic_infos"
],
[
"country"
,
true
,
"plsfill"
,
"t"
,
"basic_infos"
],
[
"initials"
,
true
,
"pref"
,
"t"
,
null
],
[
"position"
,
true
,
"plsfill"
,
"t"
,
"map_infos"
],
[
"interests_text"
,
false
,
"pref"
,
"t"
,
"other_infos"
],
[
"gender"
,
false
,
"plsfill"
,
"m"
,
"other_infos"
],
[
"job_looking_date"
,
false
,
"pref"
,
"d"
,
"map_infos"
],
[
"home_url"
,
false
,
"plsfill"
,
"t"
,
"other_infos"
],
[
"pic_url"
,
false
,
"pref"
,
"t"
,
"other_infos"
],
[
"pic_file"
,
false
,
"pref"
,
"f"
,
"other_infos"
],
// ==> *scholars* table
[
"org"
,
false
,
"plsfill"
,
"t"
,
"org_infos"
],
[
"org_type"
,
false
,
"plsfill"
,
"m"
,
"org_infos"
],
[
"team_lab"
,
true
,
"plsfill"
,
"t"
,
"map_infos"
],
[
"org_city"
,
false
,
"pref"
,
"t"
,
"org_infos"
]]
// ==> *affiliations* table
[
"keywords"
,
true
,
"plsfill"
,
"at"
,
"map_infos"
],
// ==> *keywords* table
[
"hashtags"
,
false
,
"plsfill"
,
"at"
,
"map_infos"
],
// ==> *hashtags* table
[
"doors_uid"
,
true
,
"auto"
,
"t"
,
null
],
[
"last_modified_date"
,
true
,
"auto"
,
"d"
,
null
],
[
"hon_title"
,
false
,
"plsfill"
,
"t"
,
"basic_infos"
],
[
"email"
,
true
,
"plsfill"
,
"t"
,
"login_infos"
],
[
"first_name"
,
true
,
"plsfill"
,
"t"
,
"basic_infos"
],
[
"middle_name"
,
false
,
"pref"
,
"t"
,
"basic_infos"
],
[
"last_name"
,
true
,
"plsfill"
,
"t"
,
"basic_infos"
],
[
"country"
,
true
,
"plsfill"
,
"t"
,
"basic_infos"
],
[
"initials"
,
true
,
"pref"
,
"t"
,
null
],
[
"position"
,
true
,
"plsfill"
,
"t"
,
"map_infos"
],
[
"interests_text"
,
false
,
"pref"
,
"t"
,
"other_infos"
],
[
"gender"
,
false
,
"plsfill"
,
"m"
,
"other_infos"
],
[
"job_looking_date"
,
false
,
"pref"
,
"d"
,
"map_infos"
],
[
"home_url"
,
false
,
"plsfill"
,
"t"
,
"other_infos"
],
[
"pic_url"
,
false
,
"pref"
,
"t"
,
"other_infos"
],
[
"pic_file"
,
false
,
"pref"
,
"f"
,
"other_infos"
],
// ==> *scholars* table
[
"org"
,
false
,
"plsfill"
,
"t"
,
"org_infos"
],
[
"org_type"
,
false
,
"plsfill"
,
"m"
,
"org_infos"
],
[
"team_lab"
,
true
,
"plsfill"
,
"t"
,
"map_infos"
],
[
"org_city"
,
false
,
"pref"
,
"t"
,
"org_infos"
]
// ==> *affiliations* table
]
// group "auto" === filled by controllers
// group "plsfill" === filled by user, ideally needed for a complete profile
...
...
@@ -309,12 +310,14 @@ var cmxClt = (function() {
cC
.
uform
.
allForms
[
aFormId
]
=
myUform
// events
myUform
.
elForm
.
onkeyup
=
function
(
event
)
{
// console.info('..elForm '+myUform.id+' event:'+event.type)
return
aValidationFun
(
myUform
)
if
(
aValidationFun
)
{
myUform
.
elForm
.
onkeyup
=
function
(
event
)
{
// console.info('..elForm '+myUform.id+' event:'+event.type)
return
aValidationFun
(
myUform
)
}
myUform
.
elForm
.
onchange
=
myUform
.
elForm
.
onkeyup
myUform
.
elForm
.
onblur
=
myUform
.
elForm
.
onkeyup
}
myUform
.
elForm
.
onchange
=
myUform
.
elForm
.
onkeyup
myUform
.
elForm
.
onblur
=
myUform
.
elForm
.
onkeyup
// main interaction elements, if present
// ------------------------
...
...
@@ -512,6 +515,9 @@ var cmxClt = (function() {
// diagnosticParams are optional
//
cC
.
uform
.
simpleValidateAndMessage
=
function
(
aUform
,
diagnosticParams
)
{
// console.log(">> simpleValidateAndMessage on ", aUform.id)
var
diagnostic
=
cmxClt
.
uform
.
testFillField
(
aUform
,
diagnosticParams
)
var
isValid
=
diagnostic
[
0
]
...
...
templates/claim_profile.html
0 → 100644
View file @
87912a69
This diff is collapsed.
Click to expand it.
templates/profile.html
View file @
87912a69
...
...
@@ -23,7 +23,9 @@
<!-- <h2 class="oldstyle">Your Profile Info</h2> -->
<p
class=
"mini-hero"
>
{% if current_user.empty %}
Welcome to your new empty
<strong>
profile
</strong>
!
<span
class=
"bigger"
>
Welcome to your new empty
<strong>
profile
</strong>
!
</span>
{% else %}
Welcome to your profile page,
<strong>
...
...
@@ -93,7 +95,10 @@
<!-- DOORS EMAIL -->
<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>
.
This email is your main ID. It won't be shown to the other users (but all the rest will).
<br/>
It will be soon possible to change it via the
<a
href=
"http://{{ doors_connect }}/"
>
Doors portal
</a>
.
</p>
<!-- readonly version for current profile -->
...
...
@@ -373,7 +378,7 @@
<!-- ORG QUESTIONS -->
<div
class=
"question"
>
<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>
<input
id=
"org"
name=
"org"
maxlength=
"120"
type=
"text"
class=
"form-control autocomp"
placeholder=
'eg "CNRS" or "University of Oxford"'
value=
"{{ current_user.info.org }}"
>
...
...
@@ -382,7 +387,7 @@
<div
class=
"question"
>
<div
class=
"input-group"
>
<label
for=
"org_type"
class=
"smlabel input-group-addon"
>
*
Institution Type
</label>
<label
for=
"org_type"
class=
"smlabel input-group-addon"
>
Institution Type
</label>
<select
id=
"org_type"
name=
"org_type"
class=
"custom-select form-control"
onchange=
"if(this.value=='other'){otherInstDivStyle.display = 'block'} else {otherInstDivStyle.display='none'}"
>
...
...
@@ -558,6 +563,8 @@
type=
"button"
onclick=
"theUForm.elForm.submit()"
>
Save profile
</button>
{% if not current_user.empty %}
<button
class=
"btn btn-lg btn-warning"
id=
"delete_check"
type=
"button"
data-toggle=
"modal"
data-target=
"#deleteUserModal"
>
Delete profile
...
...
@@ -592,8 +599,7 @@
</div>
</div>
</div>
{% endif %}
</div>
...
...
templates/registration_full_form.html
View file @
87912a69
...
...
@@ -10,8 +10,8 @@
{% block main_content %}
<div
class=
"row"
>
<div
class=
"spacer col-
sm-1 col-md-1
"
>
</div>
<div
class=
"my-box col-
sm-8 col-md-8
"
>
<div
class=
"spacer col-
lg-1 hidden-md-down
"
>
</div>
<div
class=
"my-box col-
lg-9 col-md-11 col-sm-12
"
>
<!-- INTRODUCTION TEXT -->
<div
id=
"intro"
>
...
...
@@ -577,7 +577,7 @@
</div>
</div>
<div
class=
"spacer col-
sm-2 col-md-2
"
>
</div>
<div
class=
"spacer col-
lg-2 col-md-1 hidden-sm-down
"
>
</div>
</div>
<div
class=
"menu-right-fixed"
>
...
...
templates/registration_short_form.html
View file @
87912a69
...
...
@@ -10,8 +10,8 @@
{% block main_content %}
<div
class=
"row"
>
<div
class=
"spacer col-
sm-1 col-md-1
"
>
</div>
<div
class=
"my-box col-
sm-8 col-md-8
"
>
<div
class=
"spacer col-
lg-1 hidden-md-down
"
>
</div>
<div
class=
"my-box col-
lg-9 col-md-11 col-sm-12
"
>
<!-- INTRODUCTION TEXT -->
<div
id=
"intro"
>
...
...
@@ -384,7 +384,7 @@
</div>
</div>
<div
class=
"spacer col-
sm-2 col-md-2
"
>
</div>
<div
class=
"spacer col-
lg-2 col-md-1 hidden-sm-down
"
>
</div>
</div>
<div
class=
"menu-right-fixed"
>
...
...
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