From 148327ca479bb1bf72b77bba6435958e924a630b Mon Sep 17 00:00:00 2001 From: Michael Collins <15347726+michaeljcollinsuk@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:26:43 +0000 Subject: [PATCH 1/7] Filter database list by user access --- ap/database_access/models/access.py | 3 +++ ap/database_access/templatetags/__init__.py | 0 .../templatetags/database_tags.py | 20 +++++++++++++++++++ ap/database_access/views.py | 5 ++++- templates/database_access/database/list.html | 16 +++++++++++++-- 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 ap/database_access/templatetags/__init__.py create mode 100644 ap/database_access/templatetags/database_tags.py diff --git a/ap/database_access/models/access.py b/ap/database_access/models/access.py index b0ac4c0e..e11af14c 100644 --- a/ap/database_access/models/access.py +++ b/ap/database_access/models/access.py @@ -63,6 +63,9 @@ def database_details(self): def target_database(self): return self.database_details.get("TargetDatabase", {}) + def get_absolute_url(self): + return reverse("database_access:detail", kwargs={"database_name": self.name}) + def grant_lakeformation_permissions(self, create_hybrid_opt_in=False): lake_formation = aws.LakeFormationService() quicksight_user = lake_formation.arn( diff --git a/ap/database_access/templatetags/__init__.py b/ap/database_access/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ap/database_access/templatetags/database_tags.py b/ap/database_access/templatetags/database_tags.py new file mode 100644 index 00000000..42e632d2 --- /dev/null +++ b/ap/database_access/templatetags/database_tags.py @@ -0,0 +1,20 @@ +from django import template +from django.urls import reverse + +register = template.Library() + + +@register.simple_tag +def database_name(database): + try: + return database.name + except AttributeError: + return database["Name"] + + +@register.simple_tag +def database_url(database): + try: + return database.get_absolute_url() + except (TypeError, AttributeError): + return reverse("database_access:detail", kwargs={"database_name": database["Name"]}) diff --git a/ap/database_access/views.py b/ap/database_access/views.py index 2a57f917..a2da2a00 100644 --- a/ap/database_access/views.py +++ b/ap/database_access/views.py @@ -21,7 +21,10 @@ class DatabaseListView(OIDCLoginRequiredMixin, TemplateView): def get_context_data(self, **kwargs: Any) -> dict[str, Any]: context = super().get_context_data(**kwargs) - context["databases"] = aws.GlueService().get_database_list() + if "my-databases" in self.request.GET.get("sort", {}): + context["databases"] = models.DatabaseAccess.objects.filter(user=self.request.user) + else: + context["databases"] = aws.GlueService().get_database_list() return context diff --git a/templates/database_access/database/list.html b/templates/database_access/database/list.html index 2e6aac20..2038074d 100644 --- a/templates/database_access/database/list.html +++ b/templates/database_access/database/list.html @@ -1,9 +1,21 @@ {% extends "base.html" %} +{% load database_tags %} {% block title %}Analytical Platform - Databases{% endblock title %} {% block content %}

Databases

+
+
+ + +
+
{% if databases %} @@ -16,9 +28,9 @@

Databases

{% for database in databases %} - + {% endfor %} From 725a1e17e69385ed3ca4005f4bf5aaeebb5ebd87 Mon Sep 17 00:00:00 2001 From: Michael Collins <15347726+michaeljcollinsuk@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:25:21 +0000 Subject: [PATCH 2/7] Refactor filtering to a mixin and include Allow filtering of databases and tables by the users access --- ap/database_access/models/access.py | 9 +++ .../templatetags/database_access_tags.py | 23 ++++++++ .../templatetags/database_tags.py | 20 ------- ap/database_access/views.py | 59 +++++++++++++++---- .../database_access/database/detail.html | 51 +++++++++------- .../database/includes/filter_form.html | 11 ++++ templates/database_access/database/list.html | 19 ++---- 7 files changed, 126 insertions(+), 66 deletions(-) create mode 100644 ap/database_access/templatetags/database_access_tags.py delete mode 100644 ap/database_access/templatetags/database_tags.py create mode 100644 templates/database_access/database/includes/filter_form.html diff --git a/ap/database_access/models/access.py b/ap/database_access/models/access.py index e11af14c..db8fdb4b 100644 --- a/ap/database_access/models/access.py +++ b/ap/database_access/models/access.py @@ -155,6 +155,15 @@ def get_absolute_url(self, viewname: str = "database_access:manage_table_access" def get_absolute_revoke_url(self): return self.get_absolute_url(viewname="database_access:revoke_table_access") + def get_absolute_table_detail_url(self): + return reverse( + viewname="database_access:table_detail", + kwargs={ + "database_name": self.database_access.name, + "table_name": self.name, + }, + ) + def grant_lakeformation_permissions(self, create_hybrid_opt_in=False): lake_formation = aws.LakeFormationService() quicksight_user = lake_formation.arn( diff --git a/ap/database_access/templatetags/database_access_tags.py b/ap/database_access/templatetags/database_access_tags.py new file mode 100644 index 00000000..805149d4 --- /dev/null +++ b/ap/database_access/templatetags/database_access_tags.py @@ -0,0 +1,23 @@ +from django import template +from django.urls import reverse + +register = template.Library() + + +@register.simple_tag +def database_detail_url(database): + try: + return database.get_absolute_url() + except (TypeError, AttributeError): + return reverse("database_access:detail", kwargs={"database_name": database["Name"]}) + + +@register.simple_tag +def table_detail_url(table, database_name): + try: + return table.get_absolute_table_detail_url() + except (TypeError, AttributeError): + return reverse( + "database_access:table_detail", + kwargs={"database_name": database_name, "table_name": table["Name"]}, + ) diff --git a/ap/database_access/templatetags/database_tags.py b/ap/database_access/templatetags/database_tags.py deleted file mode 100644 index 42e632d2..00000000 --- a/ap/database_access/templatetags/database_tags.py +++ /dev/null @@ -1,20 +0,0 @@ -from django import template -from django.urls import reverse - -register = template.Library() - - -@register.simple_tag -def database_name(database): - try: - return database.name - except AttributeError: - return database["Name"] - - -@register.simple_tag -def database_url(database): - try: - return database.get_absolute_url() - except (TypeError, AttributeError): - return reverse("database_access:detail", kwargs={"database_name": database["Name"]}) diff --git a/ap/database_access/views.py b/ap/database_access/views.py index a2da2a00..eaddadd2 100644 --- a/ap/database_access/views.py +++ b/ap/database_access/views.py @@ -5,6 +5,7 @@ from django.http import Http404, HttpResponse from django.urls import reverse from django.views.generic import CreateView, DeleteView, DetailView, TemplateView, UpdateView +from django.views.generic.base import ContextMixin from django.views.generic.detail import SingleObjectMixin import botocore @@ -16,27 +17,64 @@ from . import models -class DatabaseListView(OIDCLoginRequiredMixin, TemplateView): - template_name = "database_access/database/list.html" +class FilterAccessMixin(ContextMixin): + context_list_name = "objects" + + def get_user_access_objects(self): + raise NotImplementedError() + + def get_all_objects(self): + raise NotImplementedError() def get_context_data(self, **kwargs: Any) -> dict[str, Any]: context = super().get_context_data(**kwargs) - if "my-databases" in self.request.GET.get("sort", {}): - context["databases"] = models.DatabaseAccess.objects.filter(user=self.request.user) - else: - context["databases"] = aws.GlueService().get_database_list() + filter_by = self.request.GET.get("filter", {}) + match filter_by: + case "my-access": + context[self.context_list_name] = self.get_user_access_objects() + case "all": + context[self.context_list_name] = self.get_all_objects() + case _: + context[self.context_list_name] = self.get_all_objects() + return context -class DatabaseDetailView(OIDCLoginRequiredMixin, DetailView): +class DatabaseListView(OIDCLoginRequiredMixin, FilterAccessMixin, TemplateView): + template_name = "database_access/database/list.html" + context_list_name = "databases" + + def get_all_objects(self): + return aws.GlueService().get_database_list() + + def get_user_access_objects(self): + return models.DatabaseAccess.objects.filter(user=self.request.user) + + +class DatabaseDetailView(OIDCLoginRequiredMixin, FilterAccessMixin, TemplateView): template_name = "database_access/database/detail.html" - context_object_name = "database" + context_list_name = "tables" - def get_object(self): + def get_database(self): + database = aws.GlueService().get_database_detail(database_name=self.kwargs["database_name"]) + if not database: + raise Http404("Database not found") + return database + + def get_all_objects(self): tables = aws.GlueService().get_table_list(database_name=self.kwargs["database_name"]) if not tables: raise Http404("Database not found") - return {"name": self.kwargs["database_name"], "tables": tables} + return tables + + def get_user_access_objects(self): + database = aws.GlueService().get_database_detail(database_name=self.kwargs["database_name"]) + if not database: + raise Http404("Database not found") + return models.TableAccess.objects.filter( + database_access__name=self.kwargs["database_name"], + database_access__user=self.request.user, + ) class TableDetailView(OIDCLoginRequiredMixin, DetailView): @@ -49,6 +87,7 @@ def get_object(self): ) if not table: raise Http404("Table not found") + return { "name": self.kwargs["table_name"], "is_registered_with_lake_formation": table.get("IsRegisteredWithLakeFormation"), diff --git a/templates/database_access/database/detail.html b/templates/database_access/database/detail.html index 78ba9e05..8d303b6b 100644 --- a/templates/database_access/database/detail.html +++ b/templates/database_access/database/detail.html @@ -1,31 +1,38 @@ {% extends "base.html" %} +{% load database_access_tags %} {% block title %}Analytical Platform - Tables for {{ database.name }}{% endblock title %} {% block content %} -Database -

{{ database.name }}

+
-{% if database.tables %} -
{{ database.Name }}{% database_name database=database %} - View + View
- - - - - - - - {% for table in database.tables %} + Database +

{{ database_name }}

+ + {% include "database_access/database/includes/filter_form.html" %} + + {% if tables %} +
Table NameActions
+ - - + + - {% endfor %} - -
{{ table.Name }} - View - Table NameActions
-{% else %} -

No tables found.

-{% endif %} + + + {% for table in tables %} + + {% firstof table.name table.Name %} + + View + + + {% endfor %} + + + {% else %} +

No tables found.

+ {% endif %} + +
{% endblock %} diff --git a/templates/database_access/database/includes/filter_form.html b/templates/database_access/database/includes/filter_form.html new file mode 100644 index 00000000..5b5adbdc --- /dev/null +++ b/templates/database_access/database/includes/filter_form.html @@ -0,0 +1,11 @@ +
+
+ + +
+
diff --git a/templates/database_access/database/list.html b/templates/database_access/database/list.html index 2038074d..15e2ca2c 100644 --- a/templates/database_access/database/list.html +++ b/templates/database_access/database/list.html @@ -1,21 +1,12 @@ {% extends "base.html" %} -{% load database_tags %} +{% load database_access_tags %} {% block title %}Analytical Platform - Databases{% endblock title %} {% block content %}

Databases

-
-
- - -
-
+ + {% include "database_access/database/includes/filter_form.html" %} {% if databases %} @@ -28,9 +19,9 @@

Databases

{% for database in databases %} - + {% endfor %} From 9ad4b74814df9ca71300c84c713f269cc530d351 Mon Sep 17 00:00:00 2001 From: Michael Collins <15347726+michaeljcollinsuk@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:32:20 +0000 Subject: [PATCH 3/7] Super-linter --- templates/database_access/database/includes/filter_form.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/database_access/database/includes/filter_form.html b/templates/database_access/database/includes/filter_form.html index 5b5adbdc..b8ea5350 100644 --- a/templates/database_access/database/includes/filter_form.html +++ b/templates/database_access/database/includes/filter_form.html @@ -4,8 +4,8 @@ Filter by From 8b3b0723491f2010ea9de161f4ac5e0f7f029046 Mon Sep 17 00:00:00 2001 From: Michael Collins <15347726+michaeljcollinsuk@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:38:12 +0000 Subject: [PATCH 4/7] Disable HTML super linter --- .github/workflows/super-linter.yml | 1 + templates/database_access/database/includes/filter_form.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index 50298c13..9c3286fb 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -46,3 +46,4 @@ jobs: VALIDATE_CHECKOV: false # TODO failures to remediate at later date VALIDATE_PYTHON_PYINK: false # we are using Black instead VALIDATE_HTML_PRETTIER: false # incompatible with django templating language + VALIDATE_HTML: false # issues with django templating language, need to revist diff --git a/templates/database_access/database/includes/filter_form.html b/templates/database_access/database/includes/filter_form.html index b8ea5350..4fd751ec 100644 --- a/templates/database_access/database/includes/filter_form.html +++ b/templates/database_access/database/includes/filter_form.html @@ -2,7 +2,7 @@ +
{% database_name database=database %}{% firstof database.name database.Name %} - View + View