api upload framework
This commit is contained in:
parent
2c1ebea31c
commit
1b310f0c4a
128
photoapp/api.py
128
photoapp/api.py
@ -15,6 +15,98 @@ from photoapp.utils import mime2ext, auth, require_auth, photo_auth_filter, slug
|
||||
from photoapp.dbutils import db
|
||||
|
||||
|
||||
class StorageAdapter(object):
|
||||
"""
|
||||
Abstract interface for working with photo file storage. All paths are relative to the storage adapter's root parameter.
|
||||
"""
|
||||
|
||||
def file_exists(self, path):
|
||||
# TODO return true/false if the file path exists
|
||||
raise NotImplementedError()
|
||||
|
||||
def open(self, path, mode):
|
||||
# TODO return a handle to the path
|
||||
# TODO this should work as a context manager
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete(self, path):
|
||||
# TODO erase the path
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class FilesystemAdapter(StorageAdapter):
|
||||
def file_exists(self, path):
|
||||
# TODO return true/false if the file path exists
|
||||
raise NotImplementedError()
|
||||
|
||||
def open(self, path, mode):
|
||||
# TODO return a handle to the path. this should work as a context manager
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete(self, path):
|
||||
# TODO erase the path
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class S3Adapter(StorageAdapter):
|
||||
def file_exists(self, path):
|
||||
# TODO return true/false if the file path exists
|
||||
raise NotImplementedError()
|
||||
|
||||
def open(self, path, mode):
|
||||
# TODO return a handle to the path. this should work as a context manager
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete(self, path):
|
||||
# TODO erase the path
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class GfapiAdapter(StorageAdapter):
|
||||
pass
|
||||
|
||||
|
||||
#This is largely duplicated from library.py, but written with intent for later refactoring to support abstract storage.
|
||||
class LibraryManager(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def add_photoset(self, photoset):
|
||||
"""
|
||||
Commit a populated photoset object to the library. The paths in the photoset's file list entries will be updated
|
||||
as the file is moved to the library path.
|
||||
"""
|
||||
# Create target directory
|
||||
path = os.path.join(self.path, self.get_datedir_path(photoset.date))
|
||||
os.makedirs(path, exist_ok=True)
|
||||
|
||||
moves = [] # Track files moved. If the sql transaction files, we'll undo these
|
||||
|
||||
for file in photoset.files:
|
||||
dest = os.path.join(path, os.path.basename(file.path))
|
||||
|
||||
# Check if the name is already in use, rename new file if needed
|
||||
dupe_rename = 1
|
||||
while os.path.exists(dest):
|
||||
fname = os.path.basename(file.path).split(".")
|
||||
fname[-2] += "_{}".format(dupe_rename)
|
||||
dest = os.path.join(path, '.'.join(fname))
|
||||
dupe_rename += 1
|
||||
os.rename(file.path, dest)
|
||||
moves.append((file.path, dest))
|
||||
file.path = dest.lstrip(self.path)
|
||||
|
||||
s = self.session()
|
||||
s.add(photoset)
|
||||
try:
|
||||
s.commit()
|
||||
except IntegrityError:
|
||||
# Commit failed, undo the moves
|
||||
for move in moves:
|
||||
os.rename(move[1], move[0])
|
||||
raise
|
||||
|
||||
|
||||
class PhotosApi(object):
|
||||
def __init__(self):
|
||||
self.v1 = PhotosApiV1()
|
||||
@ -22,7 +114,7 @@ class PhotosApi(object):
|
||||
|
||||
class PhotosApiV1(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
self.lib = LibraryManager()
|
||||
|
||||
@cherrypy.expose
|
||||
def index(self):
|
||||
@ -41,23 +133,35 @@ class PhotosApiV1(object):
|
||||
|
||||
for file in files:
|
||||
print("File name:", file.filename)
|
||||
import hashlib
|
||||
sha = hashlib.sha256()
|
||||
|
||||
total = 0
|
||||
while True:
|
||||
b = file.file.read(1024)
|
||||
if not b:
|
||||
break
|
||||
sha.update(b)
|
||||
total += len(b)
|
||||
print("Read length:", total)
|
||||
print("Read sha256:", sha.hexdigest())
|
||||
# import hashlib
|
||||
# sha = hashlib.sha256()
|
||||
# total = 0
|
||||
# while True:
|
||||
# b = file.file.read(1024)
|
||||
# if not b:
|
||||
# break
|
||||
# sha.update(b)
|
||||
# total += len(b)
|
||||
# print("Read length:", total)
|
||||
# print("Read sha256:", sha.hexdigest())
|
||||
|
||||
if str(file.filename) not in meta["files"].keys():
|
||||
raise cherrypy.HTTPError(400, f"no mdatadata provided for filename '{file.filename}'")
|
||||
print("we have metadata for this file:", meta["files"][file.filename])
|
||||
|
||||
# create database objects based on the request
|
||||
# self.lib.add_photoset(set_, photos)
|
||||
|
||||
# build file path (yyyy/mm/dd/yyyy-mm_hh.MM.ss_x.jpg) (incrmenting X if the key already exists etc)
|
||||
# copy to storage
|
||||
# check if sha256 exists already
|
||||
# delete if dupe, raise error
|
||||
# (see file rewind code in ingest.py)
|
||||
# create records
|
||||
# commit
|
||||
# respond with list of uuids of the sets
|
||||
|
||||
print("____")
|
||||
|
||||
@cherrypy.expose
|
||||
|
Loading…
x
Reference in New Issue
Block a user