Commit 8fec9658 authored by Romain Loth's avatar Romain Loth

createprofile scenario: for doors users that have nothing in DB yet

parent ea907374
......@@ -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)
) ;
......@@ -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()
This diff is collapsed.
......@@ -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)]))
......@@ -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(uid):
def load_user(mixedid):
"""
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
......
......@@ -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)
) ;
......@@ -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>
......
......@@ -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">&nbsp;</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.theForm.submit()">
type="button" onclick="theUForm.elForm.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.theForm.submit()">
onclick="deleteUser.checked=true;theUForm.elForm.submit()">
Yes delete my data
</button>
</div>
......
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