mirror of https://github.com/apache/superset.git
feat: add logic to creation_method for reports schedule (#15685)
* migration * added logic for creation_method * revisions * added index * Update superset/migrations/versions/3317e9248280_add_creation_method_to_reports_model.py * filters * Update superset/models/reports.py Co-authored-by: Beto Dealmeida <roberto@dealmeida.net> * Update superset/reports/schemas.py Co-authored-by: Beto Dealmeida <roberto@dealmeida.net> * Update tests/integration_tests/reports/api_tests.py Co-authored-by: Beto Dealmeida <roberto@dealmeida.net> * revisions Co-authored-by: Beto Dealmeida <roberto@dealmeida.net>
This commit is contained in:
parent
6b790990a8
commit
674f234de6
|
@ -74,6 +74,12 @@ class ReportDataFormat(str, enum.Enum):
|
|||
DATA = "CSV"
|
||||
|
||||
|
||||
class ReportCreationMethodType(str, enum.Enum):
|
||||
CHARTS = "charts"
|
||||
DASHBOARDS = "dashboards"
|
||||
ALERTS_REPORTS = "alerts_reports"
|
||||
|
||||
|
||||
report_schedule_user = Table(
|
||||
"report_schedule_user",
|
||||
metadata,
|
||||
|
@ -102,6 +108,9 @@ class ReportSchedule(Model, AuditMixinNullable):
|
|||
context_markdown = Column(Text)
|
||||
active = Column(Boolean, default=True, index=True)
|
||||
crontab = Column(String(1000), nullable=False)
|
||||
creation_method = Column(
|
||||
String(255), server_default=ReportCreationMethodType.ALERTS_REPORTS
|
||||
)
|
||||
report_format = Column(String(50), default=ReportDataFormat.VISUALIZATION)
|
||||
sql = Column(Text())
|
||||
# (Alerts/Reports) M-O to chart
|
||||
|
|
|
@ -84,6 +84,7 @@ class ReportScheduleRestApi(BaseSupersetModelRestApi):
|
|||
"chart.id",
|
||||
"chart.slice_name",
|
||||
"context_markdown",
|
||||
"creation_method",
|
||||
"crontab",
|
||||
"dashboard.dashboard_title",
|
||||
"dashboard.id",
|
||||
|
@ -123,6 +124,7 @@ class ReportScheduleRestApi(BaseSupersetModelRestApi):
|
|||
"created_by.first_name",
|
||||
"created_by.last_name",
|
||||
"created_on",
|
||||
"creation_method",
|
||||
"crontab",
|
||||
"crontab_humanized",
|
||||
"id",
|
||||
|
@ -140,6 +142,7 @@ class ReportScheduleRestApi(BaseSupersetModelRestApi):
|
|||
"active",
|
||||
"chart",
|
||||
"context_markdown",
|
||||
"creation_method",
|
||||
"crontab",
|
||||
"dashboard",
|
||||
"database",
|
||||
|
@ -173,7 +176,13 @@ class ReportScheduleRestApi(BaseSupersetModelRestApi):
|
|||
"type",
|
||||
"crontab_humanized",
|
||||
]
|
||||
search_columns = ["name", "active", "created_by", "type", "last_state"]
|
||||
search_columns = [
|
||||
"name",
|
||||
"active",
|
||||
"created_by",
|
||||
"type",
|
||||
"last_state",
|
||||
]
|
||||
search_filters = {"name": [ReportScheduleAllTextFilter]}
|
||||
allowed_rel_fields = {"owners", "chart", "dashboard", "database", "created_by"}
|
||||
filter_rel_fields = {
|
||||
|
|
|
@ -20,8 +20,10 @@ from croniter import croniter
|
|||
from flask_babel import gettext as _
|
||||
from marshmallow import fields, Schema, validate, validates_schema
|
||||
from marshmallow.validate import Length, Range, ValidationError
|
||||
from marshmallow_enum import EnumField
|
||||
|
||||
from superset.models.reports import (
|
||||
ReportCreationMethodType,
|
||||
ReportDataFormat,
|
||||
ReportRecipientType,
|
||||
ReportScheduleType,
|
||||
|
@ -83,6 +85,10 @@ working_timeout_description = (
|
|||
"If an alert is staled at a working state, how long until it's state is reseted to"
|
||||
" error"
|
||||
)
|
||||
creation_method_description = (
|
||||
"Creation method is used to inform the frontend whether the report/alert was "
|
||||
"created in the dashboard, chart, or alerts and reports UI."
|
||||
)
|
||||
|
||||
|
||||
def validate_crontab(value: Union[bytes, bytearray, str]) -> None:
|
||||
|
@ -150,6 +156,12 @@ class ReportSchedulePostSchema(Schema):
|
|||
description=sql_description, example="SELECT value FROM time_series_table"
|
||||
)
|
||||
chart = fields.Integer(required=False, allow_none=True)
|
||||
creation_method = EnumField(
|
||||
ReportCreationMethodType,
|
||||
by_value=True,
|
||||
required=True,
|
||||
description=creation_method_description,
|
||||
)
|
||||
dashboard = fields.Integer(required=False, allow_none=True)
|
||||
database = fields.Integer(required=False)
|
||||
owners = fields.List(fields.Integer(description=owners_description))
|
||||
|
@ -226,6 +238,12 @@ class ReportSchedulePutSchema(Schema):
|
|||
allow_none=True,
|
||||
)
|
||||
chart = fields.Integer(required=False, allow_none=True)
|
||||
creation_method = EnumField(
|
||||
ReportCreationMethodType,
|
||||
by_value=True,
|
||||
allow_none=True,
|
||||
description=creation_method_description,
|
||||
)
|
||||
dashboard = fields.Integer(required=False, allow_none=True)
|
||||
database = fields.Integer(required=False)
|
||||
owners = fields.List(fields.Integer(description=owners_description), required=False)
|
||||
|
|
|
@ -29,6 +29,7 @@ from superset.models.slice import Slice
|
|||
from superset.models.dashboard import Dashboard
|
||||
from superset.models.reports import (
|
||||
ReportSchedule,
|
||||
ReportCreationMethodType,
|
||||
ReportRecipients,
|
||||
ReportExecutionLog,
|
||||
ReportScheduleType,
|
||||
|
@ -269,6 +270,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"changed_on_delta_humanized",
|
||||
"created_by",
|
||||
"created_on",
|
||||
"creation_method",
|
||||
"crontab",
|
||||
"crontab_humanized",
|
||||
"id",
|
||||
|
@ -442,6 +444,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"name": "new3",
|
||||
"description": "description",
|
||||
"crontab": "0 9 * * *",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"recipients": [
|
||||
{
|
||||
"type": ReportRecipientType.EMAIL,
|
||||
|
@ -470,6 +473,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
assert created_model.crontab == report_schedule_data["crontab"]
|
||||
assert created_model.chart.id == report_schedule_data["chart"]
|
||||
assert created_model.database.id == report_schedule_data["database"]
|
||||
assert created_model.creation_method == report_schedule_data["creation_method"]
|
||||
# Rollback changes
|
||||
db.session.delete(created_model)
|
||||
db.session.commit()
|
||||
|
@ -487,6 +491,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.ALERT,
|
||||
"name": "name3",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"chart": chart.id,
|
||||
"database": example_db.id,
|
||||
|
@ -503,6 +508,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"name": "name3",
|
||||
"description": "description",
|
||||
"crontab": "0 9 * * *",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"chart": chart.id,
|
||||
}
|
||||
uri = "api/v1/report/"
|
||||
|
@ -532,6 +538,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.REPORT,
|
||||
"name": "name3",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"chart": chart.id,
|
||||
"database": example_db.id,
|
||||
|
@ -545,6 +552,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.ALERT,
|
||||
"name": "new3",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"recipients": [
|
||||
{
|
||||
|
@ -569,6 +577,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.ALERT,
|
||||
"name": "new3",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"recipients": [
|
||||
{
|
||||
|
@ -592,6 +601,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.ALERT,
|
||||
"name": "new3",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"recipients": [
|
||||
{
|
||||
|
@ -617,6 +627,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.ALERT,
|
||||
"name": "new4",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"recipients": [
|
||||
{
|
||||
|
@ -642,6 +653,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.ALERT,
|
||||
"name": "new5",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"recipients": [
|
||||
{
|
||||
|
@ -678,6 +690,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"name": "new3",
|
||||
"description": "description",
|
||||
"crontab": "0 9 * * *",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"chart": chart.id,
|
||||
"dashboard": dashboard.id,
|
||||
"database": example_db.id,
|
||||
|
@ -701,6 +714,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.ALERT,
|
||||
"name": "new3",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"chart": chart.id,
|
||||
}
|
||||
|
@ -726,6 +740,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"type": ReportScheduleType.ALERT,
|
||||
"name": "new3",
|
||||
"description": "description",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"crontab": "0 9 * * *",
|
||||
"chart": chart_max_id + 1,
|
||||
"database": database_max_id + 1,
|
||||
|
@ -748,6 +763,7 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
"name": "new3",
|
||||
"description": "description",
|
||||
"crontab": "0 9 * * *",
|
||||
"creation_method": ReportCreationMethodType.ALERTS_REPORTS,
|
||||
"dashboard": dashboard_max_id + 1,
|
||||
"database": examples_db.id,
|
||||
}
|
||||
|
@ -757,6 +773,82 @@ class TestReportSchedulesApi(SupersetTestCase):
|
|||
data = json.loads(rv.data.decode("utf-8"))
|
||||
assert data == {"message": {"dashboard": "Dashboard does not exist"}}
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
# TODO (AAfghahi): I am going to enable this when the report schedule feature is fully finished
|
||||
# def test_create_report_schedule_no_creation_method(self):
|
||||
# """
|
||||
# ReportSchedule Api: Test create report schedule
|
||||
# """
|
||||
# self.login(username="admin")
|
||||
|
||||
# chart = db.session.query(Slice).first()
|
||||
# example_db = get_example_database()
|
||||
# report_schedule_data = {
|
||||
# "type": ReportScheduleType.ALERT,
|
||||
# "name": "new3",
|
||||
# "description": "description",
|
||||
# "crontab": "0 9 * * *",
|
||||
# "recipients": [
|
||||
# {
|
||||
# "type": ReportRecipientType.EMAIL,
|
||||
# "recipient_config_json": {"target": "target@superset.org"},
|
||||
# },
|
||||
# {
|
||||
# "type": ReportRecipientType.SLACK,
|
||||
# "recipient_config_json": {"target": "channel"},
|
||||
# },
|
||||
# ],
|
||||
# "grace_period": 14400,
|
||||
# "working_timeout": 3600,
|
||||
# "chart": chart.id,
|
||||
# "database": example_db.id,
|
||||
# }
|
||||
# uri = "api/v1/report/"
|
||||
# rv = self.client.post(uri, json=report_schedule_data)
|
||||
# response = json.loads(rv.data.decode("utf-8"))
|
||||
# assert response == {
|
||||
# "message": {"creation_method": ["Missing data for required field."]}
|
||||
# }
|
||||
# assert rv.status_code == 400
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_create_report_schedule_invalid_creation_method(self):
|
||||
"""
|
||||
ReportSchedule API: Test create report schedule
|
||||
"""
|
||||
self.login(username="admin")
|
||||
|
||||
chart = db.session.query(Slice).first()
|
||||
example_db = get_example_database()
|
||||
report_schedule_data = {
|
||||
"type": ReportScheduleType.ALERT,
|
||||
"name": "new3",
|
||||
"description": "description",
|
||||
"creation_method": "BAD_CREATION_METHOD",
|
||||
"crontab": "0 9 * * *",
|
||||
"recipients": [
|
||||
{
|
||||
"type": ReportRecipientType.EMAIL,
|
||||
"recipient_config_json": {"target": "target@superset.org"},
|
||||
},
|
||||
{
|
||||
"type": ReportRecipientType.SLACK,
|
||||
"recipient_config_json": {"target": "channel"},
|
||||
},
|
||||
],
|
||||
"grace_period": 14400,
|
||||
"working_timeout": 3600,
|
||||
"chart": chart.id,
|
||||
"database": example_db.id,
|
||||
}
|
||||
uri = "api/v1/report/"
|
||||
rv = self.client.post(uri, json=report_schedule_data)
|
||||
response = json.loads(rv.data.decode("utf-8"))
|
||||
assert response == {
|
||||
"message": {"creation_method": ["Invalid enum value BAD_CREATION_METHOD"]}
|
||||
}
|
||||
assert rv.status_code == 400
|
||||
|
||||
@pytest.mark.usefixtures("create_report_schedules")
|
||||
def test_update_report_schedule(self):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue