Add database upgrader script

This commit is contained in:
voussoir 2016-11-28 20:18:44 -08:00
parent 45a8a8ccc5
commit 2d4b07c10f
7 changed files with 127 additions and 26 deletions

View file

@ -1,7 +1,7 @@
import string import string
# Errors and warnings # Errors and warnings
ERROR_DATABASE_OUTOFDATE = 'Database is out-of-date. {current} should be {new}' ERROR_DATABASE_OUTOFDATE = 'Database is out-of-date. {current} should be {new}. Please use etiquette_upgrader.py'
ERROR_INVALID_ACTION = 'Invalid action' ERROR_INVALID_ACTION = 'Invalid action'
ERROR_NO_SUCH_TAG = 'Doesn\'t exist' ERROR_NO_SUCH_TAG = 'Doesn\'t exist'
ERROR_NO_TAG_GIVEN = 'No tag name supplied' ERROR_NO_TAG_GIVEN = 'No tag name supplied'

View file

@ -235,6 +235,11 @@ def get_albums_json():
return make_json_response(albums) return make_json_response(albums)
@site.route('/bookmarks')
def get_bookmarks():
return flask.render_template('bookmarks.html')
@site.route('/file/<photoid>') @site.route('/file/<photoid>')
def get_file(photoid): def get_file(photoid):
requested_photoid = photoid requested_photoid = photoid
@ -327,7 +332,6 @@ def get_search_core():
orderby = request.args.get('orderby', None) orderby = request.args.get('orderby', None)
if orderby: if orderby:
orderby = orderby.replace('-', ' ') orderby = orderby.replace('-', ' ')
orderby = orderby.replace('_', ' ')
orderby = orderby.split(',') orderby = orderby.split(',')
else: else:
orderby = None orderby = None

View file

@ -0,0 +1,60 @@
import argparse
import os
import sqlite3
import sys
import phototagger
def upgrade_1_to_2(sql):
'''
In this version, a column `tagged_at` was added to the Photos table, to keep
track of the last time the photo's tags were edited (added or removed).
'''
cur = sql.cursor()
cur.execute('ALTER TABLE photos ADD COLUMN tagged_at INT')
def upgrade_all(database_filename):
'''
Given the filename of a phototagger database, apply all of the needed
upgrade_x_to_y functions in order.
'''
if not os.path.isfile(database_filename):
raise FileNotFoundError(database_filename)
sql = sqlite3.connect(database_filename)
cur = sql.cursor()
cur.execute('PRAGMA user_version')
current_version = cur.fetchone()[0]
needed_version = phototagger.DATABASE_VERSION
if current_version == needed_version:
print('Already up-to-date.')
return
for version_number in range(current_version + 1, needed_version + 1):
print('Upgrading from %d to %d' % (current_version, version_number))
upgrade_function = 'upgrade_%d_to_%d' % (current_version, version_number)
upgrade_function = eval(upgrade_function)
upgrade_function(sql)
sql.cursor().execute('PRAGMA user_version = 2')
sql.commit()
current_version = version_number
print('Upgrades finished.')
def upgrade_all_argparse(args):
return upgrade_all(database_filename=args.database_filename)
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument('database_filename')
parser.set_defaults(func=upgrade_all_argparse)
args = parser.parse_args(argv)
args.func(args)
if __name__ == '__main__':
main(sys.argv[1:])

View file

