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

Custom routes + Further notification cleanup #309

Merged
merged 3 commits into from
Oct 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions amundsen_application/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,8 @@ def create_app(config_module_class: str, template_folder: str = None) -> Flask:
app.register_blueprint(search_blueprint)
init_routes(app)

init_custom_routes = app.config.get('INIT_CUSTOM_ROUTES')
if init_custom_routes:
init_custom_routes(app)

return app
43 changes: 33 additions & 10 deletions amundsen_application/api/utils/notification_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging

from http import HTTPStatus
from enum import Enum

from flask import current_app as app
from flask import jsonify, make_response, Response
Expand All @@ -9,8 +10,27 @@
from amundsen_application.api.exceptions import MailClientNotImplemented
from amundsen_application.log.action_log import action_logging


class NotificationType(str, Enum):
"""
Enum to describe supported notification types. Must match NotificationType interface defined in:
https://github.com/lyft/amundsenfrontendlibrary/blob/master/amundsen_application/static/js/interfaces/Notifications.ts
"""
OWNER_ADDED = 'owner_added'
OWNER_REMOVED = 'owner_removed'
METADATA_EDITED = 'metadata_edited'
METADATA_REQUESTED = 'metadata_requested'

@classmethod
def has_value(cls, value: str) -> bool:
for key in cls:
if key.value == value:
return True
return False


NOTIFICATION_STRINGS = {
'added': {
NotificationType.OWNER_ADDED.value: {
'comment': ('<br/>What is expected of you?<br/>As an owner, you take an important part in making '
'sure that the datasets you own can be used as swiftly as possible across the company.<br/>'
'Make sure the metadata is correct and up to date.<br/>'),
Expand All @@ -20,14 +40,14 @@
'notification': ('<br/>You have been added to the owners list of the <a href="{resource_url}">'
'{resource_name}</a> dataset by {sender}.<br/>'),
},
'removed': {
NotificationType.OWNER_REMOVED.value: {
'comment': '',
'end_note': ('<br/>If you think you have been incorrectly removed as an owner, '
'add yourself back to the owners list.<br/>'),
'notification': ('<br/>You have been removed from the owners list of the <a href="{resource_url}">'
'{resource_name}</a> dataset by {sender}.<br/>'),
},
'requested': {
NotificationType.METADATA_REQUESTED.value: {
'comment': '',
'end_note': '<br/>Please visit the provided link and improve descriptions on that resource.<br/>',
'notification': '<br/>{sender} is trying to use <a href="{resource_url}">{resource_name}</a>, ',
Expand Down Expand Up @@ -84,7 +104,7 @@ def get_notification_html(*, notification_type: str, options: Dict, sender: str)
end_note = notification_strings.get('end_note', '')
salutation = '<br/>Thanks,<br/>Amundsen Team'

if notification_type == 'requested':
if notification_type == NotificationType.METADATA_REQUESTED:
options_comment = options.get('comment')
need_resource_description = options.get('description_requested')
need_fields_descriptions = options.get('fields_requested')
Expand Down Expand Up @@ -118,12 +138,15 @@ def get_notification_subject(*, notification_type: str, options: Dict) -> str:
"""
resource_name = options.get('resource_name')
notification_subject_dict = {
'added': 'You are now an owner of {}'.format(resource_name),
'removed': 'You have been removed as an owner of {}'.format(resource_name),
'edited': 'Your dataset {}\'s metadata has been edited'.format(resource_name),
'requested': 'Request for metadata on {}'.format(resource_name),
NotificationType.OWNER_ADDED.value: 'You are now an owner of {}'.format(resource_name),
NotificationType.OWNER_REMOVED.value: 'You have been removed as an owner of {}'.format(resource_name),
NotificationType.METADATA_EDITED.value: 'Your dataset {}\'s metadata has been edited'.format(resource_name),
NotificationType.METADATA_REQUESTED.value: 'Request for metadata on {}'.format(resource_name),
}
return notification_subject_dict.get(notification_type, '')
subject = notification_subject_dict.get(notification_type)
if subject is None:
raise Exception('Unsupported notification_type')
return subject


def send_notification(*, notification_type: str, options: Dict, recipients: List, sender: str) -> Response:
Expand Down Expand Up @@ -174,7 +197,7 @@ def _log_send_notification(*, notification_type: str, options: Dict, recipients:
subject=subject,
html=html,
optional_data={
'email_type': 'notification'
'email_type': notification_type,
},
)
status_code = response.status_code
Expand Down
8 changes: 7 additions & 1 deletion amundsen_application/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import os
from typing import Dict, Optional, Set # noqa: F401
from typing import Callable, Dict, Optional, Set # noqa: F401

from flask import Flask # noqa: F401

from amundsen_application.tests.test_utils import get_test_user


Expand All @@ -22,6 +25,9 @@ class Config:
MAIL_CLIENT = None
NOTIFICATIONS_ENABLED = False

# Initialize custom routes
INIT_CUSTOM_ROUTES = None # type: Callable[[Flask], None]


class LocalConfig(Config):
DEBUG = False
Expand Down
9 changes: 4 additions & 5 deletions amundsen_application/static/js/interfaces/Notifications.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// TODO: Remove notification types that can be triggered in flask layer if necessary
export enum NotificationType {
OWNER_ADDED = 'added',
OWNER_REMOVED = 'removed',
METADATA_EDITED = 'edited',
METADATA_REQUESTED = 'requested',
OWNER_ADDED = 'owner_added',
OWNER_REMOVED = 'owner_removed',
METADATA_EDITED = 'metadata_edited',
METADATA_REQUESTED = 'metadata_requested',
}

export enum RequestMetadataType {
Expand Down
12 changes: 12 additions & 0 deletions docs/flask_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ After modifying any variable in [config.py](https://github.com/lyft/amundsenfron

**NOTE: This document is a work in progress and does not include 100% of features. We welcome PRs to complete this document**

## Custom Routes
In order to add any custom Flask endpoints to Amundsen's frontend application, configure a function on the `INIT_CUSTOM_ROUTES` variable. This function takes the created Flask application and can leverage Flask's [add_url_rule](https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.add_url_rule) method to add custom routes.

Example: Setting `INIT_CUSTOM_ROUTES` to the `init_custom_routes` method below will expose a `/custom_route` endpoint on the frontend application.
```bash
def init_custom_routes(app: Flask) -> None:
app.add_url_rule('/custom_route', 'custom_route', custom_route)

def custom_route():
pass
```

## Mail Client Features
Amundsen has two features that leverage the custom mail client -- the feedback tool and notifications. For these features a custom implementation of [base_mail_client](https://github.com/lyft/amundsenfrontendlibrary/blob/master/amundsen_application/base/base_mail_client.py) must be mapped to the `MAIL_CLIENT` configuration variable.

Expand Down
Loading