From 9103545a232416735eea60d5fe05c612e01f905b Mon Sep 17 00:00:00 2001 From: Gabriel Augendre Date: Sun, 3 Mar 2019 18:45:47 +0100 Subject: [PATCH] Allow creating, listing and leaving groups --- map/admin.py | 10 +++- map/migrations/0007_locationsharinggroup.py | 22 ++++++++ map/migrations/0008_auto_20190303_1834.py | 19 +++++++ map/models.py | 5 ++ map/static/map/style.css | 6 ++- map/templates/map/base.html | 2 +- map/templates/map/change_group.html | 19 +++++++ map/templates/map/leave_group.html | 20 +++++++ map/templates/map/list_groups.html | 27 ++++++++++ map/urls.py | 3 ++ map/views.py | 59 ++++++++++++++++++++- 11 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 map/migrations/0007_locationsharinggroup.py create mode 100644 map/migrations/0008_auto_20190303_1834.py create mode 100644 map/templates/map/change_group.html create mode 100644 map/templates/map/leave_group.html create mode 100644 map/templates/map/list_groups.html diff --git a/map/admin.py b/map/admin.py index bfc74de..29f7bea 100644 --- a/map/admin.py +++ b/map/admin.py @@ -1,7 +1,8 @@ from django.contrib import admin from django.contrib.admin import register from django.contrib.auth.admin import UserAdmin -from .models import Friend, FriendLocation + +from .models import Friend, FriendLocation, LocationSharingGroup admin.site.register(Friend, UserAdmin) @@ -13,3 +14,10 @@ class FriendLocationAdmin(admin.ModelAdmin): ('Place', {'fields': ('latitude', 'longitude')}), ('Dates', {'fields': ('start_date', 'end_date')}), ] + + +@register(LocationSharingGroup) +class LocationSharingGroupAdmin(admin.ModelAdmin): + list_display = [ + 'name', + ] diff --git a/map/migrations/0007_locationsharinggroup.py b/map/migrations/0007_locationsharinggroup.py new file mode 100644 index 0000000..4554757 --- /dev/null +++ b/map/migrations/0007_locationsharinggroup.py @@ -0,0 +1,22 @@ +# Generated by Django 2.1.7 on 2019-03-03 16:57 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('map', '0006_auto_20190303_1308'), + ] + + operations = [ + migrations.CreateModel( + name='LocationSharingGroup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=250)), + ('friends', models.ManyToManyField(related_name='location_sharing_groups', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/map/migrations/0008_auto_20190303_1834.py b/map/migrations/0008_auto_20190303_1834.py new file mode 100644 index 0000000..e3a727e --- /dev/null +++ b/map/migrations/0008_auto_20190303_1834.py @@ -0,0 +1,19 @@ +# Generated by Django 2.1.7 on 2019-03-03 17:34 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('map', '0007_locationsharinggroup'), + ] + + operations = [ + migrations.AlterField( + model_name='locationsharinggroup', + name='friends', + field=models.ManyToManyField(blank=True, related_name='location_sharing_groups', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/map/models.py b/map/models.py index 0d88eb4..94993d0 100644 --- a/map/models.py +++ b/map/models.py @@ -53,3 +53,8 @@ class FriendLocation(BaseModel): html += f' until {self.end_date}' return html + +class LocationSharingGroup(models.Model): + name = models.CharField(max_length=250) + friends = models.ManyToManyField(Friend, related_name='location_sharing_groups', blank=True) + diff --git a/map/static/map/style.css b/map/static/map/style.css index e1c5921..a1782b1 100644 --- a/map/static/map/style.css +++ b/map/static/map/style.css @@ -5,4 +5,8 @@ .messages-container { margin-top: 1em; -} \ No newline at end of file +} + +#quick-actions { + margin-bottom: 1em; +} diff --git a/map/templates/map/base.html b/map/templates/map/base.html index e654d9b..21445f5 100644 --- a/map/templates/map/base.html +++ b/map/templates/map/base.html @@ -45,7 +45,7 @@ {% block quick_actions %} {% if quick_actions %} -
+
{# Visible only on large screens #} {% for qa in quick_actions %} diff --git a/map/templates/map/change_group.html b/map/templates/map/change_group.html new file mode 100644 index 0000000..60e39f0 --- /dev/null +++ b/map/templates/map/change_group.html @@ -0,0 +1,19 @@ +{% extends 'map/base.html' %} +{% load crispy_forms_filters %} + +{% block title %}Create a group{% endblock %} +{% block h1 %}Create a group{% endblock %} + +{% block content %} +
+

Notice

+
+ All members in this group can see your location. +
+
+
+ {% csrf_token %} + {{ form|crispy }} + +
+{% endblock %} diff --git a/map/templates/map/leave_group.html b/map/templates/map/leave_group.html new file mode 100644 index 0000000..24ddfea --- /dev/null +++ b/map/templates/map/leave_group.html @@ -0,0 +1,20 @@ +{% extends 'map/base.html' %} +{% load crispy_forms_filters %} + +{% block title %}Leave a group{% endblock %} +{% block h1 %}Leave a group{% endblock %} + +{% block content %} +
+

Are you sure?

+
+ If you leave this group you will not be able to see the location of people in the group. + If you're the last member of the group, it will be deleted. +
+
+
+ {% csrf_token %} + + No, cancel +
+{% endblock %} diff --git a/map/templates/map/list_groups.html b/map/templates/map/list_groups.html new file mode 100644 index 0000000..cea13d5 --- /dev/null +++ b/map/templates/map/list_groups.html @@ -0,0 +1,27 @@ +{% extends 'map/base.html' %} +{% load crispy_forms_filters %} + +{% block title %}Manage your groups{% endblock %} +{% block h1 %}Manage your groups{% endblock %} + +{% block content %} +
+

Notice

+
+ Here you can list and manage groups you belong to. All members in these groups can see your location. +
+
+ +
    + {% for group in groups %} +
  • + {{ group.name }} + + {{ group.friends.count }} + Leave + +
  • + {% endfor %} +
+ +{% endblock %} diff --git a/map/urls.py b/map/urls.py index b28ea51..845184d 100644 --- a/map/urls.py +++ b/map/urls.py @@ -7,6 +7,9 @@ urlpatterns = [ path('change-location', views.EditLocationView.as_view(), name='change-location'), path('add-location', views.AddLocationView.as_view(), name='add-location'), path('delete-location', views.DeleteLocationView.as_view(), name='delete-location'), + path('manage-groups', views.ManageGroupsView.as_view(), name='manage-groups'), + path('add-group', views.CreateGroupView.as_view(), name='add-group'), + path('leave-group/', views.LeaveGroupView.as_view(), name='leave-group'), path('accounts/profile', views.UpdateProfileView.as_view(), name='change-profile'), path('accounts/profile/delete', views.DeleteProfileView.as_view(), name='delete-profile'), ] diff --git a/map/views.py b/map/views.py index 9fffb54..e6627a1 100644 --- a/map/views.py +++ b/map/views.py @@ -15,7 +15,7 @@ class MapView(LoginRequiredMixin, QuickActionsMixin, generic.ListView): def get_quick_actions(self): if hasattr(self.request.user, 'location'): - return [{ + actions = [{ 'url': reverse_lazy('change-location'), 'category': 'primary', 'display': f'Change your location' @@ -25,12 +25,20 @@ class MapView(LoginRequiredMixin, QuickActionsMixin, generic.ListView): 'display': f'Delete your location' }] else: - return [{ + actions = [{ 'url': reverse_lazy('add-location'), 'category': 'primary', 'display': f'Add your location' }] + actions.append({ + 'url': reverse_lazy('manage-groups'), + 'category': 'secondary', + 'display': f'Manage your groups' + }) + + return actions + class EditLocationView(LoginRequiredMixin, generic.UpdateView): model = models.FriendLocation @@ -121,3 +129,50 @@ class DeleteProfileView(LoginRequiredMixin, generic.DeleteView): def get_success_url(self): messages.success(self.request, 'Your profile has been successfully and permanently deleted') return super().get_success_url() + + +class ManageGroupsView(LoginRequiredMixin, QuickActionsMixin, generic.ListView): + model = models.LocationSharingGroup + context_object_name = 'groups' + template_name = 'map/list_groups.html' + + def get_queryset(self): + return self.request.user.location_sharing_groups.all() + + def get_quick_actions(self): + return [{ + 'url': reverse_lazy('add-group'), + 'category': 'primary', + 'display': 'Create a group' + }] + + +class CreateGroupView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): + model = models.LocationSharingGroup + context_object_name = 'group' + template_name = 'map/change_group.html' + success_url = reverse_lazy('manage-groups') + + fields = [ + 'name' + ] + + def get_success_url(self): + self.object.friends.add(self.request.user) + messages.success(self.request, 'The group has been successfully created') + return super().get_success_url() + + +class LeaveGroupView(LoginRequiredMixin, generic.UpdateView): + model = models.LocationSharingGroup + context_object_name = 'group' + template_name = 'map/leave_group.html' + fields = [] + success_url = reverse_lazy('manage-groups') + + def get_success_url(self): + self.object.friends.remove(self.request.user) + if self.object.friends.count() == 0: + self.object.delete() + messages.success(self.request, 'You successfully left the group') + return super().get_success_url()