diff --git a/qiita_db/handlers/tests/test_user.py b/qiita_db/handlers/tests/test_user.py index 38831471b..4898976ce 100644 --- a/qiita_db/handlers/tests/test_user.py +++ b/qiita_db/handlers/tests/test_user.py @@ -51,10 +51,11 @@ def test_get(self): obs = loads(obs.body) exp = {'data': [ - {'email': 'test@foo.bar', 'name': 'Dude'}, {'email': 'shared@foo.bar', 'name': 'Shared'}, {'email': 'admin@foo.bar', 'name': 'Admin'}, - {'email': 'demo@microbio.me', 'name': 'Demo'}]} + {'email': 'demo@microbio.me', 'name': 'Demo'}, + {'email': 'test@foo.bar', 'name': 'Dude'} + ]} self.assertEqual(obs, exp) diff --git a/qiita_db/support_files/patches/92.sql b/qiita_db/support_files/patches/92.sql index ad1989b2e..2162533d4 100644 --- a/qiita_db/support_files/patches/92.sql +++ b/qiita_db/support_files/patches/92.sql @@ -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 = 'test@foo.bar'; diff --git a/qiita_db/test/test_user.py b/qiita_db/test/test_user.py index 666746c36..0d14d2c8a 100644 --- a/qiita_db/test/test_user.py +++ b/qiita_db/test/test_user.py @@ -75,7 +75,8 @@ def setUp(self): 'receive_processing_job_emails': True, '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): @@ -88,7 +89,22 @@ def test_instantiate_unknown_user(self): with self.assertRaises(qdb.exceptions.QiitaDBUnknownIDError): qdb.user.User('FAIL@OMG.bar') - 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 @@ -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('testcreateuser@test.bar', 'password') # adding a couple of messages @@ -131,8 +151,9 @@ def test_create_user(self): 'email': 'testcreateuser@test.bar', '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 @@ -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('testcreateuserinfo@test.bar', 'password', self.userinfo) self.assertEqual(user.id, 'testcreateuserinfo@test.bar') @@ -171,8 +193,9 @@ def test_create_user_info(self): 'email': 'testcreateuserinfo@test.bar', '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" @@ -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): diff --git a/qiita_db/test/test_util.py b/qiita_db/test/test_util.py index 1ca0755b5..2dfc31bfa 100644 --- a/qiita_db/test/test_util.py +++ b/qiita_db/test/test_util.py @@ -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): diff --git a/qiita_pet/handlers/user_handlers.py b/qiita_pet/handlers/user_handlers.py index d75316a80..cd65f18c7 100644 --- a/qiita_pet/handlers/user_handlers.py +++ b/qiita_pet/handlers/user_handlers.py @@ -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 @@ -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): diff --git a/qiita_pet/templates/user_profile.html b/qiita_pet/templates/user_profile.html index 66da290d9..5f5336d95 100644 --- a/qiita_pet/templates/user_profile.html +++ b/qiita_pet/templates/user_profile.html @@ -27,6 +27,9 @@

User Information

{% end %} {% end %} + {%if creation_timestamp is not None %} +
account created on {{creation_timestamp}}
+ {% end %}
{{msg}}