diff --git a/rendercv/data_model.py b/rendercv/data_model.py index fceb1cd..8412cc3 100644 --- a/rendercv/data_model.py +++ b/rendercv/data_model.py @@ -1057,30 +1057,50 @@ class Connection(BaseModel): value: str @staticmethod - def MastodonUname2Url(id: str) -> Optional[HttpUrl]: - """From a Mastodon id "user@domain.example" returns profile url.""" + def MastodonUname2Url(address: str) -> Optional[HttpUrl]: + """returns profile url from a mastodon user address. + + Args: + address (str): A Mastodon user address. E.g., "user@social.example" + + Returns: + A pydantic HttpUrl object with the https URL for the user profile + + Example: + ``` + url = MastodonUname2Url("user@social.example") + assert(url == HttpUrl(http://social.example/@user)) + ``` + + Exceptions: + ValueError if the address is malformed. + """ # The closest thing to a formal spec of Mastodon usernames - # where these regular expressions from a (reference?) + # where these regular expressions from a (reference?) # implementation # # https://github.com/mastodon/mastodon/blob/852123867768e23410af5bd07ac0327bead0d9b2/app/models/account.rb#L68 # # USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i # SERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i - # MENTION_RE = %r{(?[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?) # username part @ # separator - (?P[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?) # domain part + (?P[a-z0-9]+([a-z0-9.-]+[a-z0-9]+)?) # domain part \s*$ # ignore trailing whitespace """, re.VERBOSE | re.IGNORECASE) - m = pattern.match(id) + m = pattern.match(address) if m is None: raise ValueError("Invalid mastodon address") uname = m.group("uname") diff --git a/tests/test_data_model.py b/tests/test_data_model.py index 381245d..7bab82c 100644 --- a/tests/test_data_model.py +++ b/tests/test_data_model.py @@ -862,14 +862,14 @@ class TestDataModel(unittest.TestCase): data_model.read_input_file("nonexistent.json") def test_mastodon_parsing(self): - mastodon_name = 'jpgoldberg@ioc.exchange' - expected = HttpUrl("https://ioc.exchange/@jpgoldberg") + mastodon_name = 'a_tooter@example.exchange' + expected = HttpUrl("https://example.exchange/@a_tooter") result = data_model.Connection.MastodonUname2Url(mastodon_name) with self.subTest("Without '@' prefix"): self.assertEqual(result, expected) - mastodon_name = '@jpgoldberg@ioc.exchange' - expected = HttpUrl("https://ioc.exchange/@jpgoldberg") + mastodon_name = '@a_tooter@example.exchange' + expected = HttpUrl("https://example.exchange/@a_tooter") result = data_model.Connection.MastodonUname2Url(mastodon_name) with self.subTest("With '@' prefix"): self.assertEqual(result, expected) @@ -879,5 +879,17 @@ class TestDataModel(unittest.TestCase): with self.assertRaises(ValueError): data_model.Connection.MastodonUname2Url(mastodon_name) + mastodon_name = '@not_enough_at_symbols' + with self.subTest("Missing '@' separator"): + with self.assertRaises(ValueError): + data_model.Connection.MastodonUname2Url(mastodon_name) + + mastodon_name = 'user@bad_domain.example' + with self.subTest("Underscore in domain portion"): + with self.assertRaises(ValueError): + data_model.Connection.MastodonUname2Url(mastodon_name) + + + if __name__ == '__main__': unittest.main()