From 5404a1d4110985f5ad5c9e2d43c1c55fe052434d Mon Sep 17 00:00:00 2001
From: Ethan Dalool <git@voussoir.net>
Date: Sat, 25 Feb 2017 22:47:20 -0800
Subject: [PATCH] checkpoint

fix bug in which renaming photo causes os.remove even when it's an in-place rename on case-insensitive systems; incorporate expressionmatch for filename search; minor comment cleanup
---
 etiquette/objects.py       | 32 +++++++++++----------
 etiquette/photodb.py       | 58 ++++++++++----------------------------
 etiquette/searchhelpers.py | 13 ++-------
 templates/photo.html       | 14 +++++----
 4 files changed, 44 insertions(+), 73 deletions(-)

diff --git a/etiquette/objects.py b/etiquette/objects.py
index a6a0daf..9d52a0b 100644
--- a/etiquette/objects.py
+++ b/etiquette/objects.py
@@ -606,7 +606,7 @@ class Photo(ObjectBase):
             except:
                 traceback.print_exc()
 
-        elif self.mimetype == 'audio':
+        elif self.mimetype == 'audio' and constants.ffmpeg:
             try:
                 probe = constants.ffmpeg.probe(self.real_filepath)
                 if probe and probe.audio:
@@ -671,12 +671,11 @@ class Photo(ObjectBase):
 
         os.makedirs(new_path.parent.absolute_path, exist_ok=True)
 
-        if new_path != old_path:
-            # This is different than the absolute == absolute check above,
-            # because this normalizes the paths. It's possible on
-            # case-insensitive systems to have the paths point to the same place
-            # while being differently cased, thus we couldn't make the
-            # intermediate link.
+        if new_path.normcase != old_path.normcase:
+            # It's possible on case-insensitive systems to have the paths point
+            # to the same place while being differently cased, thus we couldn't
+            # make the intermediate link.
+            # Instead, we will do a simple rename in just a moment.
             try:
                 os.link(old_path.absolute_path, new_path.absolute_path)
             except OSError:
@@ -688,18 +687,21 @@ class Photo(ObjectBase):
             [new_path.absolute_path, old_path.absolute_path]
         )
 
+        if new_path.normcase == old_path.normcase:
+            # If they are equivalent but differently cased, just rename.
+            action = os.rename
+            args = [old_path.absolute_path, new_path.absolute_path]
+        else:
+            # Delete the original, leaving only the new copy / hardlink.
+            action = os.remove
+            args = [old_path.absolute_path]
+        
         if commit:
-            if new_path == old_path:
-                # If they are equivalent but differently cased paths, just
-                # rename.
-                os.rename(old_path.absolute_path, new_path.absolute_path)
-            else:
-                # Delete the original hardlink or copy.
-                os.remove(old_path.absolute_path)
+            action(*args)
             self.photodb.log.debug('Committing - rename file')
             self.photodb.commit()
         else:
-            queue_action = {'action': os.remove, 'args': [old_path.absolute_path]}
+            queue_action = {'action': args, 'args': args}
             self.photodb.on_commit_queue.append(queue_action)
 
         self.__reinit__()
diff --git a/etiquette/photodb.py b/etiquette/photodb.py
index 84f9948..e95980c 100644
--- a/etiquette/photodb.py
+++ b/etiquette/photodb.py
@@ -719,6 +719,19 @@ class PDBPhotoMixin:
             expression_tree = expressionmatch.ExpressionTree.parse(tag_expression)
             expression_tree.map(self.normalize_tagname)
             expression_matcher = searchhelpers.tag_expression_matcher_builder(frozen_children, warning_bag)
+            for node in expression_tree.walk_leaves():
+                if node.token in frozen_children:
+                    continue
+                if warning_bag is not None:
+                    warning_bag.add(constants.WARNING_NO_SUCH_TAG.format(tag=node.token))
+                    node.token = None
+                else:
+                    raise_no_such_thing(exceptions.NoSuchTag, thing_name=node.token)
+            expression_tree.prune()
+
+        if filename:
+            filename_tree = expressionmatch.ExpressionTree.parse(filename)
+            filename_tree.map(lambda x: x.lower())
 
         photos_received = 0
 
@@ -749,7 +762,7 @@ class PDBPhotoMixin:
                 #print('Failed author')
                 continue
 
-            if filename and not _helper_filenamefilter(subject=photo.basename, terms=filename):
+            if filename and not filename_tree.evaluate(photo.basename.lower()):
                 #print('Failed filename')
                 continue
 
