Skip to content

Commit eb191de

Browse files
kathryn-daleKathryn Dalemattjreynoldssahmed06
authored
Cdd 3090 simplified BE chart watermark (#3199)
* CDD-3090: Update watermark for non public charts * Revert to models data classification * Wrap text for large watermarks * CDD-3090: Unit testing * linting * update comment * wrap watermark in auth_enabled flag * Update unit tests * CDD-3090: Remove unused variable * Make watermark scale * Make font size dynamic * tweak font size * linting * Update font height * Update tests * remove unused function * update import * linting * Update text sizing * tweak font padding * Add chart width to chart output * linting * Fix tests * Update tests * Fix unit test * update chart output test * linting * add log * remove log --------- Co-authored-by: Kathryn Dale <kathryn.dale@burendo.com> Co-authored-by: Matt Reynolds <18287679+mattjreynolds@users.noreply.github.com> Co-authored-by: sahmed06 <58435820+sahmed06@users.noreply.github.com>
1 parent a6a8cbf commit eb191de

23 files changed

Lines changed: 322 additions & 2 deletions

File tree

cms/dashboard/viewsets.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ def get_queryset(self):
8484
req = self.request
8585

8686
if req.auth is None:
87-
8887
# Get all page ids for pages with is_public
8988
public_topic_page_ids = TopicPage.objects.filter(
9089
is_public=True, page_ptr__in=queryset

metrics/api/serializers/charts/common.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,13 @@ class BaseChartsSerializer(serializers.Serializer):
9494
allow_null=True,
9595
default="",
9696
)
97+
is_public = serializers.BooleanField(
98+
required=False, default=False, help_text=help_texts.IS_PUBLIC_FIELD
99+
)
100+
data_classification = serializers.CharField(
101+
required=False,
102+
allow_blank=True,
103+
allow_null=True,
104+
default=None,
105+
help_text=help_texts.DATA_CLASSIFICATION_FIELD,
106+
)

metrics/api/serializers/charts/single_category_charts.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ def to_models(self, request: Request) -> ChartRequestParams:
8383
plot["x_axis"] = x_axis
8484
plot["y_axis"] = y_axis
8585

86+
# If not provided, default to public data
87+
is_public: bool = self.data.get("is_public", True)
88+
data_classification: str | None = self.data.get("data_classification")
89+
8690
return ChartRequestParams(
8791
plots=self.data["plots"],
8892
file_format=self.data["file_format"],
@@ -98,6 +102,8 @@ def to_models(self, request: Request) -> ChartRequestParams:
98102
legend_title=self.data.get("legend_title", ""),
99103
confidence_intervals=self.data.get("confidence_intervals", False),
100104
confidence_colour=self.data.get("confidence_colour", ""),
105+
is_public=is_public,
106+
data_classification=data_classification,
101107
request=request,
102108
)
103109

metrics/api/serializers/charts/subplot_charts.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ class SubplotChartRequestSerializer(serializers.Serializer):
157157
allow_blank=True,
158158
allow_null=True,
159159
)
160+
is_public = serializers.BooleanField(
161+
required=False, default=True, help_text=help_texts.IS_PUBLIC_FIELD
162+
)
163+
data_classification = serializers.CharField(
164+
required=False,
165+
allow_blank=True,
166+
allow_null=True,
167+
default=None,
168+
help_text=help_texts.DATA_CLASSIFICATION_FIELD,
169+
)
160170

161171
chart_parameters = ChartParametersSerializer()
162172
subplots = SubplotsSerializer()
@@ -197,6 +207,9 @@ def to_models(self, request: Request) -> SubplotChartRequestParameters:
197207
)
198208
plot["metric_value_ranges"] = metric_value_ranges
199209

210+
is_public: bool = self.validated_data.get("is_public", True)
211+
data_classification: str | None = self.validated_data.get("data_classification")
212+
200213
return SubplotChartRequestParameters(
201214
file_format=self.validated_data["file_format"],
202215
chart_height=self.validated_data["chart_height"] or DEFAULT_CHART_HEIGHT,
@@ -211,6 +224,8 @@ def to_models(self, request: Request) -> SubplotChartRequestParameters:
211224
"target_threshold_label", None
212225
),
213226
subplots=self.validated_data["subplots"],
227+
is_public=is_public,
228+
data_classification=data_classification,
214229
request=request,
215230
)
216231

metrics/api/serializers/headlines.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ class HeadlinesQuerySerializer(serializers.Serializer):
5757
required=False,
5858
help_text=help_texts.SEX_FIELD,
5959
)
60+
is_public = serializers.BooleanField(
61+
required=False,
62+
default=True,
63+
help_text=help_texts.IS_PUBLIC_FIELD,
64+
)
65+
data_classification = serializers.CharField(
66+
required=False,
67+
allow_blank=True,
68+
allow_null=True,
69+
default=None,
70+
help_text=help_texts.DATA_CLASSIFICATION_FIELD,
71+
)
6072

6173
def __init__(self, *args, **kwargs):
6274
super().__init__(*args, **kwargs)

