Add ability to join a team as a member, migrate team owners to admin members, add Attendee objects

This commit is contained in:
Michael Hall 2018-01-23 23:15:14 -05:00
parent 386d757fe9
commit b29eaf5457
12 changed files with 162 additions and 13 deletions

View file

@ -2,9 +2,9 @@ from django.contrib import admin
# Register your models here.
from .models.locale import Language, Continent, Country, SPR, City
from .models.profiles import UserProfile, Organization, Team
from .models.profiles import UserProfile, Organization, Team, Member
from .models.search import Searchable
from .models.events import Place, Event
from .models.events import Place, Event, Attendee
admin.site.register(Language)
admin.site.register(Continent)
@ -42,4 +42,6 @@ class EventAdmin(admin.ModelAdmin):
raw_id_fields = ('place', 'created_by')
admin.site.register(Event, EventAdmin)
admin.site.register(Member)

View file

@ -4,6 +4,13 @@ import datetime
from django.db import migrations, models
import django.db.models.deletion
ADMIN=2
def make_owner_admin(apps, schema_editor):
Team = apps.get_model('events', 'Team')
Member = apps.get_model('events', 'Member')
for team in Team.objects.all():
Member.objects.get_or_create(team=team, user=team.owner_profile, role=ADMIN, joined_date=team.created_date or datetime.datetime.now())
class Migration(migrations.Migration):
@ -27,4 +34,5 @@ class Migration(migrations.Migration):
name='members',
field=models.ManyToManyField(blank=True, related_name='memberships', through='events.Member', to='events.UserProfile'),
),
migrations.RunPython(make_owner_admin),
]

View file

@ -0,0 +1,36 @@
# Generated by Django 2.0 on 2018-01-24 03:03
import datetime
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('events', '0005_auto_20180108_2221'),
]
operations = [
migrations.CreateModel(
name='Attendee',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('role', models.SmallIntegerField(choices=[(0, 'Normal'), (1, 'Crew'), (2, 'Host')], db_index=True, default=0, verbose_name='Role')),
('status', models.SmallIntegerField(choices=[(-1, 'No'), (0, 'Maybe'), (1, 'Yes')], db_index=True, verbose_name='Attending?')),
('joined_date', models.DateTimeField(default=datetime.datetime.now)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.Event')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.UserProfile')),
],
),
migrations.AlterField(
model_name='team',
name='name',
field=models.CharField(max_length=256, verbose_name='Team Name'),
),
migrations.AddField(
model_name='event',
name='attendees',
field=models.ManyToManyField(blank=True, related_name='attending', through='events.Attendee', to='events.UserProfile'),
),
]

View file

@ -68,6 +68,8 @@ class Event(models.Model):
#image
#replies
attendees = models.ManyToManyField(UserProfile, through='Attendee', related_name="attending", blank=True)
def get_absolute_url(self):
return reverse('show-event', kwargs={'event_id': self.id, 'event_slug': self.slug})
@ -105,7 +107,7 @@ def update_event_searchable(event):
searchable.longitude = event.place.longitude or None
searchable.latitude = event.place.latitude
else:
searchable.location_name = ""
searchable.location_name = team.location_name
searchable.longitude = None
searchable.latitude = None
searchable.save()
@ -124,3 +126,26 @@ def slugify(s, ok=SLUG_OK, lower=True, spaces=False):
if not spaces:
new = re.sub('[-\s]+', '-', new)
return new.lower() if lower else new
class Attendee(models.Model):
NORMAL=0
CREW=1
HOST=2
ROLES = [
(NORMAL, _("Normal")),
(CREW, _("Crew")),
(HOST, _("Host"))
]
NO=-1
MAYBE=0
YES=1
STATUSES = [
(NO, _("No")),
(MAYBE, _("Maybe")),
(YES, _("Yes")),
]
event = models.ForeignKey(Event, on_delete=models.CASCADE)
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
role = models.SmallIntegerField(_("Role"), choices=ROLES, default=NORMAL, db_index=True)
status = models.SmallIntegerField(_("Attending?"), choices=STATUSES, db_index=True)
joined_date = models.DateTimeField(default=datetime.datetime.now)

View file

@ -175,3 +175,11 @@ class Member(models.Model):
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
role = models.SmallIntegerField(_("Member Role"), choices=ROLES, default=NORMAL, db_index=True)
joined_date = models.DateTimeField(default=datetime.datetime.now)
@property
def role_name(self):
print("Role name: %s=%s" % (self.role, Member.ROLES[self.role]))
return Member.ROLES[self.role][1]
def __str__(self):
return '%s in %s' % (self.user, self.team)

View file

@ -0,0 +1,15 @@
{% if member_list %}
<table border="0" width="960px">
{% for member in member_list %}
<tr>
<td>{{ member.user }}</td>
<td>{{ member.joined_date }}</td>
<td>{% if member.role > 0 %}{{ member.role_name }}{% endif %}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>No members yet.</p>
{% endif %}

View file

