Compare commits
7 Commits
56771308a6
...
9bdd9d5b78
| Author | SHA1 | Date | |
|---|---|---|---|
| 9bdd9d5b78 | |||
| d3ae9b788f | |||
| 1396cbab78 | |||
| b7500e5170 | |||
| 392708bad9 | |||
| 90b3fe4c2f | |||
| bd6c9c1fbd |
9
TODO
9
TODO
@@ -1,12 +1,3 @@
|
|||||||
* new viewing model (get ids of query on first load, then paginate only inside that known list)
|
|
||||||
- BUT, when we finish a delete, what do I do with pageList / entryList???
|
|
||||||
- start by showing them as deleted (via amend)
|
|
||||||
- then on success, remove the ids from the *List arrays in js -- but do
|
|
||||||
this via repagination, invalidate page cache fully, then getPage(currentPage)
|
|
||||||
(e.g. assume 1, 2, 3 ... 40 in eList). delete 23, 24,
|
|
||||||
then reset lists to remove 23 and 24, pageList would then
|
|
||||||
get reset to page with: 21,22,25,26 ... 30, 31
|
|
||||||
|
|
||||||
? get rid of style and just use class -- think this should work, so change in
|
? get rid of style and just use class -- think this should work, so change in
|
||||||
templates/files.html for throbber, etc. and dont set style as much in view_support.js
|
templates/files.html for throbber, etc. and dont set style as much in view_support.js
|
||||||
|
|
||||||
|
|||||||
1
amend.py
1
amend.py
@@ -32,6 +32,7 @@ class EntryAmendment(PA,db.Model):
|
|||||||
job_id = db.Column(db.Integer, db.ForeignKey("job.id"), primary_key=True )
|
job_id = db.Column(db.Integer, db.ForeignKey("job.id"), primary_key=True )
|
||||||
amend_type = db.Column(db.Integer, db.ForeignKey("amendment_type.id"))
|
amend_type = db.Column(db.Integer, db.ForeignKey("amendment_type.id"))
|
||||||
type = db.relationship("AmendmentType", backref="entry_amendment")
|
type = db.relationship("AmendmentType", backref="entry_amendment")
|
||||||
|
job = db.relationship("Job", back_populates="amendments")
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
56
files.py
56
files.py
@@ -5,6 +5,7 @@ from main import db, app, ma
|
|||||||
from sqlalchemy import Sequence, text, select, union, or_
|
from sqlalchemy import Sequence, text, select, union, or_
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
|
import numbers
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
@@ -266,6 +267,22 @@ class EntrySchema(ma.SQLAlchemyAutoSchema):
|
|||||||
def get_full_path(self, obj):
|
def get_full_path(self, obj):
|
||||||
return obj.FullPathOnFS()
|
return obj.FullPathOnFS()
|
||||||
|
|
||||||
|
class JobExtraSchema(ma.SQLAlchemyAutoSchema):
|
||||||
|
class Meta:
|
||||||
|
model = JobExtra
|
||||||
|
load_instance = True
|
||||||
|
name = ma.auto_field()
|
||||||
|
value = ma.auto_field()
|
||||||
|
|
||||||
|
class JobSchema(ma.SQLAlchemyAutoSchema):
|
||||||
|
class Meta:
|
||||||
|
model = Job
|
||||||
|
load_instance = True
|
||||||
|
id = ma.auto_field()
|
||||||
|
name = ma.auto_field()
|
||||||
|
extra = ma.Nested(JobExtraSchema, many=True)
|
||||||
|
amendments = ma.Nested(EntryAmendmentSchema, many=True)
|
||||||
|
|
||||||
# global - this will be use more than once below, so do it once for efficiency
|
# global - this will be use more than once below, so do it once for efficiency
|
||||||
entries_schema = EntrySchema(many=True)
|
entries_schema = EntrySchema(many=True)
|
||||||
FOT_Schema = FaceOverrideTypeSchema(many=True)
|
FOT_Schema = FaceOverrideTypeSchema(many=True)
|
||||||
@@ -273,6 +290,8 @@ path_Schema = PathSchema(many=True)
|
|||||||
person_Schema = PersonSchema(many=True)
|
person_Schema = PersonSchema(many=True)
|
||||||
et_schema = AmendmentTypeSchema(many=True)
|
et_schema = AmendmentTypeSchema(many=True)
|
||||||
ea_schema = EntryAmendmentSchema(many=True)
|
ea_schema = EntryAmendmentSchema(many=True)
|
||||||
|
job_schema = JobSchema(many=False)
|
||||||
|
job_schemas = JobSchema(many=True)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /get_entries_by_ids -> route where we supply list of entry ids (for next/prev
|
# /get_entries_by_ids -> route where we supply list of entry ids (for next/prev
|
||||||
@@ -312,7 +331,7 @@ def process_ids():
|
|||||||
ea = db.session.execute(stmt).unique().scalars().all()
|
ea = db.session.execute(stmt).unique().scalars().all()
|
||||||
ea_data=ea_schema.dump(ea)
|
ea_data=ea_schema.dump(ea)
|
||||||
|
|
||||||
return jsonify(entries=entries_schema.dump(sorted_data), amend=ea_data)
|
return jsonify(entries=entries_schema.dump(sorted_data), amendments=ea_data)
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -629,7 +648,7 @@ def restore_files():
|
|||||||
jex.append( JobExtra( name=f"{el}", value=str(request.form[el]) ) )
|
jex.append( JobExtra( name=f"{el}", value=str(request.form[el]) ) )
|
||||||
|
|
||||||
job=NewJob( name="restore_files", num_files=0, wait_for=None, jex=jex, desc="to restore selected file(s)" )
|
job=NewJob( name="restore_files", num_files=0, wait_for=None, jex=jex, desc="to restore selected file(s)" )
|
||||||
return redirect("/jobs")
|
return jsonify( job=job_schema.dump(job) )
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /delete_files -> create a job to delete files for the b/e to process
|
# /delete_files -> create a job to delete files for the b/e to process
|
||||||
@@ -642,7 +661,7 @@ def delete_files():
|
|||||||
jex.append( JobExtra( name=f"{el}", value=str(request.form[el]) ) )
|
jex.append( JobExtra( name=f"{el}", value=str(request.form[el]) ) )
|
||||||
|
|
||||||
job=NewJob( name="delete_files", num_files=0, wait_for=None, jex=jex, desc="to delete selected file(s)" )
|
job=NewJob( name="delete_files", num_files=0, wait_for=None, jex=jex, desc="to delete selected file(s)" )
|
||||||
return redirect("/jobs")
|
return jsonify( job=job_schema.dump(job) )
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /move_files -> create a job to move files for the b/e to process
|
# /move_files -> create a job to move files for the b/e to process
|
||||||
@@ -685,7 +704,7 @@ def view():
|
|||||||
|
|
||||||
# route called from front/end - if multiple images are being transformed, each transorm == a separate call
|
# route called from front/end - if multiple images are being transformed, each transorm == a separate call
|
||||||
# to this route (and therefore a separate transorm job. Each reponse allows the f/e to check the
|
# to this route (and therefore a separate transorm job. Each reponse allows the f/e to check the
|
||||||
# specific transorm job is finished (/check_transform_job) which will be called (say) every 1 sec. from f/e
|
# specific transorm job is finished (/check_amend_job_status) which will be called (say) every 1 sec. from f/e
|
||||||
# with a spinning wheel, then when pa_job_mgr has finished it will return the transformed thumb
|
# with a spinning wheel, then when pa_job_mgr has finished it will return the transformed thumb
|
||||||
@app.route("/transform", methods=["POST"])
|
@app.route("/transform", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
@@ -698,27 +717,28 @@ def transform():
|
|||||||
jex.append( JobExtra( name=f"{el}", value=str(request.form[el]) ) )
|
jex.append( JobExtra( name=f"{el}", value=str(request.form[el]) ) )
|
||||||
|
|
||||||
job=NewJob( name="transform_image", num_files=0, wait_for=None, jex=jex, desc="to transform selected file(s)" )
|
job=NewJob( name="transform_image", num_files=0, wait_for=None, jex=jex, desc="to transform selected file(s)" )
|
||||||
return jsonify( job_id=job.id )
|
return jsonify( job=job_schema.dump(job) )
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /check_transform_job -> URL that is called repeatedly by front-end waiting for the
|
# /check_amend_job_status -> URL that is called repeatedly by front-end waiting
|
||||||
# b/e to finish the transform job. Once done, the new / now
|
# for the b/e to finish the amendment job (delete/restore/move file).
|
||||||
# transformed image's thumbnail is returned so the f/e can
|
# Once done, return "ok"
|
||||||
# update with it
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@app.route("/check_transform_job", methods=["POST"])
|
@app.route("/check_amend_job_status", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def check_transform_job():
|
def check_amend_job_status():
|
||||||
job_id = request.form['job_id']
|
job_id = request.form['job_id']
|
||||||
stmt=select(Job).where(Job.id==job_id)
|
stmt = select(Job).options(joinedload(Job.amendments)).where(Job.id == job_id)
|
||||||
job=db.session.execute(stmt).scalars().one_or_none()
|
job=db.session.execute(stmt).unique().scalars().first()
|
||||||
j=jsonify( finished=False )
|
# FIXME: should validate job_id is real from UI
|
||||||
if job.pa_job_state == 'Completed':
|
if job.name == 'transform_image':
|
||||||
id=[jex.value for jex in job.extra if jex.name == "id"][0]
|
eid=[jex.value for jex in job.extra if jex.name == "id"][0]
|
||||||
stmt=select(Entry).where(Entry.id==id)
|
stmt=select(Entry).where(Entry.id==eid)
|
||||||
ent=db.session.execute(stmt).scalars().all()
|
ent=db.session.execute(stmt).scalars().all()
|
||||||
ent_data=entries_schema.dump(ent)
|
ent_data=entries_schema.dump(ent)
|
||||||
j=jsonify( finished=True, entry=ent_data[0] )
|
j=jsonify(finished=(job.pa_job_state == 'Completed'), job=job_schema.dump(job), entry=ent_data[0] )
|
||||||
|
else:
|
||||||
|
j=jsonify(finished=(job.pa_job_state == 'Completed'), job=job_schema.dump(job))
|
||||||
return j
|
return j
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
@@ -151,6 +151,37 @@ function MoveDBox(path_details)
|
|||||||
$("#suffix").keypress(function (e) { if (e.which == 13) { $("#move_submit").click(); return false; } } )
|
$("#suffix").keypress(function (e) { if (e.which == 13) { $("#move_submit").click(); return false; } } )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is called anytime we have a job that returns amendments
|
||||||
|
// (visually we want to show this entry is being amended by a job)
|
||||||
|
// as we check for a job to end every second, we can call this multiple times
|
||||||
|
// during the runtime of a job, so only redraw/react to a new amendment
|
||||||
|
// NOTE: we update all views, as we might go into one via jscript before the job ends
|
||||||
|
function processAmendments( ams )
|
||||||
|
{
|
||||||
|
for (const am of ams)
|
||||||
|
{
|
||||||
|
// if we return anything here, we already have this amendment, so continue to next
|
||||||
|
if( document.amendments.filter(obj => obj.eid === am.eid).length > 0 )
|
||||||
|
continue
|
||||||
|
|
||||||
|
document.amendments.push(am)
|
||||||
|
|
||||||
|
if( document.viewing && document.viewing.id == am.eid )
|
||||||
|
{
|
||||||
|
im.src=im.src + '?t=' + new Date().getTime();
|
||||||
|
DrawImg()
|
||||||
|
}
|
||||||
|
|
||||||
|
// find where in the page this image is being viewed
|
||||||
|
idx = pageList.indexOf(am.eid)
|
||||||
|
// createFigureHtml uses matching document.amendments to show thobber, etc
|
||||||
|
html = createFigureHtml( document.entries[idx] )
|
||||||
|
$('#'+am.eid).replaceWith( html )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function to add data for document.amendment based on id and amt
|
||||||
|
// used when we transform several images in files_*, or single image in viewer
|
||||||
// show the DBox for a delete/restore file, includes all thumbnails of selected files
|
// show the DBox for a delete/restore file, includes all thumbnails of selected files
|
||||||
// with appropriate coloured button to Delete or Restore files`
|
// with appropriate coloured button to Delete or Restore files`
|
||||||
function DelDBox(del_or_undel)
|
function DelDBox(del_or_undel)
|
||||||
@@ -159,28 +190,36 @@ function DelDBox(del_or_undel)
|
|||||||
$('#dbox-title').html(del_or_undel+' Selected File(s)')
|
$('#dbox-title').html(del_or_undel+' Selected File(s)')
|
||||||
div ='<div class="row col-12"><p class="col">' + del_or_undel + ' the following files?</p></div>'
|
div ='<div class="row col-12"><p class="col">' + del_or_undel + ' the following files?</p></div>'
|
||||||
div+=GetSelnAsDiv()
|
div+=GetSelnAsDiv()
|
||||||
|
if( del_or_undel == "Delete" )
|
||||||
|
{
|
||||||
|
which="delete"
|
||||||
|
col="danger"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
which="restore"
|
||||||
|
col="sucess"
|
||||||
|
}
|
||||||
|
|
||||||
|
document.ents_to_del=[]
|
||||||
|
$('.highlight').each(function( cnt ) { document.ents_to_del[cnt]=parseInt($(this).attr('id')) } )
|
||||||
div+=`<div class="row col-12 mt-3">
|
div+=`<div class="row col-12 mt-3">
|
||||||
<button onClick="$('#dbox').modal('hide')" class="btn btn-outline-secondary col-2">Cancel</button>
|
<button onClick="$('#dbox').modal('hide')" class="btn btn-outline-secondary col-2">Cancel</button>
|
||||||
`
|
<button onClick="
|
||||||
div+=`
|
$.ajax({ type: 'POST', data: to_del, url: '/${which}_files',
|
||||||
<button onClick="MoveOrDelCleanUpUI(); $.ajax({ type: 'POST', data: to_del, url:
|
success: function(data) {
|
||||||
`
|
// FIXME: what is the ! search stuff for???
|
||||||
if( del_or_undel == "Delete" )
|
// FIXME: really, also why not show 'delete' throbber, and on success of actual delete go back to /
|
||||||
div+=`
|
if( $(location).attr('pathname').match('search') !== null || document.viewing ) { window.location='/' }
|
||||||
'/delete_files',
|
|
||||||
success: function(data){
|
processAmendments( data.job.amendments )
|
||||||
if( $(location).attr('pathname').match('search') !== null || document.viewing ) { window.location='/' }; CheckForJobs() } }); return false" class="btn btn-outline-danger col-2">Ok</button>
|
checkForAmendmentJobToComplete(data.job.id)
|
||||||
</div>
|
}
|
||||||
`
|
});
|
||||||
else
|
$('#dbox').modal('hide')
|
||||||
// just force page reload to / for now if restoring files from a search path -- a search (by name)
|
return false"
|
||||||
// would match the deleted/restored file, so it would be complex to clean up the UI (and can't reload, as DB won't be changed yet)
|
class="btn btn-outline-${col} col-2">Ok</button>
|
||||||
div+=`
|
</div>`
|
||||||
'/restore_files',
|
|
||||||
success: function(data){
|
|
||||||
if( $(location).attr('pathname').match('search') !== null || document.viewing ) { window.location='/' }; CheckForJobs() } }); return false" class="btn btn-outline-success col-2">Ok</button>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
$('#dbox-content').html(div)
|
$('#dbox-content').html(div)
|
||||||
$('#dbox').modal('show')
|
$('#dbox').modal('show')
|
||||||
}
|
}
|
||||||
@@ -378,37 +417,37 @@ function createFigureHtml( obj )
|
|||||||
|
|
||||||
// Image/Video/Unknown entry
|
// Image/Video/Unknown entry
|
||||||
if (obj.type.name === "Image" || obj.type.name === "Video" || obj.type.name === "Unknown") {
|
if (obj.type.name === "Image" || obj.type.name === "Video" || obj.type.name === "Unknown") {
|
||||||
const pathType = obj.in_dir.in_path.type.name;
|
const pathType = obj.in_dir.in_path.type.name;
|
||||||
const size = obj.file_details.size_mb;
|
const size = obj.file_details.size_mb;
|
||||||
const hash = obj.file_details.hash;
|
const hash = obj.file_details.hash;
|
||||||
const inDir = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}`;
|
const inDir = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}`;
|
||||||
const fname = obj.name;
|
const fname = obj.name;
|
||||||
const yr = obj.file_details.year;
|
const yr = obj.file_details.year;
|
||||||
const date = `${yr}${String(obj.file_details.month).padStart(2, '0')}${String(obj.file_details.day).padStart(2, '0')}`;
|
const date = `${yr}${String(obj.file_details.month).padStart(2, '0')}${String(obj.file_details.day).padStart(2, '0')}`;
|
||||||
const prettyDate = `${obj.file_details.day}/${obj.file_details.month}/${obj.file_details.year}`;
|
const prettyDate = `${obj.file_details.day}/${obj.file_details.month}/${obj.file_details.year}`;
|
||||||
const type = obj.type.name;
|
const type = obj.type.name;
|
||||||
|
|
||||||
// if amendment for this obj, do not add entry class - prevents highlighting
|
// if amendment for this obj, do not add entry class - prevents highlighting
|
||||||
if( am ) {
|
if( am ) {
|
||||||
ent=""
|
ent=""
|
||||||
gs="style='filter: grayscale(100%);'"
|
gs="style='filter: grayscale(100%);'"
|
||||||
am_html ='<img class="position-absolute top-50 start-50 translate-middle" height="60" src="/internal/white-circle.png">'
|
am_html ='<img class="position-absolute top-50 start-50 translate-middle" height="60" src="/internal/white-circle.png">'
|
||||||
am_html +='<img class="position-absolute top-50 start-50 translate-middle" height="64" src="/internal/throbber.gif">'
|
am_html+='<img class="position-absolute top-50 start-50 translate-middle" height="64" src="/internal/throbber.gif">'
|
||||||
if( am.type.which == 'icon' )
|
if( am.type.which == 'icon' )
|
||||||
am_html+=`<svg class="position-absolute top-50 start-50 translate-middle" height="32" style="color:${am.type.colour}" fill="${am.type.colour}"><use xlink:href="/internal/icons.svg#${am.type.what}"></use></svg>`
|
am_html+=`<svg class="position-absolute top-50 start-50 translate-middle" height="32" style="color:${am.type.colour}" fill="${am.type.colour}"><use xlink:href="/internal/icons.svg#${am.type.what}"></use></svg>`
|
||||||
else
|
else
|
||||||
am_html+=`<img class="position-absolute top-50 start-50 translate-middle" src="/internal/${am.type.what}?v={{js_vers['r270']}}" height="32">`
|
am_html+=`<img class="position-absolute top-50 start-50 translate-middle" src="/internal/${am.type.what}?v={{js_vers['r270']}}" height="32">`
|
||||||
} else {
|
} else {
|
||||||
ent="entry"
|
ent="entry"
|
||||||
gs=""
|
gs=""
|
||||||
am_html=""
|
am_html=""
|
||||||
}
|
}
|
||||||
html += `
|
html += `
|
||||||
<figure id="${obj.id}" class="col col-auto g-0 figure ${ent} m-1"
|
<figure id="${obj.id}" class="col col-auto g-0 figure ${ent} m-1"
|
||||||
path_type="${pathType}" size="${size}" hash="${hash}" in_dir="${inDir}"
|
path_type="${pathType}" size="${size}" hash="${hash}" in_dir="${inDir}"
|
||||||
fname="${fname}" yr="${yr}" date="${date}" pretty_date="${prettyDate}" type="${type}">
|
fname="${fname}" yr="${yr}" date="${date}" pretty_date="${prettyDate}" type="${type}">
|
||||||
${renderMedia(obj,gs,am_html)}
|
${renderMedia(obj,gs,am_html)}
|
||||||
</figure>`;
|
`
|
||||||
}
|
}
|
||||||
// Directory entry
|
// Directory entry
|
||||||
else if (obj.type.name === "Directory" && OPT.folders) {
|
else if (obj.type.name === "Directory" && OPT.folders) {
|
||||||
@@ -422,7 +461,6 @@ function createFigureHtml( obj )
|
|||||||
<use xlink:href="/internal/icons.svg#Directory"></use>
|
<use xlink:href="/internal/icons.svg#Directory"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<figcaption class="svg_cap figure-caption text-center text-wrap text-break">${obj.name}</figcaption>
|
<figcaption class="svg_cap figure-caption text-center text-wrap text-break">${obj.name}</figcaption>
|
||||||
</figure>
|
|
||||||
`;
|
`;
|
||||||
html += `<script>f=$('#${obj.id}'); w=f.find('svg').width(); f.find('figcaption').width(w);</script>`;
|
html += `<script>f=$('#${obj.id}'); w=f.find('svg').width(); f.find('figcaption').width(w);</script>`;
|
||||||
}
|
}
|
||||||
@@ -434,7 +472,8 @@ function createFigureHtml( obj )
|
|||||||
$('#${obj.id}').click( function(e) { DoSel(e, this ); SetButtonState(); return false; });
|
$('#${obj.id}').click( function(e) { DoSel(e, this ); SetButtonState(); return false; });
|
||||||
$('#${obj.id}').dblclick( function(e) { startViewing( $(this).attr('id') ) } )
|
$('#${obj.id}').dblclick( function(e) { startViewing( $(this).attr('id') ) } )
|
||||||
}
|
}
|
||||||
</script>`
|
</script>
|
||||||
|
</figure>`
|
||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,6 +660,7 @@ function getEntriesByIdSuccessHandler(res,pageNumber,successCallback,viewingIdx)
|
|||||||
document.entries=res;
|
document.entries=res;
|
||||||
// cache this
|
// cache this
|
||||||
document.page[pageNumber]=res
|
document.page[pageNumber]=res
|
||||||
|
// FIXME: I want to remove successCallback, instead: if viewing, or files_*, or file_list, then call relevant draw routine
|
||||||
successCallback(res,viewingIdx)
|
successCallback(res,viewingIdx)
|
||||||
resetNextPrevButtons()
|
resetNextPrevButtons()
|
||||||
// if search, disable folders
|
// if search, disable folders
|
||||||
@@ -663,11 +703,11 @@ function getPage(pageNumber, successCallback, viewingIdx=0)
|
|||||||
data: JSON.stringify(data), contentType: 'application/json',
|
data: JSON.stringify(data), contentType: 'application/json',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
document.amendments=res.amend;
|
document.amendments=res.amendments;
|
||||||
// this is only called when we are viewing a page in files/list view, so check for job(s) ending...
|
// only called when an amendment is pending & we are viewing a page in files/list view
|
||||||
for (const tmp of document.amendments) {
|
// so check for amendment job(s) ending...
|
||||||
CheckTransformJob(tmp.eid,tmp.job_id,handleTransformFiles)
|
for (const tmp of document.amendments)
|
||||||
}
|
checkForAmendmentJobToComplete(tmp.job_id)
|
||||||
getEntriesByIdSuccessHandler( res.entries, pageNumber, successCallback, viewingIdx )
|
getEntriesByIdSuccessHandler( res.entries, pageNumber, successCallback, viewingIdx )
|
||||||
},
|
},
|
||||||
error: function(xhr, status, error) { console.error("Error:", error); } });
|
error: function(xhr, status, error) { console.error("Error:", error); } });
|
||||||
@@ -811,6 +851,64 @@ function changeSize()
|
|||||||
$('.svg_cap').width(sz);
|
$('.svg_cap').width(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when a delete or restore files job has completed successfullly, then get ids
|
||||||
|
// find the page we are on, remove amendments & ids from entryList and re-get page
|
||||||
|
// which will reset pageList and the UI of images for that page
|
||||||
|
function handleDeleteOrRestoreFileJobCompleted(job)
|
||||||
|
{
|
||||||
|
// this grabs the values from the object attributes of eid-0, eid-1, etc.
|
||||||
|
const ids = job.extra.map(item => item.value)
|
||||||
|
|
||||||
|
// find page number of first element to delete (this is the page we will return too)
|
||||||
|
pnum=getPageNumberForId( ids[0] )
|
||||||
|
|
||||||
|
// remove amendment data
|
||||||
|
for (const ent of ids)
|
||||||
|
{
|
||||||
|
id=parseInt(ent)
|
||||||
|
removeAmendment( id )
|
||||||
|
// remove the item in the entryList
|
||||||
|
index=entryList.indexOf(id);
|
||||||
|
if( index != -1 )
|
||||||
|
entryList.splice(index, 1); // Remove the element
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return; // have to get out of here, or calling getPage() below will loop forever
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-create pageList by reloading the page
|
||||||
|
getPage(pnum,getPageFigures)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST to a check URL, that will tell us if the amendment job has completed,
|
||||||
|
// it also calls CheckForJobs() which will fix up the Active Jobs badge,
|
||||||
|
function checkForAmendmentJobToComplete(job_id)
|
||||||
|
{
|
||||||
|
CheckForJobs()
|
||||||
|
$.ajax( { type: 'POST', data: '&job_id='+job_id, url: '/check_amend_job_status',
|
||||||
|
success: function(res) { handleCheckAmendmentJobStatus(res); } } )
|
||||||
|
}
|
||||||
|
|
||||||
|
// the status of a Amendment Job has been returned, finished is True/False
|
||||||
|
// if not finished try again in 1 second... If finished then invalidate page
|
||||||
|
// cache and based on job type call code correct func to update the UI appropriately
|
||||||
|
function handleCheckAmendmentJobStatus(data)
|
||||||
|
{
|
||||||
|
if( data.finished )
|
||||||
|
{
|
||||||
|
// invalidate the cache
|
||||||
|
document.page.length=0
|
||||||
|
|
||||||
|
// transforms contain the single transformed entry data for convenience
|
||||||
|
if( data.job.name == 'transform_image' )
|
||||||
|
handleTransformImageJobCompleted(data.job, data.entry)
|
||||||
|
else if ( data.job.name == 'delete_files' || data.job.name == 'restore_files' )
|
||||||
|
handleDeleteOrRestoreFileJobCompleted(data.job)
|
||||||
|
}
|
||||||
|
else { setTimeout( function() { checkForAmendmentJobToComplete(data.job.id) }, 1000 ); }
|
||||||
|
}
|
||||||
|
|
||||||
// different context menu on files
|
// different context menu on files
|
||||||
$.contextMenu({
|
$.contextMenu({
|
||||||
selector: '.entry',
|
selector: '.entry',
|
||||||
|
|||||||
@@ -2,75 +2,26 @@
|
|||||||
// can only have 1 ammendment per image, its grayed out for other changes
|
// can only have 1 ammendment per image, its grayed out for other changes
|
||||||
function removeAmendment( id )
|
function removeAmendment( id )
|
||||||
{
|
{
|
||||||
document.amendments=document.amendments.filter(obj => obj.eid !== id)
|
console.log( 'removing amendment for: ' + id )
|
||||||
|
document.amendments=document.amendments.filter(obj => obj.eid !== id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST to a check URL, that will tell us if the transformation has completed,
|
// If Transform job has finished then reset relevant document.entries
|
||||||
// if not, try again in 1 second... If it has finished then reset the thumbnail
|
// with updated from DB, remove the amendment and redraw image
|
||||||
// to full colour, put it back to being an entry and reset the thumbnail to the
|
function handleTransformImageJobCompleted(job, entry)
|
||||||
// newly created one that was sent back in the response to the POST
|
|
||||||
function handleTransformFiles(data,id,job_id)
|
|
||||||
{
|
{
|
||||||
if( data.finished )
|
removeAmendment( entry.id )
|
||||||
{
|
// update viewer and files* views, in case we view/go up without a new page load
|
||||||
id=parseInt(id)
|
// force reload with timestamped version of im.src
|
||||||
idx = entryList.indexOf(id)
|
im.src=im.src + '?t=' + new Date().getTime();
|
||||||
// replace data for this entry now its been transformed
|
DrawImg()
|
||||||
document.entries[idx]=data.entry
|
|
||||||
// update cache too
|
|
||||||
// document.page[getPageNumberForId(id)][howFarIntoPageCache(id)]=data.entry
|
|
||||||
// FIXME: for now just invalidate whole cache
|
|
||||||
document.page.length=0
|
|
||||||
removeAmendment( id )
|
|
||||||
// redraw into figure html in dom
|
|
||||||
last={ 'printed': 'not required' }
|
|
||||||
html = createFigureHtml( data.entry, last, 9999 )
|
|
||||||
$('#'+id).replaceWith( html )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setTimeout( function() { CheckTransformJob(id,job_id,handleTransformFiles) }, 1000,id, job_id );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST to a check URL, that will tell us if the transformation has completed,
|
idx = entryList.indexOf(entry.id)
|
||||||
// if not, try again in 1 second... If it has finished then reset the image
|
// replace data for this entry now its been transformed
|
||||||
// to full colour
|
document.entries[idx]=entry
|
||||||
function handleTransformViewing(data,id,job_id)
|
// redraw into figure html in dom
|
||||||
{
|
html = createFigureHtml( entry )
|
||||||
if( data.finished )
|
$('#'+entry.id).replaceWith( html )
|
||||||
{
|
|
||||||
// stop throbber, remove grayscale & then force reload with timestamped version of im.src
|
|
||||||
im.src=im.src + '?t=' + new Date().getTime();
|
|
||||||
removeAmendment( id )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setTimeout( function() { CheckTransformJob(id,job_id,handleTransformViewing) }, 1000,id, job_id );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST to a check URL, that will tell us if the transformation has completed,
|
|
||||||
// if not, try again in 1 second... If it has finished then reset the thumbnail
|
|
||||||
// to full colour, put it back to being an entry and reset the thumbnail to the
|
|
||||||
// newly created one that was sent back in the response to the POST
|
|
||||||
function CheckTransformJob(id,job_id,successCallback)
|
|
||||||
{
|
|
||||||
CheckForJobs()
|
|
||||||
$.ajax( { type: 'POST', data: '&job_id='+job_id, url: '/check_transform_job',
|
|
||||||
success: function(res) { successCallback(res,id,job_id); } } )
|
|
||||||
}
|
|
||||||
|
|
||||||
// function to add data for document.amendment based on id and amt
|
|
||||||
// used when we transform several images in files_*, or single image in viewer
|
|
||||||
function addTransformAmendment(id,amt)
|
|
||||||
{
|
|
||||||
am={}
|
|
||||||
am.eid=parseInt(id)
|
|
||||||
am.type = document.amendTypes.filter(obj => obj.job_name === 'transform_image:'+amt )[0]
|
|
||||||
document.amendments.push(am)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for each highlighted image, POST the transform with amt (90, 180, 270,
|
// for each highlighted image, POST the transform with amt (90, 180, 270,
|
||||||
@@ -81,15 +32,13 @@ function addTransformAmendment(id,amt)
|
|||||||
function Transform(amt)
|
function Transform(amt)
|
||||||
{
|
{
|
||||||
// we are in the viewer with 1 image only...
|
// we are in the viewer with 1 image only...
|
||||||
if( document.viewing )
|
if( $('#viewer_div').length && ! $('#viewer_div').hasClass('d-none') )
|
||||||
{
|
{
|
||||||
post_data = '&amt='+amt+'&id='+document.viewing.id
|
post_data = '&amt='+amt+'&id='+document.viewing.id
|
||||||
// POST /transform for image, grayscale the image, add throbber, & start checking for end of job
|
// POST /transform for image, grayscale the image, add throbber, & start checking for end of job
|
||||||
$.ajax({ type: 'POST', data: post_data, url: '/transform', success: function(data) {
|
$.ajax({ type: 'POST', data: post_data, url: '/transform', success: function(data) {
|
||||||
addTransformAmendment(document.viewing.id, amt)
|
processAmendments(data.job.amendments)
|
||||||
DrawImg();
|
checkForAmendmentJobToComplete(data.job.id)
|
||||||
CheckTransformJob(document.viewing.id,data.job_id,handleTransformViewing);
|
|
||||||
return false;
|
|
||||||
} })
|
} })
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -98,13 +47,8 @@ function Transform(amt)
|
|||||||
post_data = '&amt='+amt+'&id='+e.id
|
post_data = '&amt='+amt+'&id='+e.id
|
||||||
// POST /transform for image, grayscale the thumbnail, add throbber, & start checking for end of job
|
// POST /transform for image, grayscale the thumbnail, add throbber, & start checking for end of job
|
||||||
$.ajax({ type: 'POST', data: post_data, url: '/transform', success: function(data){
|
$.ajax({ type: 'POST', data: post_data, url: '/transform', success: function(data){
|
||||||
addTransformAmendment(e.id, amt)
|
processAmendments(data.job.amendments)
|
||||||
last={ 'printed': 'not required' }
|
checkForAmendmentJobToComplete(data.job.id)
|
||||||
idx = pageList.indexOf(parseInt(e.id))
|
|
||||||
html = createFigureHtml( document.entries[idx], last, 9999 )
|
|
||||||
$('#'+e.id).replaceWith( html )
|
|
||||||
CheckTransformJob(e.id,data.job_id,handleTransformFiles);
|
|
||||||
return false;
|
|
||||||
} })
|
} })
|
||||||
} )
|
} )
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,22 +71,15 @@ function SetActiveJobsBadge(num_jobs)
|
|||||||
// after a 1 second timeout
|
// after a 1 second timeout
|
||||||
function CheckForJobs()
|
function CheckForJobs()
|
||||||
{
|
{
|
||||||
$.ajax(
|
$.ajax( {
|
||||||
{
|
type: 'POST', url: '/check_for_jobs',
|
||||||
type: 'POST', url: '/check_for_jobs',
|
success: function(data) {
|
||||||
success: function(data) {
|
// for each status, handle it/make toast in UI
|
||||||
data.sts.forEach(
|
data.sts.forEach( function(el) { StatusMsg(el) } )
|
||||||
function(el)
|
SetActiveJobsBadge(data.num_active_jobs)
|
||||||
{
|
// still active job(s), keep checking for them to end
|
||||||
StatusMsg(el)
|
if( data.num_active_jobs > 0 ) { setTimeout( function() { CheckForJobs() }, 1000 ); }
|
||||||
}
|
},
|
||||||
)
|
} )
|
||||||
SetActiveJobsBadge(data.num_active_jobs)
|
|
||||||
if( data.num_active_jobs > 0 )
|
|
||||||
{
|
|
||||||
setTimeout( function() { CheckForJobs() }, 1000 );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
} )
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ function ViewImageOrVideo()
|
|||||||
if( ! document.viewing ) return
|
if( ! document.viewing ) return
|
||||||
if( document.viewing.type.name == 'Image' )
|
if( document.viewing.type.name == 'Image' )
|
||||||
{
|
{
|
||||||
im.src='../' + document.viewing.FullPathOnFS
|
im.src='../' + document.viewing.FullPathOnFS + '?t=' + new Date().getTime();
|
||||||
$('#video_div').hide()
|
$('#video_div').hide()
|
||||||
if( $('#fname_toggle').prop('checked' ) )
|
if( $('#fname_toggle').prop('checked' ) )
|
||||||
$('#img-cap').show()
|
$('#img-cap').show()
|
||||||
@@ -623,6 +623,8 @@ function goOutOfViewer()
|
|||||||
// hide viewer div, then show files_div
|
// hide viewer div, then show files_div
|
||||||
$('#viewer_div').addClass('d-none')
|
$('#viewer_div').addClass('d-none')
|
||||||
$('#files_div').removeClass('d-none')
|
$('#files_div').removeClass('d-none')
|
||||||
|
// no longer viewing an image too
|
||||||
|
document.viewing=null
|
||||||
}
|
}
|
||||||
|
|
||||||
// change the viewer to the previous entry (handle page change too)
|
// change the viewer to the previous entry (handle page change too)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 6.1 KiB |
31
job.py
31
job.py
@@ -4,6 +4,7 @@ from flask import request, render_template, redirect, make_response, jsonify, ur
|
|||||||
from settings import Settings
|
from settings import Settings
|
||||||
from main import db, app, ma
|
from main import db, app, ma
|
||||||
from sqlalchemy import Sequence, func, select
|
from sqlalchemy import Sequence, func, select
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import pytz
|
import pytz
|
||||||
@@ -58,10 +59,12 @@ class Job(db.Model):
|
|||||||
|
|
||||||
extra = db.relationship( "JobExtra")
|
extra = db.relationship( "JobExtra")
|
||||||
logs = db.relationship( "Joblog")
|
logs = db.relationship( "Joblog")
|
||||||
|
amendments = db.relationship("EntryAmendment", back_populates="job")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<id: {}, start_time: {}, last_update: {}, name: {}, state: {}, num_files: {}, current_file_num: {}, current_file: {}, pa_job_state: {}, wait_for: {}, extra: {}, logs: {}>".format(self.id, self.start_time, self.last_update, self.name, self.state, self.num_files, self.current_file_num, self.current_file, self.pa_job_state, self.wait_for, self.extra, self.logs)
|
return "<id: {}, start_time: {}, last_update: {}, name: {}, state: {}, num_files: {}, current_file_num: {}, current_file: {}, pa_job_state: {}, wait_for: {}, extra: {}, logs: {}>".format(self.id, self.start_time, self.last_update, self.name, self.state, self.num_files, self.current_file_num, self.current_file, self.pa_job_state, self.wait_for, self.extra, self.logs)
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Class describing PA_JobManager_Message and in the DB (via sqlalchemy)
|
# Class describing PA_JobManager_Message and in the DB (via sqlalchemy)
|
||||||
# the job manager can send a message back to the front end (this code) via the
|
# the job manager can send a message back to the front end (this code) via the
|
||||||
@@ -83,7 +86,7 @@ class PA_JobManager_Message(PA,db.Model):
|
|||||||
# Used in main html to show a red badge of # jobs to draw attention there are
|
# Used in main html to show a red badge of # jobs to draw attention there are
|
||||||
# active jobs being processed in the background
|
# active jobs being processed in the background
|
||||||
################################################################################
|
################################################################################
|
||||||
def GetNumActiveJobs():
|
def getNumActiveJobs():
|
||||||
ret=Job.query.filter(Job.pa_job_state != 'Completed').with_entities(func.count(Job.id).label('count') ).first()
|
ret=Job.query.filter(Job.pa_job_state != 'Completed').with_entities(func.count(Job.id).label('count') ).first()
|
||||||
return ret[0]
|
return ret[0]
|
||||||
|
|
||||||
@@ -122,16 +125,16 @@ def NewJob(name, num_files="0", wait_for=None, jex=None, desc="No description pr
|
|||||||
if job.name == 'transform_image':
|
if job.name == 'transform_image':
|
||||||
id=[jex.value for jex in job.extra if jex.name == "id"][0]
|
id=[jex.value for jex in job.extra if jex.name == "id"][0]
|
||||||
ea=EntryAmendment( eid=id, job_id=job.id, amend_type=at_id )
|
ea=EntryAmendment( eid=id, job_id=job.id, amend_type=at_id )
|
||||||
print( f"just added an EA for eid={id}, j={job.id}" )
|
|
||||||
db.session.add(ea)
|
db.session.add(ea)
|
||||||
elif job.name == 'delete_files':
|
job.amendments.append(ea)
|
||||||
|
# FIXME: add ea to job.amend
|
||||||
|
elif job.name == 'delete_files' or job.name == 'restore_files':
|
||||||
for j in jex:
|
for j in jex:
|
||||||
if 'eid-' in j.name:
|
if 'eid-' in j.name:
|
||||||
ea=EntryAmendment( eid=j.value, amend_type=at_id )
|
ea=EntryAmendment( eid=j.value, job_id=job.id, amend_type=at_id )
|
||||||
db.session.add(ea)
|
db.session.add(ea)
|
||||||
# need to return this to the f/e somehow
|
# FIXME: add ea to job.amend
|
||||||
# this is for removes, really need to think about this more
|
job.amendments.append(ea)
|
||||||
#job.amendment=ea
|
|
||||||
|
|
||||||
SetFELog( message=f'Created <a class="link-light" href="/job/{job.id}">Job #{job.id}</a> to {desc}', level="success" )
|
SetFELog( message=f'Created <a class="link-light" href="/job/{job.id}">Job #{job.id}</a> to {desc}', level="success" )
|
||||||
WakePAJobManager(job.id)
|
WakePAJobManager(job.id)
|
||||||
@@ -327,14 +330,22 @@ def joblog_search():
|
|||||||
@app.route("/check_for_jobs", methods=["POST"])
|
@app.route("/check_for_jobs", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def check_for_jobs():
|
def check_for_jobs():
|
||||||
num=GetNumActiveJobs()
|
from files import job_schemas
|
||||||
|
|
||||||
|
num=getNumActiveJobs()
|
||||||
|
messages = PA_JobManager_Message.query.all()
|
||||||
sts=[]
|
sts=[]
|
||||||
for msg in PA_JobManager_Message.query.all():
|
for msg in messages:
|
||||||
u=''
|
u=''
|
||||||
if 'Job #' not in msg.message and msg.job_id:
|
if 'Job #' not in msg.message and msg.job_id:
|
||||||
u='<a class="link-light" href="' + url_for('joblog', id=msg.job_id) + '">Job #' + str(msg.job_id) + '</a>: '
|
u='<a class="link-light" href="' + url_for('joblog', id=msg.job_id) + '">Job #' + str(msg.job_id) + '</a>: '
|
||||||
sts.append( { 'id': msg.id, 'message': u+msg.message, 'level': msg.level, 'job_id': msg.job_id, 'persistent': msg.persistent, 'cant_close': msg.cant_close } )
|
sts.append( { 'id': msg.id, 'message': u+msg.message, 'level': msg.level, 'job_id': msg.job_id, 'persistent': msg.persistent, 'cant_close': msg.cant_close } )
|
||||||
return make_response( jsonify( num_active_jobs=num, sts=sts ) )
|
|
||||||
|
# get jobs mentioned in messages as we may need to process the by client for UI
|
||||||
|
job_list=[obj.job_id for obj in messages]
|
||||||
|
stmt = select(Job).options(joinedload(Job.amendments)).where(Job.id.in_(job_list))
|
||||||
|
jobs=db.session.execute(stmt).unique().scalars().all()
|
||||||
|
return make_response( jsonify( num_active_jobs=num, sts=sts, jobs=job_schemas.dump(jobs) ) )
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# /clear_msg -> POST -> clears out a F/E message based on passed in <id>
|
# /clear_msg -> POST -> clears out a F/E message based on passed in <id>
|
||||||
|
|||||||
@@ -886,7 +886,6 @@ def RunJob(job):
|
|||||||
elif job.name == "run_ai_on_path":
|
elif job.name == "run_ai_on_path":
|
||||||
JobRunAIOnPath(job)
|
JobRunAIOnPath(job)
|
||||||
elif job.name == "transform_image":
|
elif job.name == "transform_image":
|
||||||
#time.sleep(10)
|
|
||||||
JobTransformImage(job)
|
JobTransformImage(job)
|
||||||
elif job.name == "clean_bin":
|
elif job.name == "clean_bin":
|
||||||
JobCleanBin(job)
|
JobCleanBin(job)
|
||||||
@@ -1874,6 +1873,20 @@ def JobRunAIOn(job):
|
|||||||
FinishJob(job, "Finished Processesing AI")
|
FinishJob(job, "Finished Processesing AI")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# removeEntryAmendment(): helper routine to remove an Etnry Amendment for a
|
||||||
|
# given job and eid (called after Transform or Delete/Restore/Move files
|
||||||
|
################################################################################
|
||||||
|
def removeEntryAmendment( job, eid ):
|
||||||
|
# now remove the matching amendment for the transform job
|
||||||
|
stmt=select(EntryAmendment).where(EntryAmendment.eid==eid)
|
||||||
|
ea=session.execute(stmt).scalars().one_or_none()
|
||||||
|
if ea:
|
||||||
|
session.delete(ea)
|
||||||
|
else:
|
||||||
|
AddLogForJob( job, f"ERROR: failed to remove entry amendment in DB for this transformation? (eid={id})" )
|
||||||
|
PAprint( f"ERROR: failed to remove entry amendment in DB for this transformation? (eid={id}, job={job} )" )
|
||||||
|
|
||||||
####################################################################################################################################
|
####################################################################################################################################
|
||||||
# JobTransformImage(): transform an image by the amount requested (can also flip horizontal or vertical)
|
# JobTransformImage(): transform an image by the amount requested (can also flip horizontal or vertical)
|
||||||
####################################################################################################################################
|
####################################################################################################################################
|
||||||
@@ -1907,14 +1920,7 @@ def JobTransformImage(job):
|
|||||||
e.file_details.hash = md5( job, e )
|
e.file_details.hash = md5( job, e )
|
||||||
PAprint( f"JobTransformImage DONE thumb: job={job.id}, id={id}, amt={amt}" )
|
PAprint( f"JobTransformImage DONE thumb: job={job.id}, id={id}, amt={amt}" )
|
||||||
session.add(e)
|
session.add(e)
|
||||||
# now remove the matching amendment for the transform job
|
removeEntryAmendment( job, id )
|
||||||
stmt=select(EntryAmendment).where(EntryAmendment.eid==id)
|
|
||||||
ea=session.execute(stmt).scalars().one_or_none()
|
|
||||||
if ea:
|
|
||||||
session.delete(ea)
|
|
||||||
else:
|
|
||||||
AddLogForJob( job, f"ERROR: failed to remove entry amendment in DB for this transformation? (eid={id})" )
|
|
||||||
PAprint( f"ERROR: failed to remove entry amendment in DB for this transformation? (eid={id}, job={job} )" )
|
|
||||||
|
|
||||||
FinishJob(job, "Finished Processesing image rotation/flip")
|
FinishJob(job, "Finished Processesing image rotation/flip")
|
||||||
return
|
return
|
||||||
@@ -2207,6 +2213,7 @@ def JobDeleteFiles(job):
|
|||||||
if 'eid-' in jex.name:
|
if 'eid-' in jex.name:
|
||||||
del_me=session.query(Entry).join(File).filter(Entry.id==jex.value).first()
|
del_me=session.query(Entry).join(File).filter(Entry.id==jex.value).first()
|
||||||
MoveFileToRecycleBin(job,del_me)
|
MoveFileToRecycleBin(job,del_me)
|
||||||
|
removeEntryAmendment(job,del_me.id)
|
||||||
NewJob( name="check_dups", num_files=0, wait_for=None, jex=None, parent_job=None, desc="check for duplicate files" )
|
NewJob( name="check_dups", num_files=0, wait_for=None, jex=None, parent_job=None, desc="check for duplicate files" )
|
||||||
FinishJob(job, f"Finished deleting selected file(s)")
|
FinishJob(job, f"Finished deleting selected file(s)")
|
||||||
return
|
return
|
||||||
@@ -2221,6 +2228,7 @@ def JobRestoreFiles(job):
|
|||||||
if 'eid-' in jex.name:
|
if 'eid-' in jex.name:
|
||||||
restore_me=session.query(Entry).join(File).filter(Entry.id==jex.value).first()
|
restore_me=session.query(Entry).join(File).filter(Entry.id==jex.value).first()
|
||||||
RestoreFile(job,restore_me)
|
RestoreFile(job,restore_me)
|
||||||
|
removeEntryAmendment(job,restore_me.id)
|
||||||
NewJob( name="check_dups", num_files=0, wait_for=None, jex=None, parent_job=None, desc="check for duplicate files" )
|
NewJob( name="check_dups", num_files=0, wait_for=None, jex=None, parent_job=None, desc="check for duplicate files" )
|
||||||
FinishJob(job, f"Finished restoring selected file(s)")
|
FinishJob(job, f"Finished restoring selected file(s)")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ else
|
|||||||
sudo -u pauser gunicorn --bind=0.0.0.0:80 --workers=1 --threads=1 main:app --env ENV="development" --error-logfile gunicorn.error.log --access-logfile gunicorn.log --capture-output --enable-stdio-inheritance --reload
|
sudo -u pauser gunicorn --bind=0.0.0.0:80 --workers=1 --threads=1 main:app --env ENV="development" --error-logfile gunicorn.error.log --access-logfile gunicorn.log --capture-output --enable-stdio-inheritance --reload
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# warm the cache to see if this helps with odd restart 404s
|
||||||
|
curl -sf http://localhost/health
|
||||||
|
|
||||||
# this should never be invoked unless gunicorn fails -- in that case, at least
|
# this should never be invoked unless gunicorn fails -- in that case, at least
|
||||||
# we will keep the container can login by hand and check the issue/error
|
# we will keep the container can login by hand and check the issue/error
|
||||||
sleep 99999
|
sleep 99999
|
||||||
|
|||||||
Reference in New Issue
Block a user