From 0f4632e2400d4ad266049c6e1f2b6695fe030a94 Mon Sep 17 00:00:00 2001 From: Damien De Paoli Date: Sat, 22 Jan 2022 21:36:58 +1100 Subject: [PATCH] changing options on files_*, search, also next/prev all now use POST->redirect model, so should allow back/forward browser buttons to work - commit so we can test in PROD --- TODO | 31 +++++++------- ai.py | 12 +++--- files.py | 13 ++++++ internal/js/face.js | 31 +++++++++++++- main.py | 2 +- person.py | 1 + states.py | 95 ++++++++++++++++++++++++++++++++----------- tables.sql | 2 +- templates/base.html | 4 +- templates/faces.html | 10 ++--- templates/files.html | 29 ++++++------- templates/states.html | 62 +++++++++++++++++++++++++++- templates/viewer.html | 1 + user.py | 48 ++++++++++++++++++++-- 14 files changed, 264 insertions(+), 77 deletions(-) diff --git a/TODO b/TODO index c08fd5c..17ffa46 100644 --- a/TODO +++ b/TODO @@ -1,28 +1,25 @@ ## GENERAL * for below.. make Options( request ) - remove all "Options()" that are not set by a user-choice in the F/E and just make sure new "Options" sets all defaults as needed - -- ALSO, preferences are different to app settings... allow prefs from "ddp" menu - -> it should allow default pagesize, default thumbsize, etc. - -- viewlist can work out new view_eids server side, and pass them back as json data - - can consider an optim-- new_view page makes calls to viewlist to ADD json data only, so only trigger a new "viewlist" if we dont have data for that part of the eids + - in fact if we "re-use" a pa_user_state, we need to update it with anything that changed -- not sure but that should just happen in State() + - use prefs in States() for defaults, rather than hardcoding "50", etc. + - search allows folder/flat change in GUI, should disable it + - search NOO -- no code to handle noo!!! - * going forward into search page (and probably all POSTs) does not work - don't render_template instead do a redirect to a GET of the new, or list? for del... - * need to catch "option changes" as POSTs to make them GETs somehow... - (search, files_ip POST change trigger issue) - -- I think it is the same URL being used issue? -- validate this in PROD only I think - - [DONE] files.py:@app.route("/view/", methods=["POST"]) - files.py:@app.route("/viewlist", methods=["POST"]) - -- this will need a total rewrite for viewer to handle fullscreen across offset/size boundaries so fix that instead - job.py:@app.route("/jobs", methods=["GET", "POST"]) - job.py:@app.route("/job/", methods=["GET","POST"]) - -- these need to store 'job prefs' somewhere... - files.py:@app.route("/fix_dups", methods=["POST"]) + * going forward into search page (and probably all POSTs) does not work -- use POST -> redirect to GET + /viewlist ? -> think it works, BUT, need a rewrite anyway to use json data rather than new urls... + job.py:@app.route("/jobs", methods=["GET", "POST"]) + job.py:@app.route("/job/", methods=["GET","POST"]) + -- these need to store 'job prefs' somewhere... + files.py:@app.route("/fix_dups", methods=["POST"]) + ??? * optim to not run_ai_on_* for scan, needs to make sure last run_ai_on actually ran/worked - might have failed (or in my case was marked stale and I cancelled it) -- also the case for get file details though, need to make sure last one was completed + * viewlist can work out new view_eids server side, and pass them back as json data + - can consider an optim-- new_view page makes calls to viewlist to ADD json data only, so only trigger a new "viewlist" if we dont have data for that part of the eids + * per file you could select an unknown face and add it as a ref img to an existing person, or make a new person and attach? * [DONE] order/ find face with largest size and at least show that as unmatched - could also try to check it vs. other faces, if it matches more than say 10? we offer it up as a required ref img, then cut that face (with margin) out and use it is a new ref image / person diff --git a/ai.py b/ai.py index 83a487e..0f69acd 100644 --- a/ai.py +++ b/ai.py @@ -94,14 +94,16 @@ def unmatched_faces(): faces=Face.query.join(FaceFileLink).join(FaceRefimgLink, isouter=True).filter(FaceRefimgLink.refimg_id==None).order_by(Face.h.desc()).limit(10).all() imgs={} for face in faces: - face.locn=json.loads("["+face.locn+"]") + face.locn=json.loads(face.locn) f = Entry.query.join(File).join(FaceFileLink).filter(FaceFileLink.face_id==face.id).first() face.file_eid=f.id face.url=f.FullPathOnFS() - x=face.locn[0][3]*0.95 - y=face.locn[0][0]*0.95 - x2=face.locn[0][1]*1.05 - y2=face.locn[0][2]*1.05 + x=face.locn[3]*0.95 + y=face.locn[0]*0.95 + x2=face.locn[1]*1.05 + y2=face.locn[2]*1.05 + + print( f"l={face.locn}, x='{x}'" ) im = Image.open(f.FullPathOnFS()) region = im.crop((x, y, x2, y2)) diff --git a/files.py b/files.py index 3efeba4..6fbf913 100644 --- a/files.py +++ b/files.py @@ -239,6 +239,7 @@ def GetEntriesInFolderView( OPT, prefix ): def GetEntries( OPT ): entries=[] if OPT.path_type == 'Search' or (OPT.path_type == 'View' and OPT.orig_ptype=='Search'): + print( f"getting entries: OPT={OPT}" ) search_term=OPT.orig_search_term if 'AI:' in search_term: search_term = search_term.replace('AI:','') @@ -307,6 +308,15 @@ def clear_jm_msg(id): ClearJM_Message(id) return redirect( url_for("main_page") ) +@app.route("/ChangeFileOpts", methods=["POST"]) +@login_required +def ChangeFileOpts(): + # reset options based on form post, then redirect back to orig page + OPT=States( request ) + for el in request.form: + print( f"{el}={request.form[el]}") + return redirect( request.referrer ) + ################################################################################ # /file_list -> show detailed file list of files from import_path(s) ################################################################################ @@ -577,6 +587,8 @@ def view(id): entries=GetEntries( OPT ) eids="" for e in entries: + print( f"id={e.id}, len(faces)={len(e.file_details.faces)}") + print(e.id) objs[e.id]=e eids += f"{e.id}," # if this is a dir, we wont view it with a click anyway, so move on... @@ -584,6 +596,7 @@ def view(id): continue # put locn data back into array format for face in e.file_details.faces: + print( f"face.locn before json: {face.locn}" ) face.locn = json.loads(face.locn) eids=eids.rstrip(",") return render_template("viewer.html", current=int(id), eids=eids, objs=objs, OPT=OPT ) diff --git a/internal/js/face.js b/internal/js/face.js index bd3726e..c9aa5df 100644 --- a/internal/js/face.js +++ b/internal/js/face.js @@ -1,5 +1,5 @@ // Define this once and before it will be called, hence at the top of this file -function DrawRefimg(fig, img, canvas, orig_face ) +function DrawUnmatchedFace(fig, img, canvas, orig_face ) { context=canvas.getContext('2d') // another call to this func will occur on load, so skip this one @@ -13,3 +13,32 @@ function DrawRefimg(fig, img, canvas, orig_face ) context.drawImage(img, 0, 0, img.width/(img.height/canvas.height), canvas.height); fig.width(canvas.width) } + +function DrawRefimg(fig, img, canvas, orig_face) +{ + // FIXME: should get this from shared.py, not sure why this doesnt work at present + thumbsize=256 + + context=canvas.getContext('2d') + // another call to this func will occur on load, so skip this one + if( img.width == 0 ) + return + + // only set canvas.width once we have valid img dimensions + canvas.width=img.width/2 + + // actually draw the pixel images to the canvas at the right size + context.drawImage(img, 0, 0, img.width/(img.height/canvas.height), canvas.height); + fig.width(canvas.width) + + // draw rectangle on face + context.beginPath(); + new_x=(orig_face.x/orig_face.orig_w)*img.width/(img.height/canvas.height) + new_y=(orig_face.y/orig_face.orig_h)*thumbsize/(img.height/canvas.height) + new_w=(orig_face.w/orig_face.orig_w)*img.width/(img.height/canvas.height) + new_h=(orig_face.h/orig_face.orig_h)*thumbsize/(img.height/canvas.height) + context.rect(new_x, new_y, new_w, new_h) + context.lineWidth = 2; + context.strokeStyle = 'green'; + context.stroke(); +} diff --git a/main.py b/main.py index 42fb7b1..94ecb03 100644 --- a/main.py +++ b/main.py @@ -92,7 +92,7 @@ def save_user(dn, username, data, memberships): # if we already have a valid user/session, and say the web has restarted, just re-use it, dont make more users if pau: return pau - pau=PAUser(dn=dn) + pau=PAUser(dn=dn, default_noo="Oldest", default_grouping="None", default_how_many=50, default_size=128, default_folders=True, default_fullscreen=False) db.session.add(pau) db.session.commit() return pau diff --git a/person.py b/person.py index 7cf9a44..4a3388c 100644 --- a/person.py +++ b/person.py @@ -211,6 +211,7 @@ def add_refimg(): settings = Settings.query.first() model=AIModel.query.get(settings.default_refimg_model) refimg.face, face_locn = GenFace( fname, model=model.name ) + print( f"GenFace -> locn={face_locn}, locn[0][0]={face_locn[0][0]}" ) refimg.face_locn = json.dumps(face_locn) refimg.model_used = settings.default_refimg_model refimg.created_on = time.time() diff --git a/states.py b/states.py index db09529..27e7c29 100644 --- a/states.py +++ b/states.py @@ -3,7 +3,7 @@ from flask import request, render_template, redirect, url_for from flask_login import login_required, current_user from main import db, app, ma from shared import PA - +from user import PAUser ################################################################################ # PA_UserState: preference data for a given user / path_type combo, so a given user @@ -30,9 +30,10 @@ class PA_UserState(db.Model): orig_ptype = db.Column(db.String, unique=False, nullable=False ) # only used if view and orig_ptype was search orig_search_term = db.Column(db.String, unique=False, nullable=False ) + orig_url = db.Column(db.String, unique=False, nullable=False ) def __repr__(self): - return f"" + return f"" ################################################################################ @@ -44,52 +45,89 @@ class States(PA): def __init__(self, request): self.path_type='' self.url = request.path + self.view_eid = None + print( f"States() - path={request.path}, ref={request.referrer}" ) + + # this is any next/prev or noo, grouping, etc. change (so use referrer to work out what to do with this) + # because this can happen on a view, or files_up, etc. change this FIRST + if 'ChangeFileOpts' in request.path: + ref=request.referrer + base=request.base_url + base=base.replace("ChangeFileOpts", "") + self.url = "/"+ref.replace(base, "" ) + print( f"started with ChangeFileOpts, so self.url now is {self.url}, bu={request.base_url}") + + # if viewlist, then we really are a view, and view_eid should be in the form + if 'viewlist' in request.path: + self.path_type = 'View' + self.view_eid = request.form['view_eid'] + self.url = request.form['orig_url'] + for el in request.form: + print( f"{el}={request.form[el]}" ) # this occurs ONLY when a POST to /view/ occurs (at this stage orig_url will be from an import, storage, bin or search) - if 'orig_url' in request.form: - self.path_type='View' + elif 'view' in request.path: + self.path_type = 'View' + self.view_eid = self.url[6:] # use orig url to define defaults/look up states for 'last' import/storage/bin/search - url = request.form['orig_url'] - # get the eid out of the url /view/ - self.view_eid = request.path[6:] - else: - url = request.path - self.view_eid = None + if request.method == "POST": + self.url = request.form['orig_url'] + else: + # GET's occur on redirect, and we don't have a form, so get it + # from pref + pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type,PA_UserState.view_eid==self.view_eid).first() + self.url = pref.orig_url + print( f"view/ so change url to: '{self.url}'" ) - if 'files_ip' in url or 'file_list_ip' in url: + print( f"NOW, url={self.url}" ) + + if 'files_ip' in self.url or 'file_list_ip' in self.url: if self.path_type == "View": self.orig_ptype = 'Import' + self.orig_url = self.url else: self.path_type = 'Import' - elif 'files_sp' in url: + elif 'files_sp' in self.url: if self.path_type == "View": self.orig_ptype = 'Storage' + self.orig_url = self.url else: self.path_type = 'Storage' - elif 'files_rbp' in url: + elif 'files_rbp' in self.url: if self.path_type == "View": self.orig_ptype = 'Bin' + self.orig_url = self.url else: self.path_type = 'Bin' - elif 'search' in url: + elif 'search' in self.url: # okay if we are a search, but came from a view then get last_search_state form prefs and use it + self.orig_search_term = self.url[8:] if self.path_type == "View": - last_search_state = PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type=='Search').first() - self.orig_search_term = last_search_state.orig_search_term + print(f"view, url={self.url}") self.orig_ptype = 'Search' + self.orig_url = self.url else: - self.orig_search_term = url[8:] self.path_type = 'Search' - elif 'view' in url: + elif 'view' in self.url: # use url to get eid of viewed entry self.view_eid = self.url[6:] self.path_type="View" + self.orig_url=self.url + print( f"in view, eid={self.view_eid}, orig_url={self.orig_url}" ) + elif 'ChangeFileOpts' in self.url: + print( f"ChangeFileOpts called, so all good?" ) else: - print( f"ERROR: DDP messed up, failed to match URL {url} for settings this will fail, redirecting to home" ) + print( f"referrer={request.referrer}" ) + print( f"ERROR: DDP messed up, failed to match URL {self.url} for settings this will fail, redirecting to home" ) return if self.path_type == 'View': + print( f"its is a view, find the pref: {self.view_eid}" ) pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type,PA_UserState.view_eid==self.view_eid).first() + if not pref: + print( f"no pref" ) + else: + print( f"pref={pref}" ) elif self.path_type == 'Search': pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type,PA_UserState.orig_search_term==self.orig_search_term).first() else: @@ -106,6 +144,8 @@ class States(PA): self.cwd=pref.cwd self.orig_ptype=pref.orig_ptype self.orig_search_term=pref.orig_search_term + self.orig_url = pref.orig_url + self.view_eid = pref.view_eid else: self.folders=False self.noo="Oldest" @@ -122,10 +162,13 @@ class States(PA): self.orig_ptype=None if not hasattr(self, 'orig_search_term'): self.orig_search_term=None - + self.orig_url = self.url # the above are defaults, if we are here, then we have current values, use them instead if they are set -- AI: searches dont set them so then we use those in the DB first if request.method=="POST": + print("this was a POST, so use form vals to update PREF" ) + for el in request.form: + print( f"{el}={request.form[el]}" ) if 'noo' in request.form: self.noo=request.form['noo'] if 'how_many' in request.form: @@ -146,6 +189,8 @@ class States(PA): # view with grouping (otherwise we print out group headings for # child content that is not in the CWD) self.grouping=None + if 'orig_url' in request.form: + self.orig_url = request.form['orig_url'] # possible to not be set for an AI: search if 'cwd' in request.form: @@ -164,7 +209,8 @@ class States(PA): # now save pref (if this is 'another' search, view, etc. then it will add a row for it with matching search_term, or view_eid, etc. if not pref: pref=PA_UserState( pa_user_dn=current_user.dn, path_type=self.path_type, view_eid=self.view_eid, noo=self.noo, grouping=self.grouping, how_many=self.how_many, - st_offset=self.offset, size=self.size, folders=self.folders, root=self.root, cwd=self.cwd, orig_ptype=self.orig_ptype, orig_search_term=self.orig_search_term ) + st_offset=self.offset, size=self.size, folders=self.folders, root=self.root, cwd=self.cwd, + orig_ptype=self.orig_ptype, orig_search_term=self.orig_search_term, orig_url=self.orig_url ) else: pref.pa_user_dn=current_user.dn pref.path_type=self.path_type @@ -179,10 +225,13 @@ class States(PA): pref.cwd = self.cwd pref.orig_ptype = self.orig_ptype pref.orig_search_term = self.orig_search_term + pref.orig_url = self.orig_url db.session.add(pref) db.session.commit() + print( f"saved pref={pref}" ) + return ################################################################################ @@ -191,6 +240,6 @@ class States(PA): @app.route("/states", methods=["GET"]) @login_required def states(): + user = PAUser.query.filter( PAUser.dn==current_user.dn ).one() states = PA_UserState.query.filter( PA_UserState.pa_user_dn==current_user.dn ).all() - return render_template("states.html", states=states ) - + return render_template("states.html", user=user, states=states ) diff --git a/tables.sql b/tables.sql index ffe223d..df3fd34 100644 --- a/tables.sql +++ b/tables.sql @@ -27,7 +27,7 @@ create table PA_USER( constraint PK_PA_USER_ID primary key(ID) ); -- this should reference pa_user_id not pa_user_dn -create table PA_USER_STATE ( ID integer, PA_USER_DN varchar(128), PATH_TYPE varchar(16), NOO varchar(16), GROUPING varchar(16), HOW_MANY integer, ST_OFFSET integer, SIZE integer, FOLDERS Boolean, FULLSCREEN Boolean, ROOT varchar, CWD varchar, VIEW_EID integer, ORIG_PTYPE varchar, ORIG_SEARCH_TERM varchar, +create table PA_USER_STATE ( ID integer, PA_USER_DN varchar(128), PATH_TYPE varchar(16), NOO varchar(16), GROUPING varchar(16), HOW_MANY integer, ST_OFFSET integer, SIZE integer, FOLDERS Boolean, FULLSCREEN Boolean, ROOT varchar, CWD varchar, VIEW_EID integer, ORIG_PTYPE varchar, ORIG_SEARCH_TERM varchar, ORIG_URL varchar, constraint FK_PA_USER_DN foreign key (PA_USER_DN) references PA_USER(DN), constraint PK_PA_USER_STATES_ID primary key(ID ) ); diff --git a/templates/base.html b/templates/base.html index 8dcca1a..b7f6686 100644 --- a/templates/base.html +++ b/templates/base.html @@ -109,8 +109,6 @@ - - @@ -119,7 +117,7 @@ diff --git a/templates/faces.html b/templates/faces.html index bbcde68..aede83e 100644 --- a/templates/faces.html +++ b/templates/faces.html @@ -18,17 +18,17 @@ fig_{{f.id}}=$('#fig_{{f.id}}') // store this stuff in an javascript Object to use when document is ready event is triggered var orig_face_{{f.id}}=new Object; - orig_face_{{f.id}}.x = (({{f.locn[0][1]}}*1.05 - {{f.locn[0][3]}}*.95) - {{f.w}}) / 2 - orig_face_{{f.id}}.y = (({{f.locn[0][2]}}*1.05 - {{f.locn[0][0]}}*.95) - {{f.h}}) / 2 + orig_face_{{f.id}}.x = (({{f.locn[1]}}*1.05 - {{f.locn[3]}}*.95) - {{f.w}}) / 2 + orig_face_{{f.id}}.y = (({{f.locn[2]}}*1.05 - {{f.locn[0]}}*.95) - {{f.h}}) / 2 orig_face_{{f.id}}.w = {{f.w}} orig_face_{{f.id}}.h = {{f.h}} - orig_face_{{f.id}}.orig_w = {{f.locn[0][1]}}*1.05 - {{f.locn[0][3]}}*.95 - orig_face_{{f.id}}.orig_h = {{f.locn[0][2]}}*1.05 - {{f.locn[0][0]}}*.95 + orig_face_{{f.id}}.orig_w = {{f.locn[1]}}*1.05 - {{f.locn[3]}}*.95 + orig_face_{{f.id}}.orig_h = {{f.locn[2]}}*1.05 - {{f.locn[0]}}*.95 console.log( orig_face_{{f.id}} ) // when the document is ready, then DrawRefimg - $(function() { DrawRefimg( fig_{{f.id}}, im_{{f.id}}, c_{{f.id}}, orig_face_{{f.id}} ) }); + $(function() { DrawUnmatchedFace( fig_{{f.id}}, im_{{f.id}}, c_{{f.id}}, orig_face_{{f.id}} ) });
Face #{{f.id}} diff --git a/templates/files.html b/templates/files.html index 6fe4d37..db017aa 100644 --- a/templates/files.html +++ b/templates/files.html @@ -16,7 +16,7 @@
-
+ {% if search_term is defined %} @@ -83,36 +83,36 @@
- {% if OPT.size == "64" %} + {% if OPT.size == 64 %} {% set bt="btn-info text-white" %} {% else %} {% set bt="btn-outline-info" %} {% endif %} - - {% if OPT.size == "96" %} + + {% if OPT.size == 96 %} {% set bt="btn-info text-white" %} {% else %} {% set bt="btn-outline-info" %} {% endif %} - - {% if OPT.size == "128" %} + + {% if OPT.size == 128 %} {% set bt="btn-info text-white" %} {% else %} {% set bt="btn-outline-info" %} {% endif %} - - {% if OPT.size == "192" %} + + {% if OPT.size == 192 %} {% set bt="btn-info text-white" %} {% else %} {% set bt="btn-outline-info" %} {% endif %} - - {% if OPT.size == "256" %} + + {% if OPT.size == 256 %} {% set bt="btn-info text-white" %} {% else %} {% set bt="btn-outline-info" %} {% endif %} - +
@@ -250,7 +250,7 @@
- +
@@ -282,15 +282,12 @@ function CallViewRoute(id) { s='' s+='' - s+='' s+='' s+='' - s+='' - s+='' s+='' - s+='' s+='' s+='' + s+='' {% if search_term is defined %} s+='' {% endif %} diff --git a/templates/states.html b/templates/states.html index 989c121..94ba7ef 100644 --- a/templates/states.html +++ b/templates/states.html @@ -1,12 +1,54 @@ {% extends "base.html" %} {% block main_content %} -

PA User state page

+
- The following values are based on navigating the application and are not set by hand. This page is for checking/debugging only. +

Defaults for {{user.dn|Username}}

+
+
+
+ + {{CreateSelect( "size", user.default_size, ["XS", "S", "M", "L", "XL"], "ChangeDefault();return false", "col-2 rounded-end", { 0:64, 1:96, 2:128, 3:192, 4:256 } )|safe }} +
+
+
+
+ + {{CreateSelect( "noo", user.default_noo, ["Oldest", "Newest","A to Z", "Z to A"], "ChangeDefault();return false", "col-2 rounded-end")|safe }} +
+
+
+
+ + {{CreateSelect( "how_many", user.default_how_many, [10, 25, 50, 75, 100, 150, 200, 500], "ChangeDefault();return false", "col-2 rounded-end")|safe }} +
+
+
+
+ + {{CreateSelect( "grouping", user.default_grouping, ["None", "Day", "Week", "Month"], "ChangeDefault();return false", "col-2 rounded-end")|safe }} +
+
+
+
+ + {{CreateSelect( "folders", user.default_folders, ["In Folder", "Flat View"], "ChangeDefault();return false", "col-2 rounded-end", { 0:true, 1:false } )|safe }} +
+
+
+
+ + {{CreateSelect( "fullscreen", user.default_fullscreen, [True,False], "ChangeDefault();return false", "col-2 rounded-end")|safe }} +
+
+
+ +
+ The following values are based on the defaults above and subsequent changes as you navigate the application and are not set by hand. The following content is for checking/debugging only.
+
@@ -43,3 +85,19 @@ {% endblock main_content %} +{% block script_content %} + +{% endblock script_content %} diff --git a/templates/viewer.html b/templates/viewer.html index 4e13f38..d292122 100644 --- a/templates/viewer.html +++ b/templates/viewer.html @@ -86,6 +86,7 @@ s+='' s+='' s+='' + s+='' s+='' s+='' {% if search_term is defined %} diff --git a/user.py b/user.py index 7a7cf4d..ffc563b 100644 --- a/user.py +++ b/user.py @@ -1,9 +1,12 @@ from main import db from sqlalchemy import Sequence -from flask_login import UserMixin +from flask import request, redirect +from flask_login import UserMixin, login_required +from main import db, app, ma from sqlalchemy.exc import SQLAlchemyError from status import st, Status + # pylint: disable=no-member ################################################################################ @@ -17,9 +20,48 @@ class PAUser(UserMixin,db.Model): __tablename__ = "pa_user" id = db.Column(db.Integer, db.Sequence('pa_user_id_seq'), primary_key=True) dn = db.Column(db.String) + default_noo = db.Column(db.String) + default_grouping = db.Column(db.String) + default_how_many = db.Column(db.Integer) + default_size = db.Column(db.Integer) + default_folders = db.Column(db.Boolean) + default_fullscreen = db.Column(db.Boolean) def __repr__(self): - return self.dn - + str=f"<{self.__class__.__name__}(" + for k, v in self.__dict__.items(): + str += f"{k}={v!r}, " + str=str.rstrip(", ") + ")>" + return str + def get_id(self): return self.dn + +################################################################################ +# /changedefaults -> POST only -> changes defaults in DB, states.html reloads +# /states once its successful +################################################################################ +@app.route("/changedefaults", methods=["POST"]) +@login_required +def changedefaults(): + print( "change defaults -- need to sanitize form!?" ) + for el in request.form: + print( f"{el}={request.form[el]}" ) + user=PAUser.query.filter(PAUser.dn==request.form['dn']).one() + user.default_size = request.form['default_size'] + user.default_noo = request.form['default_noo'] + user.default_how_many = request.form['default_how_many'] + user.default_grouping = request.form['default_grouping'] + if request.form['default_folders'] == 'True': + user.default_folders = True + else: + user.default_folders = False + print("fullscreen is failing?") + if request.form['default_fullscreen'] == 'True': + user.default_fullscreen = True + else: + user.default_fullscreen = False + print( user ) + db.session.add(user) + db.session.commit() + return "done"