diff --git a/TODO b/TODO index a4f1e9b..4cbef2b 100644 --- a/TODO +++ b/TODO @@ -4,8 +4,6 @@ * remember last import dir, so you can just go straight back to it - * offer similar existing folders (based on date range +/- say 2 days) - * in Fullscreen mode and next/prev dropped out of FS when calling /viewlist route -- only way to fix this, is for when we POST to viewlist, it returns json, and we never leave /view/X -- then we can stay on-page, and stay in FS and then just call ViewImageOrVide() @@ -18,9 +16,6 @@ * why .xcf is seen as a video??? - actually only 1 is... I think if type == 'Unknown' then do file display and use ? as the image again - * maybe strip unnecessary / at end of directory name. i think i have left behind empty folders, e.g. check switzerland and austria - - also should allow move to existing folder soon... - * add an option on the person menu to run_ai_on all photos (or at least import/storage) * when hitting back button to a search, it doesnt handle the post, etc. diff --git a/files.py b/files.py index eb702e9..4ffe8f0 100644 --- a/files.py +++ b/files.py @@ -1,6 +1,6 @@ from wtforms import SubmitField, StringField, HiddenField, validators, Form from flask_wtf import FlaskForm -from flask import request, render_template, redirect, send_from_directory, url_for +from flask import request, render_template, redirect, send_from_directory, url_for, jsonify from path import MovePathDetails from main import db, app, ma from sqlalchemy import Sequence @@ -18,6 +18,7 @@ import cv2 import time import re import json +import datetime from flask_login import login_required, current_user from options import Options @@ -615,3 +616,42 @@ def _jinja2_filter_toplevelfolderof(path, cwd): @app.template_filter('ParentPath') def _jinja2_filter_parentpath(path): return os.path.dirname(path) + +############################################################################### +# route to allow the Move Dialog Box to pass a date (YYYYMMDD) and returns a +# json? list of existing dir names that could be near it in time. Starting +# simple, by using YYYYMM-1, YYYYMM, YYYYMM+1 dirs +############################################################################### +@app.route("/getexistingpaths/
", methods=["POST"]) +@login_required +def GetExistingPathsAsDiv(dt): + dir_ft=FileType.query.filter(FileType.name=='Directory').first() + dirs_arr=[] + for delta in range(-7, 8): + new_dtime=datetime.datetime.strptime(dt, "%Y%m%d") + datetime.timedelta(days=delta) + new_dt=new_dtime.strftime('%Y%m%d') + dirs_arr+=Dir.query.distinct(Dir.rel_path).filter(Dir.rel_path.ilike('%'+new_dt+'%')).all(); + dirs_arr+=Dir.query.distinct(Dir.rel_path).join(EntryDirLink).join(Entry).filter(Entry.type_id!=dir_ft.id).filter(Entry.name.ilike('%'+new_dt+'%')).all() + + # remove duplicates from array + dirs = set(dirs_arr) + + # turn DB output into json and return it to the f/e + ret='[ ' + first_dir=1 + for dir in dirs: + print( f"process dir matching for {new_dt} => {dir}") + if not first_dir: + ret +=", " + bits=dir.rel_path.split('-') + + ret+= '{ ' + ret+= '"prefix":"' + bits[0] + '", ' + if len(bits)>1: + ret+= '"suffix":"' + bits[1] + '"' + else: + ret+= '"suffix":"''"' + ret+= ' } ' + first_dir=0 + ret+= ' ]' + return ret diff --git a/internal/js/files_support.js b/internal/js/files_support.js index 3d0f581..c311678 100644 --- a/internal/js/files_support.js +++ b/internal/js/files_support.js @@ -37,6 +37,22 @@ function change_rp_sel() $('#move_path_type').val( $('option:selected', '#rp_sel').attr('path_type') ) } +function GetExistingDirsAsDiv( dt, divname ) +{ + $.ajax({ + type: 'POST', data: null, url: '/getexistingpaths/'+dt, + success: function(data) { + $('#'+divname).html(data) + dirs = JSON.parse(data) + s='' + dirs.forEach( function(item, index) { + s+= '' + } ) + $('#'+divname).html(s) + } + } ) +} + // show the DBox for a move file, includes all thumbnails of selected files to move // and a pre-populated folder to move them into, with text field to add a suffix function MoveDBox(path_details, db_url) @@ -53,6 +69,8 @@ function MoveDBox(path_details, db_url) div+=GetSelnAsDiv() yr=$('.highlight').first().attr('yr') dt=$('.highlight').first().attr('date') + div+='
Use Existing:
' + GetExistingDirsAsDiv( dt, "existing" ) div+=`
@@ -71,7 +89,7 @@ function MoveDBox(path_details, db_url) div+="value="+yr+'/'+dt+"-" div+=` "> - +
diff --git a/pa_job_manager.py b/pa_job_manager.py index f99890e..25addf0 100644 --- a/pa_job_manager.py +++ b/pa_job_manager.py @@ -1650,6 +1650,15 @@ def JobMoveFiles(job): JobProgressState( job, "In Progress" ) prefix=[jex.value for jex in job.extra if jex.name == "prefix"][0] suffix=[jex.value for jex in job.extra if jex.name == "suffix"][0] + # Sanity check, if prefix starts with /, reject it -> no /etc/shadow potentials + # Sanity check, if .. in prefix or suffix, reject it -> no ../../etc/shadow potentials + # Sanity check, if // in prefix or suffix, reject it -> not sure code wouldnt try to make empty dirs, and I dont want to chase /////// cases, any 2 in a row is enough to reject + if '..' in prefix or '..' in suffix or prefix[0] == '/' or '//' in prefix or '//' in suffix: + FinishJob( job, f"ERROR: Not processing move as the paths contain illegal chars", "Failed" ) + return + # also remove unecessary slashes, jic + prefix=prefix.rstrip('/') + suffix=suffix.lstrip('/').rstrip('/') path_type=[jex.value for jex in job.extra if jex.name == "move_path_type"][0] rel_path=[jex.value for jex in job.extra if jex.name == "rel_path"][0] dst_storage_path = session.query(Path).filter(Path.path_prefix=='static/' + path_type + '/'+ rel_path).first()