@ -70,6 +70,7 @@ SQL_PHOTO_COLUMNS = [
'bytes', 'bytes',
'created', 'created',
'thumbnail', 'thumbnail',
'tagged_at',
] ]
SQL_TAG_COLUMNS = [ SQL_TAG_COLUMNS = [
'id', 'id',
@ -101,7 +102,10 @@ SQL_SYN = {key:index for (index, key) in enumerate(SQL_SYN_COLUMNS)}
SQL_TAG = {key:index for (index, key) in enumerate(SQL_TAG_COLUMNS)} SQL_TAG = {key:index for (index, key) in enumerate(SQL_TAG_COLUMNS)}
SQL_TAGGROUP = {key:index for (index, key) in enumerate(SQL_TAGGROUP_COLUMNS)} SQL_TAGGROUP = {key:index for (index, key) in enumerate(SQL_TAGGROUP_COLUMNS)}
DATABASE_VERSION = 1 # Note: Setting user_version pragma in init sequence is safe because it only
# happens after the out-of-date check occurs, so no chance of accidentally
# overwriting it.
DATABASE_VERSION = 2
DB_INIT = ''' DB_INIT = '''
PRAGMA count_changes = OFF; PRAGMA count_changes = OFF;
PRAGMA cache_size = 10000; PRAGMA cache_size = 10000;
@ -124,7 +128,8 @@ CREATE TABLE IF NOT EXISTS photos(
duration INT, duration INT,
bytes INT, bytes INT,
created INT, created INT,
thumbnail TEXT thumbnail TEXT,
tagged_at INT
); );
CREATE TABLE IF NOT EXISTS tags( CREATE TABLE IF NOT EXISTS tags(
id TEXT, id TEXT,
@ -180,6 +185,18 @@ CREATE INDEX IF NOT EXISTS index_grouprel_parentid on tag_group_rel(parentid);
CREATE INDEX IF NOT EXISTS index_grouprel_memberid on tag_group_rel(memberid); CREATE INDEX IF NOT EXISTS index_grouprel_memberid on tag_group_rel(memberid);
'''.format(user_version=DATABASE_VERSION) '''.format(user_version=DATABASE_VERSION)
ALLOWED_ORDERBY_COLUMNS = [
'extension',
'width',
'height',
'ratio',
'area',
'duration',
'bytes',
'created',
'tagged_at',
'random',
]
def _helper_extension(ext): def _helper_extension(ext):
''' '''
@ -240,18 +257,7 @@ def _helper_orderby(orderby):
return None return None
#print(column, sorter) #print(column, sorter)
sortable = column in [ if column not in ALLOWED_ORDERBY_COLUMNS:
'extension',
'width',
'height',
'ratio',
'area',
'duration',
'bytes',
'created',
'random',
]
if not sortable:
warnings.warn(constants.WARNING_ORDERBY_BADCOL.format(column=column)) warnings.warn(constants.WARNING_ORDERBY_BADCOL.format(column=column))
return None return None
if column == 'random': if column == 'random':
@ -1666,6 +1672,7 @@ class Photo(ObjectBase):
self.id = row_tuple[SQL_PHOTO['id']] self.id = row_tuple[SQL_PHOTO['id']]
self.real_filepath = row_tuple[SQL_PHOTO['filepath']] self.real_filepath = row_tuple[SQL_PHOTO['filepath']]
self.real_filepath = normalize_filepath(self.real_filepath) self.real_filepath = normalize_filepath(self.real_filepath)
self.real_path = pathclass.Path(self.real_filepath)
self.filepath = row_tuple[SQL_PHOTO['override_filename']] or self.real_filepath self.filepath = row_tuple[SQL_PHOTO['override_filename']] or self.real_filepath
self.basename = row_tuple[SQL_PHOTO['override_filename']] or os.path.basename(self.real_filepath) self.basename = row_tuple[SQL_PHOTO['override_filename']] or os.path.basename(self.real_filepath)
self.extension = row_tuple[SQL_PHOTO['extension']] self.extension = row_tuple[SQL_PHOTO['extension']]
@ -1677,7 +1684,7 @@ class Photo(ObjectBase):
self.duration = row_tuple[SQL_PHOTO['duration']] self.duration = row_tuple[SQL_PHOTO['duration']]
self.created = row_tuple[SQL_PHOTO['created']] self.created = row_tuple[SQL_PHOTO['created']]
self.thumbnail = row_tuple[SQL_PHOTO['thumbnail']] self.thumbnail = row_tuple[SQL_PHOTO['thumbnail']]
self.real_path = pathclass.Path(self.real_filepath) self.tagged_at = row_tuple[SQL_PHOTO['tagged_at']]
def __reinit__(self): def __reinit__(self):
''' '''
@ -1709,9 +1716,10 @@ class Photo(ObjectBase):
log.debug('Preferring new {tag:s} over {par:s}'.format(tag=tag, par=parent)) log.debug('Preferring new {tag:s} over {par:s}'.format(tag=tag, par=parent))
self.remove_tag(parent) self.remove_tag(parent)
log.debug('Applying tag {tag:s} to photo {pho:s}'.format(tag=tag, pho=self)) log.debug('Applying tag {tag:s} to photo {pho:s}'.format(tag=tag, pho=self))
now = int(getnow())
self.photodb.cur.execute('INSERT INTO photo_tag_rel VALUES(?, ?)', [self.id, tag.id]) self.photodb.cur.execute('INSERT INTO photo_tag_rel VALUES(?, ?)', [self.id, tag.id])
self.photodb.cur.execute('UPDATE photos SET tagged_at = ? WHERE id == ?', [now, self.id])
if commit: if commit:
log.debug('Committing - add photo tag') log.debug('Committing - add photo tag')
self.photodb.commit() self.photodb.commit()
@ -1913,6 +1921,8 @@ class Photo(ObjectBase):
'DELETE FROM photo_tag_rel WHERE photoid == ? AND tagid == ?', 'DELETE FROM photo_tag_rel WHERE photoid == ? AND tagid == ?',
[self.id, tag.id] [self.id, tag.id]
) )
now = int(getnow())
self.photodb.cur.execute('UPDATE photos SET tagged_at = ? WHERE id == ?', [now, self.id])
if commit: if commit:
log.debug('Committing - remove photo tag') log.debug('Committing - remove photo tag')
self.photodb.commit() self.photodb.commit()

View file

@ -0,0 +1,25 @@
<!DOCTYPE html5>
<html>
<head>
{% import "header.html" as header %}
<title>Bookmarks</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/common.css">
<script src="/static/common.js"></script>
<style>
</style>
</head>
<body>
{{header.make_header()}}
<div id="content_body">
<a href="/search?has_tags=no&orderby=random-desc&mimetype=image">Needs tagging</a>
</div>
</body>
<script type="text/javascript">
</script>
</html>

View file

@ -33,6 +33,7 @@ a:hover
<a href="/search">Search</a> <a href="/search">Search</a>
<a href="/tags">Browse tags</a> <a href="/tags">Browse tags</a>
<a href="/albums">Browse albums</a> <a href="/albums">Browse albums</a>
<a href="/bookmarks">Bookmarks</a>
</body> </body>

View file

@ -98,14 +98,15 @@ form
{% macro create_orderby_li(selected_column, selected_sorter) %} {% macro create_orderby_li(selected_column, selected_sorter) %}
<li class="search_builder_orderby_li"> <li class="search_builder_orderby_li">
<select> <select>
<option value="created" {%if selected_column=="created"%}selected{%endif%} >Creation date</option> <option value="created" {%if selected_column=="created"%}selected{%endif%} >Creation date</option>
<option value="area" {%if selected_column=="area"%}selected{%endif%} >Area</option> <option value="area" {%if selected_column=="area"%}selected{%endif%} >Area</option>
<option value="width" {%if selected_column=="width"%}selected{%endif%} >Width</option> <option value="width" {%if selected_column=="width"%}selected{%endif%} >Width</option>
<option value="height" {%if selected_column=="height"%}selected{%endif%} >Height</option> <option value="height" {%if selected_column=="height"%}selected{%endif%} >Height</option>
<option value="ratio" {%if selected_column=="ratio"%}selected{%endif%} >Aspect Ratio</option> <option value="ratio" {%if selected_column=="ratio"%}selected{%endif%} >Aspect Ratio</option>
<option value="bytes" {%if selected_column=="bytes"%}selected{%endif%} >File size</option> <option value="bytes" {%if selected_column=="bytes"%}selected{%endif%} >File size</option>
<option value="duration" {%if selected_column=="duration"%}selected{%endif%} >Duration</option> <option value="duration" {%if selected_column=="duration"%}selected{%endif%} >Duration</option>
<option value="random" {%if selected_column=="random"%}selected{%endif%} >Random</option> <option value="tagged_at" {%if selected_column=="tagged_at"%}selected{%endif%}>Recently tagged</option>
<option value="random" {%if selected_column=="random"%}selected{%endif%} >Random</option>
</select> </select>
<select> <select>
<option value="desc" {%if selected_sorter=="desc"%}selected{%endif%} >Descending</option> <option value="desc" {%if selected_sorter=="desc"%}selected{%endif%} >Descending</option>