Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

log user creation timestamp #3416

Merged
merged 12 commits into from
Jun 20, 2024
5 changes: 3 additions & 2 deletions qiita_db/handlers/tests/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ def test_get(self):

obs = loads(obs.body)
exp = {'data': [
{'email': '[email protected]', 'name': 'Dude'},
{'email': '[email protected]', 'name': 'Shared'},
{'email': '[email protected]', 'name': 'Admin'},
{'email': '[email protected]', 'name': 'Demo'}]}
{'email': '[email protected]', 'name': 'Demo'},
{'email': '[email protected]', 'name': 'Dude'}
]}
self.assertEqual(obs, exp)


Expand Down
13 changes: 13 additions & 0 deletions qiita_db/support_files/patches/92.sql
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,16 @@ ALTER TABLE qiita.prep_template ADD current_human_filtering boolean DEFAULT Fals
-- Adding a new column: reprocess_job_id to qiita.prep_template to keep track of
-- the job that reprocessed this prep
ALTER TABLE qiita.prep_template ADD reprocess_job_id uuid DEFAULT NULL;

-- Jun 19, 2024
-- Adding a new column to the user table that logs when this account was created
-- Usefull e.g. to prune non-verified=inactive user or to plot user growth

ALTER TABLE qiita.qiita_user
ADD creation_timestamp timestamp without time zone DEFAULT NOW();

COMMENT ON COLUMN qiita.qiita_user.creation_timestamp IS 'The date the user account was created';

-- for testing: provide creation date for one of the existing users

UPDATE qiita.qiita_user SET creation_timestamp = '2015-12-03 13:52:42.751331-07' WHERE email = '[email protected]';
49 changes: 42 additions & 7 deletions qiita_db/test/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ def setUp(self):
'receive_processing_job_emails': True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with this test and my suggestion about using now() in the database is that there is going to be a small difference on the tests so they will need to be adjusted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to account for these unpredictable time differences with your "before < obs < after" assertions, e.g. here https://github.com/jlab/qiita/blob/1488be79e9468e240ea318ae8920fd6559030307/qiita_db/test/test_user.py#L170-L198

'social_orcid': None,
'social_researchgate': None,
'social_googlescholar': None
'social_googlescholar': None,
'creation_timestamp': datetime(2015, 12, 3, 13, 52, 42, 751331)
}

def tearDown(self):
Expand All @@ -88,7 +89,22 @@ def test_instantiate_unknown_user(self):
with self.assertRaises(qdb.exceptions.QiitaDBUnknownIDError):
qdb.user.User('[email protected]')

def _check_correct_info(self, obs, exp):
def _check_correct_info(self, obs, exp, ts_before=None):
"""Compares info dict of user with special handling of specific keys.

Parameters
----------
obs : dict
Observed user info dictionary.
exp : dict
Expected user info dictionary.
ts_before : datetime.datetime or None
User.create records the creation timestamp through SQL's NOW().
Since it is set by the database to the microsecond, we can't
predict it a priori and therefore simply record timestamp before
execution of user.create() and compare the relation.
The DB creation_timestamp column is optional, i.e. can be None.
"""
self.assertEqual(set(exp.keys()), set(obs.keys()))
for key in exp:
# user_verify_code and password seed randomly generated so just
Expand All @@ -97,10 +113,14 @@ def _check_correct_info(self, obs, exp):
self.assertEqual(len(obs[key]), 20)
elif key == "password":
self.assertEqual(len(obs[key]), 60)
elif key == "creation_timestamp":
self.assertTrue(((exp[key] is None) and (obs[key] is None))
or (ts_before <= exp[key]))
else:
self.assertEqual(obs[key], exp[key])

def test_create_user(self):
before = datetime.now()
user = qdb.user.User.create('[email protected]', 'password')