@ -1,5 +1,7 @@
from django.shortcuts import render
from django.shortcuts import render, redirect
from django.http import HttpResponse, JsonResponse
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from rest_framework.decorators import api_view, throttle_classes
from rest_framework.response import Response
@ -7,6 +9,7 @@ from rest_framework.response import Response
from .models.search import Searchable, SearchableSerializer
from .models.events import Event, Place, PlaceSerializer
from .models.locale import Country ,CountrySerializer, SPR, SPRSerializer, City, CitySerializer
from .models.profiles import Team, UserProfile, Member
import simplejson
@ -71,3 +74,27 @@ def city_list(request, *args, **kwargs):
serializer = CitySerializer(cities, many=True)
return Response(serializer.data)
def join_team(request, team_id):
if request.user.is_anonymous:
messages.add_message(request, messages.WARNING, message=_('You must be logged in to join a team.'))
return redirect('show-team', team_id=team_id)
team = Team.objects.get(id=team_id)
if request.user.profile in team.members.all():
messages.add_message(request, messages.INFO, message=_('You are already a member of this team.'))
return redirect('show-team', team_id=team_id)
new_member = Member.objects.create(team=team, user=request.user.profile, role=Member.NORMAL)
messages.add_message(request, messages.SUCCESS, message=_('Welcome to the team!'))
return redirect('show-team', team_id=team_id)
def leave_team(request, team_id):
if request.user.is_anonymous:
messages.add_message(request, messages.WARNING, message=_('You must be logged in to leave a team.'))
return redirect('show-team', team_id=team_id)
team = Team.objects.get(id=team_id)
if request.user.profile not in team.members.all():
messages.add_message(request, messages.INFO, message=_('You are not a member of this team.'))
return redirect('show-team', team_id=team_id)
Member.objects.filter(team=team, user=request.user.profile).delete()
messages.add_message(request, messages.SUCCESS, message=_('You are no longer on this team.'))
return redirect('show-team', team_id=team_id)

View file

@ -2,7 +2,7 @@
{% block content %}
<h2>Update {{team.name}}</h2>
<form action="{% url "create-team" %}" method="post">
<form action="{% url "edit-team" team.id %}" method="post">
{% csrf_token %}
{% include "events/team_form.html" %}
<br />

View file

@ -3,6 +3,10 @@
{% block content %}
<h2>Welcome to {{ team.name }}</h2>
<h4>Members</h4>
{% include "events/member_list.html" %}
<br/>
<h4>Upcoming Events</h4>
{% include "events/event_list.html" %}
{% if can_create_event %}
@ -17,5 +21,15 @@
<button type="submit" class="btn btn-secondary">Edit Team</button>
</form>
{% endif %}
{% if is_member %}
<form action="{% url 'leave-team' team.id %}" method="get">
<button type="submit" class="btn btn-danger">Leave Team</button>
</form>
{% else %}
<form action="{% url 'join-team' team.id %}" method="get">
<button type="submit" class="btn btn-success">Join Team</button>
</form>
{% endif %}
{% endblock %}

View file

@ -1,7 +1,14 @@
{% extends "get_together/base.html" %}
{% block content %}
{% include "events/team_list.html" %}
{% if my_teams %}
<h4>My Teams</h4>
{% include "events/team_list.html" with teams_list=my_teams %}
<br/>
{% endif %}
<h4>All Teams</h4>
{% include "events/team_list.html" with teams_list=all_teams%}
{% if request.user.is_authenticated %}
<br/>

View file

@ -32,16 +32,18 @@ urlpatterns = [
path('api/cities/', event_views.city_list),
path('events/', views.events_list, name='events'),
path('create-team/', views.create_team, name='create-team'),
path('+create-team/', views.create_team, name='create-team'),
path('teams/', views.teams_list, name='teams'),
path('team/<int:team_id>/', views.show_team, name='show-team'),
path('team/<int:team_id>/edit/', views.edit_team, name='edit-team'),
path('team/<int:team_id>/create-event/', views.create_event, name='create-event'),
path('events/<int:event_id>/edit/', views.edit_event, name='edit-event'),
path('team/<int:team_id>/+edit/', views.edit_team, name='edit-team'),
path('team/<int:team_id>/+join/', event_views.join_team, name='join-team'),
path('team/<int:team_id>/+leave/', event_views.leave_team, name='leave-team'),
path('team/<int:team_id>/+create-event/', views.create_event, name='create-event'),
path('events/<int:event_id>/+edit/', views.edit_event, name='edit-event'),
path('events/<int:event_id>/<str:event_slug>/', views.show_event, name='show-event'),
path('places/', views.places_list, name='places'),
path('create-place/', views.create_place, name='create-place'),
path('+create-place/', views.create_place, name='create-place'),
path('oauth/', include('social_django.urls', namespace='social')),
]

View file

@ -4,7 +4,7 @@ from django.contrib import messages
from django.shortcuts import render, redirect
from django.http import HttpResponse, JsonResponse
from events.models.profiles import Team
from events.models.profiles import Team, UserProfile, Member
from events.forms import TeamForm, NewTeamForm, TeamEventForm, NewTeamEventForm, NewPlaceForm
from events.models.events import Event, Place
@ -45,6 +45,7 @@ def create_team(request, *args, **kwargs):
new_team = form.save()
new_team.owner_profile = request.user.profile
new_team.save()
Member.objects.create(team=new_team, user=request.user.profile, role=Member.ADMIN)
return redirect('show-team', team_id=new_team.pk)
else:
context = {
@ -87,8 +88,10 @@ def edit_team(request, team_id):
def teams_list(request, *args, **kwargs):
teams = Team.objects.all()
context = {
'teams_list': teams,
'all_teams': teams,
}
if request.user.is_authenticated:
context['my_teams'] = request.user.profile.memberships.all()
return render(request, 'get_together/teams.html', context)
@ -98,6 +101,8 @@ def show_team(request, team_id, *args, **kwargs):
context = {
'team': team,
'events_list': team_events,
'is_member': request.user.profile in team.members.all(),
'member_list': Member.objects.filter(team=team),
'can_create_event': request.user.profile.can_create_event(team),
'can_edit_team': request.user.profile.can_edit_team(team),
}