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+='
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()