Implement realm group update and deletion, Close #14, Close #8

This commit is contained in:
Götz 2019-03-29 19:05:48 +01:00
parent c204539cb6
commit 5ff47a2806
7 changed files with 624 additions and 25 deletions

View File

@ -21,9 +21,9 @@ urlpatterns = [
# Realm Group
path('realm/<int:realm_id>/groups/', account_manager.views.group_views.realm_groups, name='realm-group-list'),
path('realm/<int:realm_id>/groups/add/', account_manager.views.group_views.group_add, name='realm-group-add'),
path('realm/<int:realm_id>/group/<str:group_dn>/', account_manager.views.user_views.user_add, name='realm-group-detail'),
path('realm/<int:realm_id>/group/<str:group_dn>/update/', account_manager.views.user_views.user_add, name='realm-group-update'),
path('realm/<int:realm_id>/group/<str:group_dn>/delete/', account_manager.views.user_views.user_add, name='realm-group-delete'),
path('realm/<int:realm_id>/group/<str:group_dn>/', account_manager.views.group_views.group_detail, name='realm-group-detail'),
path('realm/<int:realm_id>/group/<str:group_dn>/update/', account_manager.views.group_views.group_update, name='realm-group-update'),
path('realm/<int:realm_id>/group/<str:group_dn>/delete/', account_manager.views.group_views.group_delete, name='realm-group-delete'),
# Permission Info
path('permission-denied', main_views.permission_denied, name='permission-denied')

View File

@ -17,13 +17,16 @@ def realm_groups(request, realm_id):
@login_required
def group_detail(request, dn):
group = LdapGroup.objects.get(dn=dn)
context = {'group': group, }
return render(request, 'user/group_detail.jinja2', context)
@is_realm_admin
def group_detail(request, realm_id, group_dn):
realm = Realm.objects.get(id=realm_id)
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
group = LdapGroup.objects.get(dn=group_dn)
return render(request, 'group/group_detail.jinja2', {'group': group, 'realm': realm})
@login_required
@is_realm_admin
def group_add(request, realm_id):
realm_obj = Realm.objects.get(id=realm_id)
# if this is a POST request we need to process the form data
@ -44,3 +47,39 @@ def group_add(request, realm_id):
form = AddLDAPGroupForm()
return render(request, 'group/group_add.jinja2', {'form': form, 'realm': realm_obj})
@login_required
@is_realm_admin
def group_update(request, realm_id, group_dn):
realm = Realm.objects.get(id=realm_id)
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
group = LdapGroup.objects.get(dn=group_dn)
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = AddLDAPGroupForm(request.POST)
# check whether it's valid:
if form.is_valid():
group.name = form.cleaned_data['name']
members = form.cleaned_data['members']
group.members = [member.dn for member in members]
group.save()
return redirect('realm-group-detail', realm_id, group.dn)
# if a GET (or any other method) we'll create a blank form
else:
# TODO: Automatic checkbox selection
data = {'name': group.name, 'members': group.members}
form = AddLDAPGroupForm(initial=data)
return render(request, 'group/group_detail.jinja2', {'form': form, 'realm': realm})
def group_delete(request, realm_id, group_dn):
realm = Realm.objects.get(id=realm_id)
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
group = LdapGroup.objects.get(dn=group_dn)
group.delete()
return redirect('realm-group-list', realm_id)

View File

@ -1,11 +1,21 @@
{% extends 'base.jinja' %}
{% block content %}
<h1>{{ group.name }}</h1>
<a href="{{ url('user-list') }}">Nutzerübersicht</a>
<p>DN: {{ group.dn }}</p>
<p>Nutzername: {{ group.name }}</p>
<h2>Mitglieder</h2>
{% for user in group.members %}
<p>{{ user }}</p>
{% endfor %}
{% extends 'realm/realm_detailed.jinja2' %}
{% import 'macros/forms_macro.jinja2' as forms %}
{% block extra_content %}
{% if not form %}
<h1>{{ group.name }}</h1>
<p>DN: {{ group.dn }}</p>
<p>Nutzername: {{ group.name }}</p>
<h2>Mitglieder</h2>
{% for user in group.members %}
<p>{{ user }}</p>
{% endfor %}
<a href="{{ url('realm-group-update', args = [realm.id, group.dn]) }}">Update Gruppe</a>
<a href="{{ url('realm-group-delete', args = [realm.id, group.dn]) }}">Delete Gruppe</a>
{% else %}
<form method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
{{ form.as_p()|safe }}
<button type="submit">Speichern</button>
</form>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,226 @@
{% macro text_input(field, list='', css_classes='') -%}
<div class="form-group">
<input type="text"
{% if css_classes %}
class="{{ css_classes }}"
{% else %}
class="form-control"
{% endif %}
placeholder="{{ field.label }}"
{% if list %}
list="{{ list }}"
{% endif %}
aria-describedby="{{ field.id_for_label }}_help"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
{% if field.value() != None %}value="{{ field.value() }}"{% endif %}
maxlength="{{ field.field.max_length }}"
{% if field.field.required %}required{% endif %}>
{% if list %}
<datalist id="{{ list }}">
</datalist>
{% endif %}
<small id="{{ field.id_for_label }}_help" class="form-text text-muted">
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% if field.help_text %}
<br/>
{% endif %}
</small>
</div>
{% endmacro %}
{% macro textarea_input(field) -%}
<div class="form-group">
<textarea type="text"
class="form-control"
placeholder="{{ field.label }}"
aria-describedby="{{ field.id_for_label }}_help"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
rows="4"
maxlength="{{ field.field.max_length }}"
{% if field.field.required %}required{% endif %}
>{% if field.value() != None %}{{ field.value() }}{% endif %}</textarea>
<small id="{{ field.id_for_label }}_help" class="form-text text-muted">
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% if field.help_text %}
<br/>{{ field.help_text() }}
{% endif %}
</small>
</div>
{% endmacro %}
{% macro number_input(field, type='', step_size='0.01') -%}
<div class="form-group">
<input type="number"
class="form-control"
placeholder="{{ field.label }}"
step="{{ step_size }}"
min="{{ field.field.min_value }}"
max="{{ field.field.max_value }}"
aria-describedby="{{ field.id_for_label }}_help"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
{% if field.value() != None %}value="{{ field.value() }}"{% endif %}
{% if field.field.required %}required{% endif %}>
<small id="{{ field.id_for_label }}_help" class="form-text text-muted">
{% if type %}
{{ field.label }} in {{ type }}
{% endif %}
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% if field.help_text %}
<br/>{{ field.help_text() }}
{% endif %}
</small>
</div>
{% endmacro %}
{% macro file_input(field, multiple=False) -%}
<div class="form-group">
<label for="{{ field.id_for_label }}">
{{ field.label }}
</label>
<input type="file"
{% if multiple %}multiple{% endif %}
class="form-control-file"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
{% if field.value() != None %}value="{{ field.value() }}"{% endif %}
{% if field.field.required %}required{% endif %}>
</div>
{% endmacro %}
{% macro image_deletion_input(existing_images) -%}
<div class="card-group">
{% for image in existing_images %}
<div class="col-12 col-xs-12 col-md-6 col-lg-6 col-xl-3 p-1">
<div class="card w-100" style="width: 18rem;" >
<input type="checkbox" id="image{{ image.id }}" name="deleteImages"
value="{{ image.id }}">
<label for="image{{ image.id }}">
<img class="img-fluid" src="{{ image.file.url }}" alt="Item default image">
</label>
</div>
</div>
{% endfor %}
</div>
{% endmacro %}
{% macro checkbox_input(field) -%}
<div class="form-check">
<input type="checkbox"
class="form-check-input"
placeholder="{{ field.label }}"
aria-describedby="{{ field.id_for_label }}_help"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
{% if field.value() != None %}value="{{ field.value() }}"{% endif %}
maxlength="{{ field.field.max_length }}"
{% if field.field.required %}required{% endif %}>
<label id="{{ field.id_for_label }}" class="form-check-label" for="{{ field.id_for_label }}">
{{ field.label }}
</label>
</div>
{% endmacro %}
{% macro select_input(field, multiple=False) -%}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
<select
{% if multiple %}multiple{% endif %}
class="form-control"
id="{{ field.id_for_label }}"
name="{{ field.html_name }}">
{% for option in field %}
{{ option }}
{% endfor %}
</select>
</div>
{% endmacro %}
{% macro password_input(field, list='', css_classes='') -%}
<div class="form-group">
<input type="password"
{% if css_classes %}
class="{{ css_classes }}"
{% else %}
class="form-control"
{% endif %}
placeholder="{{ field.label }}"
{% if list %}
list="{{ list }}"
{% endif %}
aria-describedby="{{ field.id_for_label }}_help"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
{% if field.value() != None %}value="{{ field.value() }}"{% endif %}
maxlength="{{ field.field.max_length }}"
{% if field.field.required %}required{% endif %}>
{% if list %}
<datalist id="{{ list }}">
</datalist>
{% endif %}
<small id="{{ field.id_for_label }}_help" class="form-text text-muted">
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% if field.help_text %}
<br/>
{% endif %}
</small>
</div>
{% endmacro %}
{% macro telephone_input(field, type='', step_size='0.01') -%}
<div class="form-group">
<input type="tel"
class="form-control"
placeholder="{{ field.label }}"
step="{{ step_size }}"
min="{{ field.field.min_value }}"
max="{{ field.field.max_value }}"
aria-describedby="{{ field.id_for_label }}_help"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
{% if field.value() != None %}value="{{ field.value() }}"{% endif %}
{% if field.field.required %}required{% endif %}>
<small id="{{ field.id_for_label }}_help" class="form-text text-muted">
{% if type %}
{{ field.label }} in {{ type }}
{% endif %}
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% if field.help_text %}
<br/>{{ field.help_text() }}
{% endif %}
</small>
</div>
{% endmacro %}