# adding a couple of messages
Expand Down Expand Up @@ -131,8 +151,9 @@ def test_create_user(self):
'email': '[email protected]',
'social_orcid': None,
'social_researchgate': None,
'social_googlescholar': None}
self._check_correct_info(obs, exp)
'social_googlescholar': None,
'creation_timestamp': datetime.now()}
self._check_correct_info(obs, exp, before)

# Make sure new system messages are linked to user
sql = """SELECT message_id FROM qiita.message_user
Expand All @@ -146,6 +167,7 @@ def test_create_user(self):
qdb.util.clear_system_messages()

def test_create_user_info(self):
before = datetime.now()
user = qdb.user.User.create('[email protected]', 'password',
self.userinfo)
self.assertEqual(user.id, '[email protected]')
Expand All @@ -171,8 +193,9 @@ def test_create_user_info(self):
'email': '[email protected]',
'social_orcid': None,
'social_researchgate': None,
'social_googlescholar': None}
self._check_correct_info(obs, exp)
'social_googlescholar': None,
'creation_timestamp': datetime.now()}
self._check_correct_info(obs, exp, before)

def test_create_user_column_not_allowed(self):
self.userinfo["email"] = "FAIL"
Expand Down Expand Up @@ -241,8 +264,20 @@ def test_get_info(self):
'phone': '222-444-6789',
'social_orcid': None,
'social_researchgate': None,
'social_googlescholar': None
'social_googlescholar': None,
'creation_timestamp': datetime(2015, 12, 3, 13, 52, 42, 751331)
}

# test database is re-populated during testing several times.
# Creation_timestamp depends on the percise timing of the repopulation,
# i.e. we cannot predict its value. We just test that this date should
# be within an hour and now. For the remainder of tests, we update
# our expectation.
self.assertTrue(datetime.now() - timedelta(hours=1) <
self.user.info['creation_timestamp'] <
datetime.now())
expinfo['creation_timestamp'] = self.user.info['creation_timestamp']

self.assertEqual(self.user.info, expinfo)

def test_set_info(self):
Expand Down
3 changes: 2 additions & 1 deletion qiita_db/test/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ def test_get_table_cols(self):
exp = {"email", "user_level_id", "password", "name", "affiliation",
"address", "phone", "user_verify_code", "pass_reset_code",
"pass_reset_timestamp", "receive_processing_job_emails",
"social_orcid", "social_researchgate", "social_googlescholar"}
"social_orcid", "social_researchgate", "social_googlescholar",
"creation_timestamp"}
self.assertEqual(set(obs), exp)

def test_exists_table(self):
Expand Down
8 changes: 6 additions & 2 deletions qiita_pet/handlers/user_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ class UserProfileHandler(BaseHandler):
def get(self):
profile = UserProfile()
profile.process(data=self.current_user.info)
self.render("user_profile.html", profile=profile, msg="", passmsg="")
self.render("user_profile.html", profile=profile, msg="", passmsg="",
creation_timestamp=self.current_user.info[
'creation_timestamp'])

@authenticated
@execute_as_transaction
Expand Down Expand Up @@ -248,7 +250,9 @@ def post(self):
else:
passmsg = "Incorrect old password"
self.render("user_profile.html", user=user.id, profile=form_data,
msg=msg, passmsg=passmsg)
msg=msg, passmsg=passmsg,
creation_timestamp=self.current_user.info[
'creation_timestamp'])


class ForgotPasswordHandler(BaseHandler):
Expand Down
3 changes: 3 additions & 0 deletions qiita_pet/templates/user_profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ <h3>User Information</h3>
{% end %}
</div>
{% end %}
{%if creation_timestamp is not None %}
<div style="padding-left: 1em; padding-bottom: 1em; color: grey;">account created on {{creation_timestamp}}</div>
{% end %}
<div style="color:{% if msg.startswith('ERROR:') %}red{% else %}darkgreen{% end %};">{{msg}}</div>
<button type="submit" class="btn btn-success">Save Edits</button>
</form>
Expand Down
Loading