metrics/api/serializers/help_texts.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,10 @@
132132
GEOGRAPHY_LIST_FORMATTING: str = """
133133
"List of [id, name] pairs for dropdown options"
134134
"""
135+
IS_PUBLIC_FIELD: str = """
136+
Whether the chart data is intended for public display. Defaults to True.
137+
When False, a data classification watermark will be applied to the chart.
138+
"""
139+
DATA_CLASSIFICATION_FIELD: str = """
140+
The data classification watermark to apply on non-public charts, eg "OFFICIAL-SENSITIVE".
141+
"""

metrics/api/serializers/tables.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ def to_models(self, request: Request) -> ChartRequestParams:
6868
chart_width=DEFAULT_CHART_WIDTH,
6969
x_axis=self.data.get("x_axis") or DEFAULT_X_AXIS,
7070
y_axis=self.data.get("y_axis") or DEFAULT_Y_AXIS,
71+
is_public=self.data.get("is_public", True),
72+
data_classification=self.data.get("data_classification"),
7173
request=request,
7274
)
7375

metrics/api/views/charts/single_category_charts.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ def post(cls, request, *args, **kwargs):
9797
| `label` | The label to assign on the legend for this individual plot | Females | No |
9898
| `line_colour` | The colour to use for the line of this individual plot | BLUE | No |
9999
| `line_type` | The type to assign for this individual plot i.e. SOLID or DASH | DASH | No |
100+
| `is_public` | Whether the chart is for the public / non-public dashboard environment | True | Yes |
101+
| `data_classification` | The watermark wording (only for non-public charts) | OFFICIAL-SENSITIVE | No |
100102
101103
---
102104
@@ -225,6 +227,51 @@ class EncodedChartsView(APIView):
225227
request=EncodedChartsRequestSerializer,
226228
responses={HTTPStatus.OK.value: EncodedChartResponseSerializer},
227229
tags=[CHARTS_API_TAG],
230+
examples=[
231+
OpenApiExample(
232+
"COVID-19 encoded SVG example",
233+
value={
234+
"file_format": "svg",
235+
"x_axis": "date",
236+
"y_axis": "metric",
237+
"is_public": False,
238+
"data_classification": "OFFICIAL-SENSITIVE",
239+
"plots": [
240+
{
241+
"topic": "COVID-19",
242+
"metric": "COVID-19_cases_casesByDay",
243+
"chart_type": "bar",
244+
"date_from": "2022-01-01",
245+
"date_to": "2023-02-01",
246+
}
247+
],
248+
},
249+
request_only=True,
250+
),
251+
OpenApiExample(
252+
"COVID-19 encoded SVG response example",
253+
value={
254+
"last_updated": "2023-02-01",
255+
"chart": "%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20900%20300%22%3E%3Ctext%20x%3D%22450%22%20y%3D%22150%22%20text-anchor%3D%22middle%22%3EOFFICIAL%20SENSITIVE%3C%2Ftext%3E%3C%2Fsvg%3E",
256+
"alt_text": "There is only 1 plot on this chart. The horizontal X-axis is labelled 'date'. Whilst the vertical Y-axis is labelled 'metric'. This is a blue solid bar plot showing COVID-19 cases by day.",
257+
"figure": {
258+
"data": [
259+
{
260+
"x": ["2023-01-01", "2023-01-02"],
261+
"y": [100, 150],
262+
"type": "bar",
263+
}
264+
],
265+
"layout": {
266+
"title": "COVID-19 Cases by Day",
267+
"xaxis": {"title": "Date"},
268+
"yaxis": {"title": "Cases"},
269+
},
270+
},
271+
},
272+
response_only=True,
273+
),
274+
],
228275
)
229276
@cache_response()
230277
@require_authorisation
@@ -249,6 +296,8 @@ def post(cls, request, *args, **kwargs):
249296
| `label` | The label to assign on the legend for this individual plot | Females | No |
250297
| `line_colour` | The colour to use for the line of this individual plot | BLUE | No |
251298
| `line_type` | The type to assign for this individual plot i.e. SOLID or DASH | DASH | No |
299+
| `is_public` | Whether the chart is for the public / non-public dashboard environment | True | Yes |
300+
| `data_classification` | The watermark wording (only for non-public charts) | OFFICIAL-SENSITIVE | No |
252301
253302
---
254303

metrics/api/views/charts/subplot_charts/request_example.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"target_threshold": 95,
1010
"target_threshold_label": "95% target",
1111
"chart_parameters": {
12+
"chart_width": 600,
1213
"x_axis": "geography",
1314
"y_axis": "metric",
1415
"theme": "immunisation",

metrics/domain/models/charts/common.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class BaseChartRequestParams(BaseModel):
2020
request: Request | None = None
2121
confidence_intervals: bool | None = False
2222
confidence_colour: str | None = ""
23+
is_public: bool | None = True
24+
data_classification: str | None = None
2325

2426
class Config:
2527
arbitrary_types_allowed = True

0 commit comments

Comments
 (0)