View File

@ -0,0 +1,73 @@
{% import 'macros/utils_macros.jinja2' as utils %}
{% macro item_base_attributes(item_base_form, forms, item) %}
<input type="hidden" name="type" value="{{ item_base_form.type.value() }}">
{% for error in item_base_form.non_field_errors() %}
<p class="alert alert-danger" role="alert">
{{ error }}
</p>
{% endfor %}
{{ forms.text_input(item_base_form.title) }}
{{ forms.textarea_input(item_base_form.description) }}
{{ forms.select_input(item_base_form.categories, multiple=True) }}
{{ forms.file_input(item_base_form.loan_agreement_file) }}
{{ forms.file_input(item_base_form.images, multiple=True) }}
{% if item and item.images.count() > 0 %}
<label>
Bestehende Bilder (Zum Löschen selektieren)
</label>
{{ forms.image_deletion_input(existing_images=item.images.all()) }}
<a class="btn btn-primary" href="{{ url('accounts:order-images', args=[item.id]) }}">Bilder manuell sortieren</a>
{% endif %}
{% endmacro %}
{% macro item_location(item_base_form, forms) %}
<div class="pb-4">
<p>Ort</p>
{{ forms.text_input(item_base_form.location_title) }}
{{ forms.number_input(item_base_form.location_house_number,step_size='1') }}
{{ forms.text_input(item_base_form.location_street) }}
{{ forms.text_input(item_base_form.location_city) }}
{{ forms.number_input(item_base_form.location_latitude) }}
{{ forms.number_input(item_base_form.location_longitude) }}
</div>
{% endmacro %}
{% macro item_dimension(item_base_form, forms) %}
<div class="pb-4">
<p>Abmessungen</p>
{{ forms.number_input(item_base_form.dimension_width) }}
{{ forms.number_input(item_base_form.dimension_height) }}
{{ forms.number_input(item_base_form.dimension_depth) }}
</div>
{% endmacro %}
{% macro item_weight_amount(item_base_form, forms) %}
<div class="pb-4">
{{ forms.number_input(item_base_form.weight) }}
{{ forms.number_input(item_base_form.amount, step_size='1') }}
</div>
{% endmacro %}
{% macro item_loan_agreement(item_base_form, forms) %}
<div class="pb-4">
<p>Leihvereinbarung
<small>(Für eine Schenkung bitte leer lassen)</small>
</p>
{{ forms.number_input(item_base_form.loan_caution) }}
{{ forms.number_input(item_base_form.loan_single_rent) }}
{{ forms.select_input(item_base_form.loan_rental_fee_interval_unit) }}
{{ forms.number_input(item_base_form.loan_rental_fee_costs) }}
</div>
{% endmacro %}
{% macro item_form_buttons(item_base_form, forms) %}
<div class="row mb-2">
<div class="col-6 text-right">
<a href="{{ url('accounts:account') }}" class="btn btn-danger">Abbrechen</a>
</div>
<div class="col-6 text-left">
<button type="submit" class="btn btn-primary text-right">Speichern</button>
</div>
</div>
{% endmacro %}

