From 01a51b08f4420715a1dafa190bdadacbfd8a0bd6 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 12:38:04 +0100 Subject: [PATCH 01/10] IDE complaints on Client model --- xl_auth/client/models.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/xl_auth/client/models.py b/xl_auth/client/models.py index 3d3e8633..79fd1db4 100644 --- a/xl_auth/client/models.py +++ b/xl_auth/client/models.py @@ -31,7 +31,7 @@ def __init__(self, **kwargs): """Create instance.""" client_id = Client._generate_client_id() client_secret = Client._generate_client_secret() - Model.__init__(self, client_id=client_id, client_secret=client_secret, **kwargs) + db.Model.__init__(self, client_id=client_id, client_secret=client_secret, **kwargs) @staticmethod def _generate_client_id(): @@ -52,10 +52,7 @@ def client_type(self): @property def default_redirect_uri(self): """Return default redirect URI.""" - if self.redirect_uris: - return self.redirect_uris.split()[0] - else: - return None + return self.redirect_uris.split()[0] def __repr__(self): """Represent instance as a unique string.""" From bc8a3647723200075a8a166c60aa204fdb548e45 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 12:43:06 +0100 Subject: [PATCH 02/10] Test Client model directly --- tests/models/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/models/test_client.py b/tests/models/test_client.py index a5817a7c..2de6ceb1 100644 --- a/tests/models/test_client.py +++ b/tests/models/test_client.py @@ -13,7 +13,7 @@ @pytest.mark.usefixtures('db', 'user') def test_get_by_id(user): """Get client by ID.""" - client = ClientFactory(created_by=user.id) + client = Client(created_by=user.id, redirect_uris='http://example.com', default_scopes='fake') client.save() retrieved = Client.get_by_id(client.id) From ae1eb44c78ac941b63c644addc296220a5e91183 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 12:57:31 +0100 Subject: [PATCH 03/10] Add `test_modified_at_defaults_to_current_datetime` to models/test_ test suites #78 --- tests/models/test_collection.py | 18 ++++++++++++++++++ tests/models/test_permission.py | 18 ++++++++++++++++++ tests/models/test_user.py | 26 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/tests/models/test_collection.py b/tests/models/test_collection.py index 43e9429f..68ed1c3e 100644 --- a/tests/models/test_collection.py +++ b/tests/models/test_collection.py @@ -35,6 +35,23 @@ def test_created_at_defaults_to_datetime(): assert isinstance(collection.created_at, dt.datetime) +@pytest.mark.usefixtures('db') +def test_modified_at_defaults_to_current_datetime(): + """Test modified date.""" + collection = Collection('KBU', 'Outdated name', 'library') + collection.save() + first_modified_at = collection.modified_at.isoformat() + + # Initial 'modified_at' matches 'created_at' (at least at the minute level). + assert first_modified_at[:16] == collection.created_at.isoformat()[:16] + + collection.friendly_name = 'Not outdated name!' + collection.save() + + # Initial 'modified_at' has been overwritten. + assert first_modified_at != collection.modified_at.isoformat() + + @pytest.mark.usefixtures('db') def test_factory(db): """Test collection factory.""" @@ -47,6 +64,7 @@ def test_factory(db): assert collection.replaces is None assert collection.replaced_by is None assert isinstance(collection.permissions, list) + assert bool(collection.modified_at) assert bool(collection.created_at) diff --git a/tests/models/test_permission.py b/tests/models/test_permission.py index c7348a6e..db145df9 100644 --- a/tests/models/test_permission.py +++ b/tests/models/test_permission.py @@ -35,6 +35,23 @@ def test_created_at_defaults_to_datetime(user, collection): assert isinstance(permission.created_at, dt.datetime) +@pytest.mark.usefixtures('db') +def test_modified_at_defaults_to_current_datetime(user, collection): + """Test modified date.""" + permission = Permission(user=user, collection=collection) + permission.save() + first_modified_at = permission.modified_at.isoformat() + + # Initial 'modified_at' matches 'created_at' (at least at the minute level). + assert first_modified_at[:16] == permission.created_at.isoformat()[:16] + + permission.registrant = not permission.registrant + permission.save() + + # Initial 'modified_at' has been overwritten. + assert first_modified_at != permission.modified_at.isoformat() + + @pytest.mark.usefixtures('db') def test_factory(db): """Test permission factory.""" @@ -46,6 +63,7 @@ def test_factory(db): assert permission.registrant is False assert permission.cataloger is False assert permission.cataloging_admin is False + assert bool(permission.modified_at) assert bool(permission.created_at) diff --git a/tests/models/test_user.py b/tests/models/test_user.py index 47204568..73af92fa 100644 --- a/tests/models/test_user.py +++ b/tests/models/test_user.py @@ -32,6 +32,23 @@ def test_created_at_defaults_to_datetime(): assert isinstance(user.created_at, dt.datetime) +@pytest.mark.usefixtures('db') +def test_modified_at_defaults_to_current_datetime(): + """Test modified date.""" + user = User('foo@kb.se', 'Wrong Name') + user.save() + first_modified_at = user.modified_at.isoformat() + + # Initial 'modified_at' matches 'created_at' (at least at the minute level). + assert first_modified_at[:16] == user.created_at.isoformat()[:16] + + user.full_name = 'Correct Name' + user.save() + + # Initial 'modified_at' has been overwritten. + assert first_modified_at != user.modified_at.isoformat() + + @pytest.mark.usefixtures('db') def test_password_defaults_to_a_random_one(): """Test empty password field is assigned some random password, instead of being set to tull.""" @@ -47,6 +64,7 @@ def test_factory(db): db.session.commit() assert bool(user.email) assert bool(user.full_name) + assert bool(user.modified_at) assert bool(user.created_at) assert isinstance(user.permissions, list) assert isinstance(user.roles, list) @@ -102,11 +120,19 @@ def test_get_gravatar_url(): 'b48def645758b95537d4424c84d1a9ff?d=mm&s=64' +@pytest.mark.usefixtures('db') +def test_repr(): + """Check repr output.""" + user = UserFactory(email='foo@example.com') + assert repr(user) == ''.format(user.email) + + @pytest.mark.usefixtures('db') def test_roles(): """Add a role to a user.""" role = Role(name='admin') role.save() + assert repr(role) == ''.format(role.name) user = UserFactory() user.roles.append(role) user.save() From 0ed20819d27c43b2973e5516c7e6fdee498a4896 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 12:59:17 +0100 Subject: [PATCH 04/10] Update models User, Collection and Permission with `modified_at` field #78 --- xl_auth/collection/models.py | 2 ++ xl_auth/permission/models.py | 1 + xl_auth/user/models.py | 2 ++ 3 files changed, 5 insertions(+) diff --git a/xl_auth/collection/models.py b/xl_auth/collection/models.py index 55d636f2..90ab9fdb 100644 --- a/xl_auth/collection/models.py +++ b/xl_auth/collection/models.py @@ -21,6 +21,8 @@ class Collection(SurrogatePK, Model): permissions = relationship('Permission', back_populates='collection') replaces = Column(db.String(255)) replaced_by = Column(db.String(255)) + + modified_at = Column(db.DateTime, default=dt.datetime.utcnow, onupdate=dt.datetime.utcnow) created_at = Column(db.DateTime, nullable=False, default=dt.datetime.utcnow) def __init__(self, code, friendly_name, category, **kwargs): diff --git a/xl_auth/permission/models.py b/xl_auth/permission/models.py index 6f1b2115..c913f28f 100644 --- a/xl_auth/permission/models.py +++ b/xl_auth/permission/models.py @@ -24,6 +24,7 @@ class Permission(SurrogatePK, Model): cataloger = Column(db.Boolean(), default=False, nullable=False) cataloging_admin = Column(db.Boolean(), default=False, nullable=False) + modified_at = Column(db.DateTime, default=dt.datetime.utcnow, onupdate=dt.datetime.utcnow) created_at = Column(db.DateTime, nullable=False, default=dt.datetime.utcnow) def __init__(self, **kwargs): diff --git a/xl_auth/user/models.py b/xl_auth/user/models.py index d6da7c32..683fdffe 100644 --- a/xl_auth/user/models.py +++ b/xl_auth/user/models.py @@ -42,6 +42,8 @@ class User(UserMixin, SurrogatePK, Model): is_admin = Column(db.Boolean(), default=False, nullable=False) permissions = relationship('Permission', back_populates='user') roles = relationship('Role', back_populates='user') + + modified_at = Column(db.DateTime, default=dt.datetime.utcnow, onupdate=dt.datetime.utcnow) created_at = Column(db.DateTime, default=dt.datetime.utcnow, nullable=False) def __init__(self, email, full_name, password=None, **kwargs): From 8a546403944e2624adad9cd49f41f98a8e4c0420 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 13:44:19 +0100 Subject: [PATCH 05/10] Add `test_successful_login_updates_last_login_at` to end2end/test_logging_in test suite #78 --- tests/end2end/test_logging_in.py | 24 ++++++++++++++++++++++++ tests/models/test_user.py | 1 + xl_auth/user/models.py | 1 + 3 files changed, 26 insertions(+) diff --git a/tests/end2end/test_logging_in.py b/tests/end2end/test_logging_in.py index 41333676..f584b1dc 100644 --- a/tests/end2end/test_logging_in.py +++ b/tests/end2end/test_logging_in.py @@ -3,9 +3,13 @@ from __future__ import absolute_import, division, print_function, unicode_literals +from datetime import datetime + from flask import url_for from flask_babel import gettext as _ +from xl_auth.user.models import User + def test_can_log_in_returns_200(user, testapp): """Login successful (irrespective of casing).""" @@ -21,6 +25,26 @@ def test_can_log_in_returns_200(user, testapp): assert res.status_code == 200 +def test_successful_login_updates_last_login_at(user, testapp): + """Successful login sets 'last_login_at' to current UTC datetime.""" + assert user.last_login_at is None + + # Goes to homepage. + res = testapp.get('/') + # Fills out login form. + form = res.forms['loginForm'] + form['username'] = user.email + form['password'] = 'myPrecious' + # Submits. + res = form.submit().follow() + assert res.status_code == 200 + + # Fetch user from database, now with login timestamp. + updated_user = User.get_by_id(user.id) + assert isinstance(updated_user.last_login_at, datetime) + assert (datetime.utcnow() - updated_user.last_login_at).total_seconds() < 10 + + def test_sees_alert_on_log_out(user, testapp): """Show alert on logout.""" res = testapp.get('/') diff --git a/tests/models/test_user.py b/tests/models/test_user.py index 73af92fa..ffb1fd77 100644 --- a/tests/models/test_user.py +++ b/tests/models/test_user.py @@ -71,6 +71,7 @@ def test_factory(db): assert user.is_admin is False assert user.active is True assert user.check_password('myPrecious') + assert user.last_login_at is None @pytest.mark.usefixtures('db') diff --git a/xl_auth/user/models.py b/xl_auth/user/models.py index 683fdffe..059b5fce 100644 --- a/xl_auth/user/models.py +++ b/xl_auth/user/models.py @@ -39,6 +39,7 @@ class User(UserMixin, SurrogatePK, Model): full_name = Column(db.String(255), unique=False, nullable=False) password = Column(db.Binary(128), nullable=False) active = Column(db.Boolean(), default=False, nullable=False) + last_login_at = Column(db.DateTime, default=None) is_admin = Column(db.Boolean(), default=False, nullable=False) permissions = relationship('Permission', back_populates='user') roles = relationship('Role', back_populates='user') From 484b15c2a695fc7e8475bd312dc7fce2787601d8 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 13:53:05 +0100 Subject: [PATCH 06/10] Add `User.update_last_login` method; now passing all tests --- xl_auth/public/views.py | 3 ++- xl_auth/user/models.py | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/xl_auth/public/views.py b/xl_auth/public/views.py index 9349a77f..a7216926 100644 --- a/xl_auth/public/views.py +++ b/xl_auth/public/views.py @@ -5,7 +5,7 @@ from flask import Blueprint, current_app, flash, redirect, render_template, request, url_for from flask_babel import lazy_gettext as _ -from flask_login import login_required, login_user, logout_user +from flask_login import current_user, login_required, login_user, logout_user from ..extensions import login_manager from ..public.forms import LoginForm @@ -31,6 +31,7 @@ def home(): login_user(login_form.user) flash(_('You are logged in.'), 'success') redirect_url = request.args.get('next') or url_for('user.profile') + current_user.update_last_login() return redirect(redirect_url) else: flash_errors(login_form) diff --git a/xl_auth/user/models.py b/xl_auth/user/models.py index 059b5fce..61519e87 100644 --- a/xl_auth/user/models.py +++ b/xl_auth/user/models.py @@ -63,6 +63,12 @@ def check_password(self, value): """Check password.""" return bcrypt.check_password_hash(self.password, value) + def update_last_login(self, commit=True): + """Set 'last_login_at' to current datetime.""" + self.last_login_at = dt.datetime.utcnow() + if commit: + self.save() + def get_gravatar_url(self, size=32): """Get Gravatar URL.""" hashed_email = hashlib.md5(str(self.email).lower().encode()).hexdigest() From 74bf4b6627a405448845b41f91ca6f822780b228 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 14:00:55 +0100 Subject: [PATCH 07/10] Add database upgrade #78 --- ...dd_modified_at_and_last_login_at_fields.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 migrations/versions/f3e929832ba3_add_modified_at_and_last_login_at_fields.py diff --git a/migrations/versions/f3e929832ba3_add_modified_at_and_last_login_at_fields.py b/migrations/versions/f3e929832ba3_add_modified_at_and_last_login_at_fields.py new file mode 100644 index 00000000..adc29fb7 --- /dev/null +++ b/migrations/versions/f3e929832ba3_add_modified_at_and_last_login_at_fields.py @@ -0,0 +1,44 @@ +"""Add 'modified_at' and 'last_login_at' fields. + +Revision ID: f3e929832ba3 +Revises: c9e1cd58c4a7 +Create Date: 2017-10-30 13:54:26.596122 + +""" + +from __future__ import absolute_import, division, print_function, unicode_literals + +import sqlalchemy as sa +from alembic import op + +# Revision identifiers, used by Alembic. +revision = 'f3e929832ba3' +down_revision = 'c9e1cd58c4a7' +branch_labels = None +depends_on = None + + +def upgrade(): + """Add 'modified_at' column for Collection/Permission/User, and 'last_login_at' for User.""" + with op.batch_alter_table('collections', schema=None) as batch_op: + batch_op.add_column(sa.Column('modified_at', sa.DateTime(), nullable=True)) + + with op.batch_alter_table('permissions', schema=None) as batch_op: + batch_op.add_column(sa.Column('modified_at', sa.DateTime(), nullable=True)) + + with op.batch_alter_table('users', schema=None) as batch_op: + batch_op.add_column(sa.Column('last_login_at', sa.DateTime(), nullable=True)) + batch_op.add_column(sa.Column('modified_at', sa.DateTime(), nullable=True)) + + +def downgrade(): + """Drop 'modified_at' and 'last_login_at' columns.""" + with op.batch_alter_table('users', schema=None) as batch_op: + batch_op.drop_column('modified_at') + batch_op.drop_column('last_login_at') + + with op.batch_alter_table('permissions', schema=None) as batch_op: + batch_op.drop_column('modified_at') + + with op.batch_alter_table('collections', schema=None) as batch_op: + batch_op.drop_column('modified_at') From 3c8cca587fba4f216dbbe3b09469d705efee89e4 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 14:10:50 +0100 Subject: [PATCH 08/10] Update user listing to include last login timestamp + add translations --- messages.pot | 165 ++++++++++-------- xl_auth/templates/users/home.html | 8 +- .../translations/sv/LC_MESSAGES/messages.po | 163 +++++++++-------- 3 files changed, 197 insertions(+), 139 deletions(-) diff --git a/messages.pot b/messages.pot index 23a7436d..a1cfba3f 100644 --- a/messages.pot +++ b/messages.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: xl_auth 0.4.4\n" +"Project-Id-Version: xl_auth 0.4.5\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-10-25 14:02+0200\n" +"POT-Creation-Date: 2017-10-30 14:10+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,6 +17,15 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.5.1\n" +#: tests/end2end/test_deleting_client.py:34 xl_auth/client/views.py:64 +#, python-format +msgid "Successfully deleted OAuth2 Client \"%(name)s\"." +msgstr "" + +#: tests/end2end/test_deleting_client.py:51 +msgid "Clients" +msgstr "" + #: tests/end2end/test_deleting_permission.py:24 tests/end2end/test_deleting_permission.py:51 #: tests/end2end/test_editing_permission.py:29 tests/end2end/test_editing_permission.py:63 #: tests/end2end/test_editing_permission.py:91 tests/end2end/test_editing_user.py:183 @@ -43,49 +52,6 @@ msgstr "" msgid "Successfully deleted permissions for \"%(username)s\" on collection \"%(code)s\"." msgstr "" -#: tests/end2end/test_editing_client.py:82 tests/end2end/test_editing_client.py:115 -#: tests/end2end/test_editing_collection.py:102 tests/end2end/test_registering_collection.py:102 -#: xl_auth/client/forms.py:14 xl_auth/collection/forms.py:18 xl_auth/templates/clients/home.html:17 -#: xl_auth/templates/users/home.html:18 xl_auth/templates/users/home.html:61 -msgid "Name" -msgstr "" - -#: tests/end2end/test_editing_client.py:82 tests/end2end/test_editing_client.py:148 -#: tests/end2end/test_editing_client.py:215 tests/end2end/test_editing_client.py:248 -#: tests/end2end/test_editing_collection.py:102 tests/end2end/test_editing_user.py:146 -#: tests/end2end/test_registering_collection.py:79 tests/end2end/test_registering_collection.py:102 -#: tests/forms/test_client.py:48 tests/forms/test_client.py:71 tests/forms/test_client.py:94 -#: tests/forms/test_client.py:105 tests/forms/test_client.py:141 tests/forms/test_client.py:164 -#: tests/forms/test_client.py:187 tests/forms/test_client.py:198 tests/forms/test_collection.py:21 -#: tests/forms/test_collection.py:38 tests/forms/test_permission.py:31 -#: tests/forms/test_permission.py:39 tests/forms/test_permission.py:47 -#: tests/forms/test_permission.py:55 -msgid "This field is required." -msgstr "" - -#: tests/end2end/test_editing_client.py:115 tests/forms/test_client.py:60 -#: tests/forms/test_client.py:153 -msgid "Field must be between 3 and 64 characters long." -msgstr "" - -#: tests/end2end/test_editing_client.py:148 tests/end2end/test_editing_client.py:181 -#: xl_auth/client/forms.py:15 xl_auth/templates/clients/home.html:18 -msgid "Description" -msgstr "" - -#: tests/end2end/test_editing_client.py:182 tests/forms/test_client.py:83 -#: tests/forms/test_client.py:176 -msgid "Field must be between 3 and 350 characters long." -msgstr "" - -#: tests/end2end/test_editing_client.py:215 xl_auth/client/forms.py:11 -msgid "Redirect URIs" -msgstr "" - -#: tests/end2end/test_editing_client.py:248 xl_auth/client/forms.py:12 -msgid "Default scopes" -msgstr "" - #: tests/end2end/test_editing_collection.py:53 tests/end2end/test_registering_collection.py:52 msgid "category" msgstr "" @@ -107,6 +73,23 @@ msgstr "" msgid "Code cannot be modified" msgstr "" +#: tests/end2end/test_editing_collection.py:102 tests/end2end/test_registering_collection.py:102 +#: xl_auth/client/forms.py:14 xl_auth/collection/forms.py:18 xl_auth/templates/clients/home.html:17 +#: xl_auth/templates/users/home.html:18 xl_auth/templates/users/home.html:63 +msgid "Name" +msgstr "" + +#: tests/end2end/test_editing_collection.py:102 tests/end2end/test_editing_user.py:146 +#: tests/end2end/test_registering_collection.py:79 tests/end2end/test_registering_collection.py:102 +#: tests/forms/test_client.py:48 tests/forms/test_client.py:71 tests/forms/test_client.py:94 +#: tests/forms/test_client.py:105 tests/forms/test_client.py:141 tests/forms/test_client.py:164 +#: tests/forms/test_client.py:187 tests/forms/test_client.py:198 tests/forms/test_collection.py:21 +#: tests/forms/test_collection.py:38 tests/forms/test_permission.py:31 +#: tests/forms/test_permission.py:39 tests/forms/test_permission.py:47 +#: tests/forms/test_permission.py:55 +msgid "This field is required." +msgstr "" + #: tests/end2end/test_editing_collection.py:124 tests/end2end/test_registering_collection.py:125 #: xl_auth/collection/forms.py:19 xl_auth/templates/collections/home.html:23 #: xl_auth/templates/collections/home.html:68 @@ -130,7 +113,7 @@ msgstr "" #: tests/end2end/test_editing_permission.py:75 tests/end2end/test_registering_permission.py:69 #: tests/forms/test_permission.py:64 tests/forms/test_permission.py:77 xl_auth/permission/forms.py:64 -#: xl_auth/permission/forms.py:112 +#: xl_auth/permission/forms.py:114 #, python-format msgid "Permissions for user \"%(username)s\" on collection \"%(code)s\" already registered" msgstr "" @@ -144,22 +127,22 @@ msgstr "" #: tests/end2end/test_editing_user.py:45 xl_auth/templates/clients/home.html:29 #: xl_auth/templates/permissions/home.html:30 xl_auth/templates/permissions/home.html:31 -#: xl_auth/templates/permissions/home.html:32 xl_auth/templates/users/home.html:33 -#: xl_auth/templates/users/home.html:76 xl_auth/templates/users/profile.html:58 +#: xl_auth/templates/permissions/home.html:32 xl_auth/templates/users/home.html:34 +#: xl_auth/templates/users/home.html:79 xl_auth/templates/users/profile.html:58 #: xl_auth/templates/users/profile.html:61 xl_auth/templates/users/profile.html:65 msgid "Yes" msgstr "" #: tests/end2end/test_editing_user.py:45 xl_auth/templates/clients/home.html:31 #: xl_auth/templates/permissions/home.html:30 xl_auth/templates/permissions/home.html:31 -#: xl_auth/templates/permissions/home.html:32 xl_auth/templates/users/home.html:33 -#: xl_auth/templates/users/home.html:76 xl_auth/templates/users/profile.html:58 +#: xl_auth/templates/permissions/home.html:32 xl_auth/templates/users/home.html:34 +#: xl_auth/templates/users/home.html:79 xl_auth/templates/users/profile.html:58 #: xl_auth/templates/users/profile.html:61 xl_auth/templates/users/profile.html:65 msgid "No" msgstr "" #: tests/end2end/test_editing_user.py:101 tests/end2end/test_editing_user.py:125 -#: xl_auth/templates/users/home.html:17 xl_auth/templates/users/home.html:60 xl_auth/user/forms.py:13 +#: xl_auth/templates/users/home.html:17 xl_auth/templates/users/home.html:62 xl_auth/user/forms.py:13 msgid "Email" msgstr "" @@ -179,8 +162,8 @@ msgstr "" msgid "User \"%(username)s\" does not exist" msgstr "" -#: tests/end2end/test_editing_user.py:190 xl_auth/templates/users/home.html:41 -#: xl_auth/templates/users/home.html:84 xl_auth/templates/users/profile.html:17 +#: tests/end2end/test_editing_user.py:190 xl_auth/templates/users/home.html:43 +#: xl_auth/templates/users/home.html:88 xl_auth/templates/users/profile.html:17 msgid "Change Password" msgstr "" @@ -189,15 +172,15 @@ msgstr "" msgid "Welcome" msgstr "" -#: tests/end2end/test_logging_in.py:35 xl_auth/public/views.py:45 +#: tests/end2end/test_logging_in.py:59 xl_auth/public/views.py:46 msgid "You are logged out." msgstr "" -#: tests/end2end/test_logging_in.py:49 tests/forms/test_public.py:45 xl_auth/public/forms.py:37 +#: tests/end2end/test_logging_in.py:73 tests/forms/test_public.py:45 xl_auth/public/forms.py:37 msgid "Invalid password" msgstr "" -#: tests/end2end/test_logging_in.py:64 tests/forms/test_public.py:35 xl_auth/public/forms.py:33 +#: tests/end2end/test_logging_in.py:88 tests/forms/test_public.py:35 xl_auth/public/forms.py:33 msgid "Unknown username/email" msgstr "" @@ -242,13 +225,21 @@ msgstr "" #: tests/forms/test_client.py:25 tests/forms/test_client.py:118 tests/forms/test_collection.py:124 #: tests/forms/test_collection.py:135 tests/forms/test_permission.py:144 #: tests/forms/test_permission.py:174 tests/forms/test_user.py:63 tests/forms/test_user.py:106 -#: tests/forms/test_user.py:132 tests/forms/test_user.py:169 xl_auth/client/forms.py:41 -#: xl_auth/client/forms.py:68 xl_auth/collection/forms.py:41 xl_auth/collection/forms.py:73 +#: tests/forms/test_user.py:132 tests/forms/test_user.py:169 xl_auth/client/forms.py:40 +#: xl_auth/client/forms.py:67 xl_auth/collection/forms.py:41 xl_auth/collection/forms.py:73 #: xl_auth/permission/forms.py:59 xl_auth/permission/forms.py:100 xl_auth/user/forms.py:44 #: xl_auth/user/forms.py:97 xl_auth/user/forms.py:123 xl_auth/user/forms.py:150 msgid "You do not have sufficient privileges for this operation." msgstr "" +#: tests/forms/test_client.py:60 tests/forms/test_client.py:153 +msgid "Field must be between 3 and 64 characters long." +msgstr "" + +#: tests/forms/test_client.py:83 tests/forms/test_client.py:176 +msgid "Field must be between 3 and 350 characters long." +msgstr "" + #: tests/forms/test_collection.py:30 msgid "Field must be between 1 and 5 characters long." msgstr "" @@ -289,31 +280,43 @@ msgstr "" msgid "User does not exist" msgstr "" -#: tests/models/test_collection.py:81 xl_auth/collection/models.py:38 +#: tests/models/test_collection.py:99 xl_auth/collection/models.py:40 #, python-format msgid "Replaces %(replaces_code)s, then replaced by %(replaced_by_code)s" msgstr "" -#: tests/models/test_collection.py:84 xl_auth/collection/models.py:41 +#: tests/models/test_collection.py:102 xl_auth/collection/models.py:43 #, python-format msgid "Replaces %(replaces_code)s" msgstr "" -#: tests/models/test_collection.py:87 xl_auth/collection/models.py:43 +#: tests/models/test_collection.py:105 xl_auth/collection/models.py:45 #, python-format msgid "Replaced by %(replaced_by_code)s" msgstr "" +#: xl_auth/client/forms.py:11 +msgid "Redirect URIs" +msgstr "" + +#: xl_auth/client/forms.py:12 +msgid "Default scopes" +msgstr "" + #: xl_auth/client/forms.py:13 xl_auth/templates/clients/home.html:19 msgid "Confidential" msgstr "" +#: xl_auth/client/forms.py:15 xl_auth/templates/clients/home.html:18 +msgid "Description" +msgstr "" + #: xl_auth/client/views.py:44 #, python-format msgid "Client \"%(name)s\" created." msgstr "" -#: xl_auth/client/views.py:68 +#: xl_auth/client/views.py:85 #, python-format msgid "Thank you for updating client details for \"%(id)s\"." msgstr "" @@ -407,7 +410,7 @@ msgid "xl_auth" msgstr "" #: xl_auth/templates/collections/home.html:4 xl_auth/templates/nav.html:25 -#: xl_auth/templates/users/home.html:19 xl_auth/templates/users/home.html:62 +#: xl_auth/templates/users/home.html:19 xl_auth/templates/users/home.html:64 msgid "Collections" msgstr "" @@ -419,7 +422,19 @@ msgstr "" msgid "Edit OAuth2 Client" msgstr "" -#: xl_auth/templates/clients/edit.html:31 xl_auth/templates/collections/edit.html:29 +#: xl_auth/templates/clients/edit.html:9 +msgid "OAuth2 Client Credentials" +msgstr "" + +#: xl_auth/templates/clients/edit.html:12 +msgid "Client ID" +msgstr "" + +#: xl_auth/templates/clients/edit.html:13 +msgid "Client Secret" +msgstr "" + +#: xl_auth/templates/clients/edit.html:39 xl_auth/templates/collections/edit.html:29 #: xl_auth/templates/permissions/edit.html:35 xl_auth/templates/users/administer.html:25 #: xl_auth/templates/users/change_password.html:21 xl_auth/templates/users/edit_details.html:17 msgid "Save" @@ -430,10 +445,18 @@ msgid "OAuth2 Clients" msgstr "" #: xl_auth/templates/clients/home.html:20 xl_auth/templates/users/home.html:20 -#: xl_auth/templates/users/home.html:63 +#: xl_auth/templates/users/home.html:65 msgid "Admin" msgstr "" +#: xl_auth/templates/clients/home.html:40 +msgid "Delete" +msgstr "" + +#: xl_auth/templates/clients/home.html:42 +msgid "Delete client" +msgstr "" + #: xl_auth/templates/clients/register.html:5 msgid "Register New OAuth2 Client" msgstr "" @@ -461,8 +484,8 @@ msgid "Friendly Name" msgstr "" #: xl_auth/templates/collections/home.html:25 xl_auth/templates/collections/home.html:70 -#: xl_auth/templates/permissions/home.html:21 xl_auth/templates/users/home.html:21 -#: xl_auth/templates/users/home.html:64 +#: xl_auth/templates/permissions/home.html:21 xl_auth/templates/users/home.html:22 +#: xl_auth/templates/users/home.html:67 msgid "Created At" msgstr "" @@ -564,11 +587,15 @@ msgstr "" msgid "Active Users" msgstr "" -#: xl_auth/templates/users/home.html:37 xl_auth/templates/users/home.html:80 +#: xl_auth/templates/users/home.html:21 xl_auth/templates/users/home.html:66 +msgid "Last Login At" +msgstr "" + +#: xl_auth/templates/users/home.html:39 xl_auth/templates/users/home.html:84 msgid "Edit Details" msgstr "" -#: xl_auth/templates/users/home.html:55 +#: xl_auth/templates/users/home.html:57 msgid "Inactive Users" msgstr "" diff --git a/xl_auth/templates/users/home.html b/xl_auth/templates/users/home.html index f1942689..11a33fe6 100644 --- a/xl_auth/templates/users/home.html +++ b/xl_auth/templates/users/home.html @@ -14,10 +14,11 @@

