From 628e7917f1ef9940490afcd43cdfcef7eaf514d4 Mon Sep 17 00:00:00 2001 From: Dimitra Chatzichrysou <dimitra.chatzichrysou@cern.ch> Date: Fri, 17 Dec 2021 12:29:37 +0100 Subject: [PATCH] [#62] Replace whitelist with group --- .env | 6 +- .env-email-daily | 6 +- .env-email-monthly | 6 +- .env-email-weekly | 7 +- .env.email-dlq | 6 +- .env.email-gateway-failure | 6 +- .isort.cfg | 2 +- README.md | 1 - .../authorization_service.py | 14 ++ notifications_consumer/config.py | 8 +- notifications_consumer/email_whitelist.py | 30 +++ .../processors/email/processor.py | 13 +- .../processors/email_feed/processor.py | 13 +- poetry.lock | 229 +++++++++++++++++- pyproject.toml | 2 + scripts/docker-send-email.py | 35 +-- 16 files changed, 348 insertions(+), 36 deletions(-) create mode 100644 notifications_consumer/email_whitelist.py diff --git a/.env b/.env index 3501355..14e0705 100644 --- a/.env +++ b/.env @@ -24,15 +24,13 @@ EMAIL_HOST_PASSWORD=password EMAIL_USE_TLS=None EMAIL_USE_SSL=None EMAIL_TIMEOUT=10 -EMAIL_WHITELIST=["user@cern.ch"] +EMAIL_WHITELIST_GROUP_ID=notifications-dev-users +EMAIL_AES_SECRET_KEY=fill-mefill-mefill-mefill-mefill CERN_OIDC_CLIENT_ID=notifications-dev CERN_OIDC_CLIENT_SECRET=fill-me -EMAIL_AES_SECRET_KEY=fill-mefill-mefill-mefill-mefill - # SMIME signed emails #EMAIL_BACKEND=vendor.django_mail.backends.smimesmtp.EmailBackend #EMAIL_SMIME_CERT_FILE_PATH=/etc/notifications-noreply.pem #EMAIL_SMIME_CERT_KEY_FILE_PATH=/etc/notifications-noreply-key.pem - diff --git a/.env-email-daily b/.env-email-daily index da378cb..dbea626 100644 --- a/.env-email-daily +++ b/.env-email-daily @@ -24,6 +24,10 @@ EMAIL_HOST_PASSWORD=password EMAIL_USE_TLS=None EMAIL_USE_SSL=None EMAIL_TIMEOUT=10 -EMAIL_WHITELIST=["user@cern.ch"] +EMAIL_WHITELIST_GROUP_ID=notifications-dev-users +EMAIL_AES_SECRET_KEY=fill-mefill-mefill-mefill-mefill + +CERN_OIDC_CLIENT_ID=notifications-dev +CERN_OIDC_CLIENT_SECRET=fill-me FEED_TITLE=Daily diff --git a/.env-email-monthly b/.env-email-monthly index 9648d9a..7bb1ce4 100644 --- a/.env-email-monthly +++ b/.env-email-monthly @@ -24,6 +24,10 @@ EMAIL_HOST_PASSWORD=password EMAIL_USE_TLS=None EMAIL_USE_SSL=None EMAIL_TIMEOUT=10 -EMAIL_WHITELIST=["user@cern.ch"] +EMAIL_WHITELIST_GROUP_ID=notifications-dev-users +EMAIL_AES_SECRET_KEY=fill-mefill-mefill-mefill-mefill + +CERN_OIDC_CLIENT_ID=notifications-dev +CERN_OIDC_CLIENT_SECRET=fill-me FEED_TITLE=Monthly diff --git a/.env-email-weekly b/.env-email-weekly index d26d3b4..5b34634 100644 --- a/.env-email-weekly +++ b/.env-email-weekly @@ -2,7 +2,6 @@ ENV=development PROCESSOR=email_feed CONSUMER_NAME=email_weekly_consumer PUBLISHER_NAME=email_weekly_publisher -FEED_SUMMARY=Weekly POSTGRES_USER=admin POSTGRES_PASSWORD=password @@ -25,6 +24,10 @@ EMAIL_HOST_PASSWORD=password EMAIL_USE_TLS=None EMAIL_USE_SSL=None EMAIL_TIMEOUT=10 -EMAIL_WHITELIST=["user@cern.ch"] +EMAIL_WHITELIST_GROUP_ID=notifications-dev-users +EMAIL_AES_SECRET_KEY=fill-mefill-mefill-mefill-mefill + +CERN_OIDC_CLIENT_ID=notifications-dev +CERN_OIDC_CLIENT_SECRET=fill-me FEED_TITLE=Weekly diff --git a/.env.email-dlq b/.env.email-dlq index c0dcaf0..5f98575 100644 --- a/.env.email-dlq +++ b/.env.email-dlq @@ -24,4 +24,8 @@ EMAIL_HOST_PASSWORD=password EMAIL_USE_TLS=None EMAIL_USE_SSL=None EMAIL_TIMEOUT=10 -EMAIL_WHITELIST=["user@cern.ch"] +EMAIL_WHITELIST_GROUP_ID=notifications-dev-users +EMAIL_AES_SECRET_KEY=fill-mefill-mefill-mefill-mefill + +CERN_OIDC_CLIENT_ID=notifications-dev +CERN_OIDC_CLIENT_SECRET=fill-me diff --git a/.env.email-gateway-failure b/.env.email-gateway-failure index d620cf7..a5bc795 100644 --- a/.env.email-gateway-failure +++ b/.env.email-gateway-failure @@ -23,4 +23,8 @@ EMAIL_HOST_USER=user@cern.ch EMAIL_USE_TLS=None EMAIL_USE_SSL=None EMAIL_TIMEOUT=10 -EMAIL_WHITELIST=["user@cern.ch"] +EMAIL_WHITELIST_GROUP_ID=notifications-dev-users +EMAIL_AES_SECRET_KEY=fill-mefill-mefill-mefill-mefill + +CERN_OIDC_CLIENT_ID=notifications-dev +CERN_OIDC_CLIENT_SECRET=fill-me diff --git a/.isort.cfg b/.isort.cfg index 3213b0f..918f3dd 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -4,4 +4,4 @@ multi_line_output=3 include_trailing_comma=True lines_after_imports=2 not_skip=__init__.py -known_third_party = Crypto,apns2,jinja2,mattermostdriver,megabus,pytest,pywebpush,requests,smail,sqlalchemy,stomp,yaml +known_third_party = Crypto,apns2,cachetools,jinja2,mattermostdriver,megabus,pytest,pywebpush,requests,smail,sqlalchemy,stomp,yaml diff --git a/README.md b/README.md index 8ef9c76..6e7203b 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,6 @@ Requirements: EMAIL_USE_TLS=None EMAIL_USE_SSL=None EMAIL_TIMEOUT=10 - EMAIL_WHITELIST=["<your-email>@cern.ch"] ``` Note: `EMAIL_HOST_PASSWORD` can't be in the `.env`. diff --git a/notifications_consumer/authorization_service.py b/notifications_consumer/authorization_service.py index 0479880..735a45d 100644 --- a/notifications_consumer/authorization_service.py +++ b/notifications_consumer/authorization_service.py @@ -33,3 +33,17 @@ def get_group_users_api(group_id: str): raise BadResponseCodeError(url, status_code=response.status_code) return json.loads(response.content) + + +def get_group_member_groups_api(group_id: str): + """Get member groups of a group.""" + token = get_auth_access_token() + headers = {"Authorization": "Bearer {}".format(token)} + + url = os.path.join(config.Config.CERN_GROUP_URL, group_id, config.Config.CERN_GROUP_MEMBER_GROUPS_QUERY) + response = requests.get(url, headers=headers) + + if response.status_code != requests.codes.ok: + raise BadResponseCodeError(url, status_code=response.status_code) + + return json.loads(response.content) diff --git a/notifications_consumer/config.py b/notifications_consumer/config.py index a1d3dd4..b07196a 100644 --- a/notifications_consumer/config.py +++ b/notifications_consumer/config.py @@ -38,6 +38,9 @@ class Config: CERN_GROUP_QUERY = os.getenv( "CERN_GROUP_QUERY", "memberidentities?field=upn&field=primaryAccountEmail&recursive=true" ) + CERN_GROUP_MEMBER_GROUPS_QUERY = os.getenv( + "CERN_GROUP_MEMBER_GROUPS_QUERY", "membergroups?field=idl&recursive=true" + ) # ActiveMQ CONSUMER_NAME = os.getenv("CONSUMER_NAME") @@ -52,7 +55,7 @@ class Config: EMAIL_USE_TLS = ast.literal_eval(os.getenv("EMAIL_USE_TLS", "False")) EMAIL_USE_SSL = ast.literal_eval(os.getenv("EMAIL_USE_SSL", "False")) EMAIL_TIMEOUT = int(os.getenv("EMAIL_TIMEOUT", "10")) - EMAIL_WHITELIST = ast.literal_eval(os.getenv("EMAIL_WHITELIST", "['user@cern.ch']")) + EMAIL_WHITELIST_GROUP_ID = os.getenv("EMAIL_WHITELIST_GROUP_ID", "notifications-dev-users") EMAIL_BACKEND = os.getenv("EMAIL_BACKEND", "vendor.django_mail.backends.console.EmailBackend") @@ -128,6 +131,9 @@ class Config: # Feed email title FEED_TITLE = os.getenv("FEED_TITLE", "Daily") + # Cache + CACHE_TTL = int(os.getenv("CACHE_TTL", 86400)) + class DevelopmentConfig(Config): """Development configuration overrides.""" diff --git a/notifications_consumer/email_whitelist.py b/notifications_consumer/email_whitelist.py new file mode 100644 index 0000000..3bb7085 --- /dev/null +++ b/notifications_consumer/email_whitelist.py @@ -0,0 +1,30 @@ +"""Email whitelist methods.""" + +from typing import Set + +from cachetools import TTLCache, cached + +from notifications_consumer.authorization_service import get_group_member_groups_api, get_group_users_api +from notifications_consumer.config import Config + + +@cached(cache=TTLCache(maxsize=1024, ttl=Config.CACHE_TTL)) +def get_email_whitelist(group_id: str) -> Set[str]: + """Return all the members' emails of the whitelist group.""" + email_whitelist = get_group_members_emails(group_id) + + group_member_groups_response = get_group_member_groups_api(group_id) + + if group_member_groups_response["data"]: + for member_group in group_member_groups_response["data"]: + emails = get_group_members_emails(member_group["id"]) + email_whitelist.update(emails) + + return email_whitelist + + +def get_group_members_emails(group_id: str) -> Set[str]: + """Return the emails of group members.""" + group_members_response = get_group_users_api(group_id) + + return {member["primaryAccountEmail"] for member in group_members_response["data"]} diff --git a/notifications_consumer/processors/email/processor.py b/notifications_consumer/processors/email/processor.py index 3bac1fc..8827a11 100644 --- a/notifications_consumer/processors/email/processor.py +++ b/notifications_consumer/processors/email/processor.py @@ -4,6 +4,7 @@ from datetime import datetime from typing import Dict from notifications_consumer.config import ENV_DEV, Config +from notifications_consumer.email_whitelist import get_email_whitelist from notifications_consumer.processors.email.utils import create_email, send_emails from notifications_consumer.processors.processor import Processor from notifications_consumer.processors.registry import ProcessorRegistry @@ -30,9 +31,15 @@ class EmailProcessor(Processor): logging.debug("%s - status:running - kwargs:%r", self, kwargs) recipient_email = kwargs["email"] - if Config.ENV == ENV_DEV and recipient_email not in Config.EMAIL_WHITELIST: - logging.info("Email recipient <%s> isn't on the EMAIL_WHITELIST. Email sent is skipped.", recipient_email) - return + if Config.ENV == ENV_DEV: + email_whitelist = get_email_whitelist(Config.EMAIL_WHITELIST_GROUP_ID) + if recipient_email not in email_whitelist: + logging.info( + "Email recipient <%s> isn't on the email whitelist (<%s>). Email sent is skipped.", + recipient_email, + Config.EMAIL_WHITELIST_GROUP_ID, + ) + return created_at = kwargs.get("created_at", "") try: diff --git a/notifications_consumer/processors/email_feed/processor.py b/notifications_consumer/processors/email_feed/processor.py index 9f3eadd..a3bd0e4 100644 --- a/notifications_consumer/processors/email_feed/processor.py +++ b/notifications_consumer/processors/email_feed/processor.py @@ -5,6 +5,7 @@ from datetime import datetime from typing import Dict from notifications_consumer.config import ENV_DEV, Config +from notifications_consumer.email_whitelist import get_email_whitelist from notifications_consumer.processors.email.utils import create_email, send_emails from notifications_consumer.processors.processor import Processor from notifications_consumer.processors.registry import ProcessorRegistry @@ -37,9 +38,15 @@ class EmailFeedProcessor(Processor): user_id = kwargs["user_id"] recipient_email = self.data_source.get_user_email(user_id) - if Config.ENV == ENV_DEV and recipient_email not in Config.EMAIL_WHITELIST: - logging.info("Email recipient <%s> isn't on the EMAIL_WHITELIST. Email sent is skipped.", recipient_email) - return + if Config.ENV == ENV_DEV: + email_whitelist = get_email_whitelist(Config.EMAIL_WHITELIST_GROUP_ID) + if recipient_email not in email_whitelist: + logging.info( + "Email recipient <%s> isn't on the email whitelist (<%s>). Email sent is skipped.", + recipient_email, + Config.EMAIL_WHITELIST_GROUP_ID, + ) + return title = f'{Config.FEED_TITLE} Summary - {datetime.now().strftime("%d %B %Y")}' subject = f"[{Config.SERVICE_NAME}] {title}" diff --git a/poetry.lock b/poetry.lock index ef7a89a..64031fe 100644 --- a/poetry.lock +++ b/poetry.lock @@ -22,6 +22,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "appnope" +version = "0.1.2" +description = "Disable App Nap on macOS >= 10.9" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "asn1crypto" version = "1.4.0" @@ -52,6 +60,22 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "cachetools" +version = "4.2.4" +description = "Extensible memoizing collections and decorators" +category = "main" +optional = false +python-versions = "~=3.5" + [[package]] name = "certifi" version = "2020.12.5" @@ -114,6 +138,14 @@ sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +[[package]] +name = "decorator" +version = "5.1.0" +description = "Decorators for Humans" +category = "dev" +optional = false +python-versions = ">=3.5" + [[package]] name = "distlib" version = "0.3.1" @@ -284,6 +316,60 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "ipython" +version = "7.16.2" +description = "IPython: Productive Interactive Computing" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.10,<=0.17.2" +pexpect = {version = "*", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" +pygments = "*" +traitlets = ">=4.2" + +[package.extras] +all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.14)", "pygments", "qtconsole", "requests", "testpath"] +doc = ["Sphinx (>=1.3)"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["notebook", "ipywidgets"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.14)"] + +[[package]] +name = "ipython-genutils" +version = "0.2.0" +description = "Vestigial utilities from IPython" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "jedi" +version = "0.17.2" +description = "An autocompletion tool for Python that can be used for text editors." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +parso = ">=0.7.0,<0.8.0" + +[package.extras] +qa = ["flake8 (==3.7.9)"] +testing = ["Django (<3.1)", "colorama", "docopt", "pytest (>=3.9.0,<5.0.0)"] + [[package]] name = "jinja2" version = "2.11.3" @@ -356,6 +442,36 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pyparsing = ">=2.0.2" +[[package]] +name = "parso" +version = "0.7.1" +description = "A Python Parser" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +testing = ["docopt", "pytest (>=3.0.7)"] + +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "pluggy" version = "0.13.1" @@ -388,6 +504,17 @@ pyyaml = ">=5.1" toml = "*" virtualenv = ">=20.0.8" +[[package]] +name = "prompt-toolkit" +version = "3.0.19" +description = "Library for building powerful interactive command lines in Python" +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +wcwidth = "*" + [[package]] name = "psycopg2-binary" version = "2.8.6" @@ -396,6 +523,14 @@ category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "py" version = "1.10.0" @@ -458,6 +593,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pygments" +version = "2.10.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.5" + [[package]] name = "pyjwt" version = "1.7.1" @@ -640,6 +783,22 @@ category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "traitlets" +version = "4.3.3" +description = "Traitlets Python config system" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +decorator = "*" +ipython-genutils = "*" +six = "*" + +[package.extras] +test = ["pytest", "mock"] + [[package]] name = "typing-extensions" version = "3.10.0.0" @@ -689,6 +848,14 @@ six = ">=1.9.0,<2" docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)", "xonsh (>=0.9.16)"] +[[package]] +name = "wcwidth" +version = "0.2.5" +description = "Measures the displayed width of unicode strings in a terminal" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "websockets" version = "9.1" @@ -712,7 +879,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.6.1" -content-hash = "7373c8e971edeb715dccf372829746539216d2754488c51284df267389a8aa75" +content-hash = "27d4bfdf8b68e1142fe5433e499d2b540e4b484b68ed7e0ee20fb92c7464b3d3" [metadata.files] apns2 = [ @@ -723,6 +890,10 @@ appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] +appnope = [ + {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, + {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, +] asn1crypto = [ {file = "asn1crypto-1.4.0-py2.py3-none-any.whl", hash = "sha256:4bcdf33c861c7d40bdcd74d8e4dd7661aac320fcdf40b9a3f95b4ee12fde2fa8"}, {file = "asn1crypto-1.4.0.tar.gz", hash = "sha256:f4f6e119474e58e04a2b1af817eb585b4fd72bdd89b998624712b5c99be7641c"}, @@ -735,6 +906,14 @@ attrs = [ {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] +backcall = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] +cachetools = [ + {file = "cachetools-4.2.4-py3-none-any.whl", hash = "sha256:92971d3cb7d2a97efff7c7bb1657f21a8f5fb309a37530537c71b1774189f2d1"}, + {file = "cachetools-4.2.4.tar.gz", hash = "sha256:89ea6f1b638d5a73a4f9226be57ac5e4f399d22770b92355f92dcb0f7f001693"}, +] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, @@ -818,6 +997,10 @@ cryptography = [ {file = "cryptography-3.4.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bf40af59ca2465b24e54f671b2de2c59257ddc4f7e5706dbd6930e26823668d3"}, {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"}, ] +decorator = [ + {file = "decorator-5.1.0-py3-none-any.whl", hash = "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374"}, + {file = "decorator-5.1.0.tar.gz", hash = "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7"}, +] distlib = [ {file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"}, {file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"}, @@ -879,6 +1062,18 @@ iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] +ipython = [ + {file = "ipython-7.16.2-py3-none-any.whl", hash = "sha256:2f644313be4fdc5c8c2a17467f2949c29423c9e283a159d1fc9bf450a1a300af"}, + {file = "ipython-7.16.2.tar.gz", hash = "sha256:613085f8acb0f35f759e32bea35fba62c651a4a2e409a0da11414618f5eec0c4"}, +] +ipython-genutils = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] +jedi = [ + {file = "jedi-0.17.2-py2.py3-none-any.whl", hash = "sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"}, + {file = "jedi-0.17.2.tar.gz", hash = "sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20"}, +] jinja2 = [ {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, @@ -938,6 +1133,18 @@ packaging = [ {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] +parso = [ + {file = "parso-0.7.1-py2.py3-none-any.whl", hash = "sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea"}, + {file = "parso-0.7.1.tar.gz", hash = "sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"}, +] +pexpect = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] +pickleshare = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, @@ -946,6 +1153,10 @@ pre-commit = [ {file = "pre_commit-2.9.3-py2.py3-none-any.whl", hash = "sha256:6c86d977d00ddc8a60d68eec19f51ef212d9462937acf3ea37c7adec32284ac0"}, {file = "pre_commit-2.9.3.tar.gz", hash = "sha256:ee784c11953e6d8badb97d19bc46b997a3a9eded849881ec587accd8608d74a4"}, ] +prompt-toolkit = [ + {file = "prompt_toolkit-3.0.19-py3-none-any.whl", hash = "sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"}, + {file = "prompt_toolkit-3.0.19.tar.gz", hash = "sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f"}, +] psycopg2-binary = [ {file = "psycopg2-binary-2.8.6.tar.gz", hash = "sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0"}, {file = "psycopg2_binary-2.8.6-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4"}, @@ -983,6 +1194,10 @@ psycopg2-binary = [ {file = "psycopg2_binary-2.8.6-cp39-cp39-win32.whl", hash = "sha256:6422f2ff0919fd720195f64ffd8f924c1395d30f9a495f31e2392c2efafb5056"}, {file = "psycopg2_binary-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6"}, ] +ptyprocess = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, @@ -1009,6 +1224,10 @@ pyflakes = [ {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] +pygments = [ + {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, + {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, +] pyjwt = [ {file = "PyJWT-1.7.1-py2.py3-none-any.whl", hash = "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e"}, {file = "PyJWT-1.7.1.tar.gz", hash = "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"}, @@ -1123,6 +1342,10 @@ toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +traitlets = [ + {file = "traitlets-4.3.3-py2.py3-none-any.whl", hash = "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44"}, + {file = "traitlets-4.3.3.tar.gz", hash = "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7"}, +] typing-extensions = [ {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, @@ -1139,6 +1362,10 @@ virtualenv = [ {file = "virtualenv-20.4.6-py2.py3-none-any.whl", hash = "sha256:307a555cf21e1550885c82120eccaf5acedf42978fd362d32ba8410f9593f543"}, {file = "virtualenv-20.4.6.tar.gz", hash = "sha256:72cf267afc04bf9c86ec932329b7e94db6a0331ae9847576daaa7ca3c86b29a4"}, ] +wcwidth = [ + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +] websockets = [ {file = "websockets-9.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d144b350045c53c8ff09aa1cfa955012dd32f00c7e0862c199edcabb1a8b32da"}, {file = "websockets-9.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b4ad84b156cf50529b8ac5cc1638c2cf8680490e3fccb6121316c8c02620a2e4"}, diff --git a/pyproject.toml b/pyproject.toml index aed62f7..889db5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,12 +21,14 @@ unittest = "^0.0" pycrypto = "^2.6.1" python-smail = "^0.9.0" mattermostdriver = "^7.3.1" +cachetools = "^4.2.4" [tool.poetry.dev-dependencies] pre-commit = "~2.9.2" flake8 = "~3.8.3" flake8-docstrings = "~1.5.0" flake8-logging-format = "^0.6.0" +ipython = ">=7.14" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/scripts/docker-send-email.py b/scripts/docker-send-email.py index 4a8c054..7321e0b 100644 --- a/scripts/docker-send-email.py +++ b/scripts/docker-send-email.py @@ -1,12 +1,14 @@ """Utility to send one message inside docker environment.""" -import stomp import argparse import json -parser = argparse.ArgumentParser(description='Send a test email notification.') -parser.add_argument('-l', action='store_true', default=False, help='use to connect to localhost instead of activemq') -parser.add_argument('-c', action='store_true', default=False, help='use to send an email with Category') -parser.add_argument('-e', default='user', help='use to set a target email username') +import stomp + + +parser = argparse.ArgumentParser(description="Send a test email notification.") +parser.add_argument("-l", action="store_true", default=False, help="use to connect to localhost instead of activemq") +parser.add_argument("-c", action="store_true", default=False, help="use to send an email with Category") +parser.add_argument("-e", default="user@cern.ch", help="use to set a target email username") args = parser.parse_args() category = args.c email = args.e @@ -18,18 +20,19 @@ conn = stomp.Connection([(connection_target, 61613)]) conn.connect("admin", "admin", wait=True) message = { -"channel_name": "My Channel", -"channel_id": "123", -"message_body": "<p>Dear subscribers,</p>\n\n<p>This week news follows. </p>\n\n<p> </p>\n\n<p><strong>Topic 1</strong></p>\n\n<ul>\n\t<li>bla </li>\n\t<li>bla</li>\n\t<li>bla</li>\n</ul>\n\n<p> </p>\n\n<p><strong>Topic 2</strong></p>\n\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n\n<p> </p>\n\n<p>See you next week,</p>\n\n<p>Myself.</p>\n", -"summary": "This week news!", -"created_at": "07/21/2021, 16:10:09", -"notification_id": "BD19EEA4-9DCA-48D9-A577-5DE9D2BF374A", -"link": "http://toto.cern.ch", -"priority": "important" + "channel_name": "My Channel", + "channel_id": "123", + "message_body": "<p>Dear subscribers,</p>\n\n<p>This week news follows. </p>\n\n<p> </p>\n\n<p><strong>Topic 1</strong></p>\n\n<ul>\n\t<li>bla </li>\n\t<li>bla</li>\n\t<li>bla</li>\n</ul>\n\n<p> </p>\n\n<p><strong>Topic 2</strong></p>\n\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n\n<p> </p>\n\n<p>See you next week,</p>\n\n<p>Myself.</p>\n", + "summary": "This week news!", + "created_at": "07/21/2021, 16:10:09", + "notification_id": "BD19EEA4-9DCA-48D9-A577-5DE9D2BF374A", + "link": "http://toto.cern.ch", + "priority": "important", } -message["email"] = email + "@cern.ch" -if category: message["category_name"] = "Super Duper Category" +message["email"] = email +if category: + message["category_name"] = "Super Duper Category" -conn.send(body=json.dumps(message, indent = 4), destination="/queue/np.email", headers={"persistent": "true"}) +conn.send(body=json.dumps(message, indent=4), destination="/queue/np.email", headers={"persistent": "true"}) conn.disconnect() -- GitLab