View File

@ -0,0 +1,257 @@
{# author: Marius Hofmann #}
{% macro format_money(float_value) -%}
{{ '{:10.2f} €'.format(float_value).replace('.', ',') }}
{% endmacro %}
{% macro format_mass(float_value) -%}
{{ '{:10.2f} kg'.format(float_value).replace('.', ',') }}
{% endmacro %}
{% macro format_distance(float_value) -%}
{{ '{:10.2f}m'.format(float_value).replace('.', ',') }}
{% endmacro %}
{% macro get_item_default_image(item) -%}
{% if item.images.all()[0] %}
<img class="card-img-top" src="{{ item.images.all()[0].file.url }}" alt="Item default image">
{% else %}
<i class="far fa-image fa-10x" title="Kein Standard-Bild definiert" alt="Kein Standard-Bild definiert!"></i>
{% endif %}
{% endmacro %}
{% macro get_item_shortened_desc(item) -%}
{% if item.description %}
{{ item.description|truncate(20, True, '...') }}
{% endif %}
{% endmacro %}
{% macro get_item_image_ligthbox(item) -%}
{% if item.images.all()[0] %}
{# Used this https://lokeshdhakar.com/projects/lightbox2/ to realize the lightbox#}
<script type="text/javascript">
$(document).ready(function () {
$('#lightbox-trigger').click(function () {
$('.lightbox-item').first().trigger('click');
});
});
</script>
<div class="row">
<div class="col-12">
<a id="lightbox-trigger" href="#">
<img class="img-fluid" src="{{ item.images.all()[0].file.url }}"
alt="Item default image">
</a>
</div>
</div>
<div class="row px-2">
{% for image in item.images.all() %}
<div class="col-2 px-1">
<a class="lightbox-item" href="{{ image.file.url }}" data-lightbox="{{ title }}"
data-title="{{ item.title }}">
<img src="{{ image.thumb.url }}" class="media-object img-thumbnail" alt="Bild">
</a>
</div>
{% endfor %}
</div>
{% else %}
<i class="far fa-image fa-10x" title="Kein Standard-Bild definiert" alt="Kein Standard-Bild definiert!"></i>
{% endif %}
{% endmacro %}
{% macro print_item_images(item, include_default=False) -%}
{% for image in item.images.all() %}
{% if loop.index0 > 0 or include_default %}
<div class="col-12 col-xs-12 col-md-6 col-lg-6 col-xl-3 pb-2">
<div class="card w-100" style="width: 18rem;">
<img class="img-fluid" src="{{ image.file.url }}" alt="Item image">
</div>
</div>
{% endif %}
{% endfor %}
{% endmacro %}
{% macro mini_map(location, zoomlevel=13, width=300, height=300) -%}
<script>
document.addEventListener("DOMContentLoaded", function (event) {
let map = L.map('mini-map').setView([{{ location.latitude }}, {{ location.longitude }}], {{ zoomlevel }});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
marker = L.marker([{{ location.latitude }}, {{ location.longitude }}]);
marker.addTo(map);
map.addControl(new L.Control.Fullscreen());
});
</script>
<div id="mini-map" style="width: {{ width }}px; height: {{ height }}px;">
</div>
{% endmacro %}
{% macro filter_panel(types) %}
<div class="row justify-content-center">
<div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-2 text-center">
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-secondary type-button" value="{{ types.venue }}">Venue</button>
<button type="button" class="btn btn-secondary type-button" value="{{ types.service }}">Service</button>
<button type="button" class="btn btn-secondary type-button" value="{{ types.object }}">Objekt</button>
</div>
</div>
<div class="col-6 col-sm-6 col-md-12 col-lg-12 col-xl-12 mb-1">
<button class="btn btn-secondary w-100" type="button" data-toggle="collapse"
data-target="#categories-collapse"
aria-expanded="false" aria-controls="categories-collapse">
Kategorien
</button>
<div id="categories-collapse" class="collapse bg-secondary text-dark p-1 border-top border-primary">
<div id="category-sidebar"></div>
</div>
</div>
<div class="col-6 col-sm-6 col-md-12 col-lg-12 col-xl-12 mb-1">
<button class="btn btn-secondary w-100" type="button" data-toggle="collapse"
data-target="#options-collapse"
aria-expanded="false" aria-controls="options-collapse">
Optionen
</button>
<div id="options-collapse" class="collapse bg-secondary text-dark p-1 border-top border-primary">
<input type="number" class="form-control mb-2 mr-sm-2" id="min-amount"
placeholder="Minimale Anzahl" min="0">
<input type="number" step="0.01" class="form-control mb-2 mr-sm-2" id="max-weight"
placeholder="Maximales Gewicht" min="0">
</div>
</div>
<div class="col-6 col-sm-6 col-md-12 col-lg-12 col-xl-12 mb-1">
<button class="btn btn-secondary w-100" type="button" data-toggle="collapse"
data-target="#sizing-collapse"
aria-expanded="false" aria-controls="sizing-collapse">
Abmessungen
</button>
<div class="collapse bg-secondary text-dark p-1 border-top border-primary" id="sizing-collapse">
<div class="row">
<div class="col-6">
<input type="number" step="0.01" class="form-control mb-2 mr-sm-2" id="min-height"
placeholder="Min. Höhe" min="0">
</div>
<div class="col-6">
<input type="number" step="0.01" class="form-control mb-2 mr-sm-2" id="max-height"
placeholder="Max. Höhe" min="0">
</div>
</div>
<div class="row">
<div class="col-6">
<input type="number" step="0.01" class="form-control mb-2 mr-sm-2" id="min-width"
placeholder="Min. Breite" min="0">
</div>
<div class="col-6">
<input type="number" step="0.01" class="form-control mb-2 mr-sm-2" id="max-width"
placeholder="Max. Breite" min="0">
</div>
</div>
<div class="row">
<div class="col-6">
<input type="number" step="0.01" class="form-control mb-2 mr-sm-2" id="min-depth"
placeholder="Min. Tiefe" min="0">
</div>
<div class="col-6">
<input type="number" step="0.01" class="form-control mb-2 mr-sm-2" id="max-depth"
placeholder="Max. Tiefe" min="0">
</div>
</div>
</div>
</div>
<div class="col-6 col-sm-6 col-md-12 col-lg-12 col-xl-12 mb-1">
<button class="btn btn-secondary w-100" type="button" data-toggle="collapse"
data-target="#lender-collapse"
aria-expanded="false" aria-controls="lender-collapse">
Verleiher
</button>
<div id="lender-collapse" class="collapse bg-secondary text-dark p-1 border-top border-primary">
<select multiple class="form-control" id="lenderSelect"></select>
</div>
</div>
<div class="col-6 col-sm-6 col-md-12 col-lg-12 col-xl-12 mb-1">
<button class="btn btn-secondary w-100" type="button" data-toggle="collapse"
data-target="#loan-agreement-collapse"
aria-expanded="false" aria-controls="loan-agreement-collapse">
Leihvereinbarung
</button>
<div id="loan-agreement-collapse" class="collapse bg-secondary text-dark p-1 border-top border-primary">
<input type="number" class="form-control mb-2 mr-sm-2" id="max-caution"
placeholder="Max. Kaution" min="0">
<input type="number" class="form-control mb-2 mr-sm-2" id="max-single-rent"
placeholder="Max. einmalige Leihgebühr" min="0">
<div id="rental-fee-selection-group" class="form-group">
<label for="rentalFeeIntervalSelect">Zahlungsintervall</label>
<select class="form-control" id="rentalFeeIntervalSelect"></select>
</div>
<input type="number" class="form-control mb-2 mr-sm-2" id="max-rental-fee-costs"
placeholder="Max. Mietkosten" min="0">
</div>
</div>
<div class="col-6 col-sm-6 col-md-12 col-lg-12 col-xl-12 mb-1">
<button class="btn btn-secondary w-100" type="button" data-toggle="collapse"
data-target="#availability-collapse"
aria-expanded="false" aria-controls="availability-collapse">
Verfügbarkeit
</button>
<div id="availability-collapse" class="collapse bg-secondary text-dark p-1 border-top border-primary">
<div class="form-group row">
<label for="start-date" class="col-2 col-form-label">Von</label>
<div class="col-10">
<input class="form-control" type="date" value="" id="start-date">
</div>
</div>
<div class="form-group row">
<label for="end-date" class="col-2 col-form-label">Bis</label>
<div class="col-10">
<input class="form-control" type="date" value="" id="end-date">
</div>
</div>
</div>
</div>
<div class="col-6 col-sm-6 col-md-12 col-lg-12 col-xl-12 mb-1">
<button class="btn btn-secondary w-100" type="button" data-toggle="collapse"
data-target="#radius-based-search-collapse"
aria-expanded="false" aria-controls="radius-based-search-collapse">
Umkreissuche
</button>
<div id="radius-based-search-collapse"
class="collapse bg-secondary text-dark p-1 border-top border-primary">
<input type="number" class="form-control mb-2 mr-sm-2" id="house-number"
placeholder="Hausnummer" min="0">
<input class="form-control mb-2 mr-sm-2" type="text" placeholder="Straße" id="street">
<input class="form-control mb-2 mr-sm-2" type="text" placeholder="Ort" id="city">
<input type="number" step="0.1" class="form-control mb-2 mr-sm-2" id="distance"
placeholder="Distanz in km" min="0">
</div>
</div>
<div class="col-6 col-sm-6 col-md-12 col-lg-12 col-xl-12 mb-1 text-center">
<button id="reset-filter" class="btn btn-light w-50" type="button">Filter zurücksetzen</button>
</div>
</div>
{% endmacro %}
{% macro mailto(lender, subject, content) -%}
mailto:{{ lender.user.email }}?subject={{ subject|urlencode }}&body={{ content|urlencode }}
{% endmacro %}
{% macro request_mail_subject(items) -%}
Resourcenpool Bamberg: Anfrage zu {{ items|length }} Artikeln
{% endmacro %}
{% macro request_mail_content(lender, items, requesting_user=None) -%}
Guten Tag {{ lender.user.first_name }} {{ lender.user.last_name }}
Ich habe mich über den Resourcenpool Bamberg über Ihre Angebot informiert und würde gerne folgende{{ 'n' if items|count == 1 else '' }} Artikel ausleihen/buchen:
{% for item in items %}
- {{ item.title }}
{% endfor %}
Ich freue mich auf Ihre Antwort.
Mit freundlichen Grüßen
{% if requesting_user %}
{{ requesting_user.first_name }} {{ requesting_user.last_name }}
{% endif %}
{% endmacro %}

View File

@ -3,13 +3,7 @@
{% block groups_content %}
<h2>Gruppen</h2>
{% for group in realm_groups %}
<h3>{{ group.name }}</h3>
<p>DN: {{ group.dn }}</p>
{# <p>Nutzername: {{ group.name }}</p>#}
{# <h2>Mitglieder</h2>#}
{# {% for user in group.members %}#}
{# <p>{{ user }}</p>#}
{# {% endfor %}#}
<hr>
<p>{{ group.name }} - <a href="{{ url('realm-group-detail', args=[realm.id, group.dn]) }}">{{ group.dn }}</a>
</p>
{% endfor %}
{% endblock %}