WIP: manager: offer to refresh the role summary cache (#83078) #174
|
@ -16,11 +16,12 @@
|
|||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from authentic2.role_summary import write_roles_summary_cache
|
||||
from authentic2.role_summary import RoleSummaryJob, write_roles_summary_cache
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Build role summary cache'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
write_roles_summary_cache()
|
||||
role_summary_job = RoleSummaryJob.new()
|
||||
write_roles_summary_cache(role_summary_job.uuid)
|
||||
|
|
|
@ -38,8 +38,8 @@ from authentic2.a2_rbac.models import OrganizationalUnit, Permission, Role, Role
|
|||
from authentic2.a2_rbac.utils import get_default_ou
|
||||
from authentic2.apps.journal.views import JournalViewWithContext
|
||||
from authentic2.forms.profile import modelform_factory
|
||||
from authentic2.role_summary import get_roles_summary_cache
|
||||
from authentic2.utils import crypto, hooks
|
||||
from authentic2.role_summary import RoleSummaryJob, get_roles_summary_cache
|
||||
from authentic2.utils import crypto, hooks, spooler
|
||||
from authentic2.utils.misc import redirect
|
||||
|
||||
from . import forms, resources, tables, views
|
||||
|
@ -761,6 +761,20 @@ class RolesJournal(views.SearchOUMixin, views.PermissionMixin, JournalViewWithCo
|
|||
roles_journal = RolesJournal.as_view()
|
||||
|
||||
|
||||
class RolesSummaryRefresh(views.PermissionMixin, views.TitleMixin, views.MediaMixin, TemplateView):
|
||||
template_name = 'authentic2/manager/roles_summary_refresh.html'
|
||||
permissions = ['a2_rbac.view_role']
|
||||
title = _('Refresh roles summary')
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
role_summary_job = RoleSummaryJob.new()
|
||||
spooler.refresh_roles_summary_cache(role_summary_job.uuid)
|
||||
return redirect(self.request, reverse('a2-manager-roles'))
|
||||
|
||||
|
||||
roles_summary_refresh = RolesSummaryRefresh.as_view()
|
||||
|
||||
|
||||
class UserOrRoleSelect2View(DetailView):
|
||||
form_class = forms.ChooseUserOrRoleForm
|
||||
model = Role
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
{% endif %}
|
||||
<ul class="extra-actions-menu">
|
||||
<li><a href="{% url "a2-manager-roles-journal" %}{% if multiple_ou and ou %}?search-ou={{ ou.id }}{% endif %}">{% trans "Journal" %}</a></li>
|
||||
<li><a href="{% url 'a2-manager-roles-summary-refresh' %}" rel="popup">{% trans "Role summary refresh" %}</a></li>
|
||||
<li><a download href="{% url 'a2-manager-roles-export' format="json" %}?{{ request.GET.urlencode }}">{% trans 'Export' %}</a></li>
|
||||
{% if view.can_add %}
|
||||
<li><a href="{% url 'a2-manager-roles-import' %}?{{ request.GET.urlencode }}" rel="popup">{% trans 'Import' %}</a></li>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
{% extends "authentic2/manager/form.html" %}
|
||||
{% load i18n gadjo %}
|
||||
|
||||
{% block page-title %}{% trans "Role summary refresh" %}{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'a2-manager-roles' %}">{% trans 'Roles' %}</a>
|
||||
<a href="#">{{ object }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{{ title }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="form-inner-container">
|
||||
<p>{% blocktrans %}Do you want to refresh roles summary ?{% endblocktrans %}</p>
|
||||
<div class="buttons">
|
||||
<button>{% trans "Confirm" %}</button>
|
||||
<a class="cancel" href="{% url 'a2-manager-roles' %}">{% trans "Cancel" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -121,6 +121,11 @@ urlpatterns = required(
|
|||
path('roles/add/', role_views.add, name='a2-manager-role-add'),
|
||||
re_path(r'^roles/export/(?P<format>csv|json)/$', role_views.export, name='a2-manager-roles-export'),
|
||||
path('roles/journal/', role_views.roles_journal, name='a2-manager-roles-journal'),
|
||||
path(
|
||||
'roles/summary-refresh/',
|
||||
role_views.roles_summary_refresh,
|
||||
name='a2-manager-roles-summary-refresh',
|
||||
),
|
||||
path('roles/<int:pk>/', role_views.members, name='a2-manager-role-members'),
|
||||
re_path(
|
||||
r'^roles/uuid:(?P<slug>[a-z0-9]+)/$', role_views.members, name='a2-manager-roles-by-uuid-detail'
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
import json
|
||||
import os.path
|
||||
import urllib
|
||||
import uuid
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import default_storage
|
||||
from django.db import connection
|
||||
|
||||
from .a2_rbac.models import Role
|
||||
|
@ -30,7 +32,48 @@ except ImportError: # fallback on python requests, no Publik signature
|
|||
from requests.sessions import Session as Requests # pylint: disable=ungrouped-imports
|
||||
|
||||
|
||||
def build_role_summary_cache():
|
||||
def iter_services():
|
||||
try:
|
||||
services = settings.KNOWN_SERVICES
|
||||
except AttributeError:
|
||||
services = {}
|
||||
for service_type, services in settings.KNOWN_SERVICES.items():
|
||||
if service_type == 'authentic':
|
||||
continue
|
||||
yield services
|
||||
|
||||
|
||||
def total():
|
||||
service_slugs = []
|
||||
for services in iter_services():
|
||||
service_slugs.extend(services.keys())
|
||||
return len(service_slugs)
|
||||
|
||||
|
||||
class RoleSummaryJob:
|
||||
def __init__(self, uuid):
|
||||
self.uuid = uuid
|
||||
self.base_path = os.path.join(default_storage.path('role_summary'), self.uuid)
|
||||
self.progress_path = os.path.join(self.base_path, 'progress')
|
||||
|
||||
@classmethod
|
||||
def new(cls):
|
||||
job = cls(str(uuid.uuid4()))
|
||||
os.makedirs(job.base_path)
|
||||
return job
|
||||
|
||||
@property
|
||||
def progress(self):
|
||||
with open(self.progress_path) as f:
|
||||
result = f.read()
|
||||
return int(result) if result else 0
|
||||
|
||||
def set_progress(self, number):
|
||||
with open(self.progress_path, 'w') as f:
|
||||
f.write(str(number))
|
||||
|
||||
|
||||
def build_role_summary_cache(job_uuid):
|
||||
def _requests(url):
|
||||
try:
|
||||
resp = Requests().get(url=url, timeout=settings.REQUESTS_TIMEOUT)
|
||||
|
@ -55,15 +98,11 @@ def build_role_summary_cache():
|
|||
},
|
||||
}
|
||||
|
||||
try:
|
||||
services = settings.KNOWN_SERVICES
|
||||
except AttributeError:
|
||||
services = {}
|
||||
|
||||
progress = 0
|
||||
job = RoleSummaryJob(job_uuid)
|
||||
job.set_progress(progress)
|
||||
data = {}
|
||||
for service_type, services in settings.KNOWN_SERVICES.items():
|
||||
if service_type == 'authentic':
|
||||
continue
|
||||
for services in iter_services():
|
||||
for service_data in services.values():
|
||||
url = urllib.parse.urljoin(service_data['url'], 'api/export-import/')
|
||||
for type_object in _requests(url):
|
||||
|
@ -93,7 +132,8 @@ def build_role_summary_cache():
|
|||
data[role_uuid][match_key].append(type_object_copy)
|
||||
if object not in data[role_uuid][match_key][-1]['hit']:
|
||||
data[role_uuid][match_key][-1]['hit'].append(object)
|
||||
|
||||
progress += 1
|
||||
job.set_progress(progress)
|
||||
return data
|
||||
|
||||
|
||||
|
@ -113,9 +153,9 @@ def get_roles_summary_cache():
|
|||
return json.load(fd)
|
||||
|
||||
|
||||
def write_roles_summary_cache():
|
||||
def write_roles_summary_cache(uuid):
|
||||
path = get_role_summary_cache_path()
|
||||
if not path:
|
||||
return
|
||||
with open(path, 'w') as fd:
|
||||
json.dump(build_role_summary_cache(), fd, indent=2)
|
||||
json.dump(build_role_summary_cache(uuid), fd, indent=2)
|
||||
|
|
|
@ -91,3 +91,10 @@ def export_users(uuid, query):
|
|||
from authentic2.manager.user_export import export_users_to_file
|
||||
|
||||
export_users_to_file(uuid, query)
|
||||
|
||||
|
||||
@tenantspool
|
||||
def refresh_roles_summary_cache(uuid):
|
||||
from authentic2.role_summary import write_roles_summary_cache
|
||||
|
||||
write_roles_summary_cache(uuid)
|
||||
|
|
|
@ -114,7 +114,8 @@ def test_role_summary(db, simple_role, superuser, tmpdir, monkeypatch):
|
|||
},
|
||||
)
|
||||
|
||||
data = role_summary.build_role_summary_cache()
|
||||
role_summary_job = role_summary.RoleSummaryJob.new()
|
||||
data = role_summary.build_role_summary_cache(role_summary_job.uuid)
|
||||
assert data == {
|
||||
simple_role.uuid: {
|
||||
'name': 'simple role',
|
||||
|
|
Loading…
Reference in New Issue