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
8fec9658
Commit
8fec9658
authored
Jan 31, 2017
by
Romain Loth
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
createprofile scenario: for doors users that have nothing in DB yet
parent
ea907374
Changes
8
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
246 additions
and
94 deletions
+246
-94
table_specifications.md
doc/table_specifications.md
+8
-1
db.py
services/db.py
+28
-1
main.py
services/main.py
+83
-50
tools.py
services/tools.py
+8
-0
user.py
services/user.py
+78
-25
init_comex_shared.sql
setup/dockers/comex2_mysql_server/init_comex_shared.sql
+8
-0
base_layout.html
templates/base_layout.html
+16
-10
profile.html
templates/profile.html
+17
-7
No files found.
doc/table_specifications.md
View file @
8fec9658
...
...
@@ -128,4 +128,11 @@ CREATE TABLE linked_ids(
PRIMARY KEY (linkid),
FOREIGN KEY (uid) REFERENCES scholars(luid) ON DELETE CASCADE
);
```
-- separate table for incoming doors users without a profile in scholars
-- (allows us to avoid reasking them for their doors info like email)
CREATE TABLE doors_temp_user (
doors_uid char(36) not null unique primary key,
email varchar(255) not null unique,
INDEX duid_index_dtempu (doors_uid)
) ;
services/db.py
View file @
8fec9658
...
...
@@ -457,7 +457,6 @@ def get_full_scholar(uid):
# full user info as a dict
return
urow_dict
def
save_scholar
(
safe_recs
,
reg_db
,
uactive
=
True
,
update_luid
=
None
):
"""
For new registration:
...
...
@@ -696,3 +695,31 @@ def get_or_create_affiliation(org_info, comex_db):
raise
Exception
(
"ERROR: non-unique affiliation '
%
s'"
%
str
(
db_qstrvals
))
return
the_aff_id
def
save_doors_temp_user
(
doors_uid
,
doors_email
):
db
=
connect_db
()
db_c
=
db
.
cursor
()
stmt
=
"INSERT IGNORE INTO doors_temp_user(doors_uid, email) VALUES (
%
s,
%
s)"
db_c
.
execute
(
stmt
,
(
doors_uid
,
doors_email
))
db
.
commit
()
db
.
close
()
def
get_doors_temp_user
(
doors_uid
):
info_row
=
None
db
=
connect_db
()
db_c
=
db
.
cursor
(
DictCursor
)
db_c
.
execute
(
'''SELECT *
FROM doors_temp_user
WHERE doors_uid = "
%
s"'''
%
doors_uid
)
info_row
=
db_c
.
fetchone
()
db
.
close
()
return
info_row
def
rm_doors_temp_user
(
doors_uid
):
db
=
connect_db
()
db_c
=
db
.
cursor
()
db_c
.
execute
(
'''DELETE FROM doors_temp_user
WHERE doors_uid = "
%
s"'''
%
doors_uid
)
db
.
commit
()
db
.
close
()
services/main.py
View file @
8fec9658
This diff is collapsed.
Click to expand it.
services/tools.py
View file @
8fec9658
...
...
@@ -10,6 +10,7 @@ from configparser import ConfigParser
from
os
import
environ
,
path
from
urllib.parse
import
unquote
from
ctypes
import
c_int32
from
traceback
import
format_tb
# ========================== FILL REALCONFIG ===================================
...
...
@@ -215,3 +216,10 @@ def mlog(loglvl, *args):
mlog
(
"INFO"
,
"conf
\n
"
+
"
\n
"
.
join
([
"
%
s=
%
s"
%
(
k
[
'var'
],
REALCONFIG
[
k
[
'var'
]])
for
k
in
CONFIGMENU
]))
def
format_err
(
err
):
"""
Formats the exceptions for HTML display
"""
return
"ERROR ("
+
str
(
err
.
__doc__
)
+
"):<br/>"
+
(
"<br/>"
.
join
(
format_tb
(
err
.
__traceback__
)
+
[
repr
(
err
)]))
services/user.py
View file @
8fec9658
...
...
@@ -11,12 +11,13 @@ __email__ = "romain.loth@iscpif.fr"
from
json
import
dumps
,
loads
from
datetime
import
date
from
flask_login
import
LoginManager
from
re
import
match
if
__package__
==
'services'
:
from
services.db
import
connect_db
,
get_full_scholar
from
services.db
import
connect_db
,
get_full_scholar
,
get_doors_temp_user
from
services.tools
import
mlog
,
REALCONFIG
else
:
from
db
import
connect_db
,
get_full_scholar
from
db
import
connect_db
,
get_full_scholar
,
get_doors_temp_user
from
tools
import
mlog
,
REALCONFIG
# will be exported to main for initialization with app
...
...
@@ -26,21 +27,32 @@ login_manager = LoginManager()
UCACHE
=
{}
@
login_manager
.
user_loader
def
load_user
(
u
id
):
def
load_user
(
mixed
id
):
"""
Used by flask-login to bring back user object from
uid stored in session
Used by flask-login to bring back user object from
a special id stored in session... this special id is defined in User.get_id()
"""
u
=
None
if
uid
in
UCACHE
:
u
=
UCACHE
[
uid
]
mlog
(
"DEBUG"
,
"load_user: user re-loaded by cache"
)
else
:
try
:
u
=
User
(
uid
)
UCACHE
[
uid
]
=
u
mlog
(
"DEBUG"
,
"load_user: user re-loaded from DB"
)
except
Exception
as
err
:
mlog
(
"ERROR"
,
"User(
%
s) init error:"
%
str
(
uid
),
err
)
mlog
(
"DEBUG"
,
"load_user:
%
s"
%
mixedid
)
if
mixedid
is
not
None
:
testluid
=
match
(
'normal/luid:(
\
d+)$'
,
mixedid
)
testduid
=
match
(
'empty/doors:([a-f
\
d-]+)$'
,
mixedid
)
if
testluid
:
luid
=
int
(
testluid
.
groups
()[
0
])
if
luid
in
UCACHE
:
u
=
UCACHE
[
luid
]
mlog
(
"DEBUG"
,
"load_user: normal user re-loaded by cache"
)
else
:
u
=
User
(
luid
)
UCACHE
[
luid
]
=
u
mlog
(
"DEBUG"
,
"load_user: normal user re-loaded from DB"
)
elif
testduid
:
doors_uid
=
testduid
.
groups
()[
0
]
u
=
User
(
None
,
doors_uid
=
doors_uid
)
mlog
(
"DEBUG"
,
"load_user: empty user recreated from doors_uid"
)
return
u
...
...
@@ -68,24 +80,64 @@ def jsonize_uinfo(uinfo_dict):
class
User
(
object
):
def
__init__
(
self
,
uid
):
self
.
uid
=
uid
user_info
=
get_full_scholar
(
uid
)
def
__init__
(
self
,
luid
,
doors_uid
=
None
):
"""
Normal user syntax: User(luid)
(user already in db)
=> has luid
Empty user syntax: User(None, doors_uid=foobar)
(user exists only in
doors but not in db)
=> no luid, but has doors_uid
This also causes trickier behaviour for get_id:
ie load_user() wants a *single id for both*,
which is provided by self.get_id()
"""
mlog
(
'DEBUG'
,
'new User(luid=
%
s, doors_uid="
%
s")'
%
(
str
(
luid
),
str
(
doors_uid
)))
# normal user has a nice info dict
if
luid
is
not
None
:
self
.
uid
=
luid
self
.
info
=
get_full_scholar
(
luid
)
self
.
json_info
=
jsonize_uinfo
(
self
.
info
)
self
.
doors_uid
=
self
.
info
[
'doors_uid'
]
self
.
empty
=
False
if
user_info
is
None
:
# user exists in doors but has nothing in DB yet
# user exists in doors but has nothing in scholars DB yet
elif
doors_uid
is
not
None
:
self
.
uid
=
None
self
.
info
=
{}
self
.
json_info
=
"{}"
self
.
doors_uid
=
doors_uid
self
.
doors_info
=
get_doors_temp_user
(
doors_uid
)
self
.
empty
=
True
else
:
# normal user has a nice info dict
self
.
info
=
user_info
self
.
json_info
=
jsonize_uinfo
(
user_info
)
self
.
empty
=
False
raise
TypeError
(
"User can either be initialized with comex_db luid or with doors_uid"
)
def
get_id
(
self
):
return
str
(
self
.
uid
)
"""
Provides a special ID used only by login_manager
NB double init cases forced us to introduce
here a *single id to load both cases*,
for use later in user_loader
(it's needed because when reloading user, login_manager
will do something like this: u = user_loader(old_u.get_id())
---------------------------
"""
mixedid
=
None
if
self
.
uid
:
mixedid
=
"normal/luid:"
+
str
(
self
.
uid
)
elif
self
.
doors_uid
:
mixedid
=
"empty/doors:"
+
self
.
doors_uid
else
:
raise
ValueError
(
"No IDs for this user flask-login won't refind it"
)
return
mixedid
@
property
def
is_active
(
self
):
...
...
@@ -103,6 +155,7 @@ class User(object):
"""
if
self
.
empty
:
# the user has a doors uid so he's entitled to a login
# and will be directed to the profile page to create his infos
return
True
else
:
# ... or has a record_status in comex_db
...
...
setup/dockers/comex2_mysql_server/init_comex_shared.sql
View file @
8fec9658
...
...
@@ -128,3 +128,11 @@ CREATE TABLE linked_ids(
PRIMARY
KEY
(
linkid
),
FOREIGN
KEY
(
uid
)
REFERENCES
scholars
(
luid
)
ON
DELETE
CASCADE
);
-- separate table for incoming doors users without a profile in scholars
-- (allows us to avoid reasking them for their doors info like email)
CREATE
TABLE
doors_temp_user
(
doors_uid
char
(
36
)
not
null
unique
primary
key
,
email
varchar
(
255
)
not
null
unique
,
INDEX
duid_index_dtempu
(
doors_uid
)
)
;
templates/base_layout.html
View file @
8fec9658
...
...
@@ -152,16 +152,22 @@
<span
class=
"caret"
></span>
</a>
<ul
class=
"dropdown-menu"
>
{% if current_user.info %}
<li>
<a
href=
"/services/user/profile"
>
Your Profile
</a>
</li>
<li>
<a
href=
'/explorerjs.html?type="uid"&nodeidparam="{{ current_user.uid }}"'
>
Your Map
</a>
</li>
<li>
<a
href=
'/print_scholar_directory.php?query={{ current_user.uid }}'
>
Your Neighboor Stats
</a>
</li>
{% if current_user and not current_user.is_anonymous %}
{% if current_user.empty %}
<li>
<a
href=
"/services/user/profile"
>
Create your Profile !
</a>
</li>
{% else %}
<li>
<a
href=
"/services/user/profile"
>
Your Profile
</a>
</li>
<li>
<a
href=
'/explorerjs.html?type="uid"&nodeidparam="{{ current_user.uid }}"'
>
Your Map
</a>
</li>
<li>
<a
href=
'/print_scholar_directory.php?query={{ current_user.uid }}'
>
Your Neighboor Stats
</a>
</li>
{% endif %}
<li>
<a
href=
'/services/user/logout/'
>
Logout
</a>
</li>
...
...
templates/profile.html
View file @
8fec9658
...
...
@@ -22,6 +22,9 @@
<div
id=
"intro"
>
<!-- <h2 class="oldstyle">Your Profile Info</h2> -->
<p
class=
"mini-hero"
>
{% if current_user.empty %}
Welcome to your new empty
<strong>
profile
</strong>
!
{% else %}
Welcome to your profile page,
<strong>
{% if current_user.info.hon_title is not none %}
...
...
@@ -29,6 +32,7 @@
{% endif %}
{{ current_user.info.last_name }}
</strong>
!
{% endif %}
</p>
</div>
...
...
@@ -57,6 +61,7 @@
<!-- CARTE DE VISITE -->
<h3
class=
"formcatfirst"
>
Carte de visite
</h3>
{% if not current_user.empty %}
<div
id=
"information-example"
class=
"our-vcard"
>
<ul>
<!-- TODO if empty then click on image starts showPicImg -->
...
...
@@ -79,8 +84,13 @@
</ul>
<br>
</div>
{% else %}
<p
class=
"mini-hero"
>
Once you'll fill the information below, your "Carte de visite" will appear here.
</p>
{% endif %}
<!--
EMAIL & PASSWORD
-->
<!--
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>
.
...
...
@@ -93,7 +103,7 @@
</label>
<input
id=
"email"
name=
"email"
maxlength=
"255"
readonly
type=
"text"
class=
"form-control readonly"
value=
"{{ current_user.info.email }}"
>
value=
"{{ current_user.
doors_info.email if current_user.empty else current_user.
info.email }}"
>
</div>
</div>
<div
class=
"panel-footer ccsection-footer"
>
</div>
...
...
@@ -256,9 +266,9 @@
<input
id=
"keywords"
name=
"keywords"
maxlength=
"350"
type=
"text"
class=
"form-control autocomp"
placeholder=
"Add a keyword here"
value=
"{{ current_user.info.keywords }}"
>
<div
class=
"input-group-addon operation-dark"
>
<span
class=
"glyphicon glyphicon-plus"
onclick=
"
cmxClt.uform.
mtiPopOneTag['keywords']"
></span>
</div>
<
!-- <
div class="input-group-addon operation-dark">
<span class="glyphicon glyphicon-plus" onclick="
TODO DEPRECATED
mtiPopOneTag['keywords']"></span>
</div>
-->
</div>
<p
class=
"legend"
>
Please enter at least 5 keywords (press TAB or ENTER after each)
</p>
</div>
...
...
@@ -545,7 +555,7 @@
<div
style=
"text-align:center"
>
<!-- @type button to avoid ENTER submit -->
<button
class=
"btn btn-lg btn-success"
id=
"form_submit"
type=
"button"
onclick=
"
cmxClt.uform.the
Form.submit()"
>
type=
"button"
onclick=
"
theUForm.el
Form.submit()"
>
Save profile
</button>
<button
class=
"btn btn-lg btn-warning"
id=
"delete_check"
...
...
@@ -575,7 +585,7 @@
<div
class=
"modal-footer"
>
<button
type=
"button"
class=
"btn btn-secondary"
data-dismiss=
"modal"
>
Cancel
</button>
<button
type=
"button"
class=
"btn btn-primary"
onclick=
"deleteUser.checked=true;
cmxClt.uform.the
Form.submit()"
>
onclick=
"deleteUser.checked=true;
theUForm.el
Form.submit()"
>
Yes delete my data
</button>
</div>
...
...
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