hash is a string not an Integer, not sure how this issue has been here so long. Also, first pass of using query data to allow display of files_ip only. Definitely NOT, a usable version of PA at the moment

This commit is contained in:
2025-09-26 19:26:23 +10:00
parent 9ec8195d0a
commit d2db7f6184

126
files.py
View File

@@ -1,11 +1,11 @@
from wtforms import SubmitField, StringField, HiddenField, validators, Form
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask import request, render_template, redirect, send_from_directory, url_for, jsonify, make_response from flask import request, render_template, redirect, send_from_directory, url_for, jsonify, make_response
from main import db, app, ma from main import db, app, ma
from sqlalchemy import Sequence, text from sqlalchemy import Sequence, text, select
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
import os import os
import glob import glob
import json
from PIL import Image from PIL import Image
from pymediainfo import MediaInfo from pymediainfo import MediaInfo
import hashlib import hashlib
@@ -20,8 +20,8 @@ import pytz
import html import html
from flask_login import login_required, current_user from flask_login import login_required, current_user
from states import States, PA_UserState from states import States, PA_UserState
from query import Query
################################################################################
# Local Class imports # Local Class imports
################################################################################ ################################################################################
from job import Job, JobExtra, Joblog, NewJob, SetFELog from job import Job, JobExtra, Joblog, NewJob, SetFELog
@@ -119,7 +119,7 @@ class File(db.Model):
eid = db.Column(db.Integer, db.ForeignKey("entry.id"), primary_key=True ) eid = db.Column(db.Integer, db.ForeignKey("entry.id"), primary_key=True )
size_mb = db.Column(db.Integer, unique=False, nullable=False) size_mb = db.Column(db.Integer, unique=False, nullable=False)
thumbnail = db.Column(db.String, unique=False, nullable=True) thumbnail = db.Column(db.String, unique=False, nullable=True)
hash = db.Column(db.Integer) hash = db.Column(db.String)
year = db.Column(db.Integer) year = db.Column(db.Integer)
month = db.Column(db.Integer) month = db.Column(db.Integer)
day = db.Column(db.Integer) day = db.Column(db.Integer)
@@ -141,6 +141,61 @@ class FileType(db.Model):
def __repr__(self): def __repr__(self):
return f"<id: {self.id}, name={self.name}>" return f"<id: {self.id}, name={self.name}>"
################################################################################
# this is how we order all queries based on value of 'noo' - used with
# access *order_map.get(OPT.noo)
################################################################################
order_map = {
"Newest": (File.year.desc(),File.month.desc(),File.day.desc(),Entry.name.desc()),
"Oldest": (File.year,File.month,File.day,Entry.name),
# careful, these need to be tuples, so with a , at the end
"Z to A": (Entry.name.desc(),),
"A to Z": (Entry.name.asc(),),
}
################################################################################
################################################################################
# Schemas for Path, FileType, File, Dir - used in EntrySchema
################################################################################
class PathType(ma.SQLAlchemyAutoSchema):
class Meta: model = PathType
load_instance = True
class PathSchema(ma.SQLAlchemyAutoSchema):
class Meta: model = Path
load_instance = True
type = ma.Nested(PathType)
class FileTypeSchema(ma.SQLAlchemyAutoSchema):
class Meta: model = FileType
load_instance = True
class FileSchema(ma.SQLAlchemyAutoSchema):
class Meta: model = File
load_instance = True
class DirSchema(ma.SQLAlchemyAutoSchema):
class Meta: model = Dir
load_instance = True
in_path = ma.Nested(PathSchema)
################################################################################
# Schema for Entry so we can json for data to the client
################################################################################
class EntrySchema(ma.SQLAlchemyAutoSchema):
# gives id, name, type_id
class Meta: model = Entry
load_instance = True
type = ma.Nested(FileTypeSchema)
file_details = ma.Nested(FileSchema)
# noting dir_details needs in_path to work
dir_details = ma.Nested(DirSchema)
# noting in_dir needs in_path and in_path.type to work
in_dir = ma.Nested(DirSchema)
################################################################################ ################################################################################
# util function to just update the current/first/last positions needed for # util function to just update the current/first/last positions needed for
# viewing / using pa_user_state DB table # viewing / using pa_user_state DB table
@@ -327,9 +382,66 @@ def SetOrderStrings( OPT ):
OPT.last_order_raw=f"e.name desc" OPT.last_order_raw=f"e.name desc"
return return
################################################################################
# /get_entries_by_ids -> route where we supply list of entry ids (for next/prev
# page of data we want to show). Returns json of all matching entries
################################################################################
@app.route('/get_entries_by_ids', methods=['POST'])
@login_required
def process_ids():
data = request.get_json() # Parse JSON body
ids = data.get('ids', []) # Extract list of ids
# DDP: debate here, do I get query_id, do I validate whether we are asking
# for ids not in the query? OR, dont even make/store/have query?
# marshmallow will allow us to json the data the way we need for the client
entries_schema = EntrySchema(many=True)
# Query DB for matching entries
entries = Entry.query.filter(Entry.id.in_(ids)).all()
# return entries as json
return jsonify(entries_schema.dump(entries))
###
# query_data = { 'entry_lst': entry_lst, 'query_id': query_id, ... }
###
# Call this ONCE on first menu choice of View files, or search box submission
def GetQueryData( OPT ):
query_data = {}
query_data['query_id']=None
query_data['entry_list']=None
# set up the sql order strings (back in OPT) based on value of noo
# FIXME: remove this for all last/first eid usage AND use order_map
SetOrderStrings( OPT )
if OPT.path_type == 'Search':
print ("NOT YET")
return query_data
if OPT.folders:
entries, tmp_num_ents = GetEntriesInFolderView( OPT, prefix )
else:
stmt = ( select(Entry.id).join(File).join(EntryDirLink).join(Dir).join(PathDirLink).
join(Path).filter(Path.path_prefix == OPT.prefix) )
stmt = stmt.order_by(*order_map.get(OPT.noo) )
query_data['entry_list']= db.session.execute(stmt).scalars().all()
# first time we get the data q_offset is 0, current=first one, search never gets here, so search_term=''
# FIXME: Doubt we need cwd -- I only need originals to either invalidate this list, or recreate it... need to think about that a lot more
query = Query( path_type=OPT.path_type, noo=OPT.noo, q_offset=0, folder=OPT.folders, grouping=OPT.grouping, root=OPT.root, cwd=OPT.cwd, search_term='',
entry_list=query_data['entry_list'], current=query_data['entry_list'][0], created=datetime.now(pytz.utc) )
db.session.add(query)
db.session.commit()
query_data['query_id']=query.id
return query_data
################################################################################ ################################################################################
# /GetEntries -> helper function that Gets Entries for required files to show # /GetEntries -> helper function that Gets Entries for required files to show
# for several routes (files_ip, files_sp, files_rbp, search, view_list) # for several routes (ifles_ip, files_sp, files_rbp, search, view_list)
################################################################################ ################################################################################
def GetEntries( OPT ): def GetEntries( OPT ):
entries=[] entries=[]
@@ -374,6 +486,7 @@ def GetEntries( OPT ):
OPT.num_entries=num_entries OPT.num_entries=num_entries
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==OPT.path_type).first() pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==OPT.path_type).first()
UpdatePref( pref, OPT ) UpdatePref( pref, OPT )
return entries return entries
@app.route("/change_file_opts", methods=["POST"]) @app.route("/change_file_opts", methods=["POST"])
@@ -409,7 +522,8 @@ def files_ip():
entries=GetEntries( OPT ) entries=GetEntries( OPT )
people = Person.query.all() people = Person.query.all()
move_paths = MovePathDetails() move_paths = MovePathDetails()
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", entry_data=entries, OPT=OPT, people=people, move_paths=move_paths ) query_data = GetQueryData( OPT )
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", entry_data=entries, OPT=OPT, people=people, move_paths=move_paths, query_data=query_data )
################################################################################ ################################################################################
# /files -> show thumbnail view of files from storage_path # /files -> show thumbnail view of files from storage_path