5from flask
import render_template, flash, redirect, session, request, jsonify, make_response, url_for, Response, Flask
6from flask_limiter
import Limiter
7from flask_limiter.util
import get_remote_address
11from sqlalchemy.orm.session
import make_transient
12from sqlalchemy.orm.attributes
import flag_modified
14from flask_sqlalchemy
import SQLAlchemy
15from sqlalchemy
import func
18from bs4
import BeautifulSoup
21from app
import app, socketio, db
23from app.forms import BuildRegisterForm, BuildLoginForm, Build2FAForm, BuildNewProjectForm, BuildAllProjectSessionForm, BuildOldProjectForm, BuildNewSessionForm, BuildTilesSetForm, BuildEditsessionform, BuildOldTileSetForm, BuildConfigSessionForm, BuildConnectionsForm, BuildRetreiveSessionForm, BuildAdminForm
26from app.email_utils import generate_verification_token, send_verification_email, verify_token, delete_sent_email, generate_verification_code, send_2FAcode_email, send_new_register_email
28import app.models
as models
29import json, os, pprint
38from flask_socketio
import emit, join_room, rooms
39from flask_cors
import CORS
40from flask_cors
import cross_origin
43from werkzeug.utils
import secure_filename
45import sys,re,traceback
49import tempfile, filecmp
55sys.path.append(os.path.abspath(
'../TVDatabase'))
57tvdb.session=db.session
59logging.debug(
"Flask Route start app config : "+str(app.config))
63sys.path.append(os.path.abspath(
'app'))
64from Anatreada
import anatreada
69TVconf=TVrunDir+
"/tiledviz.conf"
71if (os.path.isdir(TVrunDir)):
72 if (os.path.isfile(TVconf)):
76 mode = os.stat(TVrunDir).st_mode
77 mode -= (mode & (stat.S_IRWXG | stat.S_IRWXO))
78 os.chmod(TVrunDir,mode)
81 TVconfig = configparser.ConfigParser()
82 TVconfig.optionxform = str
86 is2FaActivated=json.loads(TVconfig[
'TVWeb'][
'is2FaActivated'].lower())
89 authchoice=json.loads(TVconfig[
'TVWeb'][
'AuthChoice'])
92 timeAlive=int(TVconfig[
'TVWeb'][
'timeAlive'])
95 TimeConnection=int(TVconfig[
'TVWeb'][
'TimeConnection'])
98 really_delete=json.loads(TVconfig[
'TVWeb'][
'really_delete'].lower())
101 LinkExpiredAfterSec=int(TVconfig[
'TVWeb'][
'LinkExpiredAfterSec'])
104 GlobalRateLimit=json.loads(TVconfig[
'TVWeb'][
'GlobalRateLimit'])
107 VulnerableRateLimit=json.loads(TVconfig[
'TVWeb'][
'VulnerableRateLimit'])
126 LinkExpiredAfterSec=240
129 GlobalRateLimit=[
"200 per day",
"50 per hour"]
132 VulnerableRateLimit=
"15/hour;5/minute;1/second"
139 default_limits=GlobalRateLimit,
140 storage_uri=
"memory://",
144valid_roles = [
'owner',
'editor',
'viewer']
145valid_manage_members=[
"owner"]
146valid_manage_project=[
'owner',
'editor']
152logFormatter = logging.Formatter(
"%(asctime)s - %(threadName)s - %(levelname)s: %(message)s ")
153outHandler = logging.StreamHandler(sys.stdout)
154outHandler.setLevel(logging.WARNING)
156outHandler.setFormatter(logFormatter)
159logFIFO=
"/tmp/logfifo"
160if (
not os.path.exists(logFIFO)):
166logfifo=posix.open(logFIFO, posix.O_NONBLOCK)
171 nLOGLEV=re.sub(
r'\n',
r'',posix.read(logfifo,8).decode(
'utf-8'))
172 except Exception
as e:
173 print(
"Erreur LOGLEV")
177 if (LOGLEV==
"WARNING"):
178 logging.warning(mystring)
179 elif (LOGLEV==
"INFO"):
180 logging.info(mystring)
181 elif (LOGLEV==
"DEBUG"):
182 logging.debug(mystring)
183 elif (LOGLEV==
"ERROR"):
184 logging.error(mystring)
186 logging.warning(mystring)
187 print(
"LOGLEV "+LOGLEV)
192cookie_persistence =
False
196tiles_data[
"nodes"]=[]
201usernamel=str(min(20,models.Users.name.type.length))
202sessionl=str(min(60,models.Sessions.name.type.length))
203tilesetl=str(min(80,models.TileSets.name.type.length))
204projectl=str(min(15,models.Projects.name.type.length))
205connectionh=str(min(40,models.Connections.host_address.type.length))
207descrl=str(min(62,models.Projects.description.type.length))
213 __slots__=[
"data",
"iseditor"]
214 def __init__(self,data,iseditor):
225def get_user_id(fun,username):
227 user=db.session.query(models.Users.id).filter_by(name=session[
"username"]).one()
229 flash(fun+
" requested : User must login !")
230 return redirect(url_for(
"login"))
235def get_user_projects(user_id):
237 Get all projects for a user with their roles
238 Returns a list of tuples: (project, role_type)
241 projects_query = db.session.query(
243 models.ProjectMembers.role_type
245 models.ProjectMembers,
246 models.Projects.id == models.ProjectMembers.project_id
248 models.ProjectMembers.user_id == user_id
251 return projects_query.all()
252 except Exception
as e:
253 logging.error(f
"Error getting user projects: {str(e)}")
256def is_project_owner(project_id, user_id):
258 Check if user is owner of the project
261 membership = db.session.query(models.ProjectMembers).filter_by(
262 project_id=project_id,
266 return membership
is not None
267 except Exception
as e:
268 logging.error(f
"Error checking project ownership: {str(e)}")
271def can_manage_project(project_id, user_id):
273 Check if user can manage the project (owner or editor)
276 membership = db.session.query(models.ProjectMembers).filter_by(
277 project_id=project_id,
280 return membership
and membership.role_type
in valid_manage_project
281 except Exception
as e:
282 logging.error(f
"Error checking project management permissions: {str(e)}")
286def can_edit_project(project_id, user_id):
288 Alias helper for edit-level permissions on a project.
289 Editing is allowed for roles: owner, admin, editor.
291 return can_manage_project(project_id, user_id)
292def can_access_project(project_id, user_id):
294 Check if user can access the project (any role including viewer and guest)
297 membership = db.session.query(models.ProjectMembers).filter_by(
298 project_id=project_id,
301 return membership
is not None
302 except Exception
as e:
303 logging.error(f
"Error checking project access permissions: {str(e)}")
306def get_project_members(project_id):
308 Get all members of a project with their details
311 from sqlalchemy.orm
import joinedload
313 members = db.session.query(models.ProjectMembers).options(
314 joinedload(models.ProjectMembers.user)
316 models.ProjectMembers.project_id == project_id
318 models.ProjectMembers.role_type,
319 models.ProjectMembers.user_id
323 except Exception
as e:
324 logging.error(f
"Error getting project members: {str(e)}")
327def add_project_member(project_id, user_id, role_type='viewer'):
329 Add a user as member to a project
333 existing_member = db.session.query(models.ProjectMembers).filter_by(
334 project_id=project_id,
339 return False,
"User is already a member of this project"
342 if role_type
not in valid_roles:
343 return False, f
"Invalid role type. Must be one of: {', '.join(valid_roles)}"
346 new_member = models.ProjectMembers(
347 project_id=project_id,
352 db.session.add(new_member)
355 return True,
"Member added successfully"
357 except Exception
as e:
358 db.session.rollback()
359 logging.error(f
"Error adding project member: {str(e)}")
360 return False, f
"Error adding member: {str(e)}"
362def remove_project_member(project_id, user_id):
364 Remove a user from a project
367 member = db.session.query(models.ProjectMembers).filter_by(
368 project_id=project_id,
373 return False,
"User is not a member of this project"
376 if member.role_type ==
'owner':
377 owner_count = db.session.query(models.ProjectMembers).filter_by(
378 project_id=project_id,
383 return False,
"Cannot remove the last owner of a project"
385 db.session.delete(member)
388 return True,
"Member removed successfully"
390 except Exception
as e:
391 db.session.rollback()
392 logging.error(f
"Error removing project member: {str(e)}")
393 return False, f
"Error removing member: {str(e)}"
395def update_member_role(project_id, user_id, new_role):
397 Update a member's role in a project
400 member = db.session.query(models.ProjectMembers).filter_by(
401 project_id=project_id,
406 return False,
"User is not a member of this project"
409 if new_role
not in valid_roles:
410 return False, f
"Invalid role type. Must be one of: {', '.join(valid_roles)}"
413 if member.role_type ==
'owner' and new_role !=
'owner':
414 owner_count = db.session.query(models.ProjectMembers).filter_by(
415 project_id=project_id,
420 return False,
"Cannot change role of the last owner"
422 member.role_type = new_role
425 return True,
"Member role updated successfully"
427 except Exception
as e:
428 db.session.rollback()
429 logging.error(f
"Error updating member role: {str(e)}")
430 return False, f
"Error updating role: {str(e)}"
432def transfer_project_ownership(project_id, current_user_id, new_owner_id):
434 Transfer project ownership to another user
438 if not is_project_owner(project_id, current_user_id):
439 return False,
"Only the project owner can transfer ownership"
442 new_owner = db.session.query(models.Users).filter_by(id=new_owner_id).first()
444 return False,
"New owner user not found"
447 new_owner_membership = db.session.query(models.ProjectMembers).filter_by(
448 project_id=project_id,
452 if not new_owner_membership:
453 return False,
"The new owner must be a member of the project first"
456 if current_user_id == new_owner_id:
457 return False,
"Cannot transfer ownership to yourself"
460 if new_owner_membership.role_type ==
'owner':
461 return False,
"The selected user is already an owner of this project"
464 current_user_membership = db.session.query(models.ProjectMembers).filter_by(
465 project_id=project_id,
466 user_id=current_user_id
469 new_owner_membership.role_type =
'owner'
472 project = db.session.query(models.Projects).filter_by(id=project_id).first()
474 project.id_users = new_owner_id
478 return True,
"Ownership transferred successfully"
480 except Exception
as e:
481 db.session.rollback()
482 logging.error(f
"Error transferring ownership: {str(e)}")
483 return False, f
"Error transferring ownership: {str(e)}"
485def get_available_users_for_project(project_id):
487 Get users who are not yet members of the project
491 current_member_ids = db.session.query(models.ProjectMembers.user_id).filter_by(
492 project_id=project_id
500 available_users = db.session.query(models.Users).filter(
501 ~models.Users.id.in_(current_member_ids)
502 ).order_by(models.Users.name).all()
504 return available_users
505 except Exception
as e:
506 logging.error(f
"Error getting available users: {str(e)}")
509def sync_user_to_project_and_session(user_id, project_id, session_id, role_type='guest'):
511 Synchronize user membership between project and session
512 - Add user to project_members if not already a member
513 - Add user to many_users_has_many_sessions if not already in session
517 existing_member = db.session.query(models.ProjectMembers).filter_by(
518 project_id=project_id,
522 if not existing_member:
524 new_member = models.ProjectMembers(
525 project_id=project_id,
529 db.session.add(new_member)
530 logging.info(f
"Added user {user_id} as {role_type} to project {project_id}")
533 existing_session_user = db.session.query(models.t_many_users_has_many_sessions).filter_by(
535 id_sessions=session_id
538 if not existing_session_user:
540 session_user = models.t_many_users_has_many_sessions.insert().values(
542 id_sessions=session_id
544 db.session.execute(session_user)
545 logging.info(f
"Added user {user_id} to session {session_id}")
548 return True,
"User synchronized successfully"
550 except Exception
as e:
551 db.session.rollback()
552 logging.error(f
"Error synchronizing user to project and session: {str(e)}")
553 return False, f
"Error synchronizing user: {str(e)}"
555def validate_session_project_consistency(session_id):
557 Validate that all users in a session are members of the project
558 Returns list of inconsistencies found
562 session_obj = db.session.query(models.Sessions).filter_by(id=session_id).first()
564 return [f
"Session {session_id} not found"]
566 project_id = session_obj.id_projects
568 return [f
"Session {session_id} has no associated project"]
571 session_users = db.session.query(models.t_many_users_has_many_sessions).filter_by(
572 id_sessions=session_id
577 for session_user
in session_users:
578 user_id = session_user.id_users
581 is_project_member = db.session.query(models.ProjectMembers).filter_by(
582 project_id=project_id,
586 if not is_project_member:
587 user = db.session.query(models.Users).filter_by(id=user_id).first()
588 user_name = user.name
if user
else f
"User ID {user_id}"
589 inconsistencies.append(f
"User {user_name} (ID: {user_id}) is in session but not a project member")
591 return inconsistencies
593 except Exception
as e:
594 logging.error(f
"Error validating session-project consistency: {str(e)}")
595 return [f
"Error during validation: {str(e)}"]
597def fix_session_project_inconsistencies(session_id, default_role='guest'):
599 Fix inconsistencies by adding session users as project members with default role
602 inconsistencies = validate_session_project_consistency(session_id)
603 if not inconsistencies:
604 return True,
"No inconsistencies found"
607 session_obj = db.session.query(models.Sessions).filter_by(id=session_id).first()
608 project_id = session_obj.id_projects
611 for inconsistency
in inconsistencies:
612 if "is in session but not a project member" in inconsistency:
615 match = re.search(
r'User .+ \(ID: (\d+)\)', inconsistency)
617 user_id = int(match.group(1))
620 new_member = models.ProjectMembers(
621 project_id=project_id,
623 role_type=default_role
625 db.session.add(new_member)
630 return True, f
"Fixed {fixed_count} inconsistencies by adding users as project members"
632 return False,
"No inconsistencies could be automatically fixed"
634 except Exception
as e:
635 db.session.rollback()
636 logging.error(f
"Error fixing session-project inconsistencies: {str(e)}")
637 return False, f
"Error fixing inconsistencies: {str(e)}"
639def role_project(oldproject,user_obj):
640 membership = db.session.query(models.ProjectMembers).filter_by(
641 project_id=oldproject.id, user_id=user_obj.id
642 ).first()
if user_obj
and oldproject
else None
643 role_type = membership.role_type
if membership
else None
644 can_manage_members = role_type
in valid_manage_members
645 can_edit_session = role_type
in valid_manage_project
646 return can_edit_session, can_manage_members, role_type, membership
648def role_session(oldsession,user_obj):
649 membership = db.session.query(models.ProjectMembers).filter_by(
650 project_id=oldsession.id_projects, user_id=user_obj.id
651 ).first()
if user_obj
and oldsession
else None
652 role_type = membership.role_type
if membership
else None
653 can_manage_members = role_type
in valid_manage_members
654 can_edit_session = role_type
in valid_manage_project
655 return can_edit_session, can_manage_members, role_type, membership
657def can_create_invite_links(user_id, project_id):
659 Check if a user can create invitation links for a project
660 Returns (can_create, reason)
664 membership = db.session.query(models.ProjectMembers).filter_by(
665 project_id=project_id,
670 return False,
"User is not a project member"
673 if membership.role_type
in valid_manage_members:
674 return True, f
"User has {membership.role_type} role"
676 return False, f
"Role '{membership.role_type}' cannot create invitation links"
678 except Exception
as e:
679 logging.error(f
"Error checking invite permissions: {str(e)}")
680 return False, f
"Error checking permissions: {str(e)}"
683def copy_users_session(newsession,oldusers):
684 if ( len(oldusers) > 0 ):
686 for newuser
in oldusers:
687 thisuserq=db.session.query(models.Users).filter_by(name=newuser.data)
688 userexists=db.session.query(thisuserq.exists())
689 if userexists.first():
690 user=thisuserq.first()
692 if (user
not in newsession.users):
693 logging.debug(
"This user not in the list : {}. We add her.him.".format(user.name))
694 newsession.users.append(user)
697 iseditor=newuser.iseditor
698 projectsession=newsession.projects
699 projectmembers=db.session.query(models.ProjectMembers).filter_by(project_id=projectsession.id).all()
700 a_member=db.session.query(models.ProjectMembers).filter_by(project_id=projectsession.id,user_id=user.id)
701 is_already_a_member=a_member.count()
702 if (is_already_a_member == 1
and iseditor):
703 hisrole=a_member[0].role_type
704 if (
not (hisrole==
'owner' or hisrole==
'editor')):
705 logging.debug(
"For project %s %d user %s's role %s will be upgrading for editor."
706 % (projectsession.name,projectsession.id,user.name,hisrole))
707 a_member[0].role_type=
"editor"
709 elif (is_already_a_member == 0):
714 new_member = models.ProjectMembers(
715 project_id=projectsession.id,
719 logging.warning(
"For project %s %d user %s will be added as project member with role %s"
720 % (projectsession.name,projectsession.id,user.name,hisrole))
721 db.session.add(new_member)
724 errorstr=
"This user doesn't exists : {}. We can't add him.".format(newuser.data)
726 logging.warning(errorstr)
729def create_newsession(sessionname, description, projectid, oldusers):
730 creation_date=datetime.datetime.now()
731 newsession = models.Sessions(name=str(sessionname),
732 description=str(description),
733 id_projects=projectid,
734 creation_date=creation_date)
736 exist=db.session.query(models.Sessions.id).filter(models.Sessions.name.like(sessionname)).first()
is not None
739 lastsession=db.session.query(models.Sessions.id).order_by(models.Sessions.id.desc()).first()
741 newsession.id=lastsession.id+1
745 copy_users_session(newsession,oldusers)
749 inconsistencies = validate_session_project_consistency(newsession.id)
751 logging.warning(f
"Found inconsistencies in newly created session {newsession.name}: {inconsistencies}")
753 fix_success, fix_message = fix_session_project_inconsistencies(newsession.id, default_role=
'viewer')
755 logging.info(f
"Fixed session inconsistencies: {fix_message}")
757 logging.error(f
"Failed to fix session inconsistencies: {fix_message}")
759 newsession=db.session.query(models.Sessions).filter(models.Sessions.name.like(sessionname)).one()
761 session[
"sessionname"]=str(sessionname)
763 return newsession,exist
766def create_newtileset(tilesetname, thesession, type_of_tiles, datapath, creation_date):
767 newtileset = models.TileSets(name=tilesetname,
768 type_of_tiles = type_of_tiles,
769 Dataset_path = datapath,
770 creation_date=creation_date)
772 exist=db.session.query(models.TileSets.id).filter_by(name=tilesetname).scalar()
is not None
776 lasttileset=db.session.query(models.TileSets.id).order_by(models.TileSets.id.desc()).first()
778 newtileset.id=lasttileset.id+1
782 thesession.tile_sets.append(newtileset)
785 newtileset=db.session.query(models.TileSets).filter_by(name=tilesetname).one()
786 return newtileset,exist
789def convertTile(Mynode,tilesetname,connectionbool,urlbool,datapath):
792 except Keyerror
as e:
793 traceback.print_exc(file=sys.stderr)
797 if (urlbool
and len(datapath) > 0):
799 searchPath=re.search(
r''+datapath,url)
802 url=datapath+Mynode[
"url"]
803 elif (connectionbool):
804 searchPort=re.search(
r'port=\d+',url)
806 ConnectionPort=int(searchPort.group().replace(
'port=',
''))
808 title=Mynode[
"title"]
818 comment=Mynode[
"comment"]
824 searchtsn=re.search(
r''+tilesetname,str(Mynode[
"tags"]))
826 if (type(Mynode[
"tags"]) ==
'str'):
827 tags=[tilesetname,Mynode[
"tags"]]
829 tags=[tilesetname]+Mynode[
"tags"]
839 variable=Mynode[
"variable"]
846 pos_px_x=Mynode[
"pos_px_x"]
847 pos_px_y=Mynode[
"pos_px_y"]
853 IdLocation=Mynode[
"IdLocation"]
857 return title,name,comment,tags,variable,pos_px_x,pos_px_y,IdLocation,url,ConnectionPort
862def copy_connection(oldtileset,newtileset,newsessionname):
863 oldconnection=oldtileset.connections
864 user_id=get_user_id(
"copy_connection",session[
"username"])
866 message =
'{"oldtilesetid":'+str(newtileset.id)+
',"oldsessionname":"'+session[
"sessionname"]+
'"}'
869 if (oldconnection.id ==
None ):
872 idconnection=oldconnection.id
873 if (
not "connection"+str(idconnection)
in session):
874 flash(
"You must use createconnection button after have given job script file and configuration files or tarball.")
875 logging.error(
"You (user "+str(user_id)+
") don't have connection information in your personal cookie for this connection : "+str(idconnection))
879 if (user_id != oldconnection.id_users) :
880 flash(
"You can not access to this connection. You are not its owner.")
881 owner=db.session.query(models.Users).filter_by(id=oldconnection.id_users).one().name
882 you=db.session.query(models.Users).filter_by(id=user_id).one().name
883 logging.error(
"You (user "+you+
") can not access to this connection owned by user "+owner)
884 return redirect(url_for(
".edittileset",message=message))
886 creation_date=datetime.datetime.now()
887 newconnection = models.Connections(host_address=oldconnection.host_address,
888 auth_type=oldconnection.auth_type,
889 container=oldconnection.container,
890 scheduler=oldconnection.scheduler,
891 scheduler_file=oldconnection.scheduler_file,
893 creation_date= creation_date)
895 lastconnection=db.session.query(models.Connections.id).order_by(models.Connections.id.desc()).first()
896 if ( lastconnection ):
897 newconnection.id=lastconnection.id+1
900 db.session.add(newconnection)
903 user_path=os.path.join(
"/TiledViz/TVFiles",str(user_id))
904 olddir=os.path.join(user_path,str(idconnection))
905 newdir=os.path.join(user_path,str(newconnection.id))
906 os.system(
"mkdir "+newdir)
909 for key
in oldconnection.config_files:
910 filetmp=oldconnection.config_files[key]
911 newtmp=filetmp.replace(olddir,newdir)
912 os.system(
"cp "+filetmp+
" "+newtmp)
913 config_files[key]=newtmp
915 newconnection.config_files=config_files
916 flag_modified(newconnection,
"config_files")
917 newconnection.scheduler_file=oldconnection.scheduler_file
918 newtileset.id_connections=newconnection.id
921 vnctransfert=json.loads(session[
"connection"+str(idconnection)])
922 vncpassword=vnctransfert[
"vncpassword"]
923 session[
"connection"+str(newconnection.id)]=
' {"callfunction":"edittileset",'+
'"args":{"oldsessionname":"'+newsessionname+
'","oldtilesetid":"'+str(newtileset.id)+
'"}, "vncpassword":"'+vncpassword+
'"}'
928def copy_tileset_connection(tileset,tileset1,sessionname ):
929 oldconnection=tileset.connections
931 copy_connection(tileset,tileset1,sessionname)
932 user_id=get_user_id(
"copy_tileset_connection",session[
"username"])
933 user_path=os.path.join(
"/TiledViz/TVFiles",str(user_id))
934 olddir=os.path.join(user_path,str(tileset.id_connections))
935 newdir=os.path.join(user_path,str(tileset1.id_connections))
938 for key
in tileset.config_files:
939 filetmp=tileset.config_files[key]
940 newtmp=filetmp.replace(olddir,newdir)
941 os.system(
"cp "+filetmp+
" "+newtmp)
942 config_files[key]=newtmp
944 tileset1.config_files=config_files
945 tileset1.launch_file=tileset.launch_file
949def launch_connection(theTS, theConnect, myhost_address, myauth_type, mycontainer, myscheduler):
951 logging.warning(
"editconnection: "
952 +str(session[
"username"])+
" ; "
953 +str(myhost_address)+
" ; "
954 +str(myauth_type)+
" ; "
955 +str(mycontainer)+
" ; "
956 +str(myscheduler)+
" ; "
963 passpath=
"/home/connect"+str(theConnect.id)+
"/vncpassword"
964 logging.warning(
"Go to vnc with path "+passpath)
968 if (count > NbTimeAlive):
969 strerror=
"Connection has never been reach. Go back to TileSet."
970 logging.error(strerror)
972 message =
'{"oldtilesetid": "'+str(theTS.id)+
'"}'
973 logging.warning(strerror+
" message "+message)
974 return redirect(url_for(
".edittileset",message=message))
976 logging.debug(
"count = "+str(count))
979 time.sleep(timeAlive)
981 if (os.path.isfile(passpath)):
982 with open(passpath,
'r')
as f:
983 vncpassword=re.sub(
r'\n',
r'',f.read())
985 logging.debug(
"and password : "+vncpassword)
987 logging.error(
"File not found in connection container "+passpath)
990 message =
'{"oldtilesetid":'+str(theTS.id)+
',"connectionid":'+str(theConnect.id)+
',"sessionname":"'+session[
"sessionname"]+
'"}'
991 session[
"connection"+str(theConnect.id)]=
' {"callfunction":"edittileset",'+
'"args":{"oldsessionname":"'+str(session[
"sessionname"])+
'","oldtilesetid":"'+str(theTS.id)+
'"}, "vncpassword":"'+vncpassword+
'"}'
993 logging.warning(
"editconnection in session : "+str(session[
"connection"+str(theConnect.id)])+
" message :"+str(message))
998 traceback.print_exc(file=sys.stderr)
1002def save_session(oldsessionname, newsuffix, newdescription, alltiles):
1003 creation_date=datetime.datetime.now()
1004 oldsession=db.session.query(models.Sessions).filter(models.Sessions.name.like(oldsessionname)).one()
1005 projectid=oldsession.id_projects
1009 newsessionname=session[
"sessionname"]+
'_'+newsuffix
1010 newsession = models.Sessions(name=newsessionname,
1011 description=newdescription,
1012 id_projects=projectid,
1013 creation_date=creation_date)
1014 lastsession=db.session.query(models.Sessions.id).order_by(models.Sessions.id.desc()).first()
1016 newsession.id=lastsession.id+1
1021 oldusers=oldsession.users
1022 for user
in oldusers:
1024 sync_success, sync_message = sync_user_to_project_and_session(
1026 project_id=newsession.id_projects,
1027 session_id=newsession.id,
1030 if not sync_success:
1031 logging.warning(f
"Failed to sync user {user.name} to copied session {newsession.name}: {sync_message}")
1033 logging.info(f
"Successfully synced user {user.name} to copied session {newsession.name}")
1035 newsession.config = oldsession.config
1036 flag_modified(newsession,
"config")
1040 inconsistencies = validate_session_project_consistency(newsession.id)
1042 logging.warning(f
"Found inconsistencies in copied session {newsession.name}: {inconsistencies}")
1044 fix_success, fix_message = fix_session_project_inconsistencies(newsession.id, default_role=
'viewer')
1046 logging.info(f
"Fixed copied session inconsistencies: {fix_message}")
1048 logging.error(f
"Failed to fix copied session inconsistencies: {fix_message}")
1050 logging.warning(
"All tilesets :"+str([ ts.name
for ts
in oldsession.tile_sets]))
1052 alltilesjson = alltiles[
"nodes"]
1053 for tileset
in oldsession.tile_sets:
1055 tilesetname=tileset.name
1056 logging.debug(
"copy tileset from :"+tileset.name)
1059 connectionbool=
False
1060 if (tileset.type_of_tiles ==
"URL"):
1062 elif(tileset.type_of_tiles ==
"CONNECTION"):
1066 datapath=tileset.Dataset_path
1067 tileset1,exist=create_newtileset(tilesetname+
'_'+newsuffix, newsession,
1068 tileset.type_of_tiles, datapath, creation_date)
1070 if (connectionbool):
1072 logging.error(
"copy config data :"+tileset.launch_file+
" "+str(tileset.config_files))
1074 copy_tileset_connection(tileset,tileset1,newsession.name)
1075 if (tileset1.connection):
1076 logging.error(
"copy id connection : "+str(tileset1.id_connections))
1078 logging.error(
"copy config data 1 :"+tileset1.launch_file+
" "+str(tileset1.config_files))
1083 db.session.add(tileset1)
1086 traceback.print_exc(file=sys.stderr)
1087 logging.warning(
"add tileset1 :"+tileset1.name)
1089 for tile
in tileset.tiles:
1091 i=next(i
for i, item
in enumerate(alltilesjson)
if (item[
"title"] == tile.title))
1092 except StopIteration:
1094 logging.debug(
"new tile :"+tile.title+
" i "+str(i))
1096 Mynode=alltilesjson[i]
1098 title,name,comment,tags,variable,pos_px_x,pos_px_y,IdLocation,url,ConnectionPort = \
1099 convertTile(Mynode,tilesetname,connectionbool,urlbool,datapath)
1101 tile.source= {
"name" : name,
1102 "connection" : ConnectionPort,
1104 "variable": variable}
1105 flag_modified(tile,
"source")
1106 tile.pos_px_x= pos_px_x
1107 tile.pos_px_y= pos_px_y
1108 tile.IdLocation=IdLocation
1109 tileset1.tiles.append(tile)
1114 newsession.config = oldsession.config
1118def delelement(thistable, chosenElement, elementid):
1119 thiselement=db.session.query(thistable).filter_by(id=elementid)
1120 logging.warning(
"Delete this %s %d : %s" % (chosenElement,elementid,str(thiselement)))
1122 thiselement.delete()
1124def remove_this_session(sessionid):
1125 thissession=db.session.query(models.Sessions).filter_by(id=sessionid).scalar()
1127 for ts
in thissession.tile_sets:
1128 thissession.tile_sets.remove(ts)
1130 logging.warning(
'in remove_this_session All users :'+str(thissession.users))
1131 logging.warning(
"in remove_this_session Link "+str(db.session.query(models.t_many_users_has_many_sessions).filter_by(id_sessions=sessionid).all()))
1132 for us
in thissession.users:
1133 thissession.users.remove(us)
1135 logging.warning(
'in remove_this_session All users after commit :'+str(thissession.users))
1137 logging.warning(
"in remove_this_session Link after commit "+str(db.session.query(models.t_many_users_has_many_sessions).filter_by(id_sessions=sessionid).all()))
1138 for link
in db.session.query(models.t_many_users_has_many_sessions).filter_by(id_sessions=sessionid).all():
1140 delelement(models.Sessions,
"session", sessionid)
1144def remove_this_project(projectid):
1146 Remove a project and all its associated data
1149 thisproject = db.session.query(models.Projects).filter_by(id=projectid).first()
1151 logging.warning(f
"Project {projectid} not found for deletion")
1155 project_sessions = db.session.query(models.Sessions).filter_by(id_projects=projectid).all()
1156 for thissession
in project_sessions:
1157 remove_this_session(thissession.id)
1160 db.session.query(models.ProjectMembers).filter_by(project_id=projectid).delete()
1163 delelement(models.Projects,
"project", projectid)
1166 logging.info(f
"Project {projectid} and all associated data removed successfully")
1169 except Exception
as e:
1170 db.session.rollback()
1171 logging.error(f
"Error removing project {projectid}: {str(e)}")
1174def remove_this_user(userid):
1175 thisuser=db.session.query(models.Users).filter_by(id=userid).one()
1178 user_connections=db.session.query(models.Connections).filter_by(id_users=userid).all()
1179 for thisconnection
in user_connections:
1182 flash(
"Suppress element connection number %d." % (thisconnection.id))
1183 delelement(models.Connections,
"connection", thisconnection.id)
1186 user_session=db.session.query(models.Sessions).filter(models.Sessions.users.any(id=userid)).all()
1187 for thissession
in user_session:
1188 thissession.users.remove(thisuser)
1192 user_project=db.session.query(models.Projects).filter_by(id_users=userid).all()
1193 for thisproject
in user_project:
1194 remove_this_project(thisproject.id)
1196 delelement(models.Users,
"user", userid)
1198def remove_this_connection(oldtileset,idconnection,user_id):
1199 oldconnection=oldtileset.connections
1200 oldtilesetid=oldtileset.id
1201 logging.warning(
"Remove connection of tileset %d" % (oldtilesetid))
1203 if (oldconnection.id != idconnection):
1204 logging.error(
"id %d to be removed is not this tileset %d id %d." % (idconnection, oldtilesetid, oldconnection.id))
1207 user_path=os.path.join(
"/TiledViz/TVFiles",str(user_id))
1208 connectionpath=os.path.join(user_path,str(idconnection))
1210 for (dirpath, dirname, filelist)
in os.walk(connectionpath):
1211 for filename
in filelist:
1212 strrm=
"rm -f "+os.path.join(dirpath,filename)
1214 logging.warning(
"Remove file for tileset "+oldtileset.name+
" : "+os.path.join(dirpath,filename))
1216 logging.warning(
"Remove dir for tileset "+oldtileset.name+
" : "+dirpath)
1218 oldtileset.id_connections=
None
1220 oldtileset.config_files=
""
1221 flag_modified(oldtileset,
"config_files")
1222 oldconnection.config_files=
""
1223 flag_modified(oldconnection,
"config_files")
1224 logging.warning(
"removeconnection: "
1225 +str(session[
"username"])+
" ; "
1226 +str(oldtilesetid)+
" ; "
1231 session[
"connection"+str(idconnection)]=
""
1232 del(session[
"connection"+str(idconnection)])
1236 myargs[
"notlogin"]=
True
1237 myargs[
"username"]=
""
1238 if (
"username" in session):
1239 myargs[
"username"]=session[
"username"]
1240 if (session[
"username"]!=
"Anonymous"):
1241 myargs[
"notlogin"]=
False
1243 User=db.session.query(models.Users).filter_by(name=session[
"username"]).one_or_none()
1247 logging.warning(f
"User '{session['username']}' in session doesn't exist in database. Clearing session.")
1248 session.pop(
"username",
None)
1249 session.pop(
"is_client_active",
None)
1250 myargs[
"username"]=
"Anonymous"
1251 myargs[
"notlogin"]=
True
1254 userAdmin=User.is_admin
1259 myargs[
"isadmin"]=userAdmin
1264@app.route('/', methods=['GET', 'POST'])
1265@app.route('/index', methods=['GET', 'POST'])
1266@app.route('/home', methods=['GET', 'POST'])
1271 user = {
"username" : session[
"username"] }
1273 user = {
"username" :
"Anonymous"}
1274 session[
"username"]=
"Anonymous"
1275 if (session[
"username"] !=
"Anonymous"):
1276 session[
"is_client_active"]=
True
1277 if (
"projectname" in session ):
1278 project = session[
"projectname"]
1281 if (
"sessionname" in session ):
1282 psession = session[
"sessionname"]
1285 except KeyError
as e:
1286 logging.error(
"Home error : "+e)
1288 project =
"noproject"
1289 psession =
"nosession"
1290 session[
"username"]=
"Anonymous"
1291 user = {
"username" : session[
"username"] }
1292 session[
"projectname"]=project
1293 session[
"sessionname"]=psession
1294 session[
"is_client_active"]=
False
1296 return render_template(
"main_template.html", **(myrender()), title=
"TiledViz home", user=user, project=project, session=psession)
1301@app.route('/register', methods=["GET", "POST"])
1302@limiter.limit(VulnerableRateLimit, methods=["POST"])
1308 if (
"username" in session):
1309 if (session[
"username"] ==
"Anonymous"):
1310 myform = BuildRegisterForm()()
1312 User=db.session.query(models.Users).filter_by(name=session[
"username"]).one()
1313 myform = BuildRegisterForm(Username=User.name,
1314 Useremail=User.mail,
1315 Usercomp=User.compagny,
1316 Usermanager=User.manager
1319 myform = BuildRegisterForm()()
1321 if myform.validate_on_submit():
1322 logging.warning(
"Register new user.")
1323 myusername = myform.username.data
1329 exists = db.session.query(models.Users.id).filter_by(name=myusername).scalar()
is not None
1334 flash(
"Known user {}, remember_me={}".format(myform.username.data, myform.remember_me.data))
1336 return render_template(
"main_login.html", **(myrender()), title=
"TiledViz register", form=myform)
1337 logging.warning(
"username already exists.")
1339 if (myform.newpassword.data):
1340 if (
"username" in session):
1341 if (session[
"username"] ==
"Anonymous"):
1342 flash(
"You can't change password if you are connected as Anonymous.")
1343 logging.warning(
"You can't change password if you are connected as Anonymous.")
1344 return redirect(
"/login")
1346 flash(
"You can't change password if you are not connected : User must login !")
1347 logging.warning(
"You can't change password if you are not connected : User must login !")
1348 return redirect(
"/login")
1350 logging.warning(
"Renew password for user {}.".format(myusername))
1351 User=db.session.query(models.Users).filter_by(name=myusername).one()
1352 hashpass, salt=tvdb.passprotected(myform.password.data)
1353 creation_date=datetime.datetime.now()
1354 User.creation_date=str(creation_date)
1356 User.password=hashpass
1357 User.dateverified=str(creation_date)
1361 hashPassword,hashSalt=db.session.query(models.Users.password,models.Users.salt).filter_by(name=myusername)
1362 testP=tvdb.testpassprotected(models.Users,myusername,myform.password.data,hashPassword,hashSalt)
1364 logging.info(
"Correct password !")
1365 session[
"username"] = myusername
1366 session[
"is_client_active"]=
True
1367 user_id=get_user_id(
"login",session[
"username"])
1369 flash(Markup(
"Correct Login for user {} remember_me={}".format(myform.username.data, myform.remember_me.data)))
1371 return render_template(
"main_login.html", **(myrender()), title=
"TiledViz register", form=myform)
1372 user = {
"username" : session[
"username"] }
1373 session[
"is_client_active"]=
True
1376 flash(
"You have entered an already existing username, but wrong password for user {}".format(myform.username.data))
1378 return render_template(
"main_login.html", **(myrender()), title=
"TiledViz register", form=myform)
1380 flash(
"This username {} already exists and passwd is incorrect : ".format(session[
"username"]))
1381 return render_template(
"main_login.html", **(myrender()),
1382 title=
"TiledViz register",
1385 hashpass, salt=tvdb.passprotected(myform.password.data)
1387 creation_date=datetime.datetime.now()
1390 user = models.Users(name=str(myusername),
1391 creation_date=str(creation_date),
1392 mail=str(myform.email.data),
1393 compagny=str(myform.compagny.data),
1394 manager=str(myform.manager.data),
1397 dateverified=str(creation_date),
1400 db.session.add(user)
1402 logging.warning(
"Commit new user.")
1408 token = generate_verification_token(user_id)
1410 email_sent = send_verification_email(
1411 user_email=myform.email.data,
1412 username=myusername,
1418 admin_records = db.session.query(models.Users.mail).filter_by(is_admin=
True).all()
1419 admin_emails = [record.mail
for record
in admin_records
if record.mail]
1422 logging.info(f
"Sending registration alert to {len(admin_emails)} admins.")
1423 send_new_register_email(
1424 admin_emails=admin_emails,
1425 username=str(myusername),
1426 creation_date=str(creation_date),
1427 user_email=str(myform.email.data),
1428 user_company=str(myform.compagny.data),
1429 user_manager=str(myform.manager.data)
1431 except Exception
as e:
1432 logging.error(f
"Failed to fetch admins or send admin notification: {e}")
1435 logging.warning(
"Verification email sent to {}".format(myform.email.data))
1436 flash(
"Registration successful! Please check your email and click the verification link to activate your account.")
1439 db.session.delete(user)
1441 logging.error(
"Failed to send verification email to {}. User deleted.".format(myform.email.data))
1442 flash(
"Registration failed: Unable to send verification email. Please check your email address and try again.")
1443 return render_template(
"main_login.html", **(myrender()),
1444 title=
"TiledViz register",
1450 user.is_verified=
True
1452 logging.warning(
"New user is Admin and auto-verified.")
1454 session[
"username"] = myusername
1455 session[
"is_client_active"]=
True
1458 logging.info(
"New user {} needs to verify email before login.".format(myusername))
1461 user.is_verified =
True
1463 user.is_admin =
True
1465 logging.warning(f
"New user {myusername} registered and auto-verified without email (is2FaActivated=False).")
1467 session[
"username"] = myusername
1468 session[
"is_client_active"] =
True
1469 flash(
"Registration successful! You are now logged in.")
1470 cookie_persistence = myform.remember_me.data
1471 logging.warning(
"[!] Cookie persistence set to %s" % (str(cookie_persistence)))
1474 logging.debug(
"Project Choice :"+myform.choice_project.data)
1477 if "username" in session
and session[
"username"] !=
"Anonymous":
1478 if(myform.choice_project.data ==
"create"):
1479 logging.info(
"Go to create new project for user "+session[
"username"]+
".")
1480 return redirect(
"/project")
1483 return redirect(
"/allsessions")
1485 logging.info(
"New user "+session[
"username"]+
" : create a new project or ask for invite_link.")
1486 flash(
"New user {} registred : please create a new project or ask another user for an invite_link.".format(session[
"username"]))
1488 return render_template(
"main_login.html", **(myrender()),
1489 title=
"TiledViz register",
1492 return redirect(
"/allsessions")
1496 flash(
"Please login as {} avec have clicked on received email on {}.".format(myform.username.data,myform.email.data))
1497 return redirect(
"/login")
1498 return render_template(
"main_login.html", **(myrender()), title=
"TiledViz register", form=myform)
1501@app.route('/login', methods=["GET", "POST"])
1502@limiter.limit(VulnerableRateLimit, methods=["POST"])
1504 if (
"username" not in session):
1505 session[
"username"] =
"Anonymous"
1506 if (
"username" in session):
1507 if (session[
"username"] ==
"Anonymous"):
1510 User = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
1512 exists = User.id
is not None
1513 logging.error(f
"User already connected with username {session['username']}.")
1517 if not User.is_verified:
1518 flash(
"Your email address has not been verified yet. Please check your email and click the verification link.")
1519 return render_template(
"main_login.html", **(myrender()), title=
"TiledViz login", form=myform)
1521 hashPassword = User.password
1522 hashSalt = User.salt
1524 myform = BuildLoginForm(session)()
1525 myusername = myform.username.data
if hasattr(myform,
'username')
else session[
"username"]
1526 if (myusername != str(session[
"username"])):
1527 flash(f
"User already connected with username {session['username']} but one tried to login as different user {myusername}.\n"+\
1528 +
"Please logout before login as another user.")
1529 logging.error(f
"User already connected with username {session['username']} but one tried to login as user {myusername}.")
1530 session.pop(
'username',
None)
1531 session.pop(
"is_client_active")
1532 return redirect(url_for(
'index'))
1535 logging.error(f
"User {session['username']} already connected.")
1536 flash(
"Your were already connected.")
1537 return redirect(
"/allsessions")
1539 myform = BuildLoginForm(session)()
1540 if myform.validate_on_submit():
1541 myusername = myform.username.data
1542 mypassword = myform.password.data
1543 user = db.session.query(models.Users).filter_by(name=myusername).first()
1546 if not user.is_verified:
1548 flash(
"Your email address has not been verified yet. Please check your email and click the verification link.")
1549 return render_template(
"main_login.html", **(myrender()), title=
"TiledViz login", form=myform)
1551 user.is_verified =
True
1554 if tvdb.testpassprotected(models.Users, myusername, mypassword, user.password, user.salt):
1555 logging.info(
'Correct password.')
1559 code = generate_verification_code()
1560 email_sent = send_2FAcode_email(
1561 user_email=user.mail,
1562 username=myusername,
1566 expiration_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=360)
1567 codes2FA[myusername]={
"code":code,
"expiration_time":expiration_time}
1569 strerror=f
"We have sent you a security code on your mail. Please check your inbox before UTC {expiration_time}."
1571 message =
'{"username": "'+myusername+
'", '+\
1572 '"newuser": "'+str(myform.newuser.data)+
'", "choice_project": "'+myform.choice_project.data+
'"}'
1573 logging.info(strerror+
" message "+message)
1574 logging.warning(f
"User {myusername} try to connect.")
1575 return redirect(url_for(
".check2FA",message=message))
1577 session[
"username"] = myusername
1578 session[
"is_client_active"] =
True
1580 logging.warning(f
"User {myusername} has loggined without 2FA.")
1582 if (str(myform.newuser.data) ==
"True"):
1583 return redirect(
"/register")
1586 if "pending_invite_link" in session:
1587 link = session.pop(
"pending_invite_link")
1588 return redirect(url_for(
".handle_join_with_invite_link", link=link))
1590 if (myform.choice_project.data ==
"create"):
1591 return redirect(
"/project")
1592 elif (myform.choice_project.data ==
"connect"):
1593 return redirect(
"/allsessions")
1595 return redirect(
"/allsessions")
1598 flash(
"Invalid password")
1599 return redirect(
"/login")
1601 flash(
"Invalid username")
1602 return redirect(
"/login")
1604 return render_template(
"main_login.html", **(myrender()), title=
"TiledViz login", form=myform)
1606@app.route('/check2FA', methods=["GET", "POST"])
1608 message = json.loads(request.args[
"message"])
1609 myusername=message[
"username"]
1610 if (myusername
in codes2FA):
1611 code=codes2FA[myusername][
"code"]
1612 expiration_time=codes2FA[myusername][
"expiration_time"]
1614 flash(
"User didn't received a 2FA code. Please try to login again.")
1615 return redirect(
"/login")
1617 myform = Build2FAForm(session,myusername)()
1618 if myform.validate_on_submit():
1619 if (datetime.timedelta(seconds=360) < datetime.datetime.utcnow()-expiration_time):
1620 flash(
"Timeout for code verification. Please try to login again.")
1621 return redirect(
"/login")
1623 logging.info(f
"code created {code} and from form {myform.code.data}")
1624 if (code == int(myform.code.data)):
1625 session[
"username"] = myusername
1626 session[
"is_client_active"] =
True
1628 logging.info(f
"code OK message {message}")
1629 logging.warning(f
"User {myusername} has loggined with 2FA code.")
1630 codes2FA.pop(myusername)
1632 if (message[
"newuser"]==
"True"):
1633 return redirect(
"/register")
1636 if "pending_invite_link" in session:
1637 link = session.pop(
"pending_invite_link")
1638 return redirect(url_for(
".handle_join_with_invite_link", link=link))
1640 if (message[
"choice_project"] ==
"create"):
1641 return redirect(
"/project")
1642 elif (message[
"choice_project"] ==
"connect"):
1643 return redirect(
"/allsessions")
1645 flash(
"Code mismatch. Please try to login again.")
1646 return redirect(
"/login")
1648 return render_template(
"main_login.html", **(myrender()), title=
"TiledViz login", form=myform)
1650@app.route('/logout')
1652 if (
"username" in session):
1653 if (session[
"username"] ==
"Anonymous"):
1654 return redirect(
"/")
1656 flash(
"User is already not connected !")
1657 return redirect(
"/")
1659 session.pop(
'username',
None)
1660 session.pop(
"is_client_active")
1661 return redirect(url_for(
'index'))
1666 return render_template(
"test.html")
1668@app.route('/savesession', methods=['GET', 'POST'])
1671 if (
"username" in session):
1672 user_id=get_user_id(
"Savession",session[
"username"])
1674 flash(
"You are not connected. You must login before saving a session.")
1675 return redirect(
"/login")
1677 if (
not "is_client_active" in session):
1678 flash(
"You must be connected and not Anonymous to save a session.")
1679 return redirect(
"/login")
1681 all_session={
"username":session[
'username'],
"is_client_active":session[
"is_client_active"],
1682 "projectname":session[
"projectname"],
"sessionname":session[
"sessionname"]}
1684 for item
in session:
1685 logging.info(
"item all_session : "+str(item))
1686 if item
in all_session:
1688 elif (item ==
'csrf_token'):
1691 all_session[item]=session[item]
1693 logging.info(
"complete all_session : "+str(all_session))
1698 json_all_session=json.JSONEncoder().encode(all_session)
1700 if ( request.method ==
'POST'):
1701 flash(
"Session cookie saved.")
1702 return redirect(
"/index")
1705 return render_template(
"savesession.html", **(myrender()),
1706 all_session=json_all_session)
1708@app.route('/retreivesession', methods=["GET", "POST"])
1709def retreivesession():
1711 if (
"username" in session):
1712 user_id=get_user_id(
"retreivesession",session[
"username"])
1714 flash(
"You are not connected. You must login before retreive a session.")
1715 return redirect(
"/login")
1720 myform = BuildRetreiveSessionForm()()
1722 if myform.validate_on_submit():
1723 logging.info(
"in tileset editor")
1725 if(myform.goback.data):
1726 logging.warning(
"go back to home without session.")
1727 return redirect(url_for(
".index"))
1729 if (myform.session_file.data) :
1730 session_file = myform.session_file.data
1731 logging.warning(
"Read session_file :"+myform.session_file.data.filename)
1732 session_data = json.loads(json.loads(session_file.read().decode(
'utf-8')))
1733 logging.warning(
"Session_data :"+str(session_data))
1735 session[
"username"]=session_data[
'username']
1736 session[
"is_client_active"]=session_data[
"is_client_active"]
1737 session[
"projectname"]=session_data[
"projectname"]
1738 session[
"sessionname"]=session_data[
"sessionname"]
1739 all_session={
"username":session[
'username'],
"is_client_active":session[
"is_client_active"],
1740 "projectname":session[
"projectname"],
"sessionname":session[
"sessionname"]}
1742 logging.info(
"basic all_session : "+str(all_session))
1743 for item
in session_data:
1744 if item
in all_session:
1747 session[item]=session_data[item]
1749 flash(
"Session cookie restored.")
1750 return redirect(
"/index")
1758 return render_template(
"main_login.html", **(myrender()), title=
"Retreive saved session for TiledViz", form=myform)
1762@app.route('/project', methods=["GET", "POST"])
1764 if (
"username" in session):
1765 if (session[
"username"] ==
"Anonymous"):
1766 return redirect(
"/login")
1767 user_id=get_user_id(
"Project",session[
"username"])
1768 flash(
"Create new or use an old project for user {}".format(session[
"username"]))
1770 return redirect(
"/login")
1773 printstr=
"{0:\xa0<"+projectl+
"."+projectl+
"}|\xa0{2:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{1:\xa0<"+descrl+
"."+descrl+
"}|\xa0{3:\xa0<"+descrl+
"}"
1776 user_projects = get_user_projects(user_id)
1779 myprojects.append((
'NoChoice',printstr.format(
"Project name",
"Description",
"Date and Time",
"All sessions")))
1782 for project, role_type
in user_projects:
1783 ListsessionsTheproject=db.session.query(models.Sessions.name).filter_by(id_projects=project.id)
1784 allsessionsname=[ asessionTheproject.name
for asessionTheproject
in ListsessionsTheproject ]
1785 thedate=project.creation_date.isoformat().replace(
"T",
" ")
if project.creation_date
else "Unknown"
1788 project_display_name = f
"{project.name} ({role_type})"
1790 myprojects.append((str(project.id),
1792 project_display_name,
1793 project.description
or "",
1795 str(allsessionsname))
1797 except Exception
as e:
1798 logging.error(f
"Error loading user projects: {str(e)}")
1801 myform = BuildNewProjectForm(myprojects)()
1806 selected_val = myform.chosen_project.data
1807 selected_project_id =
None
1809 if selected_val
and selected_val !=
"NoChoice":
1810 selected_project_id = int(selected_val)
1812 selected_project_id =
None
1814 if selected_project_id:
1815 role = db.session.query(models.ProjectMembers.role_type).filter_by(
1816 project_id=selected_project_id,
1819 can_edit_role = role
in [
"owner",
"admin",
"editor"]
1820 if not can_edit_role:
1821 myform.action_sessions.choices = [(
"use",
"Use an existing session for the grid")]
1822 myform.action_sessions.default =
"use"
1825 if myform.validate_on_submit():
1826 logging.info(
"in project")
1828 if (myform.chosen_project.data==
"NoChoice"):
1829 if (myform.projectname.data !=
""):
1830 project_id = db.session.query(models.Projects.id).filter_by(name=myform.projectname.data).scalar()
1832 logging.warning(
"You must create a new project or choose an old one.")
1833 flash(
"You must create a new project or choose an old one.")
1834 return redirect(
"/project")
1837 project_id = int(myform.chosen_project.data)
1839 exists = project_id
is not None
1840 logging.debug(
"Project exists "+str(exists)+
" id : "+str(project_id))
1844 if not can_access_project(project_id, user_id):
1845 flash(
"You don't have permission to access this project!")
1846 return redirect(
"/project")
1848 if (myform.chosen_project.data ==
"NoChoice"):
1849 session[
"projectname"]=myform.projectname.data
1851 session[
"projectname"]=db.session.query(models.Projects.name).filter_by(id=project_id).scalar()
1853 oldproject=db.session.query(models.Projects).filter_by(id=project_id).scalar()
1856 current_user_obj = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
1857 can_edit_session, can_manage_members, role_type, membership = role_project(oldproject,current_user_obj)
1859 can_manage_members =
False
1860 can_edit_session =
False
1862 logging.debug(
"Chosen project : "+str(session[
"projectname"]))
1864 user_can_edit = can_manage_project(project_id, user_id)
1865 if(myform.action_sessions.data ==
"create"):
1866 if (can_edit_session):
1867 logging.warning(
"Create new session ")
1868 flash(
"Create new session for user {}".format(session[
"username"]))
1869 return redirect(
"/newsession")
1871 sentence=
"You don't have permission to create new session on this project!"
1872 logging.warning(sentence)
1874 return redirect(
"/project")
1876 logging.debug(
"Use old sessions (view)")
1877 flash(
"Use an old session for user {}".format(session[
"username"]))
1878 return redirect(
"/oldsessions")
1879 elif (myform.chosen_project.data==
"NoChoice"):
1880 creation_date=datetime.datetime.now()
1881 screation_date=str(creation_date)
1882 logging.error(
"create project date "+screation_date)
1885 project = models.Projects(name=str(myform.projectname.data),
1886 creation_date=screation_date,
1889 description=myform.description.data)
1890 db.session.add(project)
1894 success, message = add_project_member(project.id, user_id,
'owner')
1896 db.session.rollback()
1897 flash(f
"Error creating project: {message}")
1898 return redirect(
"/project")
1900 session[
"projectname"]=myform.projectname.data
1901 logging.debug(
"Project created : create new session ")
1902 return redirect(
"/newsession")
1904 except Exception
as e:
1905 db.session.rollback()
1906 logging.error(f
"Error creating project: {str(e)}")
1907 flash(f
"Error creating project: {str(e)}")
1908 return redirect(
"/project")
1910 logging.error(
"Error for chosen project.")
1911 return redirect(
"/project")
1913 return render_template(
"main_login.html", **(myrender()), title=
"New project TiledViz", form=myform)
1916@app.route('/admin', methods=["GET", "POST"])
1918 if (
"username" in session):
1919 if (session[
"username"] ==
"Anonymous"):
1920 return redirect(
"/login")
1921 user_id=get_user_id(
"admin",session[
"username"])
1922 logging.warning(
"Admin page with user {}".format(session[
"username"]))
1924 flash(
"Admin page with user {}\nALERT : click any suppress buttons will remove elements in DB.".format(session[
"username"]))
1926 flash(
"Admin page with user {}".format(session[
"username"]))
1927 logging.warning(
"User id {}".format(user_id))
1929 flash(
"Admin page : User must login !")
1930 return redirect(
"/login")
1932 User=db.session.query(models.Users).filter_by(name=session[
"username"]).one()
1933 userAdmin=User.is_admin
1935 flash(
"You must be an administrator to access this page.")
1936 return redirect(
"/")
1938 message=
'{"username": '+session[
"username"]+
'}'
1939 logging.info(
"in administration page.")
1942 allusers = db.session.query(models.Users).all()
1943 logging.debug(
"All users :"+str([ theuser.name
for theuser
in allusers]))
1945 printstr=
"{0:\xa0<"+usernamel+
"."+usernamel+
"}|\xa0{1:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{2:\xa0<"+descrl+
"."+descrl+
"}"
1947 listallusers.append((
'NoChoice',printstr.format(
"User name",
"Date and Time",
"Description")))
1949 for thisuser
in allusers:
1950 thedate=thisuser.creation_date.isoformat().replace(
"T",
" ")
1955 if (thisuser.compagny):
1956 compagny=thisuser.compagny
1959 if (thisuser.manager):
1960 manager=thisuser.manager
1963 Desc=mail+
"; "+compagny+
"; "+manager
1964 Desc=Desc[:int(descrl)]
1965 listallusers.append(
1966 (str(thisuser.id),printstr.
1967 format(str(thisuser.name),
1973 if request.method ==
'POST':
1974 if 'toggle_admin' in request.form:
1975 user_id = request.form.get(
'user_id')
1977 user = db.session.query(models.Users).filter_by(id=user_id).one()
1978 user.is_admin =
not user.is_admin
1980 flash(f
"Admin status updated for user {user.name}")
1981 except Exception
as e:
1982 flash(f
"Error updating admin status: {str(e)}")
1983 return redirect(url_for(
'admin'))
1985 allprojects = db.session.query(models.Projects).all()
1986 logging.debug(
"All projects :"+str([ theproject.name
for theproject
in allprojects]))
1988 printstr=
"{0:\xa0<"+projectl+
"."+projectl+
"}|\xa0{1:\xa0<"+usernamel+
"."+usernamel+
"}\xa0|\xa0{2:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{3:\xa0<"+descrl+
"."+descrl+
"}"
1990 listallprojects.append((
'NoChoice',printstr.format(
"Project name",
"Owner",
"Date and Time",
"Description")))
1992 for thisproject
in allprojects:
1993 thedate=thisproject.creation_date.isoformat().replace(
"T",
" ")
1994 Desc=thisproject.description
1997 owner_member = db.session.query(models.ProjectMembers).filter(
1998 models.ProjectMembers.project_id == thisproject.id,
1999 models.ProjectMembers.role_type ==
'owner'
2002 owner_name =
'Unknown'
2003 if owner_member
and owner_member.user:
2004 owner_name = owner_member.user.name
2005 elif thisproject.id_users:
2006 old_owner = db.session.query(models.Users).filter_by(id=thisproject.id_users).first()
2008 owner_name = old_owner.name
2010 listallprojects.append(
2011 (str(thisproject.id),printstr.
2012 format(str(thisproject.name), owner_name, thedate, Desc)
2017 allsessions = db.session.query(models.Sessions).all()
2018 logging.debug(
"All sessions :"+str([ thesession.name
for thesession
in allsessions]))
2020 printstr=
"{0:\xa0<"+sessionl+
"."+sessionl+
"}|\xa0{1:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{2:\xa0<"+descrl+
"."+descrl+
"}"
2022 listallsessions.append((
'NoChoice',printstr.format(
"Session name",
"Date and Time",
"Description")))
2024 for thissession
in allsessions:
2025 thedate=thissession.creation_date.isoformat().replace(
"T",
" ")
2026 Desc=thissession.description
2027 listallsessions.append(
2028 (str(thissession.id),printstr.
2029 format(str(thissession.name),
2034 projects = db.session.query(models.Projects).filter_by(id_users=user_id).all()
2035 logging.debug(
"My projects :"+str([ theproject.name
for theproject
in projects]))
2037 printstr=
"{0:\xa0<"+projectl+
"."+projectl+
"}|\xa0{1:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{2:\xa0<"+descrl+
"."+descrl+
"}"
2039 listmyprojects.append((
'NoChoice',printstr.format(
"Project name",
"Date and Time",
"Description")))
2041 for thisproject
in projects:
2042 thedate=thisproject.creation_date.isoformat().replace(
"T",
" ")
2043 Desc=thisproject.description
2044 listmyprojects.append(
2045 (str(thisproject.id),printstr.
2046 format(str(thisproject.name),
2054 for theproject
in projects:
2055 ListsessionsTheproject=db.session.query(models.Sessions.name).filter_by(id_projects=theproject.id).all()
2056 [ mysessions.append((theproject.name,ListsessionTheproject))
for ListsessionTheproject
in ListsessionsTheproject ]
2059 logging.debug(
"My sessions :"+str(mysessions))
2061 printstr=
"{1:\xa0<"+sessionl+
"."+sessionl+
"}|{0:\xa0<"+projectl+
"."+projectl+
"}|\xa0{2:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{3:\xa0<"+descrl+
"."+descrl+
"}"
2062 listmyprojectssession=[]
2063 listmyprojectssession.append((
'NoChoice',printstr.format(
"Project name",
"Session name",
"Date and Time",
"Description")))
2065 for thissessions
in mysessions:
2067 for thissession
in thissessions[1]:
2068 listmysession.append(thissession)
2069 thedate=
"1970-01-01"
2071 thedate=db.session.query(models.Sessions.creation_date).filter_by(name=str(thissession)).scalar().isoformat().replace(
"T",
" ")
2074 SessDesc=db.session.query(models.Sessions).filter_by(name=thissession).scalar().description
2075 thissessionid=db.session.query(models.Sessions.id).filter_by(name=str(thissession)).one()
2076 listmyprojectssession.append(
2077 (str(thissessionid),printstr.
2078 format(str(thissessions[0]),
2109 connections = db.session.query(models.Connections).filter_by(id_users=user_id)
2110 logging.debug(
"My connections :"+str([ theconnection.host_address
for theconnection
in connections]))
2112 printstr=
"{0:\xa0<"+connectionh+
"."+connectionh+
"}|\xa0{1:\xa0<"+datel+
"."+datel+
"}\xa0\xa0\xa0\xa0\xa0|\xa0{2:\xa0<"+datel+
"."+datel+
"}\xa0\xa0\xa0\xa0|\xa0{3:\xa0<"+datel+
"."+datel+
"}"
2113 listmyconnections=[]
2114 listmyconnections.append((
'NoChoice',printstr.format(
"Host address",
"Date and Time",
"id",
"In session")))
2115 for thisconnection
in connections:
2117 if (
"connection"+str(thisconnection.id)
in session):
2119 listmyconnections.append(
2120 (str(thisconnection.id),printstr.
2121 format(str(thisconnection.host_address),
2122 str(thisconnection.creation_date),
2123 str(thisconnection.id),
2129 listallconnections=[]
2131 allconnections = db.session.query(models.Connections)
2132 logging.debug(
"All connections :"+str([ theconnection.host_address
for theconnection
in allconnections]))
2134 printstr=
"{0:\xa0<"+usernamel+
"."+usernamel+
"}|\xa0"+\
2135 "{1:\xa0<"+connectionh+
"."+connectionh+
"}|\xa0"+\
2136 "{2:\xa0<"+datel+
"."+datel+
"}\xa0\xa0\xa0\xa0\xa0|\xa0"+\
2137 "{3:\xa0<"+datel+
"."+datel+
"}\xa0\xa0\xa0\xa0|\xa0"+\
2138 "{4:\xa0<"+datel+
"."+datel+
"}"
2139 listallconnections.append((
'NoChoice',printstr.format(
"Username",
"Host address",
"Date and Time",
"id",
"In session")))
2140 for thisconnection
in allconnections:
2142 if (
"connection"+str(thisconnection.id)
in session):
2144 theuser=db.session.query(models.Users).filter_by(id=thisconnection.id_users).one().name
2145 listallconnections.append(
2146 (str(thisconnection.id),printstr.
2147 format(str(theuser),
2148 str(thisconnection.host_address),
2149 str(thisconnection.creation_date),
2150 str(thisconnection.id),
2155 logging.debug(
"My project sessions :"+str(listmyprojectssession))
2158 myform = BuildAdminForm(listmyprojects,listmyprojectssession,listmyconnections,
2159 list_all_users=listallusers,list_all_projects=listallprojects,list_all_sessions=listallsessions,list_all_connections=listallconnections)()
2161 myform = BuildAdminForm(listmyprojects,listmyprojectssession,listmyconnections)()
2163 if myform.validate_on_submit():
2170 if (myform.suprressfreetiles.data):
2171 flash(
"All free tiles were suppressed.")
2172 for freetile
in db.session.query(models.t_freetiles).all():
2173 delelement(models.Tiles,
"tile", freetile[0])
2175 if (myform.suprressUnusedTilesets.data):
2176 flash(
"All free tilesets were suppressed.\n You may suppress all free tiles now.")
2177 for freetilesets
in db.session.query(models.t_freetilesets).all():
2178 elementid=freetilesets[0]
2179 logging.warning(
"Delete this %s %d : %s" % (
"tileset",elementid,str(freetilesets[1])))
2180 db.session.query(func.deltileset(freetilesets[0])).all()
2183 if ( myform.suppressSelected.data):
2185 if (myform.all_users.data !=
"NoChoice"):
2187 elementid=int(myform.all_users.data)
2188 logging.warning(
"Admin suppress %s %d " % (chosenObject,elementid))
2189 flash(
"Admin suppress element %s number %s." % (chosenObject,elementid))
2190 objects.append(chosenObject)
2191 ids.append(elementid)
2193 remove_this_user(elementid)
2195 if (myform.all_projects.data !=
"NoChoice"):
2196 chosenObject=
"project"
2197 elementid=int(myform.all_projects.data)
2198 logging.warning(
"Admin suppress %s %d " % (chosenObject,elementid))
2199 flash(
"Admin suppress element %s number %s." % (chosenObject,elementid))
2200 objects.append(chosenObject)
2201 ids.append(elementid)
2203 remove_this_project(elementid)
2205 if (myform.all_sessions.data !=
"NoChoice"):
2206 chosenObject=
"session"
2207 elementid=int(myform.all_sessions.data)
2208 logging.warning(
"Admin suppress %s %d " % (chosenObject,elementid))
2209 flash(
"Suppress element %s number %s." % (chosenObject,elementid))
2210 objects.append(chosenObject)
2211 ids.append(elementid)
2213 remove_this_session(elementid)
2217 if (myform.chosen_project.data !=
"NoChoice"):
2218 chosenObject=
"project"
2219 elementid=int(re.sub(
r'[(),]',
'',myform.chosen_project.data))
2220 logging.warning(
"Chosen my %s %d " % (chosenObject,elementid))
2221 flash(
"Suppress element %s number %d." % (chosenObject,elementid))
2222 objects.append(chosenObject)
2223 ids.append(elementid)
2225 delelement(models.Projects, chosenObject, elementid)
2227 if (myform.chosen_project_session.data !=
"NoChoice"):
2228 chosenObject=
"mysession"
2229 elementid=int(re.sub(
r'[(),]',
'',myform.chosen_project_session.data))
2230 logging.warning(
"Chosen my %s %d " % (chosenObject,elementid))
2231 flash(
"Suppress element %s number %d." % (chosenObject,elementid))
2232 objects.append(chosenObject)
2233 ids.append(elementid)
2235 thissession=db.session.query(models.Sessions).filter_by(id=elementid).scalar()
2236 remove_this_session(elementid)
2244 if (myform.chosen_user_connection.data !=
"NoChoice"):
2245 chosenObject=
"connection"
2246 elementid=int(myform.chosen_user_connection.data)
2247 logging.warning(
"Chosen my %s %d " % (chosenObject,elementid))
2248 flash(
"Suppress element %s number %d." % (chosenObject,elementid))
2249 objects.append(chosenObject)
2250 ids.append(elementid)
2253 thisConnection=db.session.query(models.Connections).filter_by(id=elementid).one()
2254 user_id=thisConnection.id_users
2255 oldtileset=db.session.query(models.TileSets).filter_by(id_connections=elementid).one()
2256 if (oldtileset.connections.id==elementid):
2257 remove_this_connection(oldtileset,elementid,user_id)
2259 delelement(models.Connections, chosenObject, elementid)
2261 delelement(models.Connections, chosenObject, elementid)
2263 if (myform.suppressAllMyConnections.data):
2264 flash(
"All my connections were suppressed {}".format(session[
"username"]))
2266 for thisconnection
in connections:
2267 chosenObject=
"connection"
2268 objects.append(chosenObject)
2269 ids.append(thisconnection.id)
2271 user_id=thisconnection.id_users
2272 oldtileset=db.session.query(models.TileSets).filter_by(id_connections=thisconnection.id).one()
2273 if (oldtileset.connections.id==thisconnection.id):
2274 remove_this_connection(oldtileset,thisconnection.id,user_id)
2276 delelement(models.Connections, chosenObject, thisconnection.id)
2278 delelement(models.Connections, chosenObject, thisconnection.id)
2283 if (myform.chosen_connections.data !=
"NoChoice"):
2284 chosenObject=
"connection"
2285 elementid=int(myform.chosen_connections.data)
2286 logging.warning(
"Chosen my %s %d " % (chosenObject,elementid))
2287 flash(
"Suppress element %s number %d." % (chosenObject,elementid))
2288 objects.append(chosenObject)
2289 ids.append(elementid)
2292 thisConnection=db.session.query(models.Connections).filter_by(id=elementid).one()
2293 user_id=thisConnection.id_users
2294 oldtileset=db.session.query(models.TileSets).filter_by(id_connections=elementid).one()
2295 if (oldtileset.connections.id==elementid):
2296 remove_this_connection(oldtileset,elementid,user_id)
2298 delelement(models.Connections, chosenObject, elementid)
2300 delelement(models.Connections, chosenObject, elementid)
2303 if (myform.suppressAllConnections.data):
2304 flash(
"All connections for all users were suppressed.")
2307 for thisconnection
in allconnections:
2308 chosenObject=
"connection"
2309 objects.append(chosenObject)
2310 ids.append(thisconnection.id)
2312 user_id=thisconnection.id_users
2313 oldtileset=db.session.query(models.TileSets).filter_by(id_connections=thisconnection.id).one()
2314 if (oldtileset.connections.id==thisconnection.id):
2315 remove_this_connection(oldtileset,thisconnection.id,user_id)
2317 delelement(models.Connections, chosenObject, thisconnection.id)
2319 delelement(models.Connections, chosenObject, thisconnection.id)
2324 return redirect(
"/admin")
2326 return render_template(
"main_login.html", **(myrender()), title=
"Admin for user.", form=myform, message=message)
2330@app.route('/allsessions', methods=["GET", "POST"])
2332 if (
"username" in session):
2333 if (session[
"username"] ==
"Anonymous"):
2334 return redirect(
"/login")
2336 flash(
"All projects and sessions for user {}".format(session[
"username"]))
2337 logging.warning(
"All projects and sessions for user {}".format(session[
"username"]))
2338 user_id=get_user_id(
"allsavessions",session[
"username"])
2339 logging.warning(
"User id {}".format(user_id))
2341 flash(
"All projects and sessions : User must login !")
2342 return redirect(
"/login")
2344 message=
'{"username": '+session[
"username"]+
'}'
2345 logging.info(
"in allsessions")
2348 projects = db.session.query(models.Projects).filter_by(id_users=user_id)
2349 logging.debug(
"My projects :"+str([ theproject.name
for theproject
in projects]))
2354 for theproject
in projects:
2355 ListsessionsTheproject=db.session.query(models.Sessions.name).filter_by(id_projects=theproject.id)
2356 [ mysessions.append((theproject.name,ListsessionTheproject))
for ListsessionTheproject
in ListsessionsTheproject ]
2359 logging.debug(
"My sessions :"+str(mysessions))
2361 printstr=
"{1:\xa0<"+sessionl+
"."+sessionl+
"}|{0:\xa0<"+projectl+
"."+projectl+
"}|\xa0{2:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{3:\xa0<"+descrl+
"."+descrl+
"}"
2362 listmyprojectssession=[]
2363 listmyprojectssession.append((
'NoChoice',printstr.format(
"Project name",
"Session name",
"Date and Time",
"Description")))
2365 for thissessions
in mysessions:
2366 for thissession
in thissessions[1]:
2367 listmysession.append(thissession)
2368 dbSession=db.session.query(models.Sessions).filter(models.Sessions.name.like(thissession)).first()
2369 logging.debug(f
"Session : {thissession} {dbSession}")
2371 logging.debug(f
" : {dbSession.name}")
2372 thedate=dbSession.creation_date.isoformat().replace(
"T",
" ")
2374 logging.debug(f
"Error date session {thissession}")
2375 thedate=
"1972-08-05"
2378 SessDesc=dbSession.description
2380 logging.debug(f
"Error desc session {thissession}")
2384 listmyprojectssession.append(
2385 (str(thissession),printstr.
2386 format(str(thissessions[0]),
2395 invite_sessions = db.session.query(models.Sessions.name).filter(models.Sessions.users.any(id=user_id)).all()
2396 printstr=
"{0:\xa0<"+sessionl+
"."+sessionl+
"}|\xa0{1:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{2:\xa0<"+descrl+
"."+descrl+
"}"
2397 listsessions.append((
'NoChoice',printstr.format(
"Session name",
"Date and Time",
"Description")))
2398 for thissession
in invite_sessions:
2399 if (thissession.name
not in listmysession):
2400 dbSession=db.session.query(models.Sessions).filter(models.Sessions.name.like(thissession.name)).first()
2401 logging.debug(f
"iSession : {thissession} {dbSession}")
2403 logging.debug(f
" : {dbSession.name}")
2404 thedate=dbSession.creation_date.isoformat().replace(
"T",
" ")
2406 logging.debug(f
"Error date invited session {thissession}")
2407 thedate=
"1972-08-05"
2410 SessDesc=dbSession.description
2412 logging.debug(f
"Error desc invited session {thissession}")
2415 listsessions.append(
2416 (str(thissession.name),printstr.
2417 format(str(thissession.name),
2422 logging.debug(
"My project sessions :"+str(listmyprojectssession))
2423 logging.debug(
"My invited sessions :"+str(listsessions))
2424 if (len(listmyprojectssession) == 0
and len(listmysession) == 0
and len(invite_sessions) == 0):
2425 flash(
"You are not in any project or session now. Please create your first one or ask somebody to invite you.")
2426 return redirect(url_for(
".index"))
2428 myform = BuildAllProjectSessionForm(listmyprojectssession,listsessions)()
2432 has_edit_rights = db.session.query(models.ProjectMembers).filter(
2433 models.ProjectMembers.user_id == user_id,
2434 models.ProjectMembers.role_type.in_([
"owner",
"admin",
"editor"])
2436 if not has_edit_rights
and hasattr(myform,
'edit'):
2438 myform.edit.render_kw = {
"style":
"display:none"}
2443 if myform.validate_on_submit():
2444 if (myform.chosen_project_session.data !=
"NoChoice"):
2445 logging.debug(
"Chosen project session "+str(myform.chosen_project_session.data))
2446 session[
"sessionname"]=myform.chosen_project_session.data
2447 elif (myform.chosen_session_invited.data !=
"NoChoice"):
2448 logging.debug(
"Chosen session invited "+str(myform.chosen_session_invited.data))
2449 session[
"sessionname"]=myform.chosen_session_invited.data
2451 logging.warning(
"You must choose a session")
2452 flash(
"You didn't select a session or click 'Go' button on search bar.\n"+
2453 "You must choose a session in your projects or one you were invited on.")
2454 return redirect(
"/allsessions")
2456 logging.warning(
"Which is session "+str(db.session.query(models.Sessions.id).filter(models.Sessions.name.like(f
'{session["sessionname"]}')).first()))
2457 its_project_id=db.session.query(models.Sessions).filter(models.Sessions.name.like(f
'{session["sessionname"]}')).first().id_projects
2458 session[
"projectname"]=db.session.query(models.Projects).filter_by(id=its_project_id).scalar().name
2459 logging.warning(
"And have project id "+str(its_project_id)+
" which is "+str(session[
"projectname"]))
2460 session[
"is_client_active"]=
True
2461 if(myform.edit.data):
2463 if not can_manage_project(its_project_id, user_id):
2464 flash(
"You don't have permission to edit sessions in this project.")
2465 return redirect(
"/grid")
2466 logging.debug(
"go to edit old session : "+session[
"sessionname"])
2467 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
2468 return redirect(url_for(
".editsession",message=message))
2469 return redirect(
"/grid")
2471 return render_template(
"main_login.html", **(myrender()), title=
"All projects/sessions TiledViz", form=myform, message=message)
2475@app.route('/oldsessions', methods=["GET", "POST"])
2477 if (
"username" in session):
2478 if (session[
"username"] ==
"Anonymous"):
2479 return redirect(
"/login")
2481 flash(
"Old sessions : User must login !")
2482 return redirect(
"/login")
2484 if (
not "projectname" in session):
2485 flash(
"Old sessions : Must define a project first !")
2486 return redirect(
"/project")
2490 Project = db.session.query(models.Projects).filter_by(name=session[
"projectname"]).first()
2491 user_id=get_user_id(
"OldSessionsPerm",session[
"username"])
2492 if not Project
or not can_access_project(Project.id, user_id):
2493 flash(
"You don't have permission to access this project.")
2494 return redirect(
"/project")
2495 user_can_edit = can_manage_project(Project.id, user_id)
2497 user_can_edit =
False
2499 Project = db.session.query(models.Projects).filter_by(name=session[
"projectname"]).scalar()
2500 project_id=Project.id
2501 project_desc=Project.description
2502 querysessions = db.session.query(models.Sessions.name).filter_by(id_projects=project_id)
2504 for thissession
in querysessions:
2505 logging.debug(
"Build listsessions "+str(thissession[0]))
2506 listsessions.append((str(thissession[0]),str(thissession[0])))
2507 oldproject={
"name":session[
"projectname"],
2508 "description":project_desc}
2509 logging.debug(
"Old project : "+str(oldproject[
"name"])+
" list old sessions :"+str(listsessions))
2513 current_user_obj = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
2514 can_edit_session, can_manage_members, role_type, membership = role_project(Project,current_user_obj)
2516 can_manage_members =
False
2517 can_edit_session =
False
2519 myform = BuildOldProjectForm(oldproject, listsessions, session)()
2520 if myform.validate_on_submit():
2521 session[
"sessionname"]=myform.chosen_session.data
2522 if(myform.from_session.data==
"use"):
2523 logging.debug(
"reuse old session : "+myform.chosen_session.data)
2524 session[
"is_client_active"]=
True
2525 return redirect(
"/grid")
2526 elif(myform.from_session.data==
"edit"):
2527 if not user_can_edit:
2528 flash(
"You don't have permission to edit sessions in this project.")
2529 return redirect(
"/oldsessions")
2530 logging.debug(
"go to edit old session : "+myform.chosen_session.data)
2531 message =
'{"oldsessionname":"'+myform.chosen_session.data+
'"}'
2532 return redirect(url_for(
".editsession",message=message))
2533 elif(myform.from_session.data==
"copy"):
2534 if not user_can_edit:
2535 flash(
"You don't have permission to copy sessions in this project.")
2536 return redirect(
"/oldsessions")
2537 logging.debug(
"go to copy old session : "+myform.chosen_session.data)
2538 message =
'{"oldsessionname":"'+myform.chosen_session.data+
'"}'
2539 return redirect(url_for(
".copysession",message=message))
2541 return render_template(
"main_login.html", **(myrender()), title=
"Old projects TiledViz", form=myform)
2545@app.route('/newsession', methods=["GET", "POST"])
2547 if (
"username" in session):
2548 if (session[
"username"] ==
"Anonymous"):
2549 return redirect(
"/login")
2551 flash(
"Create new sessions : User must login !")
2552 return redirect(
"/login")
2556 user_id=get_user_id(
"NewSessionPerm",session[
"username"])
2557 Project = db.session.query(models.Projects).filter_by(name=session.get(
"projectname")).first()
2558 if not Project
or not can_manage_project(Project.id, user_id):
2559 flash(
"You don't have permission to create sessions for this project.")
2560 return redirect(
"/project")
2562 flash(
"Unable to validate permissions for creating a session.")
2563 return redirect(
"/project")
2566 myform = BuildNewSessionForm()()
2567 if myform.validate_on_submit():
2568 if myform.add_users.data:
2569 myform.users.append_entry()
2570 flash(
"New user for user {} in session {}".format(session[
"username"], myform.sessionname.data))
2571 return render_template(
"main_login.html", **(myrender()), title=
"New session TiledViz", form=myform)
2572 logging.info(
"in session")
2573 id_projects=db.session.query(models.Projects.id).filter_by(name=session[
"projectname"])
2574 sessionname=myform.sessionname.data
2577 if (
"users" in myform):
2580 logging.debug(
"myform.users : %s" % str(myform.users))
2581 for newuser
in myform.users:
2582 soup=BeautifulSoup(str(newuser),
'lxml')
2583 outsoup=soup.find_all(
"input")
2584 outfind=[ input.get(
"value")
for input
in outsoup ]
2585 outchecked=[ input.get(
"checked")
for input
in outsoup ]
2586 if (len(outfind[0]) > 0):
2587 logging.debug(
"myform.users : %s %s" % (str(outfind[0]),str(outchecked[1] ==
"")))
2588 thisuser=
FormUser(data=outfind[0],iseditor=(outchecked[1]==
""))
2589 list_users.append(thisuser)
2591 ok_list_users=
"Owner %s add users %s to the session %s" % (session[
"username"],str(list_users),sessionname)
2592 logging.debug(
"ok_list_users : %s " % ok_list_users)
2595 newsession,exist=create_newsession(sessionname, myform.description.data, id_projects, oldusers)
2598 db.session.add(newsession)
2601 traceback.print_exc(file=sys.stderr)
2603 flash(
"Session with name {} creation problem.".format(sessionname))
2604 return render_template(
"main_login.html", **(myrender()), title=
"New Session TiledViz", form=myform, message=message)
2606 flash(
"Session with name {} already exists".format(sessionname))
2607 return render_template(
"main_login.html", **(myrender()), title=
"New Session TiledViz", form=myform)
2610 config_default_file=open(
"app/static/js/config_default.json",
'r')
2611 json_configs=json.load(config_default_file)
2612 config_default_file.close()
2613 newsession.config=json_configs
2616 if myform.Session_config.data:
2617 message =
'{"sessionname":"'+newsession.name+
'"}'
2618 return redirect(url_for(
".configsession",message=message))
2622 flash(
"One must validate new session before create a tiledset.")
2623 message=
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
2624 return redirect(url_for(
".editsession",message=message))
2625 return render_template(
"main_login.html", **(myrender()), title=
"New session TiledViz", form=myform)
2629@app.route('/copysession', methods=["GET", "POST"])
2631 if (
"username" in session):
2632 if (session[
"username"] ==
"Anonymous"):
2633 return redirect(
"/login")
2635 flash(
"Copy session : User must login !")
2636 return redirect(
"/login")
2638 if (
not "sessionname" in session ):
2639 return redirect(
"/allsessions")
2641 message=json.loads(request.args[
"message"])
2642 oldsessionname=message[
"oldsessionname"]
2643 oldsession = db.session.query(models.Sessions).filter(models.Sessions.name.like(oldsessionname)).first()
2646 current_user_obj = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
2647 can_edit_session, can_manage_members, role_type, membership = role_session(oldsession,current_user_obj)
2649 can_manage_members =
False
2650 can_edit_session =
False
2653 if (can_edit_session):
2654 flash(
"User {} don't have rights to copy session {} with role {}".format(session[
"username"], myform.sessionname.data, role_type))
2655 return redirect(
"/oldsessions")
2657 session[
"can_manage_members"]=can_manage_members
2658 session[
"can_edit_session"]=can_edit_session
2659 myform = BuildEditsessionform(oldsession,session,edit=
False)()
2660 if myform.validate_on_submit():
2661 logging.debug(
"copySessionForm : ")
2663 if myform.add_users.data:
2664 myform.users.append_entry()
2665 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
2666 flash(
"New user avaible for user {} in session {}".format(session[
"username"], myform.sessionname.data))
2668 return render_template(
"main_login.html", **(myrender()), title=
"Copy session TiledViz", form=myform)
2672 for newuser
in myform.users:
2673 soup=BeautifulSoup(str(newuser),
'lxml')
2674 outsoup=soup.find_all(
"input")
2675 outfind=[ input.get(
"value")
for input
in outsoup ]
2676 outchecked=[ input.get(
"checked")
for input
in outsoup ]
2677 if (len(outfind) > 0):
2678 logging.debug(
"myform.users : %s %s" % (str(outfind[0]),str(outchecked[1] ==
"")))
2679 thisuser=
FormUser(data=outfind[0],iseditor=(outchecked[1]==
""))
2680 list_users.append(thisuser)
2682 newsession,exist=create_newsession(myform.sessionname.data, myform.description.data, oldsession.id_projects, list_users)
2685 nbts=len(oldsession.tile_sets)
2686 for i
in range(nbts):
2687 newsession.tile_sets.append(oldsession.tile_sets[i])
2691 db.session.add(newsession)
2695 inconsistencies = validate_session_project_consistency(newsession.id)
2697 logging.warning(f
"Found inconsistencies in copied session {newsession.name}: {inconsistencies}")
2699 fix_success, fix_message = fix_session_project_inconsistencies(newsession.id, default_role=
'viewer')
2701 logging.info(f
"Fixed copied session inconsistencies: {fix_message}")
2703 logging.error(f
"Failed to fix copied session inconsistencies: {fix_message}")
2706 traceback.print_exc(file=sys.stderr)
2708 message =
'{"oldsessionname":"'+oldsessionname+
'"}'
2709 flash(
"Session with name {} creation problem.".format(newsession.name))
2710 return render_template(
"main_login.html", **(myrender()), title=
"Copy session TiledViz", form=myform, message=message)
2713 flash(
"You must change session name {} for new session.".format(newsession.data))
2715 flash(
"You must change session name {} for new session.".format(str(newsession)))
2716 return render_template(
"main_login.html", **(myrender()), title=
"Copy Session TiledViz", form=myform)
2718 theaction=myform.tilesetaction.data
2731 logging.debug(
"Action tileset : "+str(message)+
" "+theaction)
2732 if(theaction ==
"useold"):
2733 session[
"is_client_active"]=
True
2734 return redirect(
"/grid")
2735 elif myform.Session_config.data:
2736 message =
'{"sessionname":"'+newsession.name+
'"}'
2737 return redirect(url_for(
".configsession",message=message))
2738 elif(theaction ==
"copy"):
2739 tilesetid=int(myform.tilesetchoice.data)
2740 message =
'{"oldtilesetid":"'+str(tilesetid)+
'"}'
2741 return redirect(url_for(
".copytileset",message=message))
2742 elif (theaction ==
"search"):
2743 message =
'{"oldsessionname":"'+newsession.name+
'"}'
2744 return redirect(url_for(
".searchtileset",message=message))
2745 return render_template(
"main_login.html", **(myrender()), title=
"Copy session TiledViz", form=myform, message=message)
2749@app.route('/editsession', methods=["GET", "POST"])
2751 if (
"username" in session):
2752 if (session[
"username"] ==
"Anonymous"):
2753 return redirect(
"/login")
2755 flash(
"Edit session : User must login !")
2756 return redirect(
"/login")
2758 message=json.loads(request.args[
"message"])
2759 oldsessionname=message[
"oldsessionname"]
2760 oldsession = db.session.query(models.Sessions).filter(models.Sessions.name.like(oldsessionname)).first()
2763 current_user_obj = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
2764 can_edit_session, can_manage_members, role_type, membership = role_session(oldsession,current_user_obj)
2766 can_manage_members =
False
2767 can_edit_session =
False
2769 session[
"can_manage_members"]=can_manage_members
2770 session[
"can_edit_session"]=can_edit_session
2772 myform = BuildEditsessionform(oldsession,session,edit=
True)()
2773 if myform.validate_on_submit():
2775 if hasattr(myform,
'manage_members')
and myform.manage_members.data:
2776 if not can_manage_members:
2777 message =
'{"oldsessionname":"'+oldsessionname+
'"}'
2778 flash(
"Only owners or admins can manage project members.")
2779 return render_template(
"main_login.html", **(myrender()), title=
"Edit session TiledViz", form=myform, can_manage_members=can_manage_members)
2780 return redirect(url_for(
'.project_members', project_id=oldsession.id_projects))
2781 logging.debug(
"editSessionForm : ")
2783 if (myform.editusers.data):
2784 return redirect(url_for(
'project_members', project_id=oldsession.projects.id))
2794 if myform.has_pca.data ==
"YES" :
2815 dict_tiles_all_session = dict()
2816 dict_tiles_all_session[
"nodes"] = []
2818 for tileset
in oldsession.tile_sets:
2819 for tile
in tileset.tiles:
2820 dict_tiles_all_session[
"nodes"].append( {
2822 "title" : tile.title,
2828 json_tiles_text=json.dumps(dict_tiles_all_session)
2829 logging.error(json_tiles_text)
2833 dict_pca_tiles_all_session = json.loads(dict_pca_tiles_all_session)
2834 groups_dict = json.loads(groups_dict)
2837 for i
in range(0, len(oldsession.tile_sets)):
2838 tileset = oldsession.tile_sets[i]
2839 for j
in range(0, len(tileset.tiles)):
2841 tile = tileset.tiles[j]
2842 tile.tags.append(groups_dict[str(tile.id)])
2844 flag_modified(tile,
"tags")
2847 logging.error(
"An error occurred : can't find tile id in groups dict ...")
2851 if (
"add_users" in myform):
2852 if myform.add_users.data:
2853 myform.users.append_entry()
2854 message =
'{"oldsessionname":"'+oldsessionname+
'"}'
2855 flash(
"New user avaible for user {} in session {}".format(session[
"username"], myform.sessionname.data))
2857 return render_template(
"main_login.html", **(myrender()), title=
"Edit session TiledViz", form=myform)
2859 if (myform.sessionname.data != oldsessionname):
2860 message =
'{"oldsessionname":"'+oldsessionname+
'"}'
2861 flash(
"You must NOT change session name to edit session {}".format(oldsessionname))
2862 return render_template(
"main_login.html", **(myrender()), title=
"Edit session TiledViz", form=myform, message=message)
2864 if can_edit_session:
2865 oldsession.description=str(myform.description.data)
2866 creation_date=datetime.datetime.now()
2867 oldsession.creation_date=str(creation_date)
2869 session[
"sessionname"]=oldsessionname
2871 if (
"users" in myform):
2874 logging.debug(
"myform.users : %s" % str(myform.users))
2875 for newuser
in myform.users:
2876 soup=BeautifulSoup(str(newuser),
'lxml')
2877 outsoup=soup.find_all(
"input")
2878 outfind=[ input.get(
"value")
for input
in outsoup ]
2879 outchecked=[ input.get(
"checked")
for input
in outsoup ]
2880 if (len(outfind[0]) > 0):
2881 logging.debug(
"myform.users : %s %s" % (str(outfind[0]),str(outchecked[1] ==
"")))
2882 thisuser=
FormUser(data=outfind[0],iseditor=(outchecked[1]==
""))
2883 list_users.append(thisuser)
2885 ok_list_users=
"Owner %s add users %s to the session %s" % (session[
"username"],str(list_users),oldsessionname)
2886 logging.debug(
"ok_list_users : %s " % ok_list_users)
2888 copy_users_session(oldsession,list_users)
2891 if myform.Session_config.data
and can_edit_session:
2892 message =
'{"sessionname":"'+oldsessionname+
'"}'
2893 return redirect(url_for(
".configsession",message=message))
2895 theaction=myform.tilesetaction.data
2897 ListAllTileSet_ThisSession=[ (str(thistileset.id), thistileset.name)
for thistileset
in oldsession.tile_sets]
2898 if (len(ListAllTileSet_ThisSession) > 0):
2900 tilesetid=int(myform.tilesetchoice.data)
2901 message =
'{"oldtilesetid":'+str(tilesetid)+
'}'
2904 if ( theaction
not in [
"search",
"copy",
"create",
"useold"]
and not (hasattr(myform,
'edit')
and myform.edit.data)):
2905 logging.debug(
"You must check a tileset for this action {}".format(theaction))
2906 flash(
"You must check a tileset for this action {}".format(theaction))
2907 message =
'{"oldsessionname":"'+oldsessionname+
'"}'
2908 return redirect(url_for(
".editsession",message=message))
2909 if(hasattr(myform,
'edit')
and myform.edit.data
and can_edit_session):
2910 logging.debug(
"message before edittileset "+str(message))
2911 return redirect(url_for(
".edittileset",message=message))
2913 logging.debug(
"Action tileset : "+str(message)+
" "+theaction)
2914 if(theaction ==
"useold"):
2915 session[
"is_client_active"]=
True
2916 return redirect(
"/grid")
2917 elif (theaction ==
"create")
and can_edit_session:
2918 flash(
"Tileset requested for user {} in session {}".format(session[
"username"],session[
"sessionname"]))
2919 message=
'{"username":"'+session[
"username"]+
'","sessionname":"'+session[
"sessionname"]+
'"}'
2920 return redirect(url_for(
".addtileset",message=message))
2921 elif(theaction ==
"copy")
and can_edit_session:
2922 return redirect(url_for(
".copytileset",message=message))
2923 elif(theaction ==
"search")
and can_edit_session:
2924 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
2925 return redirect(url_for(
".searchtileset",message=message))
2926 elif(theaction ==
"remove")
and can_edit_session:
2928 thistileset=db.session.query(models.TileSets).filter_by(id=tilesetid).scalar()
2929 logging.debug(
"TileSet for remove : "+str(thistileset))
2930 oldsession.tile_sets.remove(thistileset)
2933 traceback.print_exc(file=sys.stderr)
2935 flash(
"Error remove tileset {}".format(db.session.query(models.TileSets).filter_by(id=tilesetid).scalar().name))
2936 message =
'{"oldsessionname":"'+oldsessionname+
'"}'
2937 return redirect(url_for(
".editsession",message=message))
2940 if not can_edit_session:
2941 flash(
"You have view-only permissions on this project.")
2942 return render_template(
"main_login.html", **(myrender()), title=
"Edit session TiledViz", form=myform, message=
'{"oldsessionname":"'+oldsessionname+
'"}')
2943 return render_template(
"main_login.html", **(myrender()), title=
"Edit session TiledViz", form=myform, message=message)
2946@app.route('/editnodes', methods=["GET", "POST"])
2948 if (
"username" in session):
2949 if (session[
"username"] ==
"Anonymous"):
2950 return redirect(
"/login")
2952 flash(
"Edit nodes : User must login !")
2953 return redirect(
"/login")
2955 message=json.loads(request.args[
"message"])
2956 oldsessionname=message[
"oldsessionname"]
2957 ThisSession = db.session.query(models.Sessions).filter(models.Sessions.name.like(oldsessionnam)).first()
2961 current_user_obj = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
2962 membership = db.session.query(models.ProjectMembers).filter_by(
2963 project_id=ThisSession.id_projects, user_id=current_user_obj.id
2964 ).first()
if current_user_obj
and ThisSession
else None
2965 role_type = membership.role_type
if membership
else None
2966 can_edit_nodes = role_type
in valid_manage_project
2968 can_edit_nodes =
False
2970 if not can_edit_nodes:
2971 flash(
"You do not have permission to edit nodes in this project.")
2972 return redirect(
"/grid")
2974 if (type(ThisSession) != type(
None)):
2975 ListAllTileSet_ThisSession=ThisSession.tile_sets
2977 logging.warning(
"You must choose a valid session for editnodes")
2978 flash(
"You didn't select a valid session in editnodes.")
2979 return redirect(
"/editsession")
2981 session[
"tilesetnames"]=[ thistileset.name
for thistileset
in ListAllTileSet_ThisSession ]
2982 logging.debug(
"All TileSet for session "+str(session[
"sessionname"])+
" : "+str(session[
"tilesetnames"]))
2989 tiles_data[
"nodes"]=[]
2991 lts=len(ThisSession.tile_sets)
2993 thistileset=ThisSession.tile_sets[ts]
2994 nbtiles=len(thistileset.tiles)
2995 nbr_of_tiles = nbr_of_tiles + nbtiles
2997 if (thistileset.type_of_tiles ==
"CONNECTION"):
2998 oldconnection=thistileset.connections
2999 out_nodes_json = os.path.join(
"/TiledViz/TVFiles", str(oldconnection.id_users), str(oldconnection.id),
"nodes.json")
3001 if ( os.path.exists( out_nodes_json ) ):
3003 with open(out_nodes_json)
as json_tiles_file:
3004 tsjson=json.loads(json_tiles_file.read())
3006 logging.warning(
"nodes.json read and OK "+out_nodes_json)
3007 tiledata=tsjson[
"nodes"]
3009 if ( O !=
"nodes" ):
3010 if ( O
in tiles_data ):
3011 tiles_data[O]=tiles_data[O]+tsjson[O]
3013 tiles_data[O]=tsjson[O]
3014 except Exception
as err:
3015 traceback.print_exc(file=sys.stderr)
3016 strerror=
"Error from json "+out_nodes_json+
" file from connection : "+str(err)
3017 logging.error(strerror)
3020 tiledata=tvdb.encode_tileset(thistileset)
3022 tiles_data[
"nodes"]=tiles_data[
"nodes"]+tiledata
3024 jsontransfert[session[
"sessionname"]]={
"callfunction":
'{"function":"show_grid",'+
'"args":{"sessionname":"'+oldsessionname+
'"}}'}
3025 jsontransfert[session[
"sessionname"]][
"TheJson"]=tiles_data
3027 return redirect(url_for(
".jsoneditor"))
3031@app.route('/searchtileset', methods=["GET", "POST"])
3034 if (
"username" in session):
3035 if (session[
"username"] ==
"Anonymous"):
3036 return redirect(
"/login")
3038 flash(
"Search TileSet : User must login !")
3039 return redirect(
"/login")
3041 message=json.loads(request.args[
"message"])
3042 except json.decoder.JSONDecodeError
as e:
3043 logging.error(
"message error ! "+str(e))
3044 logging.error(
"message : "+str(request.args[
"message"]))
3045 traceback.print_exc(file=sys.stderr)
3046 message=json.loads(request.args[
"message"].replace(
"'",
'"'))
3048 oldsessionname=message[
"oldsessionname"]
3049 oldsession = db.session.query(models.Sessions).filter(models.Sessions.name.like(oldsessionname)).first()
3054 user_id=get_user_id(
"SearchTileSetPerm",session[
"username"])
3055 if not oldsession
or not can_manage_project(oldsession.id_projects, user_id):
3056 flash(
"You don't have permission to modify tilesets for this project.")
3057 return redirect(
"/allsessions")
3059 flash(
"Unable to validate permissions for tileset search.")
3060 return redirect(
"/allsessions")
3062 querysessions= db.session.query(models.Sessions).filter(models.Sessions.users.any(name=session[
"username"])).all()
3064 printstr=
"{0:\xa0<"+tilesetl+
"."+tilesetl+
"}|\xa0{1:\xa0<"+datel+
"."+datel+
"}\xa0|\xa0{2:\xa0<"+descrl+
"."+descrl+
"}"
3067 listtilesets.append((
'NoChoice',printstr.format(
"Tileset name",
"Date and Time",
"Data Path")))
3068 for thissession
in querysessions:
3070 for tileset
in thissession.tile_sets:
3071 if ( tileset.name
not in listtilesets ):
3072 thedate=db.session.query(models.TileSets.creation_date).filter_by(name=tileset.name).scalar().isoformat().replace(
"T",
" ")
3073 logging.warning(
"Compare thedate : %s %s" % (thedate, tileset.creation_date.isoformat().replace(
"T",
" ")))
3074 listtilesets.append((str(tileset.id),
3078 tileset.Dataset_path)))
3081 myform = BuildOldTileSetForm(session[
"username"], listtilesets)()
3082 if myform.validate_on_submit():
3083 if (myform.chosen_tileset.data==
"NoChoice"):
3084 flash(
"Error : no TileSet Selected.")
3085 return redirect(url_for(
".searchtileset",message=message))
3087 logging.warning(
"Out of forms, add tilesets :"+str(myform.chosen_tileset.data))
3088 thisTS=db.session.query(models.TileSets).filter_by(id=myform.chosen_tileset.data).scalar()
3089 logging.warning(
"For user : "+session[
"username"]+
", add tilesets :"+str(thisTS.name))
3090 oldsession.tile_sets.append(thisTS)
3092 message =
'{"oldsessionname":"'+oldsessionname+
'"}'
3093 flash(
"Add tileSet {}.".format(thisTS.name))
3094 return redirect(url_for(
".editsession",message=message))
3096 return render_template(
"main_login.html", **(myrender()), title=
"All my Tiledsets ", form=myform)
3099@app.route('/configsession', methods=["GET", "POST"])
3101 if (
"username" in session):
3102 if (session[
"username"] ==
"Anonymous"):
3103 return redirect(
"/login")
3105 flash(
"Config session : User must login !")
3106 return redirect(
"/login")
3107 if (
not "sessionname" in session ):
3108 return redirect(
"/allsessions")
3110 message=json.loads(request.args[
"message"])
3112 sessionname=message[
"sessionname"]
3113 thesession = db.session.query(models.Sessions).filter(models.Sessions.name.like(sessionname)).first()
3116 if ( session[
"sessionname"]
in jsontransfert):
3117 if (
"TheJson" in jsontransfert[session[
"sessionname"]]):
3119 json_configs=jsontransfert[session[
"sessionname"]][
"TheJson"]
3120 jsontransfert[session[
"sessionname"]].pop(
"TheJson")
3121 logging.debug(
"configsession : come back from jsoneditor")
3128 logging.debug(
"configsession : we can't be here !")
3129 if ( thesession.config ==
None ):
3130 logging.debug(
"configsession : using config_default.json")
3131 config_default_file=open(
"app/static/js/config_default.json",
'r')
3132 json_configs=json.load(config_default_file)
3133 config_default_file.close()
3135 logging.debug(
"configsession : old session config.")
3136 json_configs=thesession.config
3138 if ( thesession.config ==
None ):
3139 logging.debug(
"configsession : using config_default.json")
3140 config_default_file=open(
"app/static/js/config_default.json",
'r')
3141 json_configs=json.load(config_default_file)
3142 config_default_file.close()
3144 logging.debug(
"configsession : old session config.")
3145 json_configs=thesession.config
3147 json_configs_text=json.JSONEncoder().encode(json_configs)
3149 myform = BuildConfigSessionForm(json_configs,json_configs_text)()
3151 if myform.validate_on_submit():
3153 json_configs = myform.json_config_text.data
3155 if myform.editjson.data:
3158 jsontransfert[session[
"sessionname"]]={
"callfunction":
'{"function":"configsession",'+
'"args":{"sessionname":"'+sessionname+
'"}}',
3159 "TheJson":json_configs}
3161 return redirect(url_for(
".jsoneditor"))
3164 jsonConfigs = json.loads(json_configs)
3170 thesession.config=jsonConfigs
3171 flag_modified(thesession,
"config")
3174 message =
'{"oldsessionname":"'+sessionname+
'"}'
3175 return redirect(url_for(
".editsession",message=message))
3177 return render_template(
"main_login.html", **(myrender()), title=
"Config session", form=myform, message=message)
3181@app.route('/addtileset', methods=["GET", "POST"])
3183 if (
"username" in session):
3184 if (session[
"username"] ==
"Anonymous"):
3185 return redirect(
"/login")
3187 flash(
"Add TileSet : User must login !")
3188 return redirect(
"/login")
3189 if (
not "sessionname" in session ):
3190 return redirect(
"/allsessions")
3194 ThisSession = db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
3195 user_id=get_user_id(
"AddTileSetPerm",session[
"username"])
3196 if not ThisSession
or not can_manage_project(ThisSession.id_projects, user_id):
3197 flash(
"You don't have permission to add tilesets in this project.")
3198 return redirect(
"/allsessions")
3200 flash(
"Unable to validate permissions for tileset creation.")
3201 return redirect(
"/allsessions")
3203 myform = BuildTilesSetForm()()
3205 message=json.loads(request.args[
"message"])
3206 if myform.validate_on_submit():
3207 logging.info(
"in addtileset")
3211 if (myform.json_tiles_file.data) :
3212 json_tiles_file = myform.json_tiles_file.data
3213 json_tiles = json_tiles_file.read()
3214 elif (myform.json_tiles_text.data):
3216 json_tiles = myform.json_tiles_text.data
3221 jsonTileSet = json.loads(json_tiles)
3222 except json.decoder.JSONDecodeError
as e:
3223 logging.error(
"Addtileset : json TileSet error ! "+str(e))
3224 logging.error(
"Data : "+str(json_tiles))
3225 traceback.print_exc(file=sys.stderr)
3226 json_tiles=json.loads(json_tiles.replace(
"'",
'"'))
3228 jsonTileSet = json.loads(json_tiles)
3229 except json.decoder.JSONDecodeError
as e:
3230 logging.error(
"Addtileset : correction with double quotes not efficient ! "+str(e))
3231 flash(
"Please look on data for TileSet json compliance")
3232 return redirect(url_for(
".addtileset",message=message))
3234 nbr_of_tiles = len(jsonTileSet[
"nodes"])
3235 logging.info(
"Number of tiles "+str(nbr_of_tiles))
3240 connectionbool=
False
3241 if (myform.type_of_tiles.data ==
"URL"):
3243 elif(myform.type_of_tiles.data ==
"CONNECTION"):
3244 launch_file=myform.script_launch_file.data
3245 if (
not launch_file):
3246 flash(
"TileSet with connection must have at least a script to launch your tiles.\n You must add launch_file script.")
3247 return render_template(
"main_login.html", **(myrender()), title=
"New TileSet TiledViz", form=myform, message=message)
3251 conn_session=db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
3252 creation_date=datetime.datetime.now()
3253 tilesetname=myform.name.data
3254 if ( myform.dataset_path.data ):
3255 datapath=str(myform.dataset_path.data)
3262 newtileset,exist=create_newtileset(tilesetname, conn_session, myform.type_of_tiles.data, datapath, creation_date)
3265 db.session.add(newtileset)
3268 traceback.print_exc(file=sys.stderr)
3270 flash(
"TileSet with name {} creation problem :".format(tilesetname))
3271 return render_template(
"main_login.html", **(myrender()), title=
"New TileSet TiledViz", form=myform, message=message)
3273 flash(
"TileSet with name {} already exists : Please give another name ".format(tilesetname))
3274 return render_template(
"main_login.html", **(myrender()), title=
"New TileSet TiledViz", form=myform, message=message)
3277 if (connectionbool):
3278 TStmpName=
"tileset_"+str(newtileset.id)
3279 if (
not TStmpName
in jsontransfert):
3280 jsontransfert[TStmpName]={}
3281 if (myform.configfiles.data):
3282 for FileS
in myform.configfiles.data:
3283 jsontransfert[TStmpName][FileS.filename]=FileS.read()
3286 jsontransfert[
"tileset_"+str(newtileset.id)][launch_file.filename]=launch_file.read()
3287 newtileset.launch_file=launch_file.filename
3294 for i
in range(nbr_of_tiles):
3295 Mynode=jsonTileSet[
"nodes"][i]
3297 title,name,comment,tags,variable,pos_px_x,pos_px_y,IdLocation,url,ConnectionPort = \
3298 convertTile(Mynode,tilesetname,connectionbool,urlbool,datapath)
3299 except Exception
as e:
3300 etype, value, tb = sys.exc_info()
3301 flash(
"TileSet with name {} creation problem :".format(tilesetname)+
"\n"+
3302 ''.join(traceback.format_tb(tb)))
3303 logging.error(
''.join(traceback.format_tb(tb)))
3304 return redirect(url_for(
".addtileset",message=message))
3306 newtile = models.Tiles(title=title,
3309 source= {
"name" : name,
3310 "connection" : ConnectionPort,
3312 "variable": variable
3316 IdLocation=IdLocation,
3317 creation_date= creation_date)
3318 lasttile=db.session.query(models.Tiles.id).order_by(models.Tiles.id.desc()).first()
3320 newtile.id=lasttile.id+1
3324 db.session.add(newtile)
3326 logging.warning(str(i)+
" add tile "+str(newtile.id)+
" "+str(newtile.title))
3328 newtileset.tiles.append(newtile)
3332 session[
"is_client_active"]=
True
3334 if (connectionbool):
3335 message =
'{"oldtilesetid":'+str(newtileset.id)+
',"oldsessionname":"'+session[
"sessionname"]+
'"}'
3336 return redirect(url_for(
".addconnection",message=message))
3338 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
3339 return redirect(url_for(
".editsession",message=message))
3341 return render_template(
"edittileset.html", **(myrender()), title=
"New TileSet TiledViz", form=myform, message=message)
3346@app.route('/copytileset', methods=["GET", "POST"])
3348 if (
"username" in session):
3349 if (session[
"username"] ==
"Anonymous"):
3350 return redirect(
"/login")
3352 flash(
"Copy TileSet : User must login !")
3353 return redirect(
"/login")
3354 if (
not "sessionname" in session ):
3355 return redirect(
"/allsessions")
3359 ThisSession = db.session.query(models.Sessions).filter(models.Sessions.name(session[
"sessionname"])).first()
3360 user_id=get_user_id(
"CopyTileSetPerm",session[
"username"])
3361 if not ThisSession
or not can_manage_project(ThisSession.id_projects, user_id):
3362 flash(
"You don't have permission to copy tilesets in this project.")
3363 return redirect(
"/allsessions")
3365 flash(
"Unable to validate permissions for tileset copy.")
3366 return redirect(
"/allsessions")
3368 message=json.loads(request.args[
"message"])
3369 logging.warning(
"copytileset : "+str(message))
3370 oldtilesetid=message[
"oldtilesetid"]
3371 oldtileset=db.session.query(models.TileSets).filter_by(id=oldtilesetid).scalar()
3373 myform = BuildTilesSetForm(oldtileset,onlycopy=
True)()
3375 flash(
"Tileset {} copy for user {} in session {}".format(oldtileset.name,session[
"username"],session[
"sessionname"]))
3376 if myform.validate_on_submit():
3377 logging.info(
"in copy tileset")
3379 if (myform.name.data == oldtileset.name):
3380 message =
'{"oldtilsetid":"'+str(oldtilesetid)+
'"}'
3381 flash(
"You must change tilsetname to copy tileset {}".format(oldtileset.name))
3383 return render_template(
"main_login.html", **(myrender()), title=
"Copy tileset TiledViz", form=myform, message=message)
3385 nbr_of_tiles = len(oldtileset.tiles)
3387 sessioncopy=db.session.query(models.Sessions).filter_by(models.Sessions.name.like(session[
"sessionname"])).scalar()
3388 creation_date=datetime.datetime.now()
3389 tilesetname=myform.name.data
3390 newtileset, exist=create_newtileset(myform.name.data, sessioncopy, oldtileset.type_of_tiles, oldtileset.Dataset_path, creation_date)
3393 db.session.add(newtileset)
3396 traceback.print_exc(file=sys.stderr)
3398 flash(
"TileSet creation with name {} already exist :".format(tilesetname))
3399 return render_template(
"main_login.html", **(myrender()), title=
"New TileSet TiledViz", form=myform, message=message)
3403 for i
in range(nbr_of_tiles):
3404 oldtile=oldtileset.tiles[i]
3405 newtileset.tiles.append(oldtile)
3408 session[
"is_client_active"]=
True
3412 connectionbool=
False
3413 if (oldtileset.type_of_tiles ==
"URL"):
3415 elif(oldtileset.type_of_tiles ==
"CONNECTION"):
3418 if (connectionbool):
3420 copy_tileset_connection(oldtileset,newtileset,session[
"sessionname"])
3421 logging.error(
"copy id connection : "+str(newtileset.id_connections))
3423 flag_modified(newtileset,
"config_files")
3426 message =
'{"oldtilesetid":'+str(newtileset.id)+
',"oldsessionname":"'+session[
"sessionname"]+
'"}'
3427 return redirect(url_for(
".edittileset",message=message))
3429 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
3430 return redirect(url_for(
".editsession",message=message))
3432 return render_template(
"edittileset.html", **(myrender()), title=
"Copy TileSet TiledViz", form=myform, message=message)
3434def save_tiles(oldtileset,nbr_of_tiles,connectionbool,urlbool,datapath,jsonTileSet,creation_date):
3436 tilesetname=oldtileset.name
3438 for i
in range(nbr_of_tiles):
3439 Mynode=jsonTileSet[
"nodes"][i]
3443 title,name,comment,tags,variable,pos_px_x,pos_px_y,IdLocation,url,ConnectionPort = \
3444 convertTile(Mynode,tilesetname,connectionbool,urlbool,datapath)
3445 except Exception
as e:
3446 etype, value, tb = sys.exc_info()
3447 flash(
"TileSet with name {} edition problem :".format(tilesetname)+
"\n"+
3448 ''.join(traceback.format_tb(tb)))
3449 message=json.loads(request.args[
"message"].replace(
"'",
'"'))
3450 logging.error(
''.join(traceback.format_tb(tb)))
3451 return redirect(url_for(
".edittileset",message=message))
3490 newtile = models.Tiles(title=title,
3493 source= {
"name" : name,
3494 "connection" : ConnectionPort,
3496 "variable": variable
3500 IdLocation=IdLocation,
3501 creation_date= creation_date)
3502 lasttile=db.session.query(models.Tiles.id).order_by(models.Tiles.id.desc()).first()
3504 newtile.id=lasttile.id+1
3507 db.session.add(newtile)
3508 oldtileset.tiles.append(newtile)
3509 logging.warning(str(i)+
" add tile "+str(newtile.id))
3517@app.route('/edittileset', methods=["GET", "POST"])
3519 if (
"username" in session):
3520 if (session[
"username"] ==
"Anonymous"):
3521 return redirect(
"/login")
3523 flash(
"Edit TileSet : User must login !")
3524 return redirect(
"/login")
3525 if (
not "sessionname" in session ):
3526 return redirect(
"/allsessions")
3529 message=json.loads(request.args[
"message"].replace(
"'",
'"'))
3530 except json.decoder.JSONDecodeError
as e:
3531 logging.error(
"message error ! "+str(e))
3532 logging.error(
"message : "+str(request.args[
"message"]))
3533 traceback.print_exc(file=sys.stderr)
3535 logging.warning(
"edittileset : "+str(message))
3537 oldtilesetid=message[
"oldtilesetid"]
3538 oldtileset=db.session.query(models.TileSets).filter_by(id=oldtilesetid).one()
3543 ThisSession = db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
3544 user_id=get_user_id(
"EditTileSetPerm",session[
"username"])
3545 if not ThisSession
or not can_manage_project(ThisSession.id_projects, user_id):
3546 flash(
"You don't have permission to edit tilesets in this project.")
3547 return redirect(
"/allsessions")
3549 flash(
"Unable to validate permissions for tileset edition.")
3550 return redirect(
"/allsessions")
3554 buildargs[
"oldtileset"]=oldtileset
3560 if ( session[
"sessionname"]
in jsontransfert):
3561 if (
"TheJson" in jsontransfert[session[
"sessionname"]]):
3563 logging.debug(
"TheJson is already define in message")
3564 TheJson=jsontransfert[session[
"sessionname"]][
"TheJson"]
3565 jsontransfert[session[
"sessionname"]].pop(
"TheJson")
3567 json_tiles_text=json.JSONEncoder().encode(TheJson)
3569 buildargs[
"json_tiles_text"]=json_tiles_text
3571 traceback.print_exc(file=sys.stderr)
3572 flash(
"Error from json editor. Please try again.")
3573 return redirect(url_for(
".edittileset",message=message))
3575 connectionbool=
False
3576 if(oldtileset.type_of_tiles ==
"CONNECTION"):
3580 oldconnection=db.session.query(models.Connections).filter_by(id=oldtileset.id_connections).one()
3581 oldConnection_id=oldtileset.id_connections
3582 buildargs[
"editconnection"]=
True
3584 except sqlalchemy.orm.exc.NoResultFound:
3585 flash(
"Tileset {} edit for user {} : no connection found ! ".format(oldtileset.name,session[
"username"]))
3586 oldConnection_id = 0
3587 buildargs[
"editconnection"]=
True
3588 except AttributeError
as err:
3591 traceback.print_exc(file=sys.stderr)
3592 logging.error(
"Error get old connection for tileset %s : %s" % ( oldtileset.name, err ))
3593 flash(
"Tileset {} edit for user {} : AttributeError ! ".format(oldtileset.name,session[
"username"]))
3595 except Exception
as err:
3596 traceback.print_exc(file=sys.stderr)
3597 logging.error(
"Error get old connection for tileset %s : %s" % ( oldtileset.name, err ))
3598 flash(
"Error get old connection for tileset %s : %s" % ( oldtileset.name, err ))
3600 if ( oldConnection_id < 0):
3601 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
3602 return redirect(url_for(
".editsession",message=message))
3605 myform = BuildTilesSetForm(**buildargs)()
3607 if (
"username" in session):
3608 flash(
"Tileset {} edit for user {} in session {}".format(oldtileset.name,session[
"username"],session[
"sessionname"]))
3610 flash(
"You are not connected. You must login before using a connection.")
3611 return redirect(
"/login")
3613 if myform.validate_on_submit():
3614 logging.info(
"in tileset editor")
3616 if(connectionbool
and buildargs[
"editconnection"]):
3617 if (myform.editconnection.data):
3618 message =
'{"oldtilesetid":'+str(oldtileset.id)+
',"oldsessionname":"'+session[
"sessionname"]+
'"}'
3619 return redirect(url_for(
".editconnection",message=message))
3620 if (myform.shellconnection.data):
3621 message =
'{"direct":1,"oldtilesetid":'+str(oldtileset.id)+
',"oldsessionname":"'+session[
"sessionname"]+
'"}'
3622 return redirect(url_for(
".editconnection",message=message))
3624 if(myform.goback.data):
3625 logging.debug(
"go back to edit old session : "+session[
"sessionname"])
3626 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
3627 return redirect(url_for(
".editsession",message=message))
3631 logging.info(
"Calling pca_nodes methode of anatread")
3632 logging.info(
"The user as selected the option : " + myform.has_pca.data)
3635 if (myform.json_tiles_file.data) :
3636 json_tiles_file = myform.json_tiles_file.data
3637 logging.warning(
"Read json_tiles_file :"+myform.json_tiles_file.data.filename)
3641 if myform.has_pca.data ==
"YES" :
3642 json_tiles_text=json_tiles_file.read()
3644 json_tiles = json_pca_tiles_text
3646 json_tiles = json_tiles_file.read()
3652 if myform.has_pca.data ==
"YES" :
3654 json_tiles = json_pca_tiles_text
3655 logging.info(
"edittileset -> myform.has_pca.data = YES -> json_tiles")
3657 json_tiles = myform.json_tiles_text.data
3660 if myform.editjson.data:
3661 jsontransfert[session[
"sessionname"]]={
"callfunction":
'{"function":"edittileset",'+
'"args":{"oldtilesetid":"'+str(oldtilesetid)+
'"}}',
3662 "TheJson":json_tiles}
3665 return redirect(url_for(
".jsoneditor"))
3666 except Exception
as err:
3667 traceback.print_exc(file=sys.stderr)
3668 logging.error(
"Error editjson %s : %s" % ( str(myform.editjson), err ))
3670 if(oldtileset.type_of_tiles ==
"CONNECTION" and myform.manage_connection.data !=
"reNew" and not myform.createconnection.data):
3671 user_id=get_user_id(
"edittileset",session[
"username"])
3672 if (
not "connection"+str(oldConnection_id)
in session):
3673 flash(
"You don't have connection information in your personal cookie for this connection.")
3674 logging.error(
"You (user "+str(user_id)+
") don't have connection information in your personal cookie for this connection : "+str(oldConnection_id))
3675 message=request.args[
"message"]
3676 return redirect(url_for(
".edittileset",message=message))
3679 user_path=os.path.join(
"/TiledViz/TVFiles",str(user_id))
3680 connectionpath=os.path.join(user_path,str(oldConnection_id))
3683 oldtileset_config_files=oldtileset.config_files
3684 if (myform.configfiles.data):
3685 for FileS
in myform.configfiles.data:
3687 tf = tempfile.NamedTemporaryFile(mode=
"w+b",dir=connectionpath,prefix=
"",delete=
False)
3688 tf.write(FileS.read())
3691 if (os.stat(tf.name).st_size > 0):
3692 if (FileS.filename
in oldtileset_config_files):
3694 boolDiff=filecmp.cmp(f1=oldtileset_config_files[FileS.filename],f2=newfilename)
3695 logging.warning(
"Diff with modified config file : "+str(boolDiff))
3698 strrm=
"rm -f "+oldtileset_config_files[FileS.filename]
3699 logging.warning(
"Update old config file "+FileS.filename+
" in edittileset.")
3701 oldtileset.config_files[FileS.filename]=newfilename
3702 flag_modified(oldtileset,
"config_files")
3706 strrm=
"rm -f "+newfilename
3710 oldtileset.config_files[FileS.filename]=newfilename
3711 logging.warning(
"Add new config file "+FileS.filename+
" in edittileset.")
3712 flag_modified(oldtileset,
"config_files")
3716 strrm=
"rm -f "+newfilename
3720 launch_file=myform.script_launch_file.data
3722 oldtileset_launch_file=oldtileset.launch_file
3723 FileS=myform.script_launch_file.data
3724 tf = tempfile.NamedTemporaryFile(mode=
"w+b",dir=connectionpath,prefix=
"",delete=
False)
3725 tf.write(FileS.read())
3728 if (os.stat(tf.name).st_size > 0):
3729 if (FileS.filename
in oldtileset_config_files):
3731 boolDiff=filecmp.cmp(f1=oldtileset_config_files[FileS.filename],f2=newfilename)
3732 logging.warning(
"Diff with modified launch case file : "+str(boolDiff))
3735 strrm=
"rm -f "+oldtileset_config_files[FileS.filename]
3736 logging.warning(
"Update old launch file "+FileS.filename+
" in edittileset.")
3738 oldtileset.config_files[FileS.filename]=newfilename
3739 flag_modified(oldtileset,
"config_files")
3743 strrm=
"rm -f "+newfilename
3748 strrm=
"rm -f "+oldtileset_config_files[oldtileset_launch_file]
3749 del(oldtileset_config_files[oldtileset_launch_file])
3750 logging.warning(
"Rename launch file from "+oldtileset_launch_file
3751 +
" to "+FileS.filename+
" in edittileset.")
3753 oldtileset.launch_file=FileS.filename
3754 oldtileset.config_files[FileS.filename]=newfilename
3755 flag_modified(oldtileset,
"config_files")
3759 strrm=
"rm -f "+newfilename
3762 elif(oldtileset.type_of_tiles ==
"CONNECTION" and (myform.manage_connection.data ==
"reNew" or myform.createconnection.data)):
3763 launch_file=myform.script_launch_file.data
3764 if (
not launch_file):
3765 flash(
"TileSet with connection must have at least a script to launch your tiles.\n You must add launch_file script.")
3766 return render_template(
"main_login.html", **(myrender()), title=
"Edit TileSet TiledViz", form=myform, message=message)
3768 TStmpName=
"tileset_"+str(oldtileset.id)
3769 if (
not TStmpName
in jsontransfert):
3770 jsontransfert[TStmpName]={}
3771 if (myform.configfiles.data):
3772 for FileS
in myform.configfiles.data:
3773 jsontransfert[TStmpName][FileS.filename]=FileS.read()
3776 jsontransfert[
"tileset_"+str(oldtileset.id)][launch_file.filename]=launch_file.read()
3777 oldtileset.launch_file=launch_file.filename
3782 if (len(json_tiles) > 0):
3783 jsonTileSet = json.loads(json_tiles)
3785 jsonTileSet = {
"nodes":[]}
3808 nbr_of_tiles = len(jsonTileSet[
"nodes"])
3809 logging.info(
"Number of tiles "+str(nbr_of_tiles))
3810 except Exception
as e:
3811 return redirect(url_for(
".edittileset",message=message))
3821 old_nbr_of_tiles=len(oldtileset.tiles)
3822 if (nbr_of_tiles > old_nbr_of_tiles):
3824 elif (nbr_of_tiles < old_nbr_of_tiles):
3825 deletesometiles=
True
3829 if (myform.type_of_tiles.data ==
"URL"):
3832 creation_date=datetime.datetime.now()
3833 if (myform.dataset_path.data):
3834 datapath=str(myform.dataset_path.data)
3840 oldtileset.datapath=datapath
3841 oldtileset.creation_date=creation_date
3845 session[
"is_client_active"]=
True
3848 if (connectionbool
and myform.manage_connection.data):
3849 message =
'{"oldtilesetid":'+str(oldtileset.id)+
',"oldsessionname":"'+session[
"sessionname"]+
'"}'
3851 if (myform.manage_connection.data ==
"reNew" or myform.createconnection.data):
3852 return redirect(url_for(
".addconnection",message=message))
3855 elif (myform.manage_connection.data ==
"Quit"):
3856 return redirect(url_for(
".removeconnection",message=message))
3858 save_tiles(oldtileset,nbr_of_tiles,connectionbool,urlbool,datapath,jsonTileSet,creation_date)
3859 return redirect(url_for(
".editsession",message=message))
3865 save_tiles(oldtileset,nbr_of_tiles,connectionbool,urlbool,datapath,jsonTileSet,creation_date)
3866 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
3867 return redirect(url_for(
".editsession",message=message))
3869 return render_template(
"edittileset.html", **(myrender()), title=
"Edit TileSet TiledViz", form=myform, message=message)
3872def linkrandom(nbchar):
3873 ALPHABET =
"B6P8VbhZoGp9JYd0uLCsAT4DXF1xqIUSyQMniNgje5_~3crvlHR-7W2f=kEtmazwKO"
3874 mystring=
''.join(random.choice(ALPHABET)
for i
in range(nbchar)).encode(
'utf-8')
3879@app.route('/vncconnection', methods=['GET', 'POST'])
3881 if (
"username" in session):
3882 if (session[
"username"] ==
"Anonymous"):
3883 return redirect(
"/login")
3885 flash(
"VNC connection : User must login !")
3886 return redirect(
"/login")
3887 logging.warning(
"Enter in connection.")
3892 message=json.loads(request.args[
"message"])
3893 except json.decoder.JSONDecodeError
as e:
3894 logging.error(
"message error ! "+str(e))
3895 logging.error(
"message : "+str(request.args[
"message"]))
3896 traceback.print_exc(file=sys.stderr)
3897 message=json.loads(request.args[
"message"].replace(
"'",
'"'))
3899 idconnection=message[
"connectionid"]
3900 idtileset=message[
"oldtilesetid"]
3902 oldconnection=db.session.query(models.Connections).filter_by(id=idconnection).first()
3904 flash(
"This connection doesn't exist.")
3905 logging.error(
"This connection doesn't exist.")
3906 message=request.args[
"message"]
3907 return redirect(url_for(
".edittileset",message=message))
3909 if (
"username" in session):
3910 user_id=get_user_id(
"vncconnection",session[
"username"])
3912 flash(
"You are not connected. You must login before using a connection.")
3913 return redirect(
"/login")
3914 if (
not "connection"+str(idconnection)
in session):
3915 flash(
"You don't have connection information in your personal cookie for this connection.")
3916 logging.error(
"You (user "+str(user_id)+
") don't have connection information in your personal cookie for this connection : "+str(idconnection))
3917 message=request.args[
"message"]
3918 return redirect(url_for(
".edittileset",message=message))
3920 vnctransfert=json.loads(session[
"connection"+str(idconnection)])
3921 logging.debug(
"With infos :"+str(vnctransfert))
3923 flaskaddr=os.getenv(
"flaskhost")
3924 logging.debug(
"Detected flask address :"+str(flaskaddr))
3926 callfunction=vnctransfert[
"callfunction"]
3928 if (user_id != oldconnection.id_users) :
3929 flash(
"You can not access to this connection. You are not its owner.")
3930 owner=db.session.query(models.Users).filter_by(id=oldconnection.id_users).one().name
3931 you=db.session.query(models.Users).filter_by(id=user_id).one().name
3932 logging.error(
"You (user "+you+
") can not access to this connection owned by user "+owner)
3933 message=request.args[
"message"]
3934 return redirect(url_for(
".edittileset",message=message))
3937 db.session.refresh(oldconnection)
3938 connection_vnc=oldconnection.connection_vnc
3939 logging.warning(
"PORT VNC :"+str(connection_vnc))
3940 if (connection_vnc == 0):
3941 flash_msg=
"Error reading PORT VNC :"+str(connection_vnc)
3942 logging.error(flash_msg)
3944 message=request.args[
"message"]
3945 return redirect(url_for(
".edittileset",message=message))
3946 connection_vnc=connection_vnc+32768
3948 if ( request.method ==
'POST'):
3949 logging.warning(
"in POST")
3951 message=json.JSONEncoder().encode(vnctransfert[
"args"])
3953 logging.warning(
"killconnection: "
3954 +str(session[
"username"])+
" ; "
3955 +str(idtileset)+
" ; "
3959 out_nodes_json = os.path.join(
"/TiledViz/TVFiles", str(user_id), str(idconnection),
"nodes.json")
3960 logging.warning(
"out_nodes_json after vncconnection.html :"+out_nodes_json)
3965 if (
not session[
"sessionname"]
in jsontransfert):
3966 jsontransfert[session[
"sessionname"]]={}
3970 time.sleep(timeAlive)
3971 if (count > NbTimeAlive):
3972 if (
"TheJson" in jsontransfert[session[
"sessionname"]]):
3973 del(jsontransfert[session[
"sessionname"]][
"TheJson"])
3974 return redirect(url_for(
"."+callfunction,message=message))
3975 if ( os.path.exists( out_nodes_json ) ):
3977 json_tiles_file=open(out_nodes_json)
3978 jsontransfert[session[
"sessionname"]][
"TheJson"]=json.loads(json_tiles_file.read())
3979 json_tiles_file.close()
3980 logging.warning(
"nodes.json read and OK "+out_nodes_json)
3981 return redirect(url_for(
"."+callfunction,message=message))
3982 except Exception
as err:
3983 traceback.print_exc(file=sys.stderr)
3984 strerror=
"Error from json "+out_nodes_json+
" file from connection : "+str(err)
3985 logging.error(strerror)
3987 logging.warning(
"Wait for "+out_nodes_json)
3990 return render_template(
"vncconnection.html", **(myrender()),
3991 port=connection_vnc,
3994 vncpassword=vnctransfert[
"vncpassword"],
3995 session=session[
"sessionname"],
3996 flaskaddr=flaskaddr)
3998@app.route('/addconnection', methods=["GET", "POST"])
4000 global TimeConnection
4002 if (
"username" in session):
4003 if (session[
"username"] ==
"Anonymous"):
4004 return redirect(
"/login")
4006 flash(
"Add connection : User must login !")
4007 return redirect(
"/login")
4009 User = db.session.query(models.Users).filter_by(name=session[
"username"]).one()
4011 logging.warning(f
"authchoices before {authchoice}")
4012 myform = BuildConnectionsForm(is_admin=User.is_admin,authchoice=authchoice)()
4014 print(
'message=',str(request.args[
"message"]))
4015 message=json.loads(request.args[
"message"])
4016 message[
"TimeConnection"]=TimeConnection
4018 logging.debug(
"ConnectionForm built."+str(message))
4022 ThisSession = db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
4023 user_id=get_user_id(
"AddConnectionPerm",session[
"username"])
4024 if not ThisSession
or not can_manage_project(ThisSession.id_projects, user_id):
4025 flash(
"You don't have permission to manage connections in this project.")
4026 return redirect(
"/allsessions")
4028 flash(
"Unable to validate permissions for connection management.")
4029 return redirect(
"/allsessions")
4031 if myform.validate_on_submit():
4032 logging.info(
"in addconnection")
4040 logging.info(str(session[
"username"])+
" "+str(myform.host_address.data)+
" "+str(myform.auth_type.data)+
" "+str(myform.container.data))
4042 creation_date=datetime.datetime.now()
4043 user_id=get_user_id(
"addconnection",session[
"username"])
4046 newtileset=db.session.query(models.TileSets).filter_by(id=message[
"oldtilesetid"]).one()
4048 if (type(newtileset.id_connections) != type(
None)):
4049 logging.warning(
"New connection created :"+str(newtileset.id_connections))
4051 oldConnection=db.session.query(models.Connections).filter_by(id=newtileset.id_connections).one()
4052 olddate=oldConnection.creation_date
4053 if ((creation_date-olddate).seconds < 3):
4058 if (myform.scheduler_file.data):
4059 scheduler_filename=myform.scheduler_file.data.filename
4061 scheduler_filename=
""
4063 newConnection = models.Connections(host_address=myform.host_address.data,
4064 auth_type=myform.auth_type.data,
4065 container=myform.container.data,
4066 scheduler=myform.scheduler.data,
4067 scheduler_file=scheduler_filename,
4069 creation_date= creation_date)
4071 lastconnection=db.session.query(models.Connections.id).order_by(models.Connections.id.desc()).first()
4072 if ( lastconnection ):
4073 newConnection.id=lastconnection.id+1
4076 db.session.add(newConnection)
4080 newtileset.id_connections=newConnection.id
4087 user_path=os.path.join(
"/TiledViz/TVFiles",str(user_id))
4088 connectionpath=os.path.join(user_path,str(newConnection.id))
4092 logging.warning(
"Creation of connection path for config files : "+user_path)
4093 except FileExistsError:
4096 os.mkdir(connectionpath)
4097 logging.warning(
"Creation of connection path for config files : "+connectionpath)
4098 except FileExistsError:
4102 TStmpName=
"tileset_"+str(newtileset.id)
4103 if ( TStmpName
in jsontransfert):
4104 for FileS
in jsontransfert[TStmpName]:
4105 tf = tempfile.NamedTemporaryFile(mode=
"w+b",dir=connectionpath,prefix=
"",delete=
False)
4106 tf.write(jsontransfert[TStmpName][FileS])
4108 TSConfigjson[FileS]=tf.name
4112 jsontransfert.pop(TStmpName)
4115 if ( myform.configfiles.data
and str(myform.configfiles.data) != str([
""]) ):
4116 logging.info(
"Config files : %s " % (str(myform.configfiles.data)))
4117 for FileS
in myform.configfiles.data:
4118 logging.warning(
"Config files File : %s " % (str(FileS)))
4119 tf = tempfile.NamedTemporaryFile(mode=
"w+b",dir=connectionpath,prefix=
"",delete=
False)
4120 tf.write(FileS.read())
4122 ConnConfigjson[FileS.filename]=tf.name
4141 if (myform.scheduler_file.data):
4142 logging.warning(
"Scheduler file : %s " % (str(myform.scheduler_file.data)))
4143 scheduler_file=myform.scheduler_file.data
4144 if ( scheduler_file !=
"" ):
4145 tf = tempfile.NamedTemporaryFile(mode=
"w+b",dir=connectionpath,prefix=
"",delete=
False)
4146 tf.write(scheduler_file.read())
4147 ConnConfigjson[scheduler_file.filename]=tf.name
4150 sTSConfigjson=str(TSConfigjson).replace(
"'",
'"')
4151 logging.warning(
"Configuration files for TileSet %s : %s " % (newtileset.name,sTSConfigjson) )
4152 newtileset.config_files=json.loads(sTSConfigjson)
4154 sConnConfigjson=str(ConnConfigjson).replace(
"'",
'"')
4155 logging.warning(
"Configuration files for connection %d : %s " % (newConnection.id,sConnConfigjson) )
4156 newConnection.config_files=json.loads(sConnConfigjson)
4159 deb=(myform.debug.data & 1 | 0)
4161 passpath=
"/home/connect"+str(newConnection.id)+
"/vncpassword"
4162 logging.warning(
"Go to vnc with path "+passpath)
4164 config = configparser.ConfigParser()
4165 config.optionxform = str
4167 if (
"config.tar" in newtileset.config_files ):
4168 tar_config_file=tarfile.TarFile(name=newtileset.config_files[
"config.tar"],mode=
'r')
4169 tar_config_file.list()
4171 with tar_config_file.extractfile(
"case_config.ini")
as case_config_file:
4172 config.read_string(case_config_file.read().decode(
'utf-8'))
4173 nbtiles=int(config[
'CASE'][
'NUM_DOCKERS'])
4174 except Exception
as err:
4175 traceback.print_exc(file=sys.stderr)
4176 strerror=
"Error getting number of tiles from case_config in config.tar before connection : "+str(err)
4177 logging.error(strerror)
4181 config.read(newtileset.config_files[
"case_config.ini"])
4182 nbtiles=int(config[
'CASE'][
'NUM_DOCKERS'])
4183 except Exception
as err:
4184 traceback.print_exc(file=sys.stderr)
4185 strerror=
"Error getting number of tiles from case_config.ini before connection : "+str(err)
4186 logging.error(strerror)
4189 logging.warning(
"addconnection: "
4190 +str(session[
"username"])+
" ; "
4191 +str(myform.host_address.data)+
" ; "
4192 +str(myform.auth_type.data)+
" ; "
4193 +str(myform.container.data)+
" ; "
4194 +str(myform.scheduler.data)+
" ; "
4195 +str(newtileset.id)+
" ; "
4196 +str(newConnection.id)+
" ; "
4204 countTimeConnection=time.time()
4206 if (count > NbTimeAlive):
4207 strerror=
"Connection has never been reach. Go back to TileSet."
4208 logging.error(strerror)
4210 message =
'{"oldtilesetid": "'+str(newtileset.id)+
'"}'
4211 return redirect(url_for(
".edittileset",message=message))
4217 time.sleep(timeAlive)
4220 if (os.path.isfile(passpath)):
4221 countTimeConnection=int(time.time()-countTimeConnection)
4222 if (TimeConnection!=countTimeConnection):
4223 TimeConnection=countTimeConnection
4224 with open(passpath,
'r')
as f:
4225 vncpassword=re.sub(
r'\n',
r'',f.read())
4227 logging.debug(
"and password : "+vncpassword)
4229 message =
'{"oldtilesetid":'+str(newtileset.id)+
',"connectionid":'+str(newConnection.id)+
',"sessionname":"'+session[
"sessionname"]+
'"}'
4230 session[
"connection"+str(newConnection.id)]=
' {"callfunction":"edittileset",'+
'"args":{"oldsessionname":"'+str(session[
"sessionname"])+
'","oldtilesetid":"'+str(newtileset.id)+
'"}, "vncpassword":"'+vncpassword+
'"}'
4232 logging.warning(
"addconnection in session : "+str(session[
"connection"+str(newConnection.id)]))
4233 logging.warning(
"Go to vncconnection : "+str(url_for(
".vncconnection",message=message)))
4236 return redirect(url_for(
".vncconnection",message=message))
4238 return render_template(
"addconnection.html", **(myrender()), title=
"Add new Connection TiledViz", form=myform, message=message)
4241@app.route('/editconnection', methods=["GET", "POST"])
4242def editconnection():
4243 logging.warning(
'editconnection message='+str(request.args[
"message"]))
4245 if (
"username" in session):
4246 if (session[
"username"] ==
"Anonymous"):
4247 return redirect(
"/login")
4249 flash(
"Edit connection : User must login !")
4250 return redirect(
"/login")
4254 ThisSession = db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
4255 user_id=get_user_id(
"EditConnectionPerm",session[
"username"])
4256 if not ThisSession
or not can_manage_project(ThisSession.id_projects, user_id):
4257 flash(
"You don't have permission to edit connections in this project.")
4258 return redirect(
"/allsessions")
4260 flash(
"Unable to validate permissions for connection edition.")
4261 return redirect(
"/allsessions")
4264 message=json.loads(request.args[
"message"])
4265 except json.decoder.JSONDecodeError
as e:
4266 logging.error(
"message error ! "+str(e))
4267 logging.error(
"message : "+str(request.args[
"message"]))
4268 traceback.print_exc(file=sys.stderr)
4269 message=json.loads(request.args[
"message"].replace(
"'",
'"'))
4271 oldtilesetid=message[
"oldtilesetid"]
4272 oldtileset=db.session.query(models.TileSets).filter_by(id=oldtilesetid).one()
4274 oldconnection=oldtileset.connections
4276 idconnection=oldconnection.id
4278 flash(
"This connection doesn't exist.")
4279 logging.error(
"This connection doesn't exist.")
4280 message=request.args[
"message"]
4281 return redirect(url_for(
".edittileset",message=message))
4283 user_id=get_user_id(
"editconnection",session[
"username"])
4285 user_path=os.path.join(
"/TiledViz/TVFiles",str(user_id))
4286 connectionpath=os.path.join(user_path,str(oldconnection.id))
4289 if (
not "connection"+str(idconnection)
in session):
4290 flash(
"You don't have connection information in your personal cookie for this connection.")
4291 logging.error(
"You (user "+str(user_id)+
") don't have connection information in your personal cookie for this connection : "+str(idconnection))
4292 message=request.args[
"message"]
4293 return redirect(url_for(
".edittileset",message=message))
4295 if (
"direct" in message):
4296 del message[
"direct"]
4297 message=launch_connection(oldtileset,oldconnection,
4298 oldconnection.host_address,
4299 oldconnection.auth_type,
4300 oldconnection.container,
4301 oldconnection.scheduler)
4302 return redirect(url_for(
".vncconnection",message=message))
4303 flash(
"Error direct connection to shell.")
4306 User = db.session.query(models.Users).filter_by(name=session[
"username"]).one()
4308 myform = BuildConnectionsForm(is_admin=User.is_admin,oldconnection=oldconnection)()
4310 logging.debug(
"ConnectionForm edit."+str(message))
4311 if myform.validate_on_submit():
4312 logging.info(
"in editconnection")
4314 logging.info(str(myform.host_address.data)+
" "+str(myform.auth_type.data)+
" "+str(myform.container.data))
4325 oldconnection_config_files=oldconnection.config_files
4327 if (myform.configfiles.data):
4328 for FileS
in myform.configfiles.data:
4330 tf = tempfile.NamedTemporaryFile(mode=
"w+b",dir=connectionpath,prefix=
"",delete=
False)
4331 tf.write(FileS.read())
4334 if (os.stat(tf.name).st_size > 0):
4335 if (FileS.filename
in oldconnection_config_files):
4337 boolDiff=filecmp.cmp(f1=oldconnection_config_files[FileS.filename],f2=newfilename)
4338 logging.warning(
"Diff with modified config file : "+str(boolDiff))
4341 strrm=
"rm -f "+oldconnection_config_files[FileS.filename]
4342 logging.warning(
"Update old config file "+FileS.filename+
" in editconnection.")
4344 oldconnection.config_files[FileS.filename]=newfilename
4345 flag_modified(oldconnection,
"config_files")
4349 strrm=
"rm -f "+newfilename
4353 oldconnection.config_files[FileS.filename]=newfilename
4354 logging.warning(
"Add new config file "+FileS.filename+
" in editconnection.")
4355 flag_modified(oldconnection,
"config_files")
4359 strrm=
"rm -f "+newfilename
4363 if (myform.scheduler_file.data):
4364 oldconnection_scheduler_file=oldconnection.scheduler_file
4365 FileS=myform.scheduler_file.data
4366 tf = tempfile.NamedTemporaryFile(mode=
"w+b",dir=connectionpath,prefix=
"",delete=
False)
4367 tf.write(FileS.read())
4370 if (os.stat(tf.name).st_size > 0):
4371 if (FileS.filename
in oldconnection_config_files):
4373 boolDiff=filecmp.cmp(f1=oldconnection_config_files[FileS.filename],f2=newfilename)
4374 logging.warning(
"Diff with modified scheduler file : "+str(boolDiff))
4377 strrm=
"rm -f "+oldconnection_config_files[FileS.filename]
4378 logging.warning(
"Update old scheduler file "+FileS.filename+
" in editconnection.")
4380 oldconnection.config_files[FileS.filename]=newfilename
4381 flag_modified(oldconnection,
"config_files")
4385 strrm=
"rm -f "+newfilename
4388 if (oldconnection_scheduler_file):
4390 strrm=
"rm -f "+oldconnection_config_files[oldconnection_scheduler_file]
4391 logging.warning(
"Rename scheduler file from "+oldconnection_scheduler_file
4392 +
" to "+FileS.filename+
" in editconnection.")
4395 logging.warning(
"Add scheduler file "+FileS.filename+
" in editconnection.")
4396 oldconnection.scheduler_file=FileS.filename
4397 oldconnection.config_files[FileS.filename]=newfilename
4398 flag_modified(oldconnection,
"config_files")
4402 strrm=
"rm -f "+newfilename
4405 message=launch_connection(oldtileset,oldconnection,
4406 myform.host_address.data,
4407 myform.auth_type.data,
4408 myform.container.data,
4409 myform.scheduler.data)
4410 return redirect(url_for(
".vncconnection",message=message))
4412 return render_template(
"main_login.html", **(myrender()), title=
"Edit Connection TiledViz", form=myform, message=message)
4416@app.route('/removeconnection', methods=["GET", "POST"])
4417def removeconnection():
4418 logging.warning(
'removeconnection message='+str(request.args[
"message"]))
4420 if (
"username" in session):
4421 if (session[
"username"] ==
"Anonymous"):
4422 return redirect(
"/login")
4424 flash(
"Remove connection : User must login !")
4425 return redirect(
"/login")
4428 message=json.loads(request.args[
"message"])
4429 except json.decoder.JSONDecodeError
as e:
4430 logging.error(
"message error ! "+str(e))
4431 logging.error(
"message : "+str(request.args[
"message"]))
4432 traceback.print_exc(file=sys.stderr)
4433 message=json.loads(request.args[
"message"].replace(
"'",
'"'))
4435 oldtilesetid=message[
"oldtilesetid"]
4436 oldtileset=db.session.query(models.TileSets).filter_by(id=oldtilesetid).one()
4438 oldconnection=oldtileset.connections
4440 idconnection=oldconnection.id
4442 flash(
"This connection doesn't exist.")
4443 logging.error(
"This connection doesn't exist.")
4444 message=request.args[
"message"]
4445 return redirect(url_for(
".edittileset",message=message))
4447 user_id=get_user_id(
"removeconnection",session[
"username"])
4448 if (
not "connection"+str(idconnection)
in session):
4449 flash(
"You don't have connection information in your personal cookie for this connection.")
4450 logging.error(
"You (user "+str(user_id)+
") don't have connection information in your personal cookie for this connection : "+str(idconnection))
4451 message=request.args[
"message"]
4452 return redirect(url_for(
".edittileset",message=message))
4454 remove_this_connection(oldtileset,idconnection,user_id)
4456 flash(
"Connection "+str(idconnection)+
" for tileset "+oldtileset.name+
" has been removed.")
4457 message=request.args[
"message"]
4458 return redirect(url_for(
".edittileset",message=message))
4463@app.route('/jsoneditor', methods=['GET', 'POST'])
4471 TheJson=jsontransfert[session[
"sessionname"]][
"TheJson"]
4472 except Exception
as e:
4473 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
4474 return redirect(url_for(
".editsession",message=message))
4476 callfunction=json.loads(jsontransfert[session[
"sessionname"]][
"callfunction"])
4478 logging.debug(
"jsoneditor : "+str(callfunction))
4479 if ( request.method ==
'POST'):
4480 message=callfunction[
"args"]
4481 TheJson=json.loads(request.form.get(
"submit"))
4482 OutJson=json.dumps(TheJson).replace(
"'",
'"')
4484 jsontransfert[session[
"sessionname"]]={
"TheJson":TheJson}
4486 message=json.dumps(message)
4489 return redirect(url_for(
"."+callfunction[
"function"],message=message))
4490 return render_template(
"jsoneditor.html", **(myrender()), TheJson=TheJson)
4495@app.route('/grid', methods=['GET', 'POST'])
4499 logging.warning(
"session in grid : "+str(session))
4501 if (
not 'is_client_active' in session):
4502 flash(
"You are not connected. You must login before using a grid.")
4503 logging.error(
"You are not connected. You must login before using a grid."+str(session))
4504 return redirect(
"/login")
4506 if request.method ==
'POST' and "new room" in request.form :
4507 psession = request.form[
'new room']
4510 logging.info(
"[!] Change session room to " + psession)
4511 session[
"sessionname"]=psession
4512 thesession = db.session.query(models.Sessions).filter_by(name=psession).scalar()
4513 if (type(thesession) != type(
None)):
4515 project = session[
"projectname"] = thesession.projects.name
4518 logging.warning(
"You must choose a valid session")
4519 flash(
"You didn't select a valid session in grid.")
4520 return redirect(
"/allsessions")
4522 if (session[
"is_client_active"]):
4524 cookieuser = {
"username" : session[
"username"] }
4526 return redirect(
"/login")
4529 if (
not "sessionname" in session
or
4530 not "projectname" in session):
4531 flash(
"No project or session defined yet. Please chose one.")
4532 return redirect(
"/allsessions")
4534 psession = session[
"sessionname"]
4535 project = session[
"projectname"]
4536 logging.info(
"Into '/grid' with GET for session room to " + psession)
4539 part_nbr = str(len(room_dict[psession]))
4540 logging.debug(str(room_dict[psession]))
4541 except KeyError
as e:
4543 logging.info(
"first to join the room "+session[
"username"])
4546 logging.debug(
"Grid with session :"+str(session[
"projectname"])+
" "+str(session[
"sessionname"])+
" "+str(session[
"username"]))
4551 ThisSession=db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
4554 if (len(ThisSession.tile_sets) == 0):
4555 flash(
"No TileSet in this session : You must define tileset before going to grid.")
4556 message =
'{"oldsessionname":"'+session[
"sessionname"]+
'"}'
4557 return redirect(url_for(
".editsession",message=message))
4562 if (type(ThisSession) != type(
None)):
4563 ListAllTileSet_ThisSession=ThisSession.tile_sets
4565 logging.warning(
"You must choose a valid session")
4566 flash(
"You didn't select a valid session in grid.")
4567 return redirect(
"/allsessions")
4568 session[
"tilesetnames"]=[ thistileset.name
for thistileset
in ListAllTileSet_ThisSession ]
4569 logging.warning(
"All TileSet for session "+str(session[
"sessionname"])+
" : "+str(session[
"tilesetnames"]))
4597 tiles_data[
"nodes"]=[]
4599 lts=len(ThisSession.tile_sets)
4601 thistileset=ThisSession.tile_sets[ts]
4602 nbtiles=len(thistileset.tiles)
4603 nbr_of_tiles = nbr_of_tiles + nbtiles
4605 flash(
"Before grid, ERROR IN SESSION '%s' with TileSet '%s' : no tiles." % (ThisSession.name,thistileset.name))
4606 return redirect(
"/allsessions")
4608 tiledata=tvdb.encode_tileset(thistileset)
4609 tiles_data[
"nodes"]=tiles_data[
"nodes"]+tiledata
4613 session[
"nbr_of_tiles"]=nbr_of_tiles
4614 logging.info(
"nbr_of_tiles="+str(session[
"nbr_of_tiles"]))
4616 config[
"nbr_of_tiles"] = nbr_of_tiles
4620 Tags[
"globalTags"]=[]
4621 Tags[
"FloatingTags"]={}
4625 df_nodes_normalized = pd.json_normalize(tiles_data[
"nodes"])
4629 df_column_tag_normalized = df_nodes_normalized[
"tags"]
4630 print(df_column_tag_normalized)
4633 df_tags_normalized = pd.DataFrame()
4641 for i
in range(0, len(df_column_tag_normalized)):
4647 for j
in range(0, len(df_column_tag_normalized[i])):
4649 newline = df_column_tag_normalized[i][j]
4650 newline = newline.replace(
"{",
"")
4651 newline = newline.replace(
"}",
"")
4655 list_line = newline.split(
',')
4658 tag_name = list_line[0]
4659 tags_node.append(tag_name)
4662 if len(list_line) > 1:
4663 value_min = list_line[1]
4664 value = list_line[2]
4665 value_max = list_line[3]
4666 dict_line[tag_name] = float(value)
4667 floating_tag[tag_name]={
'm':value_min,
'M':value_max}
4670 if j == len(df_column_tag_normalized[i]) -1 :
4671 tag_lines.append(dict_line)
4674 for tag
in tags_node:
4675 if (
not tag
in Tags[
"globalTags"]):
4676 Tags[
"globalTags"].append(tag)
4677 if (tag
in floating_tag):
4678 Tags[
"FloatingTags"][tag]=floating_tag[tag]
4681 tiles_data[
"config"] = config
4683 if (
not session[
"is_client_active"]):
4685 psgeom=json.loads(session[
"geometry"])
4686 logging.warning(
"geom for passive client :"+str(psgeom)+
" "+str(type(psgeom)))
4688 traceback.print_exc(file=sys.stderr)
4690 TheConfig=ThisSession.config;
4691 if (ThisSession.config
is None):
4692 flash(
"Session {} does not have a valid configuration for grid.".format(session[
"sessionname"]))
4693 message =
'{"sessionname":"'+session[
"sessionname"]+
'"}'
4694 return redirect(url_for(
".configsession",message=message))
4700 logging.debug(
"config : "+str(TheConfig))
4703 lang=TheConfig[
"language"];
4708 lts=len(ThisSession.tile_sets)
4713 thistileset=ThisSession.tile_sets[ts]
4715 tsconnection=thistileset.connections
4717 if (type(tsconnection) != type(
None)
and
4718 len(thistileset.config_files) > 0):
4719 if (
"connection"+str(tsconnection.id)
in session):
4721 if (
"config.tar" in thistileset.config_files ):
4722 tar_config_file=tarfile.TarFile(name=thistileset.config_files[
"config.tar"],mode=
'r')
4723 tar_config_file.list()
4725 actions_file=tar_config_file.extractfile(
"actions.json")
4726 tiles_actions[thistileset.name]=json.loads(actions_file.read().decode(
'utf-8'))
4731 if (
"actions.json" in thistileset.config_files ):
4732 actions_file=open(thistileset.config_files[
"actions.json"],
'r')
4733 tiles_actions[thistileset.name]=json.load(actions_file)
4736 tiles_actions[thistileset.name][
"action0"]=[
"get_new_nodes",
"system_update_alt"]
4738 if (session[
"is_client_active"]):
4739 rekillid=re.compile(
r'"killid"')
4740 for actionid
in tiles_actions[thistileset.name]:
4741 if (tiles_actions[thistileset.name][actionid][0] ==
"kill_all_containers" and
4742 not re.search(rekillid,session[
"connection"+str(tsconnection.id)])):
4743 session[
"connection"+str(tsconnection.id)]=session[
"connection"+str(tsconnection.id)].replace(
', "vncpassword"',
', "killid":"'+actionid.replace(
"action",
"")+
'", "vncpassword"')
4745 tiles_actions[thistileset.name]={}
4747 tiles_actions[thistileset.name]={}
4750 if (len(tiles_actions)>0):
4751 logging.warning(
"Global tile actions : "+str(tiles_actions))
4753 if (
"colorTheme" in TheConfig[
"colors"]):
4754 colorTheme=TheConfig[
"colors"][
"colorTheme"]
4755 logging.info(
"Color : "+str(colorTheme))
4758 logging.info(
"Color always "+str(colorTheme))
4759 help_path=
"doc/user_doc_" + lang +
"_" + colorTheme +
".html";
4760 logging.info(
"helpPath ="+str(help_path))
4764 current_user_obj = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
4766 if current_user_obj
and ThisSession:
4767 membership = db.session.query(models.ProjectMembers).filter_by(
4768 project_id=ThisSession.id_projects, user_id=current_user_obj.id
4770 project_role = membership.role_type
if membership
else None
4774 return render_template(
"grid_template.html",
4775 user=session[
"username"],
4776 title=
"TiledViz on "+project,
4779 description=str(ThisSession.description),
4781 participants=part_nbr,
4782 is_client_active=session[
"is_client_active"],
4783 project_role=project_role,
4784 json_data=tiles_data,
4785 json_actions=tiles_actions,
4786 json_config=TheConfig,
4788 helpPath = help_path)
4790@socketio.on("save_Session")
4791def saveSession(cdata):
4793 logging.warning(
"[->] saveSession \"" + str(cdata[
"NewSuffix"]) +
"\" with description \"" + str(cdata[
"NewDescription"]) +
"\" in room " + str(croom))
4794 alltilesjson=json.loads(cdata[
"Session"].replace(
"'",
'"'));
4795 save_session(str(session[
"sessionname"]),str(cdata[
"NewSuffix"]),str(cdata[
"NewDescription"]),alltilesjson)
4797@socketio.on("share_Selection")
4798def shareSelection(cdata):
4800 listSelectionIds=json.loads(cdata[
"Selection"]);
4801 logfun(
"[->] shareSelection " + str(len(listSelectionIds)) +
" nodes in room " + str(croom))
4802 sdata = {
"Selection":cdata[
"Selection"]}
4803 socketio.emit(
'receive_deploy_Selection', sdata,room=croom)
4805@socketio.on("deploy_Session")
4806def deploySession(cdata):
4808 logging.warning(
"[->] deploySession NEW ROOM : '" + str(cdata[
"NewRoom"]) +
"' from room " + str(croom))
4809 sdata = {
"NewRoom":cdata[
"NewRoom"]}
4810 session[
"sessionname"]=cdata[
"NewRoom"];
4811 socketio.emit(
'receive_deploy_Session', sdata,room=croom)
4813@socketio.on("share_Config")
4814def shareConfig(cdata):
4817 logging.warning(
"[->] shareConfig in room " + str(croom))
4818 configJson=json.loads(cdata[
"Config"].replace(
"'",
'"'));
4819 logging.info(
"Config: "+str(configJson))
4820 oldsessionname=session[
"sessionname"]
4821 ThisSession = db.session.query(models.Sessions).filter(models.Sessions.name.like(oldsessionname)).first()
4822 oldconfig=ThisSession.config
4824 for section
in configJson:
4825 thisConfigSection=configJson[section]
4826 for key
in thisConfigSection:
4827 ThisSession.config[section][key]=thisConfigSection[key]
4828 flag_modified(ThisSession,
"config")
4830 sdata = {
"Config":configJson};
4831 socketio.emit(
'receive_deploy_Config', sdata,room=croom)
4832 except Exception
as e:
4833 logging.error(
"err : "+str(e))
4834 logging.error(
"cData : "+str(cdata))
4835 traceback.print_exc(file=sys.stderr)
4837@socketio.on('move_tile')
4838def handle_click_event(cdata):
4840 croom = cdata[
"room"]
4841 logfun(
"[->] Click on tile " + str(cdata[
"id"]) +
" in room " + str(croom))
4842 logging.info(
"[+] Position: (" + str(cdata[
"posX"]) +
", " + str(cdata[
"posY"])+
")")
4844 session_id = request.sid
4845 sdata = {
"id":cdata[
"id"],
"posX":cdata[
"posX"],
"posY":cdata[
"posY"],
"session_id":session_id}
4847 socketio.emit(
'receive_move', sdata, room=croom )
4848 tileid=tiles_data[
"nodes"][int(cdata[
"id"])][
"dbid"]
4849 logging.debug(
"move id = "+cdata[
"id"]+
" db id = "+str(tileid))
4850 tile=db.session.query(models.Tiles).filter_by(id=tileid).one()
4851 logging.debug(
"title = "+tile.title)
4852 logging.debug(
"old pos = (%d,%d)" % (int(tile.pos_px_x),int(tile.pos_px_y)))
4853 tile.pos_px_x=int(cdata[
"posX"])
4854 tile.pos_px_y=int(cdata[
"posY"])
4855 logging.debug(
"new pos = (%d,%d)" % (int(tile.pos_px_x),int(tile.pos_px_y)))
4858 logging.info(
"[+] New position for tile " + cdata[
"id"] +
" transmitted to " + str(len(room_dict[croom])) +
" sockets")
4859 return [cdata[
"id"], 2, croom]
4862@socketio.on("click_Menu")
4863def MenuShare(cdata):
4865 logging.info(
"MenuShare :"+str(cdata))
4866 logfun(
"[->] Click on menu " + str(cdata[
"Menu"]) +
" option icon " + str(cdata[
"optionButton"]) +
" in room " + str(croom))
4868 sdata = {
"Menu":cdata[
"Menu"],
"optionNumber":cdata[
"optionNumber"],
"optionButton":cdata[
"optionButton"]}
4869 socketio.emit(
'receive_Menu_click', sdata,room=croom)
4871@socketio.on("click")
4872def ClickShare(cdata):
4874 action=cdata[
"action"]
4875 logging.info(action+
"Share :"+str(cdata))
4876 logfun(
"[->] Click on "+action+
" "+ str(cdata[
"id"]) +
" in room " + str(croom))
4877 sdata = {
"action":action,
"id":cdata[
"id"]}
4878 socketio.emit(
'receive_click', sdata,room=croom)
4880@socketio.on("click_val")
4881def ClickShareVal(cdata):
4883 action=cdata[
"action"]
4884 logging.info(action+
"Share with val :"+str(cdata))
4885 logfun(
"[->] Click on "+action+
" "+ str(cdata[
"id"]) +
" with val " + str(cdata[
"val"]) +
" in room " + str(croom))
4886 sdata = {
"action":action,
"id":cdata[
"id"],
"val":cdata[
"val"]}
4887 socketio.emit(
'receive_click_val', sdata,room=croom)
4889@socketio.on("change_Opacity")
4890def changeOpacityShare(cdata):
4892 logging.info(
"changeOpacityShare :"+str(cdata))
4893 logfun(
"[->] Click on an opacity slider " + str(cdata[
"Id"]) +
" in room " + str(croom))
4895 sdata = {
"Id":cdata[
"Id"],
"Opacity":cdata[
"Opacity"]}
4896 socketio.emit(
'receive_Force_Opacity', sdata,room=croom)
4898@socketio.on("add_Tag")
4899def addNewTagShare(cdata):
4901 logging.info(
"addNewTagShare :"+str(cdata))
4902 logfun(
"[->] Add a new tag " + str(cdata[
"NewTag"]) +
" in room " + str(croom) +
" from button " + str(cdata[
"option"]))
4904 sdata = {
"NewTag":cdata[
"NewTag"],
"option":cdata[
"option"]}
4905 socketio.emit(
'receive_Add_Tag', sdata,room=croom)
4907@socketio.on("switch_MultipleTag")
4908def switchMultipleTagShare(cdata):
4910 logging.info(
"MultipleTagsSelection :"+str(cdata))
4911 logfun(
"[->] Switch a multiple tags selection " + str(cdata[
"SelTags"]) +
" in room " + str(croom) +
" on/off " + str(cdata[
"bool"]))
4913 sdata = {
"SelTags":cdata[
"SelTags"],
"bool":cdata[
"bool"]}
4914 socketio.emit(
'receive_multiple_Tags', sdata,room=croom)
4917@socketio.on("color_Tag")
4918def colorTagShare(cdata):
4920 logging.info(
"changeColorTagShare :"+str(cdata))
4921 logfun(
"[->] Change color for the tag " + str(cdata[
"OldTag"]) +
" for " + str(cdata[
"TagColor"]) +
" in room " + str(croom))
4923 sdata = {
"OldTag":cdata[
"OldTag"],
"TagColor":cdata[
"TagColor"]}
4924 socketio.emit(
'receive_Color_Tag', sdata,room=croom)
4926@socketio.on("action_click")
4927def ClickAction(cdata):
4928 if (session[
"is_client_active"]):
4930 action=cdata[
"action"]
4932 selections=cdata[
"selections"]
4933 logging.info(action+
" for TileSet "+TS)
4934 logfun(
"[->] Click on action "+action+
" "+ str(cdata[
"id"]) +
" in room " + str(croom) +
" for selection "+ str(selections))
4936 actionid=int(action.replace(
"action",
""))
4937 command=str(actionid)+
","+selections
4939 oldtileset=db.session.query(models.TileSets).filter_by(name=TS).one()
4940 oldconnection=oldtileset.connections
4941 user_id=get_user_id(
"action_click",session[
"username"])
4943 if (
not oldconnection):
4944 logging.error(
"[->] NO Connection : "+str(oldconnection)+
" on tileset "+str(oldtileset)+
" for user "+str(user_id))
4947 if (user_id != oldconnection.id_users
or not session[
"is_client_active"]):
4948 logging.error(
"[->] Connection id : "+str(oldconnection.id_users)+
" for user "+str(user_id)+
" and session active "+str(session[
"is_client_active"]))
4952 logfun(
"actionid %d" % (actionid))
4955 ThisSession=db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
4957 out_nodes_json = os.path.join(
"/TiledViz/TVFiles", str(oldconnection.id_users), str(oldconnection.id),
"nodes.json")
4958 mvDATE=datetime.datetime.now().isoformat().replace(
":",
"-")
4959 save_nodes_json=out_nodes_json+
"_"+mvDATE
4960 logging.warning(
"action 0 : Save old nodes.json in %s" % (save_nodes_json))
4962 os.system(
"mv "+out_nodes_json+
" "+save_nodes_json)
4965 command=str(actionid)+
","+
","
4966 logfun(
"action command %s" % (command))
4969 searchKillid=re.search(
r'"killid":"\d+"',session[
"connection"+str(oldconnection.id)])
4972 killid=int(searchKillid.group().replace(
'"killid":',
'').replace(
'"',
''))
4973 if (actionid==killid):
4974 logging.warning(
"action %d : Find kill_all_containers action." % (actionid))
4975 command=str(actionid)+
","+
","
4977 logging.warning(
"action: "
4978 +str(session[
"username"])+
" ; "
4979 +str(oldtileset.id)+
" ; "
4980 +str(oldconnection.id)+
" ; "
4985 if (actionid==killid):
4986 time.sleep(timeAlive)
4987 logging.warning(
"action %d : Remove connection %d ." % (actionid,oldconnection.id))
4988 remove_this_connection(oldtileset,oldconnection.id,user_id)
4992 logging.warning(
"Update nodes for session %s" % (session[
"sessionname"]))
4994 ThisSession=db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
4996 time.sleep(timeAlive)
4999 out_nodes_json = os.path.join(
"/TiledViz/TVFiles", str(oldconnection.id_users), str(oldconnection.id),
"nodes.json")
5003 with open(save_nodes_json)
as save_json_tiles_file:
5004 tiledata1=json.loads(save_json_tiles_file.read())
5005 save_json_tiles_file.close()
5008 itiledata1={
"nodes":[]};
5009 for idx, tile
in enumerate(tiledata1[
"nodes"]):
5010 itiledata1[
"nodes"].append({
"i":idx,
"title":tile[
"title"]})
5013 count_exist_new_nodes=0
5017 time.sleep(timeAlive)
5018 with open(out_nodes_json)
as json_tiles_file:
5019 tiledata2=json.loads(json_tiles_file.read())
5020 json_tiles_file.close()
5022 except Exception
as err:
5023 count_exist_new_nodes=count_exist_new_nodes+1
5025 if ( count_exist_new_nodes > NbIter):
5026 traceback.print_exc(file=sys.stderr)
5028 logging.error(
"After %d x %d s we still have this error :\n %s" % (NbIter, timeAlive,strerror))
5032 sortdata1 = sorted(tiledata1[
"nodes"], key=
lambda v: v[
"title"])
5033 isortdata1 = sorted(itiledata1[
"nodes"], key=
lambda v: v[
"title"])
5034 sortdata2 = sorted(tiledata2[
"nodes"], key=
lambda v: v[
"title"])
5039 creation_date=datetime.datetime.now()
5042 logging.warning(
"DIFF sorted tiledata1 and tildedata2 ")
5045 for idx1, tile1
in enumerate(sortdata1):
5047 for idx2, tile2
in enumerate(sortdata2):
5048 if (tile1 == tile2):
5050 logging.debug(
"OK equal tiles %d %d " % (idx1, idx2))
5053 elif (tile1[
"url"] == tile2[
"url"]):
5054 logging.debug(
"equal url modify tiles %d %d " % (idx1, idx2))
5055 i=isortdata1[idx1][
"i"]
5057 title,name,comment,tags,variable,pos_px_x,pos_px_y,IdLocation,url,ConnectionPort = \
5058 convertTile(tile2,oldtileset.name,connectionbool,urlbool,datapath)
5060 oldtileset.tiles[i].tags=tags
5061 oldtileset.tiles[i].source= {
"name" : name,
5062 "connection" : ConnectionPort,
5064 "variable": variable}
5065 flag_modified(oldtileset.tiles[i],
"source")
5067 oldtileset.tiles[i].pos_px_x= pos_px_x
5068 oldtileset.tiles[i].pos_px_y= pos_px_y
5069 oldtileset.tiles[i].IdLocation=IdLocation
5071 logging.debug(
"OK equal url modify tile")
5073 modtiles_data.append((i,tile2))
5080 sdata = {
"id":cdata[
"id"],
"modtiles_data":modtiles_data}
5081 logging.debug(
"receive_deploy_nodes data : "+str(sdata))
5084 socketio.emit(
'receive_deploy_nodes', sdata,room=croom)
5085 except Exception
as err:
5086 traceback.print_exc(file=sys.stderr)
5088 logging.error(strerror)
5092@socketio.on("drawBlob")
5093def drawBlobShare(cdata):
5094 sidDraw = request.sid
5096 logging.info(
"drawBlobShare :"+str(cdata))
5097 logfun(
"[->] Share image from draws with blob " + str(cdata[
"nodeId"]) +
" in room " + str(croom))
5098 nbsend=cdata[
"nbsend"]
5100 for csid
in room_dict[croom]:
5101 if (
not csid == sidDraw ):
5102 socketio.emit(
'receive_draw_img', cdata,room=croom+str(csid))
5103 logging.info(
"Send draw_img signal to client "+croom+str(csid))
5105@socketio.on("uploadDraw")
5106def uploadDraw(cdata):
5109 for csid
in room_dict[croom]:
5110 if (
not csid == sidDraw ):
5111 socketio.emit(
'receive_draw_part', cdata,room=croom+str(csid))
5114@socketio.on("modif_draws")
5115def ModifDraws(cdata):
5117 action=cdata[
"action"]
5118 logging.debug(action+
" Share :"+str(cdata))
5119 logfun(
"[->] Modification of draw from "+str(cdata[
"nodeId"])+
" with "+action +
" in room " + str(croom))
5120 sdata = {
"nodeId":cdata[
"nodeId"]}
5121 socketio.emit(
'receive_'+action, sdata,room=croom)
5124@socketio.on('connected_grid')
5125def config_client(cdata):
5126 logging.warning(
"[->] Socket connected to a grid")
5127 logging.info(
"[+] Project : " + str(cdata[
'project']))
5128 logging.info(
"[+] Session : " + str(cdata[
'session']))
5130 logging.warning(
"Connect "+str(cdata[
"user"])+str(cdata[
"project"])+str(cdata[
"session"]))
5131 croom = cdata[
'session']
5132 session[
"projectname"]=cdata[
'project']
5133 session[
"sessionname"]=cdata[
'session']
5135 clients.append(request.sid)
5136 logging.debug(rooms())
5140 if croom
in room_dict:
5141 room_dict[croom].append(request.sid)
5142 logging.info(
"[+] " + croom +
" : Now " + str(len(room_dict[croom])) +
" sockets connected to the room")
5144 room_dict[croom] = [request.sid]
5145 if (
"username" in session):
5146 logging.info(
"[+] " + croom +
" : First client to join the room "+session[
"username"])
5148 logging.info(
"[+] " + croom +
" : Anonymous client to join the room.")
5149 croomsid = cdata[
'session']+str(request.sid)
5151 room_dict[croomsid] = [request.sid]
5152 if (
"username" in session):
5153 logging.info(
"[+] " + croomsid +
" : Individual room "+session[
"username"])
5155 logging.info(
"[+] " + croomsid +
" : Individual room for Anonymous client.")
5158 logging.info(
"room_dict are : "+ str(room_dict) +
" my rooms "+ str(croom)+
" and "+str(croomsid))
5161 sdata = {
"part_nbr_update": str(len(room_dict[croom])-1)}
5162 socketio.emit(
"new_client", sdata, room=croom)
5164 traceback.print_exc(file=sys.stderr)
5165 logging.error(
"Unknown room %s id %d in room_dict %s " % (croom,croomsid,str(room_dict)))
5166 return {
"room":croom,
"session_id":request.sid}
5168@socketio.on("disconnect")
5169def disconnect_socket():
5170 logging.debug(
"[<-] Socket disconnected")
5171 tmp_sid = request.sid
5172 for key
in room_dict:
5173 if tmp_sid
in room_dict[key]:
5174 room_dict[key].remove(tmp_sid)
5175 logging.info (
"[-] " + key +
" : Socket " + tmp_sid +
" disconnected")
5176 sdata = {
"part_nbr_update": str(len(room_dict[key])-1)}
5177 socketio.emit(
"new_client", sdata, room=key)
5182 for key
in room_dict:
5183 if (
not room_dict[key]):
5189@socketio.on("get_link")
5190def handle_invite_link_request(cdata):
5191 croom = cdata[
"session"]
5192 is_new_client_active = cdata[
"type"]
5193 max_uses = cdata.get(
"max_uses", 1)
5194 invitee_name = cdata.get(
"invitee_name",
"")
5197 if "username" not in session
or session[
"username"] ==
"Anonymous":
5198 socketio.emit(
"get_link_back", {
"error":
"You must be logged in to create invitation links"}, room=croom)
5202 if "projectname" not in session
or "sessionname" not in session:
5203 socketio.emit(
"get_link_back", {
"error":
"Invalid session context"}, room=croom)
5207 current_user = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
5208 if not current_user:
5209 socketio.emit(
"get_link_back", {
"error":
"User not found"}, room=croom)
5213 session_obj = db.session.query(models.Sessions).filter(models.Sessions.name.like(session[
"sessionname"])).first()
5215 socketio.emit(
"get_link_back", {
"error":
"Session not found"}, room=croom)
5218 project_id = session_obj.id_projects
5220 socketio.emit(
"get_link_back", {
"error":
"Session has no associated project"}, room=croom)
5224 user_membership = db.session.query(models.ProjectMembers).filter_by(
5225 project_id=project_id,
5226 user_id=current_user.id
5229 if not user_membership:
5230 socketio.emit(
"get_link_back", {
"error":
"You must be a project member to create invitation links"}, room=croom)
5234 if user_membership.role_type
not in valid_manage_members:
5235 socketio.emit(
"get_link_back", {
"error": f
"Insufficient permissions. Your role '{user_membership.role_type}' cannot create invitation links"}, room=croom)
5240 max_uses = int(max_uses)
5242 socketio.emit(
"get_link_back", {
"error":
"Maximum uses must be a positive number"}, room=croom)
5244 except (ValueError, TypeError):
5245 socketio.emit(
"get_link_back", {
"error":
"Invalid maximum uses value"}, room=croom)
5249 if is_new_client_active:
5250 if not invitee_name:
5251 socketio.emit(
"get_link_back", {
"error":
"Invitee name is required for active links"}, room=croom)
5255 invitee = db.session.query(models.Users).filter_by(name=invitee_name).first()
5257 socketio.emit(
"get_link_back", {
"error": f
"User {invitee_name} does not exist"}, room=croom)
5260 if (is_new_client_active):
5261 client_type =
"active"
5263 client_type =
"passive"
5266 DEFAULT_URL=os.getenv(
"SERVER_NAME")+
"."+os.getenv(
"DOMAIN")
5269 DEFAULT_URL =
"0.0.0.0:5000"
5271 creation_date = datetime.datetime.now().isoformat()
5274 key = linkrandom(32)
5276 key = key.decode(
'utf-8')
5277 except AttributeError:
5281 if (client_type ==
"active"):
5282 link_key = f
"{session['sessionname']}{linkChar}{client_type}{linkChar}{invitee_name}{linkChar}{creation_date}{linkChar}{key}"
5284 link_key = f
"{session['sessionname']}{linkChar}{client_type}{linkChar}Anonymous{linkChar}{creation_date}{linkChar}{key}"
5288 "link": f
"https://{DEFAULT_URL}/join/{link_key}",
5289 "max_uses": max_uses
5294 ErrLink=
"Full link %s with session %s " % (sdata[
"link"],session[
"sessionname"])
5296 logging.warning(ErrLink)
5297 invite_link = models.InviteLinks(
5299 host_user=session[
"username"],
5300 host_project=session[
"projectname"],
5301 type=is_new_client_active,
5302 creation_date=datetime.datetime.now(),
5305 id_sessions=db.session.query(models.Sessions.id).filter(models.Sessions.name.like(session[
"sessionname"])).scalar(),
5306 id_users=invitee.id
if is_new_client_active
else None
5308 db.session.add(invite_link)
5310 except Exception
as e:
5311 logging.error(f
"Error storing invite link: {str(e)}")
5312 db.session.rollback()
5313 socketio.emit(
"get_link_back", {
"error":
"Failed to create invitation link"}, room=croom)
5316 socketio.emit(
"get_link_back" ,sdata,room=croom)
5318@app.route("/join/<link>")
5319def handle_join_with_invite_link(link):
5320 logging.warning(
"Handle join with invite link : " + link)
5323 link_parts = link.split(linkChar)
5324 if len(link_parts) < 5:
5325 flash(
"Invalid invitation link : wrong parts number %d in your link." % (len(link_parts)))
5326 return redirect(url_for(
".index"))
5328 session_name = link_parts[0]
5329 new_client_type = link_parts[1]
5330 username = link_parts[2]
5331 creation_date = link_parts[3]
5334 if len(link_parts) == 6:
5335 geom = link_parts[5]
5337 logging.warning(
"Link with geom : %s " % (geom))
5338 link=session_name+linkChar+new_client_type+linkChar+username+linkChar+creation_date+linkChar+key
5341 invite_link = db.session.query(models.InviteLinks).filter_by(link=link).first()
5343 flash(
"Invalid invitation link : not found in DB")
5344 return redirect(url_for(
".index"))
5347 if invite_link.use_count >= invite_link.max_uses:
5348 flash(
"This invitation has reached its maximum number of uses")
5349 delelement(models.InviteLinks,
"link "+link, invite_link.id)
5351 return redirect(url_for(
".index"))
5353 if (datetime.datetime.now() > invite_link.creation_date+datetime.timedelta(seconds=LinkExpiredAfterSec)):
5355 flash(
"This invitation created at %s is older than expiration time after %d minutes" % (invite_link.creation_date,LinkExpiredAfterSec/60) )
5356 delelement(models.InviteLinks,
"link "+link, invite_link.id)
5358 return redirect(url_for(
".index"))
5362 if new_client_type ==
"active":
5363 if "username" not in session:
5365 session[
"pending_invite_link"] = link
5366 flash(
"You must be logged in to use this invitation link")
5367 return redirect(url_for(
".login"))
5370 if session[
"username"] != username:
5371 flash(
"This invitation link is for a different user")
5372 return redirect(url_for(
".index"))
5375 user = db.session.query(models.Users).filter_by(name=username).first()
5377 flash(
"Invalid user account : user not found")
5378 return redirect(url_for(
".index"))
5381 invite_link.use_count += 1
5385 session[
"sessionname"] = session_name
5386 session[
"is_client_active"] = (new_client_type ==
"active")
5387 session[
"username"] = username
5390 ThisSession = db.session.query(models.Sessions).filter_by(name=session_name).first()
5392 flash_mess=
"Anonymous connection with unknown session : "+str(session[
"sessionname"])
5393 logging.error(flash_mess)
5394 flash(flash_mess+
". Please check your command line")
5395 return redirect(url_for(
".index"))
5398 session[
"projectname"]=ThisSession.projects.name
5399 project_id = ThisSession.projects.id
5401 ErrLink=
"Error in link %s with project of session %s " % (link,ThisSession)
5403 logging.error(ErrLink)
5404 return redirect(url_for(
".index"))
5407 if new_client_type ==
"active" and user:
5408 sync_success, sync_message = sync_user_to_project_and_session(
5410 project_id=project_id,
5411 session_id=ThisSession.id,
5414 if not sync_success:
5415 logging.warning(f
"Failed to synchronize user {user.name}: {sync_message}")
5416 flash(f
"Warning: {sync_message}")
5418 logging.info(f
"Successfully synchronized user {user.name} to project and session")
5420 session[
"geometry"]=
'{}'
5421 if "passive" in link:
5423 my_geom=geom.replace(
'{',
'{"').replace(
',',
',"').replace(
'=',
'":')
5424 logging.warning(
"str json my_geom "+str(my_geom))
5425 session[
"geometry"]=my_geom
5428 if invite_link.use_count >= invite_link.max_uses:
5429 delelement(models.InviteLinks,
"link "+link, invite_link.id)
5431 logging.warning(
"session after join before grid : "+str(session))
5432 return redirect(
'/grid')
5438@app.errorhandler(400)
5440 logging.error(
"Bad request or cookie expired for user "+str(session[
"username"]))
5441 return render_template(
'error_pages/400.html'), 400
5443@app.errorhandler(502)
5445 logging.error(
"Cookie expired for user "+str(session[
"username"]))
5446 return render_template(
'error_pages/502.html'), 502
5448@app.errorhandler(504)
5450 logging.error(
"Error of TVSecure for user "+str(session[
"username"]))
5451 return render_template(
'error_pages/504.html'), 504
5454@app.errorhandler(404)
5456 return render_template(
'error_pages/404.html'), 404
5458@app.errorhandler(429)
5460 return render_template(
'error_pages/429.html'), 429
5462@app.errorhandler(500)
5464 logging.error(
"Error with TiledViz for user "+str(session[
"username"]))
5465 return render_template(
'error_pages/500.html'), 500
5539@app.route("/revoke_invite/<int:invite_id>", methods=["POST"])
5540def revoke_invite(invite_id):
5541 if "username" not in session:
5542 return jsonify({
"error":
"User not logged in"}), 401
5544 invite_link = db.session.query(models.InviteLinks).filter_by(id=invite_id).first()
5546 return jsonify({
"error":
"Invitation not found"}), 404
5549 if invite_link.host_user != session[
"username"]:
5550 return jsonify({
"error":
"Not authorized to revoke this invitation"}), 403
5552 invite_link.is_revoked =
True
5555 return jsonify({
"message":
"Invitation revoked successfully"})
5558@app.route('/project_members/<int:project_id>/members', methods=["GET", "POST"])
5559def project_members(project_id):
5560 if (
"username" not in session
or session[
"username"] ==
"Anonymous"):
5561 return redirect(
"/login")
5563 user_id = get_user_id(
"Project Members", session[
"username"])
5566 project = db.session.query(models.Projects).filter_by(id=project_id).first()
5568 flash(
"Project not found!")
5569 return redirect(
"/project")
5572 if not can_manage_project(project_id, user_id):
5573 flash(
"You don't have permission to manage members for this project!")
5574 return redirect(
"/project")
5577 current_members = get_project_members(project_id)
5580 available_users = get_available_users_for_project(project_id)
5583 if request.method ==
"POST":
5584 if 'add_member' in request.form:
5585 new_user_id = request.form.get(
'user_id')
5586 new_role = request.form.get(
'role_type')
5588 if new_user_id
and new_role:
5589 success, message = add_project_member(project_id, int(new_user_id), new_role)
5593 return redirect(url_for(
'project_members', project_id=project_id))
5595 elif 'remove_member' in request.form:
5596 member_id = request.form.get(
'member_id')
5598 success, message = remove_project_member(project_id, int(member_id))
5602 return redirect(url_for(
'project_members', project_id=project_id))
5604 elif 'change_role' in request.form:
5605 member_id = request.form.get(
'member_id')
5606 new_role = request.form.get(
'new_role')
5608 if member_id
and new_role:
5609 success, message = update_member_role(project_id, int(member_id), new_role)
5613 return redirect(url_for(
'project_members', project_id=project_id))
5615 elif 'transfer_ownership' in request.form:
5616 new_owner_id = request.form.get(
'new_owner_id')
5618 success, message = transfer_project_ownership(project_id, user_id, int(new_owner_id))
5622 return redirect(url_for(
'project_members', project_id=project_id))
5625 return redirect(url_for(
'project_members', project_id=project_id))
5628 current_members = get_project_members(project_id)
5630 return render_template(
5631 "project_members.html",
5633 username=session[
"username"],
5634 current_members=current_members,
5635 available_users=available_users,
5636 title=f
"Manage Members - {project.name}"
5640@app.route('/api/project/<int:project_id>/transfer-ownership', methods=['POST'])
5641def transfer_ownership_api(project_id):
5643 API endpoint for transferring project ownership with comprehensive validation
5645 if "username" not in session
or session[
"username"] ==
"Anonymous":
5646 return jsonify({
"error":
"Authentication required"}), 401
5648 user_id = get_user_id(
"Transfer Ownership", session[
"username"])
5651 data = request.get_json()
5652 if not data
or 'new_owner_id' not in data:
5653 return jsonify({
"error":
"new_owner_id is required"}), 400
5655 new_owner_id = data[
'new_owner_id']
5658 success, message = transfer_project_ownership(project_id, user_id, new_owner_id)
5662 new_owner = db.session.query(models.Users).filter_by(id=new_owner_id).first()
5667 "name": new_owner.name
5671 "name": session[
"username"]
5675 return jsonify({
"error": message}), 400
5677 except Exception
as e:
5678 db.session.rollback()
5679 logging.error(f
"Error in ownership transfer API: {str(e)}")
5680 return jsonify({
"error":
"Internal server error during ownership transfer"}), 500
5683@app.route('/api/project/<int:project_id>/ownership-constraints', methods=['GET'])
5684def check_ownership_constraints(project_id):
5686 API endpoint to check ownership constraints and business rules
5688 if "username" not in session
or session[
"username"] ==
"Anonymous":
5689 return jsonify({
"error":
"Authentication required"}), 401
5691 user_id = get_user_id(
"Check Ownership Constraints", session[
"username"])
5695 project = db.session.query(models.Projects).filter_by(id=project_id).first()
5697 return jsonify({
"error":
"Project not found"}), 404
5700 user_membership = db.session.query(models.ProjectMembers).filter_by(
5701 project_id=project_id,
5705 if not user_membership:
5706 return jsonify({
"error":
"User is not a member of this project"}), 403
5709 owner_count = db.session.query(models.ProjectMembers).filter_by(
5710 project_id=project_id,
5715 all_members = db.session.query(models.ProjectMembers).filter_by(
5716 project_id=project_id
5720 eligible_members = []
5721 for member
in all_members:
5722 if member.role_type !=
'owner' and member.user_id != user_id:
5723 user_info = db.session.query(models.Users).filter_by(id=member.user_id).first()
5725 eligible_members.append({
5726 "id": member.user_id,
5727 "name": user_info.name,
5728 "role": member.role_type
5732 "is_owner": user_membership.role_type ==
'owner',
5733 "owner_count": owner_count,
5734 "is_last_owner": owner_count <= 1
and user_membership.role_type ==
'owner',
5735 "can_transfer_ownership": user_membership.role_type ==
'owner' and len(eligible_members) > 0,
5736 "eligible_for_ownership_transfer": eligible_members,
5738 "cannot_remove_last_owner": owner_count <= 1,
5739 "must_be_member_to_receive_ownership":
True,
5740 "cannot_transfer_to_self":
True,
5741 "cannot_transfer_to_existing_owner":
True
5745 except Exception
as e:
5746 logging.error(f
"Error checking ownership constraints: {str(e)}")
5747 return jsonify({
"error":
"Internal server error"}), 500
5750@app.route('/my-projects', methods=["GET"])
5752 if (
"username" not in session
or session[
"username"] ==
"Anonymous"):
5753 return redirect(
"/login")
5755 user_id = get_user_id(
"My Projects", session[
"username"])
5758 user_projects = get_user_projects(user_id)
5761 projects_by_role = {
5767 for project, role_type
in user_projects:
5771 'can_manage': role_type
in valid_manage_members
5774 if role_type ==
'owner':
5775 projects_by_role[
'owned'].append(project_data)
5777 projects_by_role[
'member'].append(project_data)
5779 return render_template(
5781 projects_by_role=projects_by_role,
5782 username=session[
"username"],
5788@app.route('/admin/migration', methods=['GET', 'POST'])
5789def migration_admin():
5790 """Admin interface for managing database migrations"""
5791 if (
"username" not in session
or session[
"username"] ==
"Anonymous"):
5792 return redirect(
"/login")
5794 user_id = get_user_id(
"Migration Admin", session[
"username"])
5795 User = db.session.query(models.Users).filter_by(name=session[
"username"]).one()
5797 if not User.is_admin:
5798 flash(
"You must be an administrator to access this page.")
5799 return redirect(
"/")
5801 from app.migration import migrate_project_owners, check_migration_status, validate_migration, rollback_migration, get_orphaned_projects
5804 if request.method ==
"POST":
5805 action = request.form.get(
'action')
5807 if action ==
'run_migration':
5808 if migrate_project_owners():
5809 flash(
"Migration completed successfully!")
5811 flash(
"Migration failed! Check logs for details.")
5813 elif action ==
'validate_migration':
5814 validation = validate_migration()
5815 if validation
and validation[
'is_valid']:
5816 flash(
"Migration validation passed - data is consistent!")
5818 flash(f
"Migration validation failed: {validation}")
5820 elif action ==
'rollback_migration':
5821 if rollback_migration():
5822 flash(
"Migration rollback completed!")
5824 flash(
"Migration rollback failed! Check logs for details.")
5827 status = check_migration_status()
5828 validation = validate_migration()
5829 orphaned_projects = get_orphaned_projects()
5831 return render_template(
5832 "migration_admin.html",
5834 validation=validation,
5835 orphaned_projects=orphaned_projects,
5836 title=
"Migration Management"
5839@app.route('/admin/consistency', methods=['GET', 'POST'])
5840def consistency_admin():
5842 Admin interface for session-project consistency management
5844 if (
"username" not in session
or session[
"username"] ==
"Anonymous"):
5845 return redirect(
"/login")
5847 user_id = get_user_id(
"Consistency Admin", session[
"username"])
5848 User = db.session.query(models.Users).filter_by(name=session[
"username"]).one()
5850 if not User.is_admin:
5851 flash(
"You must be an administrator to access this page.")
5852 return redirect(
"/")
5855 if request.method ==
'GET':
5857 sessions = db.session.query(models.Sessions).all()
5858 for session_obj
in sessions:
5859 inconsistencies = validate_session_project_consistency(session_obj.id)
5860 sessions_data.append({
5861 'id': session_obj.id,
5862 'name': session_obj.name,
5863 'project_name': session_obj.projects.name
if session_obj.projects
else 'No Project',
5864 'inconsistencies': inconsistencies,
5865 'is_consistent': len(inconsistencies) == 0
5868 if request.method ==
'POST':
5869 action = request.form.get(
'action')
5870 session_id = request.form.get(
'session_id')
5872 if action ==
'validate_session' and session_id:
5873 inconsistencies = validate_session_project_consistency(int(session_id))
5875 flash(f
"Found {len(inconsistencies)} inconsistencies in session {session_id}")
5876 for inc
in inconsistencies:
5879 flash(f
"Session {session_id} is consistent with its project")
5881 elif action ==
'fix_session' and session_id:
5882 success, message = fix_session_project_inconsistencies(int(session_id))
5886 flash(f
"Error: {message}")
5888 elif action ==
'validate_all':
5890 sessions = db.session.query(models.Sessions).all()
5891 total_inconsistencies = 0
5892 inconsistent_sessions = 0
5894 for session_obj
in sessions:
5895 inconsistencies = validate_session_project_consistency(session_obj.id)
5897 inconsistent_sessions += 1
5898 total_inconsistencies += len(inconsistencies)
5899 flash(f
"Session '{session_obj.name}' (ID: {session_obj.id}): {len(inconsistencies)} inconsistencies")
5900 for inc
in inconsistencies:
5903 if total_inconsistencies == 0:
5904 flash(
"All sessions are consistent with their projects!")
5906 flash(f
"Found {total_inconsistencies} inconsistencies across {inconsistent_sessions} sessions")
5908 elif action ==
'fix_all':
5910 sessions = db.session.query(models.Sessions).all()
5914 for session_obj
in sessions:
5915 success, message = fix_session_project_inconsistencies(session_obj.id)
5916 if success
and "Fixed" in message:
5919 match = re.search(
r'Fixed (\d+)', message)
5921 fixed_count = int(match.group(1))
5922 total_fixed += fixed_count
5925 flash(f
"Session '{session_obj.name}': {message}")
5928 flash(f
"Successfully fixed {total_fixed} inconsistencies across {fixed_sessions} sessions")
5930 flash(
"No inconsistencies found to fix")
5932 return render_template(
'admin_consistency.html',
5933 title=
"Consistency Admin",
5934 sessions=sessions_data,
5938@app.route('/project/<int:project_id>/invite', methods=['GET', 'POST'])
5939def project_invite(project_id):
5941 Project invitation management interface
5943 if (
"username" not in session
or session[
"username"] ==
"Anonymous"):
5944 return redirect(
"/login")
5947 current_user = db.session.query(models.Users).filter_by(name=session[
"username"]).first()
5948 if not current_user:
5949 flash(
"User not found")
5950 return redirect(
"/")
5953 can_create, reason = can_create_invite_links(current_user.id, project_id)
5955 flash(f
"Access denied: {reason}")
5956 return redirect(
"/")
5959 project = db.session.query(models.Projects).filter_by(id=project_id).first()
5961 flash(
"Project not found")
5962 return redirect(
"/")
5965 sessions = db.session.query(models.Sessions).filter_by(id_projects=project_id).all()
5968 invite_links = db.session.query(models.InviteLinks).filter_by(
5969 host_project=project.name
5970 ).order_by(models.InviteLinks.creation_date.desc()).all()
5972 if request.method ==
'POST':
5973 action = request.form.get(
'action')
5975 if action ==
'create_invite':
5976 session_id = request.form.get(
'session_id')
5977 invitee_name = request.form.get(
'invitee_name',
'').strip()
5978 max_uses = request.form.get(
'max_uses', 1)
5979 invite_type = request.form.get(
'invite_type',
'passive')
5982 max_uses = int(max_uses)
5984 flash(
"Maximum uses must be a positive number")
5985 return redirect(url_for(
'.project_invite', project_id=project_id))
5986 except (ValueError, TypeError):
5987 flash(
"Invalid maximum uses value")
5988 return redirect(url_for(
'.project_invite', project_id=project_id))
5991 session_obj = db.session.query(models.Sessions).filter_by(
5993 id_projects=project_id
5996 flash(
"Invalid session for this project")
5997 return redirect(url_for(
'.project_invite', project_id=project_id))
6000 if invite_type ==
'active':
6001 if not invitee_name:
6002 flash(
"Invitee name is required for active invitations")
6003 return redirect(url_for(
'.project_invite', project_id=project_id))
6005 invitee = db.session.query(models.Users).filter_by(name=invitee_name).first()
6007 flash(f
"User '{invitee_name}' does not exist")
6008 return redirect(url_for(
'.project_invite', project_id=project_id))
6010 invitee_name =
"Anonymous"
6013 creation_date = datetime.datetime.now().isoformat()
6014 key = linkrandom(32)
6016 key = key.decode(
'utf-8')
6017 except AttributeError:
6020 link_key = f
"{session_obj.name}{linkChar}{invite_type}{linkChar}{invitee_name}{linkChar}{creation_date}{linkChar}{key}"
6023 invite_link = models.InviteLinks(
6025 host_user=current_user.name,
6026 host_project=project.name,
6027 type=(invite_type ==
'active'),
6028 creation_date=datetime.datetime.now(),
6031 id_sessions=session_id,
6032 id_users=invitee.id
if invite_type ==
'active' else None
6034 db.session.add(invite_link)
6037 full_link = f
"https://{DEFAULT_URL}/join/{link_key}"
6038 flash(f
"Invitation link created successfully: {full_link}")
6040 except Exception
as e:
6041 db.session.rollback()
6042 logging.error(f
"Error creating invite link: {str(e)}")
6043 flash(
"Failed to create invitation link")
6045 elif action ==
'revoke_invite':
6046 invite_id = request.form.get(
'invite_id')
6047 invite_link = db.session.query(models.InviteLinks).filter_by(
6049 host_project=project.name
6053 invite_link.is_revoked =
True
6055 flash(
"Invitation link revoked successfully")
6057 flash(
"Invitation link not found")
6059 return redirect(url_for(
'.project_invite', project_id=project_id))
6061 return render_template(
'project_invite.html',
6062 title=f
"Invite Users - {project.name}",
6065 invite_links=invite_links,
6069@app.route('/verify-email/<token>')
6070def verify_email(token):
6071 """Verify user email with JWT token"""
6074 data = verify_token(token, app.secret_key)
6076 flash(
'Invalid or expired verification link.',
'error')
6077 return redirect(
'/register')
6079 user_id = data.get(
'confirm_id')
6081 flash(
'Invalid verification link.',
'error')
6082 return redirect(
'/register')
6085 user = db.session.query(models.Users).filter_by(id=user_id).first()
6087 flash(
'User not found.',
'error')
6088 return redirect(
'/register')
6090 if user.is_verified:
6091 flash(
'User already verified. You can login.',
"success")
6092 return redirect(
'/login')
6095 user.is_verified =
True
6096 user.dateverified = datetime.datetime.now()
6101 delete_sent_email(
"TiledViz - Email Verification", user.mail)
6103 flash(
'Email verified successfully! You can now log in.',
'success')
6104 return redirect(
'/login')
6106 except Exception
as e:
6107 logging.error(f
"Error verifying email: {e}")
6108 flash(
'An error occurred during verification. Please try again.',
'error')
6109 return redirect(
'/register')
6111@app.route('/resend-verification', methods=['GET', 'POST'])
6112def resend_verification():
6113 """Resend verification email"""
6114 if request.method ==
'POST':
6115 email = request.form.get(
'email')
6117 flash(
'Please enter your email address.',
'error')
6118 return render_template(
'resend_verification.html', **myrender())
6121 user = db.session.query(models.Users).filter_by(mail=email).first()
6123 flash(
'No account found with this email address.',
'error')
6124 return render_template(
'resend_verification.html', **myrender())
6126 if user.is_verified:
6127 flash(
'This email is already verified. You can log in.',
'info')
6128 return redirect(
'/login')
6131 token = generate_verification_token(user.id)
6132 email_sent = send_verification_email(
6133 user_email=user.mail,
6139 flash(
'Verification email sent! Please check your inbox.',
'success')
6141 flash(
'Failed to send verification email. Please try again later.',
'error')
6143 return redirect(
'/login')
6145 return render_template(
'resend_verification.html', **myrender())
pca_on_multiple_nodes(nodes_json_text)
pca_on_one_node(nodes_json_text)