@@ -924,6 +937,7 @@ class PDBTagMixin:
         else:
             return tagname
 
+
 class PDBUserMixin:
     def generate_user_id(self):
         '''
@@ -1228,48 +1242,6 @@ class PhotoDB(PDBAlbumMixin, PDBBookmarkMixin, PDBPhotoMixin, PDBTagMixin, PDBUs
         else:
             return None
 
-    # def digest_new_files(
-    #         self,
-    #         directory,
-    #         exclude_directories=None,
-    #         exclude_filenames=None,
-    #         recurse=False,
-    #         commit=True
-    #     ):
-    #     '''
-    #     Walk the directory and add new files as Photos.
-    #     Does NOT create or modify any albums like `digest_directory` does.
-    #     '''
-    #     if not os.path.isdir(directory):
-    #         raise ValueError('Not a directory: %s' % directory)
-    #     if exclude_directories is None:
-    #         exclude_directories = self.config['digest_exclude_dirs']
-    #     if exclude_filenames is None:
-    #         exclude_filenames = self.config['digest_exclude_files']
-
-    #     directory = spinal.str_to_fp(directory)
-    #     generator = spinal.walk_generator(
-    #         directory,
-    #         exclude_directories=exclude_directories,
-    #         exclude_filenames=exclude_filenames,
-    #         recurse=recurse,
-    #         yield_style='flat',
-    #     )
-    #     for filepath in generator:
-    #         filepath = filepath.absolute_path
-    #         try:
-    #             self.get_photo_by_path(filepath)
-    #         except exceptions.NoSuchPhoto:
-    #             # This is what we want.
-    #             pass
-    #         else:
-    #             continue
-    #         photo = self.new_photo(filepath, commit=False)
-    #     if commit:
-    #         self.log.debug('Committing - digest_new_files')
-    #         self.commit()
-
-
     def easybake(self, ebstring):
         '''
         Easily create tags, groups, and synonyms with a string like
diff --git a/etiquette/searchhelpers.py b/etiquette/searchhelpers.py
index 692677d..7dc883e 100644
--- a/etiquette/searchhelpers.py
+++ b/etiquette/searchhelpers.py
@@ -153,7 +153,7 @@ def normalize_filename(filename_terms):
         filename_terms = ' '.join(filename_terms)
 
     filename_terms = filename_terms.strip()
-    filename_terms = [term.lower() for term in shlex.split(filename_terms)]
+    filename_terms = shlex.split(filename_terms)
 
     if not filename_terms:
         return None
@@ -331,14 +331,7 @@ def tag_expression_matcher_builder(frozen_children, warning_bag=None):
         if not photo_tags:
             return False
 
-        try:
-            options = frozen_children[tagname]
-        except KeyError:
-            if warning_bag is not None:
-                warning_bag.add(constants.WARNING_NO_SUCH_TAG.format(tag=tagname))
-                return False
-            else:
-                raise exceptions.NoSuchTag(tagname)
-
+        options = frozen_children[tagname]
         return any(option in photo_tags for option in options)
+
     return matcher
diff --git a/templates/photo.html b/templates/photo.html
index 70d9da9..fb1dc06 100644
--- a/templates/photo.html
+++ b/templates/photo.html
@@ -15,8 +15,6 @@
     /* Override common.css */
     flex-direction: row;
     flex: 1;
-    /*height: 100%;
-    width: 100%;*/
 }
 #left
 {
@@ -78,8 +76,6 @@
     flex-direction: column;
     justify-content: center;
     align-items: center;
-/*    height: 100%;
-    width: 100%;*/
 }
 .photo_viewer a
 {
@@ -174,7 +170,15 @@
     <!-- THE PHOTO ITSELF -->
     <div class="photo_viewer">
         {% if photo.mimetype == "image" %}
-        <div id="photo_img_holder"><img id="photo_img" src="{{link}}" onclick="toggle_hoverzoom()" onload="this.style.opacity=0.99"></div>
+        <div id="photo_img_holder">
+            <img
+            id="photo_img"
+            src="{{link}}"
+            alt="{{photo.basename}}"
+            onclick="toggle_hoverzoom()"
+            onload="this.style.opacity=0.99"
+            >
+        </div>
         {% elif photo.mimetype == "video" %}
         <video src="{{link}}" controls preload=none {%if photo.thumbnail%}poster="/thumbnail/{{photo.id}}.jpg"{%endif%}></video>
         {% elif photo.mimetype == "audio" %}