mirror of
https://github.com/umap-project/umap.git
synced 2025-04-29 11:52:38 +02:00
wip: add very basic CRUD for groups
This commit is contained in:
parent
a3e972bf5d
commit
9b2a99019b
11 changed files with 199 additions and 18 deletions
|
@ -1,6 +1,7 @@
|
|||
from functools import wraps
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse_lazy
|
||||
|
@ -60,3 +61,14 @@ def can_view_map(view_func):
|
|||
return view_func(request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def group_members_only(view_func):
|
||||
@wraps(view_func)
|
||||
def wrapper(request, *args, **kwargs):
|
||||
group = get_object_or_404(Group, pk=kwargs["pk"])
|
||||
if group not in request.user.groups.all():
|
||||
return HttpResponseForbidden()
|
||||
return view_func(request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
from django.contrib.gis.geos import Point
|
||||
from django.forms.utils import ErrorList
|
||||
from django.template.defaultfilters import slugify
|
||||
|
@ -110,3 +111,13 @@ class UserProfileForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = User
|
||||
fields = ("username", "first_name", "last_name")
|
||||
|
||||
|
||||
class GroupForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = ["name", "members"]
|
||||
|
||||
members = forms.ModelMultipleChoiceField(
|
||||
queryset=User.objects.all(), widget=forms.CheckboxSelectMultiple
|
||||
)
|
||||
|
|
19
umap/templates/auth/group_confirm_delete.html
Normal file
19
umap/templates/auth/group_confirm_delete.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends "umap/content.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% include "umap/dashboard_menu.html" with selected="groups" %}
|
||||
<div class="wrapper">
|
||||
<div class="row">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
Are you sure you want to delete "{{ object }}"?
|
||||
</p>
|
||||
{{ form }}
|
||||
<input type="submit" value="Confirm">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock maincontent %}
|
22
umap/templates/auth/group_detail.html
Normal file
22
umap/templates/auth/group_detail.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
{% extends "umap/content.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block maincontent %}
|
||||
<div class="col wide">
|
||||
<h2 class="section">
|
||||
{% blocktrans %}Browse {{ current_group }}'s maps{% endblocktrans %}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<div class="map_list row">
|
||||
{% if maps %}
|
||||
{% include "umap/map_list.html" %}
|
||||
{% else %}
|
||||
<div>
|
||||
{% blocktrans %}{{ current_group }} has no public maps.{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock maincontent %}
|
28
umap/templates/auth/group_form.html
Normal file
28
umap/templates/auth/group_form.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
{% extends "umap/content.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% include "umap/dashboard_menu.html" with selected="groups" %}
|
||||
<div class="wrapper">
|
||||
<div class="row">
|
||||
{% if form.non_field_errors %}
|
||||
<ul class="form-errors">
|
||||
{% for error in form.non_field_errors %}
|
||||
<li>
|
||||
{{ error }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<form id="group_form" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<input type="submit" value="{% trans 'Save' %}" />
|
||||
</form>
|
||||
{% if group.user_set.count == 1 %}
|
||||
<a href="{% url 'group_delete' group.pk %}">{% trans "Delete this group" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock maincontent %}
|
|
@ -3,12 +3,7 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% block maincontent %}
|
||||
<div class="row">
|
||||
<h2 class="section tabs">
|
||||
<a href="{% url "user_dashboard" %}">{% trans "My Maps" %}</a>
|
||||
<a class="selected" href="{% url 'user_profile' %}">{% trans "My Profile" %}</a>
|
||||
</h2>
|
||||
</div>
|
||||
{% include "umap/dashboard_menu.html" with selected="profile" %}
|
||||
<div class="wrapper">
|
||||
<div class="row">
|
||||
{% if form.non_field_errors %}
|
||||
|
|
15
umap/templates/umap/dashboard_menu.html
Normal file
15
umap/templates/umap/dashboard_menu.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% load i18n %}
|
||||
|
||||
<div class="row">
|
||||
<h2 class="section tabs">
|
||||
{% if selected == "maps" %}
|
||||
<a class="selected" href="{% url 'user_dashboard' %}">{% blocktranslate with count=maps.paginator.count %}My Maps ({{ count }}){% endblocktranslate %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'user_dashboard' %}">{% trans "My Maps" %}</a>
|
||||
{% endif %}
|
||||
<a {% if selected == "profile" %}class="selected"{% endif %}
|
||||
href="{% url 'user_profile' %}">{% trans "My profile" %}</a>
|
||||
<a {% if selected == "groups" %}class="selected"{% endif %}
|
||||
href="{% url 'user_groups' %}">{% trans "My teams" %}</a>
|
||||
</h2>
|
||||
</div>
|
|
@ -7,13 +7,7 @@
|
|||
{% endblock head_title %}
|
||||
{% block maincontent %}
|
||||
{% trans "Search my maps" as placeholder %}
|
||||
<div class="row">
|
||||
<h2 class="section tabs">
|
||||
<a class="selected" href="{% url 'user_dashboard' %}">{% blocktranslate with count=maps.paginator.count %}My Maps ({{ count }}){% endblocktranslate %}
|
||||
</a>
|
||||
<a href="{% url 'user_profile' %}">{% trans "My profile" %}</a>
|
||||
</h2>
|
||||
</div>
|
||||
{% include "umap/dashboard_menu.html" with selected="maps" %}
|
||||
<div class="wrapper">
|
||||
<div class="row">
|
||||
<div class="table-header">
|
||||
|
|
19
umap/templates/umap/user_groups.html
Normal file
19
umap/templates/umap/user_groups.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends "umap/content.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% include "umap/dashboard_menu.html" with selected="groups" %}
|
||||
<div class="wrapper">
|
||||
<div class="row">
|
||||
<ul>
|
||||
{% for group in groups %}
|
||||
<li>
|
||||
{{ group }} <a href="{% url 'group_update' group.pk %}">({% trans "Edit" %})</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<a href="{% url 'group_new' %}">{% trans "New team" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
18
umap/urls.py
18
umap/urls.py
|
@ -15,6 +15,7 @@ from . import views
|
|||
from .decorators import (
|
||||
can_edit_map,
|
||||
can_view_map,
|
||||
group_members_only,
|
||||
login_required_if_not_anonymous_allowed,
|
||||
)
|
||||
from .utils import decorated_patterns
|
||||
|
@ -96,8 +97,8 @@ i18n_urls += decorated_patterns(
|
|||
)
|
||||
i18n_urls += decorated_patterns(
|
||||
[ensure_csrf_cookie],
|
||||
re_path(r"^map/$", views.MapPreview.as_view(), name="map_preview"),
|
||||
re_path(r"^map/new/$", views.MapNew.as_view(), name="map_new"),
|
||||
path("map/", views.MapPreview.as_view(), name="map_preview"),
|
||||
path("map/new/", views.MapNew.as_view(), name="map_new"),
|
||||
)
|
||||
i18n_urls += decorated_patterns(
|
||||
[login_required_if_not_anonymous_allowed, never_cache],
|
||||
|
@ -110,9 +111,16 @@ i18n_urls += decorated_patterns(
|
|||
views.ToggleMapStarStatus.as_view(),
|
||||
name="map_star",
|
||||
),
|
||||
re_path(r"^me$", views.user_dashboard, name="user_dashboard"),
|
||||
re_path(r"^me/profile$", views.user_profile, name="user_profile"),
|
||||
re_path(r"^me/download$", views.user_download, name="user_download"),
|
||||
path("me", views.user_dashboard, name="user_dashboard"),
|
||||
path("me/profile", views.user_profile, name="user_profile"),
|
||||
path("me/download", views.user_download, name="user_download"),
|
||||
path("me/groups", views.UserGroups.as_view(), name="user_groups"),
|
||||
path("group/create/", views.GroupNew.as_view(), name="group_new"),
|
||||
)
|
||||
i18n_urls += decorated_patterns(
|
||||
[login_required, group_members_only],
|
||||
path("group/<int:pk>/edit/", views.GroupUpdate.as_view(), name="group_update"),
|
||||
path("group/<int:pk>/delete/", views.GroupDelete.as_view(), name="group_delete"),
|
||||
)
|
||||
map_urls = [
|
||||
re_path(
|
||||
|
|
|
@ -61,6 +61,7 @@ from .forms import (
|
|||
DataLayerForm,
|
||||
DataLayerPermissionsForm,
|
||||
FlatErrorList,
|
||||
GroupForm,
|
||||
MapSettingsForm,
|
||||
SendLinkForm,
|
||||
UpdateMapPermissionsForm,
|
||||
|
@ -189,6 +190,63 @@ class About(Home):
|
|||
about = About.as_view()
|
||||
|
||||
|
||||
class GroupNew(CreateView):
|
||||
model = Group
|
||||
fields = ["name"]
|
||||
success_url = reverse_lazy("user_groups")
|
||||
|
||||
def form_valid(self, form):
|
||||
response = super().form_valid(form)
|
||||
self.request.user.groups.add(self.object)
|
||||
self.request.user.save()
|
||||
return response
|
||||
|
||||
|
||||
class GroupUpdate(UpdateView):
|
||||
model = Group
|
||||
form_class = GroupForm
|
||||
success_url = reverse_lazy("user_groups")
|
||||
|
||||
def get_initial(self):
|
||||
initial = super().get_initial()
|
||||
initial["members"] = self.object.user_set.all()
|
||||
return initial
|
||||
|
||||
def form_valid(self, form):
|
||||
for user in form.cleaned_data["members"]:
|
||||
user.groups.add(self.object)
|
||||
user.save()
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class GroupDelete(DeleteView):
|
||||
model = Group
|
||||
success_url = reverse_lazy("user_groups")
|
||||
|
||||
def form_valid(self, form):
|
||||
if self.object.user_set.count() > 1:
|
||||
return HttpResponseBadRequest(
|
||||
_("Cannot delete a group with more than one member")
|
||||
)
|
||||
messages.info(
|
||||
self.request,
|
||||
_("Group “%(name)s” has been deleted") % {"name": self.object.name},
|
||||
)
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class UserGroups(DetailView):
|
||||
model = User
|
||||
template_name = "umap/user_groups.html"
|
||||
|
||||
def get_object(self):
|
||||
return self.get_queryset().get(pk=self.request.user.pk)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs.update({"groups": self.object.groups.all()})
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class UserProfile(UpdateView):
|
||||
model = User
|
||||
form_class = UserProfileForm
|
||||
|
|
Loading…
Reference in a new issue