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

This commit is contained in:
2022-01-22 21:36:58 +11:00
parent 491663f1c9
commit 0f4632e240
14 changed files with 264 additions and 77 deletions

31
TODO
View File

@@ -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/<id>", 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/<id>", 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/<id>", 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

12
ai.py
View File

@@ -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))

View File

@@ -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 )

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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"<pa_user_dn: {self.pa_user_dn}, path_type: {self.path_type}, noo: {self.noo}, grouping: {self.grouping}, how_many: {self.how_many}, st_offset: {self.st_offset}, size: {self.size}, folders: {self.folders}, root: {self.root}, cwd: {self.cwd}, view_eid: {self.view_eid}, orig_ptype: {self.orig_ptype}, orig_search_term: {self.orig_search_term}>"
return f"<pa_user_dn: {self.pa_user_dn}, path_type: {self.path_type}, noo: {self.noo}, grouping: {self.grouping}, how_many: {self.how_many}, st_offset: {self.st_offset}, size: {self.size}, folders: {self.folders}, root: {self.root}, cwd: {self.cwd}, view_eid: {self.view_eid}, orig_ptype: {self.orig_ptype}, orig_search_term: {self.orig_search_term}, orig_url: {self.orig_url}>"
################################################################################
@@ -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/<id> 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/<id>
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 )

View File

@@ -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 ) );

View File

@@ -109,8 +109,6 @@
<input type="hidden" id="search_how_many" name="how_many" value="">
<input type="hidden" id="search_offset" name="offset" value="">
<input type="hidden" id="search_size" name="size" value="">
<input type="hidden" id="search_folders" name="folders" value="">
<input type="hidden" id="search_cwd" name="cwd" value="">
<input id="search_term" class="form-control" type="search" placeholder="by file, date (YYYMMDD) or tag" aria-label="Search" name="search_term">
<button class="btn btn-outline-success" onClick="javascript:st=$('#search_term').val(); document.location.href='/search/'+st" type="button">Search</button>
</form>
@@ -119,7 +117,7 @@
<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#user"/></svg>
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuLink">
<div><a class="dropdown-item" href="{{url_for('states')}}">{{current_user|Username}}</a></div>
<div><a class="dropdown-item" href="{{url_for('states')}}">{{current_user.dn|Username}}</a></div>
<div><a class="dropdown-item" href="{{url_for('logout')}}">Logout</a></div>
</div>
</div>

View File

@@ -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}} ) });
</script>
<figcaption>Face #{{f.id}}</figcation>
</div>

View File

