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.
|
||||
- Generate thumbnails for vector files without falling victim to bombs.
|
||||
- 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.
|
||||
- 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.
|
||||
|
|
|
@ -42,7 +42,7 @@ FILENAME_BADCHARS = '\\/:*?<>|"'
|
|||
# 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 = 12
|
||||
DATABASE_VERSION = 13
|
||||
DB_INIT = f'''
|
||||
PRAGMA cache_size = 10000;
|
||||
PRAGMA count_changes = OFF;
|
||||
|
@ -54,6 +54,7 @@ CREATE TABLE IF NOT EXISTS users(
|
|||
id TEXT PRIMARY KEY NOT NULL,
|
||||
username TEXT NOT NULL COLLATE NOCASE,
|
||||
password BLOB NOT NULL,
|
||||
display_name TEXT,
|
||||
created INT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS index_users_id on users(id);
|
||||
|
@ -291,6 +292,7 @@ DEFAULT_CONFIGURATION = {
|
|||
'new': True,
|
||||
},
|
||||
'user': {
|
||||
'edit': True,
|
||||
'login': True,
|
||||
'new': True,
|
||||
},
|
||||
|
@ -305,8 +307,9 @@ DEFAULT_CONFIGURATION = {
|
|||
'user': {
|
||||
'min_length': 2,
|
||||
'min_password_length': 6,
|
||||
'max_display_name_length': 24,
|
||||
'max_length': 24,
|
||||
'valid_chars': string.ascii_letters + string.digits + '~!@#$%^*()[]{}:;,.<>/\\-_+=',
|
||||
'valid_chars': string.ascii_letters + string.digits + '_-',
|
||||
},
|
||||
|
||||
'digest_exclude_files': [
|
||||
|
|
|
@ -147,6 +147,9 @@ class UsernameTooLong(InvalidUsername):
|
|||
class UsernameTooShort(InvalidUsername):
|
||||
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):
|
||||
error_message = 'Wrong username-password combination.'
|
||||
|
||||
|
|
|
@ -49,12 +49,16 @@ class ObjectBase:
|
|||
|
||||
@staticmethod
|
||||
def normalize_author_id(author_id):
|
||||
if author_id is None or author_id == '':
|
||||
if author_id is None:
|
||||
return None
|
||||
|
||||
if not isinstance(author_id, str):
|
||||
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
|
||||
|
||||
def get_author(self):
|
||||
|
@ -1476,6 +1480,7 @@ class User(ObjectBase):
|
|||
self.username = db_row['username']
|
||||
self.created = db_row['created']
|
||||
self.password_hash = db_row['password']
|
||||
self._display_name = self.normalize_display_name(db_row['display_name'])
|
||||
|
||||
def __repr__(self):
|
||||
rep = f'User:{self.id}:{self.username}'
|
||||
|
@ -1485,6 +1490,50 @@ class User(ObjectBase):
|
|||
rep = f'User:{self.username}'
|
||||
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:
|
||||
def __init__(self):
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
<a class="header_element" href="/search">Search</a>
|
||||
<a class="header_element" href="/tags">Tags</a>
|
||||
{% 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>
|
||||
{% else %}
|
||||
<a class="header_element" href="/login">Log in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
{% endmacro %}
|
||||
|
|
|
@ -186,7 +186,7 @@
|
|||
<li>Filename: {{photo.basename}}</li>
|
||||
{% set author = photo.get_author() %}
|
||||
{% 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 %}
|
||||
{% if photo.width %}
|
||||
<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="/bookmarks">Bookmarks</a>
|
||||
{% 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 %}
|
||||
<a class="nice_link" href="/login">Log in</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
{% import "header.html" as header %}
|
||||
<title>User {{user.username}}</title>
|
||||
<title>User {{user.display_name}}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="stylesheet" href="/static/css/common.css">
|
||||
|
@ -20,9 +20,9 @@
|
|||
<body>
|
||||
{{header.make_header(session=session)}}
|
||||
<div id="content_body">
|
||||
<h2>{{user.username}}</h2>
|
||||
<h2>{{user.display_name}}</h2>
|
||||
<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>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -238,6 +238,25 @@ def upgrade_11_to_12(photodb):
|
|||
'''
|
||||
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):
|
||||
'''
|
||||
Given the directory containing a phototagger database, apply all of the
|
||||
|
|
Loading…
Reference in a new issue