{{ _('Users') }}

- + + {% if current_user.is_admin %} @@ -31,6 +32,7 @@

{{ _('Users') }}

+ {% if current_user.is_admin %}
{{ _('Email') }}{{ _('Email') }} {{ _('Name') }} {{ _('Collections') }} {{ _('Admin') }}{{ _('Last Login At') }} {{ _('Created At') }} {{ user.full_name }} {{ user.permissions | length }} {{ _('Yes') if user.is_admin else _('No') }}{{ '-' if not user.last_login_at else user.last_login_at.strftime('%y-%m-%d') }} {{ user.created_at.strftime('%y-%m-%d') }} @@ -57,10 +59,11 @@

{{ _('Users') }}

- + + {% if current_user.is_admin %} @@ -74,6 +77,7 @@

{{ _('Users') }}

+ {% if current_user.is_admin %}
{{ _('Email') }}{{ _('Email') }} {{ _('Name') }} {{ _('Collections') }} {{ _('Admin') }}{{ _('Last Login At') }} {{ _('Created At') }} {{ user.full_name }} {{ user.permissions | length }} {{ _('Yes') if user.is_admin else _('No') }}{{ '-' if not user.last_login_at else user.last_login_at.strftime('%y-%m-%d') }} {{ user.created_at.strftime('%y-%m-%d') }} diff --git a/xl_auth/translations/sv/LC_MESSAGES/messages.po b/xl_auth/translations/sv/LC_MESSAGES/messages.po index 9c29e7ae..1fd52047 100644 --- a/xl_auth/translations/sv/LC_MESSAGES/messages.po +++ b/xl_auth/translations/sv/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.2.1\n" "Report-Msgid-Bugs-To: mats.blomdahl@gmail.com\n" -"POT-Creation-Date: 2017-10-25 14:02+0200\n" +"POT-Creation-Date: 2017-10-30 14:10+0100\n" "PO-Revision-Date: 2017-09-19 12:23+0200\n" "Last-Translator: Mats Blomdahl \n" "Language: sv\n" @@ -18,6 +18,15 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.5.1\n" +#: tests/end2end/test_deleting_client.py:34 xl_auth/client/views.py:64 +#, python-format +msgid "Successfully deleted OAuth2 Client \"%(name)s\"." +msgstr "Raderade OAuth2-klient \"%(name)s\"." + +#: tests/end2end/test_deleting_client.py:51 +msgid "Clients" +msgstr "Klienter" + #: tests/end2end/test_deleting_permission.py:24 tests/end2end/test_deleting_permission.py:51 #: tests/end2end/test_editing_permission.py:29 tests/end2end/test_editing_permission.py:63 #: tests/end2end/test_editing_permission.py:91 tests/end2end/test_editing_user.py:183 @@ -44,49 +53,6 @@ msgstr "🙀 Ta bort behörighet" msgid "Successfully deleted permissions for \"%(username)s\" on collection \"%(code)s\"." msgstr "Behörighet borttagen för \"%(username)s\" pĂ„ samling \"%(code)s\"." -#: tests/end2end/test_editing_client.py:82 tests/end2end/test_editing_client.py:115 -#: tests/end2end/test_editing_collection.py:102 tests/end2end/test_registering_collection.py:102 -#: xl_auth/client/forms.py:14 xl_auth/collection/forms.py:18 xl_auth/templates/clients/home.html:17 -#: xl_auth/templates/users/home.html:18 xl_auth/templates/users/home.html:61 -msgid "Name" -msgstr "Namn" - -#: tests/end2end/test_editing_client.py:82 tests/end2end/test_editing_client.py:148 -#: tests/end2end/test_editing_client.py:215 tests/end2end/test_editing_client.py:248 -#: tests/end2end/test_editing_collection.py:102 tests/end2end/test_editing_user.py:146 -#: tests/end2end/test_registering_collection.py:79 tests/end2end/test_registering_collection.py:102 -#: tests/forms/test_client.py:48 tests/forms/test_client.py:71 tests/forms/test_client.py:94 -#: tests/forms/test_client.py:105 tests/forms/test_client.py:141 tests/forms/test_client.py:164 -#: tests/forms/test_client.py:187 tests/forms/test_client.py:198 tests/forms/test_collection.py:21 -#: tests/forms/test_collection.py:38 tests/forms/test_permission.py:31 -#: tests/forms/test_permission.py:39 tests/forms/test_permission.py:47 -#: tests/forms/test_permission.py:55 -msgid "This field is required." -msgstr "Det hĂ€r fĂ€ltet Ă€r obligatoriskt." - -#: tests/end2end/test_editing_client.py:115 tests/forms/test_client.py:60 -#: tests/forms/test_client.py:153 -msgid "Field must be between 3 and 64 characters long." -msgstr "FĂ€ltet mĂ„ste vara mellan 3 och 64 tecken lĂ„ngt." - -#: tests/end2end/test_editing_client.py:148 tests/end2end/test_editing_client.py:181 -#: xl_auth/client/forms.py:15 xl_auth/templates/clients/home.html:18 -msgid "Description" -msgstr "Beskrivning" - -#: tests/end2end/test_editing_client.py:182 tests/forms/test_client.py:83 -#: tests/forms/test_client.py:176 -msgid "Field must be between 3 and 350 characters long." -msgstr "FĂ€ltet mĂ„ste vara mellan 3 och 350 tecken lĂ„ngt." - -#: tests/end2end/test_editing_client.py:215 xl_auth/client/forms.py:11 -msgid "Redirect URIs" -msgstr "Redirect URIs" - -#: tests/end2end/test_editing_client.py:248 xl_auth/client/forms.py:12 -msgid "Default scopes" -msgstr "Default scopes" - #: tests/end2end/test_editing_collection.py:53 tests/end2end/test_registering_collection.py:52 msgid "category" msgstr "kategori" @@ -108,6 +74,23 @@ msgstr "Sigel" msgid "Code cannot be modified" msgstr "Koden kan inte Ă€ndras" +#: tests/end2end/test_editing_collection.py:102 tests/end2end/test_registering_collection.py:102 +#: xl_auth/client/forms.py:14 xl_auth/collection/forms.py:18 xl_auth/templates/clients/home.html:17 +#: xl_auth/templates/users/home.html:18 xl_auth/templates/users/home.html:63 +msgid "Name" +msgstr "Namn" + +#: tests/end2end/test_editing_collection.py:102 tests/end2end/test_editing_user.py:146 +#: tests/end2end/test_registering_collection.py:79 tests/end2end/test_registering_collection.py:102 +#: tests/forms/test_client.py:48 tests/forms/test_client.py:71 tests/forms/test_client.py:94 +#: tests/forms/test_client.py:105 tests/forms/test_client.py:141 tests/forms/test_client.py:164 +#: tests/forms/test_client.py:187 tests/forms/test_client.py:198 tests/forms/test_collection.py:21 +#: tests/forms/test_collection.py:38 tests/forms/test_permission.py:31 +#: tests/forms/test_permission.py:39 tests/forms/test_permission.py:47 +#: tests/forms/test_permission.py:55 +msgid "This field is required." +msgstr "Det hĂ€r fĂ€ltet Ă€r obligatoriskt." + #: tests/end2end/test_editing_collection.py:124 tests/end2end/test_registering_collection.py:125 #: xl_auth/collection/forms.py:19 xl_auth/templates/collections/home.html:23 #: xl_auth/templates/collections/home.html:68 @@ -131,7 +114,7 @@ msgstr "Behörighet uppdaterad för \"%(username)s\" pĂ„ samling \"%(code)s\"." #: tests/end2end/test_editing_permission.py:75 tests/end2end/test_registering_permission.py:69 #: tests/forms/test_permission.py:64 tests/forms/test_permission.py:77 xl_auth/permission/forms.py:64 -#: xl_auth/permission/forms.py:112 +#: xl_auth/permission/forms.py:114 #, python-format msgid "Permissions for user \"%(username)s\" on collection \"%(code)s\" already registered" msgstr "En behörighet för anvĂ€ndare \"%(username)s\" pĂ„ samling \"%(code)s\" finns redan registrerad" @@ -145,22 +128,22 @@ msgstr "AnvĂ€ndare" #: tests/end2end/test_editing_user.py:45 xl_auth/templates/clients/home.html:29 #: xl_auth/templates/permissions/home.html:30 xl_auth/templates/permissions/home.html:31 -#: xl_auth/templates/permissions/home.html:32 xl_auth/templates/users/home.html:33 -#: xl_auth/templates/users/home.html:76 xl_auth/templates/users/profile.html:58 +#: xl_auth/templates/permissions/home.html:32 xl_auth/templates/users/home.html:34 +#: xl_auth/templates/users/home.html:79 xl_auth/templates/users/profile.html:58 #: xl_auth/templates/users/profile.html:61 xl_auth/templates/users/profile.html:65 msgid "Yes" msgstr "Ja" #: tests/end2end/test_editing_user.py:45 xl_auth/templates/clients/home.html:31 #: xl_auth/templates/permissions/home.html:30 xl_auth/templates/permissions/home.html:31 -#: xl_auth/templates/permissions/home.html:32 xl_auth/templates/users/home.html:33 -#: xl_auth/templates/users/home.html:76 xl_auth/templates/users/profile.html:58 +#: xl_auth/templates/permissions/home.html:32 xl_auth/templates/users/home.html:34 +#: xl_auth/templates/users/home.html:79 xl_auth/templates/users/profile.html:58 #: xl_auth/templates/users/profile.html:61 xl_auth/templates/users/profile.html:65 msgid "No" msgstr "Nej" #: tests/end2end/test_editing_user.py:101 tests/end2end/test_editing_user.py:125 -#: xl_auth/templates/users/home.html:17 xl_auth/templates/users/home.html:60 xl_auth/user/forms.py:13 +#: xl_auth/templates/users/home.html:17 xl_auth/templates/users/home.html:62 xl_auth/user/forms.py:13 msgid "Email" msgstr "Epost" @@ -180,8 +163,8 @@ msgstr "FullstĂ€ndigt namn" msgid "User \"%(username)s\" does not exist" msgstr "AnvĂ€ndaren \"%(username)s\" existerar inte" -#: tests/end2end/test_editing_user.py:190 xl_auth/templates/users/home.html:41 -#: xl_auth/templates/users/home.html:84 xl_auth/templates/users/profile.html:17 +#: tests/end2end/test_editing_user.py:190 xl_auth/templates/users/home.html:43 +#: xl_auth/templates/users/home.html:88 xl_auth/templates/users/profile.html:17 msgid "Change Password" msgstr "Byt lösenord" @@ -190,15 +173,15 @@ msgstr "Byt lösenord" msgid "Welcome" msgstr "VĂ€lkommen" -#: tests/end2end/test_logging_in.py:35 xl_auth/public/views.py:45 +#: tests/end2end/test_logging_in.py:59 xl_auth/public/views.py:46 msgid "You are logged out." msgstr "Du Ă€r utloggad." -#: tests/end2end/test_logging_in.py:49 tests/forms/test_public.py:45 xl_auth/public/forms.py:37 +#: tests/end2end/test_logging_in.py:73 tests/forms/test_public.py:45 xl_auth/public/forms.py:37 msgid "Invalid password" msgstr "Felaktigt lösenord" -#: tests/end2end/test_logging_in.py:64 tests/forms/test_public.py:35 xl_auth/public/forms.py:33 +#: tests/end2end/test_logging_in.py:88 tests/forms/test_public.py:35 xl_auth/public/forms.py:33 msgid "Unknown username/email" msgstr "OkĂ€nd epost/anvĂ€ndarnamn" @@ -243,13 +226,21 @@ msgstr "Epost-adressen Ă€r redan registrerad" #: tests/forms/test_client.py:25 tests/forms/test_client.py:118 tests/forms/test_collection.py:124 #: tests/forms/test_collection.py:135 tests/forms/test_permission.py:144 #: tests/forms/test_permission.py:174 tests/forms/test_user.py:63 tests/forms/test_user.py:106 -#: tests/forms/test_user.py:132 tests/forms/test_user.py:169 xl_auth/client/forms.py:41 -#: xl_auth/client/forms.py:68 xl_auth/collection/forms.py:41 xl_auth/collection/forms.py:73 +#: tests/forms/test_user.py:132 tests/forms/test_user.py:169 xl_auth/client/forms.py:40 +#: xl_auth/client/forms.py:67 xl_auth/collection/forms.py:41 xl_auth/collection/forms.py:73 #: xl_auth/permission/forms.py:59 xl_auth/permission/forms.py:100 xl_auth/user/forms.py:44 #: xl_auth/user/forms.py:97 xl_auth/user/forms.py:123 xl_auth/user/forms.py:150 msgid "You do not have sufficient privileges for this operation." msgstr "Du har inte tillrĂ€cklig behörighet för att utföra denna operation." +#: tests/forms/test_client.py:60 tests/forms/test_client.py:153 +msgid "Field must be between 3 and 64 characters long." +msgstr "FĂ€ltet mĂ„ste vara mellan 3 och 64 tecken lĂ„ngt." + +#: tests/forms/test_client.py:83 tests/forms/test_client.py:176 +msgid "Field must be between 3 and 350 characters long." +msgstr "FĂ€ltet mĂ„ste vara mellan 3 och 350 tecken lĂ„ngt." + #: tests/forms/test_collection.py:30 msgid "Field must be between 1 and 5 characters long." msgstr "FĂ€ltet mĂ„ste vara mellan 1 och 5 tecken lĂ„ngt." @@ -290,31 +281,43 @@ msgstr "FĂ€ltet mĂ„ste vara mellan 3 och 255 tecken lĂ„ngt." msgid "User does not exist" msgstr "AnvĂ€ndaren existerar inte" -#: tests/models/test_collection.py:81 xl_auth/collection/models.py:38 +#: tests/models/test_collection.py:99 xl_auth/collection/models.py:40 #, python-format msgid "Replaces %(replaces_code)s, then replaced by %(replaced_by_code)s" msgstr "ErsĂ€tter %(replaces_code)s, dĂ€refter ersatt av samling %(replaced_by_code)s" -#: tests/models/test_collection.py:84 xl_auth/collection/models.py:41 +#: tests/models/test_collection.py:102 xl_auth/collection/models.py:43 #, python-format msgid "Replaces %(replaces_code)s" msgstr "ErsĂ€tter samling %(replaces_code)s" -#: tests/models/test_collection.py:87 xl_auth/collection/models.py:43 +#: tests/models/test_collection.py:105 xl_auth/collection/models.py:45 #, python-format msgid "Replaced by %(replaced_by_code)s" msgstr "Ersatt av samling %(replaced_by_code)s" +#: xl_auth/client/forms.py:11 +msgid "Redirect URIs" +msgstr "Redirect URIs" + +#: xl_auth/client/forms.py:12 +msgid "Default scopes" +msgstr "Default scopes" + #: xl_auth/client/forms.py:13 xl_auth/templates/clients/home.html:19 msgid "Confidential" msgstr "Konfidentiell" +#: xl_auth/client/forms.py:15 xl_auth/templates/clients/home.html:18 +msgid "Description" +msgstr "Beskrivning" + #: xl_auth/client/views.py:44 #, python-format msgid "Client \"%(name)s\" created." msgstr "Klient \"%(name)s\" skapad." -#: xl_auth/client/views.py:68 +#: xl_auth/client/views.py:85 #, python-format msgid "Thank you for updating client details for \"%(id)s\"." msgstr "Tack för att du uppdaterade detaljer för klient \"%(id)s\"." @@ -408,7 +411,7 @@ msgid "xl_auth" msgstr "Libris Login alpha" #: xl_auth/templates/collections/home.html:4 xl_auth/templates/nav.html:25 -#: xl_auth/templates/users/home.html:19 xl_auth/templates/users/home.html:62 +#: xl_auth/templates/users/home.html:19 xl_auth/templates/users/home.html:64 msgid "Collections" msgstr "Samlingar/sigler" @@ -420,7 +423,19 @@ msgstr "Logga ut" msgid "Edit OAuth2 Client" msgstr "Redigera OAuth2-klient" -#: xl_auth/templates/clients/edit.html:31 xl_auth/templates/collections/edit.html:29 +#: xl_auth/templates/clients/edit.html:9 +msgid "OAuth2 Client Credentials" +msgstr "OAuth2-credentials" + +#: xl_auth/templates/clients/edit.html:12 +msgid "Client ID" +msgstr "Klient-ID" + +#: xl_auth/templates/clients/edit.html:13 +msgid "Client Secret" +msgstr "Klienthemlighet" + +#: xl_auth/templates/clients/edit.html:39 xl_auth/templates/collections/edit.html:29 #: xl_auth/templates/permissions/edit.html:35 xl_auth/templates/users/administer.html:25 #: xl_auth/templates/users/change_password.html:21 xl_auth/templates/users/edit_details.html:17 msgid "Save" @@ -431,10 +446,18 @@ msgid "OAuth2 Clients" msgstr "OAuth2-klienter" #: xl_auth/templates/clients/home.html:20 xl_auth/templates/users/home.html:20 -#: xl_auth/templates/users/home.html:63 +#: xl_auth/templates/users/home.html:65 msgid "Admin" msgstr "Admin" +#: xl_auth/templates/clients/home.html:40 +msgid "Delete" +msgstr "Ta bort" + +#: xl_auth/templates/clients/home.html:42 +msgid "Delete client" +msgstr "Ta bort klient" + #: xl_auth/templates/clients/register.html:5 msgid "Register New OAuth2 Client" msgstr "Registrera ny OAuth2-klient" @@ -462,8 +485,8 @@ msgid "Friendly Name" msgstr "Namn" #: xl_auth/templates/collections/home.html:25 xl_auth/templates/collections/home.html:70 -#: xl_auth/templates/permissions/home.html:21 xl_auth/templates/users/home.html:21 -#: xl_auth/templates/users/home.html:64 +#: xl_auth/templates/permissions/home.html:21 xl_auth/templates/users/home.html:22 +#: xl_auth/templates/users/home.html:67 msgid "Created At" msgstr "Skapad" @@ -570,11 +593,15 @@ msgstr "Byt anvĂ€ndarlösenord" msgid "Active Users" msgstr "Aktiva anvĂ€ndare" -#: xl_auth/templates/users/home.html:37 xl_auth/templates/users/home.html:80 +#: xl_auth/templates/users/home.html:21 xl_auth/templates/users/home.html:66 +msgid "Last Login At" +msgstr "Inloggad" + +#: xl_auth/templates/users/home.html:39 xl_auth/templates/users/home.html:84 msgid "Edit Details" msgstr "Ändra profil" -#: xl_auth/templates/users/home.html:55 +#: xl_auth/templates/users/home.html:57 msgid "Inactive Users" msgstr "Inaktiva anvĂ€ndare" From dd9d7c20bcae71dfb17b106973f2373ba43713dc Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 14:12:59 +0100 Subject: [PATCH 09/10] Bump patch version + add changelog entry with #78 --- README.rst | 6 ++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 372e2050..1e798dbe 100644 --- a/README.rst +++ b/README.rst @@ -183,6 +183,12 @@ DB Models Changelog ========= +v. 0.4.6 +-------- + +* Minor traceability improvements (`#78 `_) + + v. 0.4.5 -------- diff --git a/package-lock.json b/package-lock.json index 3749a77c..fce4ba08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "xl_auth", - "version": "0.4.5", + "version": "0.4.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a020ccda..9d1365c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xl_auth", - "version": "0.4.5", + "version": "0.4.6", "author": "National Library of Sweden", "license": "Apache-2.0", "description": "OAuth2 authorization for LibrisXL, replacing BibDB counterpart", From c2310a312354a4b9ee691e82ff43c6fa1be8f826 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 30 Oct 2017 14:30:15 +0100 Subject: [PATCH 10/10] Address review comments --- tests/models/test_collection.py | 8 +++----- tests/models/test_permission.py | 8 +++----- tests/models/test_user.py | 7 +++---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/tests/models/test_collection.py b/tests/models/test_collection.py index 68ed1c3e..3d5929cf 100644 --- a/tests/models/test_collection.py +++ b/tests/models/test_collection.py @@ -40,16 +40,14 @@ def test_modified_at_defaults_to_current_datetime(): """Test modified date.""" collection = Collection('KBU', 'Outdated name', 'library') collection.save() - first_modified_at = collection.modified_at.isoformat() + first_modified_at = collection.modified_at - # Initial 'modified_at' matches 'created_at' (at least at the minute level). - assert first_modified_at[:16] == collection.created_at.isoformat()[:16] + assert abs((first_modified_at - collection.created_at).total_seconds()) < 10 collection.friendly_name = 'Not outdated name!' collection.save() - # Initial 'modified_at' has been overwritten. - assert first_modified_at != collection.modified_at.isoformat() + assert first_modified_at != collection.modified_at @pytest.mark.usefixtures('db') diff --git a/tests/models/test_permission.py b/tests/models/test_permission.py index db145df9..8a57d27f 100644 --- a/tests/models/test_permission.py +++ b/tests/models/test_permission.py @@ -40,16 +40,14 @@ def test_modified_at_defaults_to_current_datetime(user, collection): """Test modified date.""" permission = Permission(user=user, collection=collection) permission.save() - first_modified_at = permission.modified_at.isoformat() + first_modified_at = permission.modified_at - # Initial 'modified_at' matches 'created_at' (at least at the minute level). - assert first_modified_at[:16] == permission.created_at.isoformat()[:16] + assert abs((first_modified_at - permission.created_at).total_seconds()) < 10 permission.registrant = not permission.registrant permission.save() - # Initial 'modified_at' has been overwritten. - assert first_modified_at != permission.modified_at.isoformat() + assert first_modified_at != permission.modified_at @pytest.mark.usefixtures('db') diff --git a/tests/models/test_user.py b/tests/models/test_user.py index ffb1fd77..1030253a 100644 --- a/tests/models/test_user.py +++ b/tests/models/test_user.py @@ -37,16 +37,15 @@ def test_modified_at_defaults_to_current_datetime(): """Test modified date.""" user = User('foo@kb.se', 'Wrong Name') user.save() - first_modified_at = user.modified_at.isoformat() + first_modified_at = user.modified_at - # Initial 'modified_at' matches 'created_at' (at least at the minute level). - assert first_modified_at[:16] == user.created_at.isoformat()[:16] + assert abs((first_modified_at - user.created_at).total_seconds()) < 10 user.full_name = 'Correct Name' user.save() # Initial 'modified_at' has been overwritten. - assert first_modified_at != user.modified_at.isoformat() + assert first_modified_at != user.modified_at @pytest.mark.usefixtures('db')