@@ -16,7 +16,7 @@
</script>
<div class="container-fluid">
<form id="main_form" method="POST">
<form id="main_form" method="POST" action="/ChangeFileOpts">
<input type="hidden" name="cwd" id="cwd" value="{{OPT.cwd}}">
{% if search_term is defined %}
<input type="hidden" name="search_term" id="view_term" value="{{search_term}}">
@@ -83,36 +83,36 @@
</div>
<div class="d-flex col col-auto justify-content-end">
<div class="btn-group">
{% if OPT.size == "64" %}
{% if OPT.size == 64 %}
{% set bt="btn-info text-white" %}
{% else %}
{% set bt="btn-outline-info" %}
{% endif %}
<button aria-label="extra small" id="64" class="px-2 sm-txt sz-but btn {{bt}}" onClick="ChangeSize(this,64); return false;">XS</button>
{% if OPT.size == "96" %}
<button aria-label="extra small" id="64" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(64)">XS</button>
{% if OPT.size == 96 %}
{% set bt="btn-info text-white" %}
{% else %}
{% set bt="btn-outline-info" %}
{% endif %}
<button aria-label="small" id="96" class="px-2 sm-txt sz-but btn {{bt}}" onClick="ChangeSize(this,96); return false;">S</button>
{% if OPT.size == "128" %}
<button aria-label="small" id="96" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(96)">S</button>
{% if OPT.size == 128 %}
{% set bt="btn-info text-white" %}
{% else %}
{% set bt="btn-outline-info" %}
{% endif %}
<button aria-label="medium" id="128" class="px-2 sm-txt sz-but btn {{bt}}" onClick="ChangeSize(this,128); return false;">M</button>
{% if OPT.size == "192" %}
<button aria-label="medium" id="128" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(128)">M</button>
{% if OPT.size == 192 %}
{% set bt="btn-info text-white" %}
{% else %}
{% set bt="btn-outline-info" %}
{% endif %}
<button aria-label="large" id="192" class="px-2 sm-txt sz-but btn {{bt}}" onClick="ChangeSize(this,192); return false;">L</button>
{% if OPT.size == "256" %}
<button aria-label="large" id="192" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(192)">L</button>
{% if OPT.size == 256 %}
{% set bt="btn-info text-white" %}
{% else %}
{% set bt="btn-outline-info" %}
{% endif %}
<button aria-label="extra large" id="256" class="px-2 sm-txt sz-but btn {{bt}}" onClick="ChangeSize(this,256); return false;">XL</button>
<button aria-label="extra large" id="256" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(256)">XL</button>
</div class="btn-group">
</div class="col">
<input id="offset" type="hidden" name="offset" value="{{OPT.offset}}">
@@ -250,7 +250,7 @@
</div>
<div class="container-fluid">
<form id="nav_form" method="POST"">
<form id="nav_form" method="POST" action="/ChangeFileOpts">
<input type="hidden" name="cwd" id="cwd" value="{{OPT.cwd}}">
<div class="row">
<div class="col my-auto d-flex justify-content-center">
@@ -282,15 +282,12 @@ function CallViewRoute(id)
{
s='<form id="_fm" method="POST" action="/view/' + id + '">'
s+='<input type="hidden" name="eids" value="'+$("#eids").val() + '">'
s+='<input type="hidden" name="noo" value="{{OPT.noo}}">'
s+='<input type="hidden" name="cwd" value="{{OPT.cwd}}">'
s+='<input type="hidden" name="root" value="{{OPT.root}}">'
s+='<input type="hidden" name="size" value="{{OPT.size}}">'
s+='<input type="hidden" name="grouping" value="{{OPT.grouping}}">'
s+='<input type="hidden" name="offset" value="{{OPT.offset}}">'
s+='<input type="hidden" name="folders" value="{{OPT.folders}}">'
s+='<input type="hidden" name="how_many" value="{{OPT.how_many}}">'
s+='<input type="hidden" name="orig_url" value="{{request.path}}">'
s+='<input type="hidden" name="view_eid" value="'+id+'">'
{% if search_term is defined %}
s+='<input type="hidden" name="search_term" value="{{search_term}}">'
{% endif %}

View File

@@ -1,12 +1,54 @@
{% extends "base.html" %}
{% block main_content %}
<h3>PA User state page</h3>
<div class="container-fluid">
<div class="row">
<alert class="alert alert-warning">The following values are based on navigating the application and are not set by hand. This page is for checking/debugging only.</alert>
<h3>Defaults for {{user.dn|Username}}</h3>
<div class="col-6">
<div class="row">
<div class="input-group">
<label class="py-1 input-group-text col-6 justify-content-end">When viewing show in fullscreen:</label>
{{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 }}
</div>
</div class="row">
<div class="row">
<div class="input-group">
<label class="py-1 input-group-text col-6 justify-content-end">Ordered by:</label>
{{CreateSelect( "noo", user.default_noo, ["Oldest", "Newest","A to Z", "Z to A"], "ChangeDefault();return false", "col-2 rounded-end")|safe }}
</div class="input-group">
</div>
<div class="row">
<div class="input-group">
<label class="py-1 input-group-text col-6 justify-content-end">How many thumbnails to show at once:</label>
{{CreateSelect( "how_many", user.default_how_many, [10, 25, 50, 75, 100, 150, 200, 500], "ChangeDefault();return false", "col-2 rounded-end")|safe }}
</div class="input-group">
</div>
<div class="row">
<div class="input-group">
<label class="py-1 input-group-text col-6 justify-content-end">Group by:</label>
{{CreateSelect( "grouping", user.default_grouping, ["None", "Day", "Week", "Month"], "ChangeDefault();return false", "col-2 rounded-end")|safe }}
</div class="input-group">
</div>
<div class="row">
<div class="input-group">
<label class="py-1 input-group-text col-6 justify-content-end">Folders or Flat view of thumbnails:</label>
{{CreateSelect( "folders", user.default_folders, ["In Folder", "Flat View"], "ChangeDefault();return false", "col-2 rounded-end", { 0:true, 1:false } )|safe }}
</div>
</div>
<div class="row">
<div class="input-group">
<label class="py-1 input-group-text col-6 justify-content-end">When viewing show in fullscreen:</label>
{{CreateSelect( "fullscreen", user.default_fullscreen, [True,False], "ChangeDefault();return false", "col-2 rounded-end")|safe }}
</div>
</div>
</div class="col-6">
<div class="row pt-5">
<alert class="alert alert-warning">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.</alert>
</div class="row">
<div class="row">
<table id="pa_user_state_tbl" class="table table-striped table-sm" data-toolbar="#toolbar" data-search="true">
<thead>
@@ -43,3 +85,19 @@
</div class="row">
</div class="container-fluid">
{% endblock main_content %}
{% block script_content %}
<script>
function ChangeDefault()
{
data="dn={{user.dn}}"
data+="&default_size="+$('#size').val()
data+="&default_noo="+$('#noo').val()
data+="&default_how_many="+$('#how_many').val()
data+="&default_grouping="+$('#grouping').val()
data+="&default_folders="+$('#folders').val()
data+="&default_fullscreen="+$('#fullscreen').val()
console.log("Changing Default:"+data )
$.ajax({ type: 'POST', data: data, url: '/changedefaults', success: function(data){ window.location='/states'; return false; } })
}
</script>
{% endblock script_content %}

View File

@@ -86,6 +86,7 @@
s+='<input type="hidden" name="folders" value="{{OPT.folders}}">'
s+='<input type="hidden" name="how_many" value="{{OPT.how_many}}">'
s+='<input type="hidden" name="orig_url" value="{{OPT.orig_url}}">'
s+='<input type="hidden" name="view_eid" value="{{OPT.view_eid}}">'
s+='<input type="hidden" name="fullscreen" value="' + fullscreen + '">'
s+='<input type="hidden" name="' + dir + '" value="1">'
{% if search_term is defined %}

46
user.py
View File

@@ -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"