Merge pull request #733 from dod-ccpo/add-last-login-timestamp
Add last login timestamp
This commit is contained in:
commit
f1c6717a1e
28
alembic/versions/49e12ae7c9ca_add_last_login_to_user.py
Normal file
28
alembic/versions/49e12ae7c9ca_add_last_login_to_user.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""add last login to user
|
||||
|
||||
Revision ID: 49e12ae7c9ca
|
||||
Revises: fc08d99bb7f7
|
||||
Create Date: 2019-03-28 15:46:58.226281
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '49e12ae7c9ca'
|
||||
down_revision = 'fc08d99bb7f7'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('users', sa.Column('last_login', sa.TIMESTAMP(timezone=True), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('users', 'last_login')
|
||||
# ### end Alembic commands ###
|
@ -22,6 +22,8 @@ def apply_authentication(app):
|
||||
user = get_current_user()
|
||||
if user:
|
||||
g.current_user = user
|
||||
g.last_login = get_last_login()
|
||||
|
||||
if should_redirect_to_user_profile(request, user):
|
||||
return redirect(url_for("users.user", next=request.path))
|
||||
elif not _unprotected_route(request):
|
||||
@ -50,9 +52,14 @@ def get_current_user():
|
||||
return False
|
||||
|
||||
|
||||
def get_last_login():
|
||||
return session.get("user_id") and session.get("last_login")
|
||||
|
||||
|
||||
def logout():
|
||||
if session.get("user_id"): # pragma: no branch
|
||||
del session["user_id"]
|
||||
del session["last_login"]
|
||||
|
||||
|
||||
def _unprotected_route(request):
|
||||
|
@ -1,5 +1,6 @@
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from datetime import datetime
|
||||
|
||||
from atst.database import db
|
||||
from atst.models import User
|
||||
@ -82,6 +83,12 @@ class Users(object):
|
||||
|
||||
return user
|
||||
|
||||
@classmethod
|
||||
def update_last_login(cls, user):
|
||||
user.last_login = datetime.now()
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
@classmethod
|
||||
def finalize(cls, user):
|
||||
user.provisional = False
|
||||
|
@ -1,4 +1,4 @@
|
||||
from sqlalchemy import String, ForeignKey, Column, Date, Boolean, Table
|
||||
from sqlalchemy import String, ForeignKey, Column, Date, Boolean, Table, TIMESTAMP
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
|
||||
@ -36,6 +36,7 @@ class User(
|
||||
citizenship = Column(String)
|
||||
designation = Column(String)
|
||||
date_latest_training = Column(Date)
|
||||
last_login = Column(TIMESTAMP(timezone=True), nullable=True)
|
||||
|
||||
provisional = Column(Boolean)
|
||||
|
||||
|
@ -122,6 +122,12 @@ def redirect_after_login_url():
|
||||
return url_for("atst.home")
|
||||
|
||||
|
||||
def current_user_setup(user):
|
||||
session["user_id"] = user.id
|
||||
session["last_login"] = user.last_login
|
||||
Users.update_last_login(user)
|
||||
|
||||
|
||||
@bp.route("/login-redirect")
|
||||
def login_redirect():
|
||||
auth_context = _make_authentication_context()
|
||||
@ -131,8 +137,7 @@ def login_redirect():
|
||||
if user.provisional:
|
||||
Users.finalize(user)
|
||||
|
||||
session["user_id"] = user.id
|
||||
|
||||
current_user_setup(user)
|
||||
return redirect(redirect_after_login_url())
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
from flask import (
|
||||
Blueprint,
|
||||
request,
|
||||
session,
|
||||
redirect,
|
||||
render_template,
|
||||
url_for,
|
||||
@ -9,7 +8,7 @@ from flask import (
|
||||
)
|
||||
import pendulum
|
||||
|
||||
from . import redirect_after_login_url
|
||||
from . import redirect_after_login_url, current_user_setup
|
||||
from atst.domain.users import Users
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
from atst.queue import queue
|
||||
@ -124,8 +123,7 @@ def login_dev():
|
||||
user_data,
|
||||
),
|
||||
)
|
||||
session["user_id"] = user.id
|
||||
|
||||
current_user_setup(user)
|
||||
return redirect(redirect_after_login_url())
|
||||
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: $footer-height;
|
||||
color: $color-gray-dark;
|
||||
font-size: 1.5rem;
|
||||
|
||||
.app-footer__info {
|
||||
flex-grow: 1;
|
||||
|
@ -7,4 +7,9 @@
|
||||
<span>{{ "footer.jedi_help_link_text" | translate }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% if g.last_login %}
|
||||
<div class="">
|
||||
Last Login: <local-datetime timestamp='{{ g.last_login }}'></local-datetime>
|
||||
</div>
|
||||
{% endif %}
|
||||
</footer>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
from atst.domain.users import Users
|
||||
@ -65,3 +66,11 @@ def test_update_user_with_dod_id():
|
||||
Users.update(new_user, {"dod_id": "1234567890"})
|
||||
|
||||
assert "dod_id" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_update_user_with_last_login():
|
||||
new_user = UserFactory.create()
|
||||
Users.update_last_login(new_user)
|
||||
last_login = new_user.last_login
|
||||
Users.update_last_login(new_user)
|
||||
assert new_user.last_login > last_login
|
||||
|
@ -1,6 +1,7 @@
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from flask import session, url_for
|
||||
from .mocks import DOD_SDN_INFO, DOD_SDN, FIXTURE_EMAIL_ADDRESS
|
||||
from atst.domain.users import Users
|
||||
@ -224,3 +225,18 @@ def test_error_on_invalid_crl(client, monkeypatch):
|
||||
response = _login(client)
|
||||
assert response.status_code == 401
|
||||
assert "Error Code 008" in response.data.decode()
|
||||
|
||||
|
||||
def test_last_login_set_when_user_logs_in(client, monkeypatch):
|
||||
last_login = datetime.now()
|
||||
user = UserFactory.create(last_login=last_login)
|
||||
monkeypatch.setattr(
|
||||
"atst.domain.authnid.AuthenticationContext.authenticate", lambda *args: True
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"atst.domain.authnid.AuthenticationContext.get_user", lambda *args: user
|
||||
)
|
||||
response = _login(client)
|
||||
assert session["last_login"]
|
||||
assert user.last_login > session["last_login"]
|
||||
assert isinstance(session["last_login"], datetime)
|
||||
|
Loading…
x
Reference in New Issue
Block a user