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.
+
+
+
+{% 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.
+
+
+
+{% 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()