Give Users a display_name.
This commit is contained in:
parent
8562b355ce
commit
21bd211889
9 changed files with 84 additions and 11 deletions
|
|
@ -60,7 +60,6 @@ Here is a brief overview of the project to help you learn your way around:
|
||||||
- Add a `Photo.merge` to combine duplicate entries.
|
- Add a `Photo.merge` to combine duplicate entries.
|
||||||
- Generate thumbnails for vector files without falling victim to bombs.
|
- Generate thumbnails for vector files without falling victim to bombs.
|
||||||
- Allow photos to have nonstandard, orderby-able properties like "release year". How?
|
- Allow photos to have nonstandard, orderby-able properties like "release year". How?
|
||||||
- When users have '%' or '#', etc. in their username, it is difficult to access their /user/ URL. I would prefer to fix it without simply blacklisting those characters.
|
|
||||||
- Currently, the Jinja templates are having a tangling influence on the backend objects, because Jinja cannot import my other modules like bytestring, but it can access the methods of the objects I pass into the template. As a result, the objects have excess helper methods. Consider making them into Jinja filters instead. Which is also kind of ugly but will move that pollution out of the backend at least.
|
- Currently, the Jinja templates are having a tangling influence on the backend objects, because Jinja cannot import my other modules like bytestring, but it can access the methods of the objects I pass into the template. As a result, the objects have excess helper methods. Consider making them into Jinja filters instead. Which is also kind of ugly but will move that pollution out of the backend at least.
|
||||||
- Perhaps instead of actually deleting objects, they should just have a `deleted` flag, to make easy restoration possible. Also consider regrouping the children of restored Groupables if those children haven't already been reassigned somewhere else.
|
- Perhaps instead of actually deleting objects, they should just have a `deleted` flag, to make easy restoration possible. Also consider regrouping the children of restored Groupables if those children haven't already been reassigned somewhere else.
|
||||||
- Add a new table to store permanent history of add/remove of tags on photos, so that accidents or trolling can be reversed.
|
- Add a new table to store permanent history of add/remove of tags on photos, so that accidents or trolling can be reversed.
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ FILENAME_BADCHARS = '\\/:*?<>|"'
|
||||||
# Note: Setting user_version pragma in init sequence is safe because it only
|
# 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
|
# happens after the out-of-date check occurs, so no chance of accidentally
|
||||||
# overwriting it.
|
# overwriting it.
|
||||||
DATABASE_VERSION = 12
|
DATABASE_VERSION = 13
|
||||||
DB_INIT = f'''
|
DB_INIT = f'''
|
||||||
PRAGMA cache_size = 10000;
|
PRAGMA cache_size = 10000;
|
||||||
PRAGMA count_changes = OFF;
|
PRAGMA count_changes = OFF;
|
||||||
|
|
@ -54,6 +54,7 @@ CREATE TABLE IF NOT EXISTS users(
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
username TEXT NOT NULL COLLATE NOCASE,
|
username TEXT NOT NULL COLLATE NOCASE,
|
||||||
password BLOB NOT NULL,
|
password BLOB NOT NULL,
|
||||||
|
display_name TEXT,
|
||||||
created INT
|
created INT
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS index_users_id on users(id);
|
CREATE INDEX IF NOT EXISTS index_users_id on users(id);
|
||||||
|
|
@ -291,6 +292,7 @@ DEFAULT_CONFIGURATION = {
|
||||||
'new': True,
|
'new': True,
|
||||||
},
|
},
|
||||||
'user': {
|
'user': {
|
||||||
|
'edit': True,
|
||||||
'login': True,
|
'login': True,
|
||||||
'new': True,
|
'new': True,
|
||||||
},
|
},
|
||||||
|
|
@ -305,8 +307,9 @@ DEFAULT_CONFIGURATION = {
|
||||||
'user': {
|
'user': {
|
||||||
'min_length': 2,
|
'min_length': 2,
|
||||||
'min_password_length': 6,
|
'min_password_length': 6,
|
||||||
|
'max_display_name_length': 24,
|
||||||
'max_length': 24,
|
'max_length': 24,
|
||||||
'valid_chars': string.ascii_letters + string.digits + '~!@#$%^*()[]{}:;,.<>/\\-_+=',
|
'valid_chars': string.ascii_letters + string.digits + '_-',
|
||||||
},
|
},
|
||||||
|
|
||||||
'digest_exclude_files': [
|
'digest_exclude_files': [
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,9 @@ class UsernameTooLong(InvalidUsername):
|
||||||
class UsernameTooShort(InvalidUsername):
|
class UsernameTooShort(InvalidUsername):
|
||||||
error_message = 'Username "{username}" is shorter than minimum of {min_length}.'
|
error_message = 'Username "{username}" is shorter than minimum of {min_length}.'
|
||||||
|
|
||||||
|
class DisplayNameTooLong(EtiquetteException):
|
||||||
|
error_message = 'Display name "{display_name}" is longer than maximum of {max_length}.'
|
||||||
|
|
||||||
class WrongLogin(EtiquetteException):
|
class WrongLogin(EtiquetteException):
|
||||||
error_message = 'Wrong username-password combination.'
|
error_message = 'Wrong username-password combination.'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,12 +49,16 @@ class ObjectBase:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def normalize_author_id(author_id):
|
def normalize_author_id(author_id):
|
||||||
if author_id is None or author_id == '':
|
if author_id is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not isinstance(author_id, str):
|
if not isinstance(author_id, str):
|
||||||
raise TypeError('author_id must be string, not %s' % type(author_id))
|
raise TypeError('author_id must be string, not %s' % type(author_id))
|
||||||
|
|
||||||
|
author_id = author_id.strip()
|
||||||
|
if author_id == '':
|
||||||
|
return None
|
||||||
|
|
||||||
return author_id
|
return author_id
|
||||||
|
|
||||||
def get_author(self):
|
def get_author(self):
|
||||||
|
|
@ -1476,6 +1480,7 @@ class User(ObjectBase):
|
||||||
self.username = db_row['username']
|
self.username = db_row['username']
|
||||||
self.created = db_row['created']
|
self.created = db_row['created']
|
||||||
self.password_hash = db_row['password']
|
self.password_hash = db_row['password']
|
||||||
|
self._display_name = self.normalize_display_name(db_row['display_name'])
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
rep = f'User:{self.id}:{self.username}'
|
rep = f'User:{self.id}:{self.username}'
|
||||||
|
|
@ -1485,6 +1490,50 @@ class User(ObjectBase):
|
||||||
rep = f'User:{self.username}'
|
rep = f'User:{self.username}'
|
||||||
return rep
|
return rep
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def normalize_display_name(display_name, max_length=None):
|
||||||
|
if display_name is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not isinstance(display_name, str):
|
||||||
|
raise TypeError('Display Name must be string, not %s' % type(display_name))
|
||||||
|
|
||||||
|
display_name = display_name.strip()
|
||||||
|
|
||||||
|
if display_name == '':
|
||||||
|
return None
|
||||||
|
|
||||||
|
if max_length is not None and len(display_name) > max_length:
|
||||||
|
raise exceptions.DisplayNameTooLong(display_name=display_name, max_length=max_length)
|
||||||
|
|
||||||
|
return display_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display_name(self):
|
||||||
|
if self._display_name is None:
|
||||||
|
return self.username
|
||||||
|
else:
|
||||||
|
return self._display_name
|
||||||
|
|
||||||
|
@decorators.required_feature('user.edit')
|
||||||
|
@decorators.transaction
|
||||||
|
def set_display_name(self, display_name, *, commit=True):
|
||||||
|
display_name = self.normalize_display_name(
|
||||||
|
display_name,
|
||||||
|
max_length=self.photodb.config['user']['max_display_name_length'],
|
||||||
|
)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'id': self.id,
|
||||||
|
'display_name': display_name,
|
||||||
|
}
|
||||||
|
self.photodb.sql_update(table='users', pairs=data, where_key='id')
|
||||||
|
|
||||||
|
self._display_name = display_name
|
||||||
|
|
||||||
|
if commit:
|
||||||
|
self.photodb.log.debug('Committing - set display name')
|
||||||
|
self.photodb.commit()
|
||||||
|
|
||||||
class WarningBag:
|
class WarningBag:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@
|
||||||
<a class="header_element" href="/search">Search</a>
|
<a class="header_element" href="/search">Search</a>
|
||||||
<a class="header_element" href="/tags">Tags</a>
|
<a class="header_element" href="/tags">Tags</a>
|
||||||
{% if session.user %}
|
{% if session.user %}
|
||||||
<a class="header_element" href="/user/{{session.user.username}}">{{session.user.username}}</a>
|
<a class="header_element" href="/user/{{session.user.username}}">{{session.user.display_name}}</a>
|
||||||
<a class="header_element" href="/logout" style="flex:0">Logout</a>
|
<a class="header_element" href="/logout" style="flex:0">Logout</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="header_element" href="/login">Log in</a>
|
<a class="header_element" href="/login">Log in</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@
|
||||||
<li>Filename: {{photo.basename}}</li>
|
<li>Filename: {{photo.basename}}</li>
|
||||||
{% set author = photo.get_author() %}
|
{% set author = photo.get_author() %}
|
||||||
{% if author is not none %}
|
{% if author is not none %}
|
||||||
<li>Author: <a href="/user/{{author.username}}">{{author.username}}</a></li>
|
<li>Author: <a href="/user/{{author.username}}">{{author.display_name}}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if photo.width %}
|
{% if photo.width %}
|
||||||
<li>Dimensions: {{photo.width}}x{{photo.height}} px</li>
|
<li>Dimensions: {{photo.width}}x{{photo.height}} px</li>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ body, .nice_link
|
||||||
<a class="nice_link" href="/albums">Browse albums</a>
|
<a class="nice_link" href="/albums">Browse albums</a>
|
||||||
<a class="nice_link" href="/bookmarks">Bookmarks</a>
|
<a class="nice_link" href="/bookmarks">Bookmarks</a>
|
||||||
{% if session.user %}
|
{% if session.user %}
|
||||||
<a class="nice_link" href="/user/{{session.user.username}}">{{session.user.username}}</a>
|
<a class="nice_link" href="/user/{{session.user.username}}">{{session.user.display_name}}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="nice_link" href="/login">Log in</a>
|
<a class="nice_link" href="/login">Log in</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
{% import "header.html" as header %}
|
{% import "header.html" as header %}
|
||||||
<title>User {{user.username}}</title>
|
<title>User {{user.display_name}}</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<link rel="stylesheet" href="/static/css/common.css">
|
<link rel="stylesheet" href="/static/css/common.css">
|
||||||
|
|
@ -20,9 +20,9 @@
|
||||||
<body>
|
<body>
|
||||||
{{header.make_header(session=session)}}
|
{{header.make_header(session=session)}}
|
||||||
<div id="content_body">
|
<div id="content_body">
|
||||||
<h2>{{user.username}}</h2>
|
<h2>{{user.display_name}}</h2>
|
||||||
<p>ID: {{user.id}}</p>
|
<p>ID: {{user.id}}</p>
|
||||||
<p><a href="/search?author={{user.username}}">Photos by {{user.username}}</a></p>
|
<p><a href="/search?author={{user.username}}">Photos by {{user.display_name}}</a></p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,25 @@ def upgrade_11_to_12(photodb):
|
||||||
'''
|
'''
|
||||||
photodb.sql.cursor().execute(query)
|
photodb.sql.cursor().execute(query)
|
||||||
|
|
||||||
|
def upgrade_12_to_13(photodb):
|
||||||
|
'''
|
||||||
|
Added display_name column to the User table.
|
||||||
|
'''
|
||||||
|
cur = photodb.sql.cursor()
|
||||||
|
cur.execute('PRAGMA foreign_keys = OFF')
|
||||||
|
cur.execute('ALTER TABLE users RENAME TO users_old')
|
||||||
|
cur.execute('''
|
||||||
|
CREATE TABLE users(
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
username TEXT NOT NULL COLLATE NOCASE,
|
||||||
|
password BLOB NOT NULL,
|
||||||
|
display_name TEXT,
|
||||||
|
created INT
|
||||||
|
)''')
|
||||||
|
cur.execute('INSERT INTO users SELECT id, username, password, NULL, created FROM users_old')
|
||||||
|
cur.execute('DROP TABLE users_old')
|
||||||
|
cur.execute('PRAGMA foreign_keys = ON')
|
||||||
|
|
||||||
def upgrade_all(data_directory):
|
def upgrade_all(data_directory):
|
||||||
'''
|
'''
|
||||||
Given the directory containing a phototagger database, apply all of the
|
Given the directory containing a phototagger database, apply all of the
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue