Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

Commit eb38574

Browse files
authored
Merge pull request #30 from belatrix/develop
Version 2.0 to production
2 parents 69a703f + a4f9c92 commit eb38574

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2000
-243
lines changed

BxEvents/settings/base.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# encoding: utf-8
12
"""
23
Django settings for BxEvents project.
34
@@ -90,6 +91,24 @@
9091
CONSTANCE_CONFIG = {
9192
'TEAM_MIN_SIZE': (5, 'Mininum number of team members.', int),
9293
'TEAM_MAX_SIZE': (8, 'Maximum number of team members.', int),
94+
'PARTICIPANT_REGISTERED': ('El participante ya está registrado',
95+
'Participant already registered', str),
96+
'IDEA_DELETED': ('Idea eliminada', 'Idea deletion message', str),
97+
'IDEA_EDIT_RESTRICTION': ('No puedes editar o borrar esta idea',
98+
'Idea edit or delete restriction', str),
99+
'IDEA_EXISTS': ('Esta idea ya existe', 'Idea already exists', str),
100+
'CANDIDATE_ALREADY': ('Ya se registró como candidato',
101+
'User already register as a candidate', str),
102+
'PARTICIPANT_IDEA_RESTRICTION': ('Ya se registro en una idea para este evento.',
103+
'Restriction message to avoid multiple registers for ideas in same event', str),
104+
'TEAM_MAX_SIZE_MESSAGE': ('Se alcanzó el número máximo de participantes por idea o ya está completo.',
105+
'Team max size reached', str),
106+
'TEAM_MIN_SIZE_MESSAGE': ('No se tiene el número mínimo de integrantes.',
107+
'Team min size not reached', str),
108+
'NOT_IDEA_OWNER': ('No eres el autor de la idea.', 'Not owner idea message', str),
109+
'USER_VOTED': ('Ya has registrado previamente tu voto', 'Message to user who already voted', str),
110+
'IDEA_EVALUATED': ('Esta idea ya fue evaluada en esta categoría',
111+
'Message to jury who already evaluate this idea in this category', str)
93112
}
94113

95114
# Database
@@ -135,7 +154,7 @@
135154

136155
LANGUAGE_CODE = 'en-us'
137156

138-
TIME_ZONE = 'UTC'
157+
TIME_ZONE = 'America/Lima'
139158

140159
USE_I18N = True
141160

events/admin.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from django.contrib import admin
22
from .models import City, Event, Interaction, Location, EventParticipant
3+
from .models import Meeting, Attendance
34

45

56
class CityAdmin(admin.ModelAdmin):
67
list_display = ('name', )
78

89

910
class EventAdmin(admin.ModelAdmin):
10-
list_display = ('title', 'datetime', 'image', 'details', 'is_upcoming', 'is_featured', 'get_cities')
11+
list_display = ('title', 'datetime', 'image', 'details', 'is_upcoming', 'is_featured', 'get_cities', 'is_active')
1112

1213

1314
class EventParticipantAdmin(admin.ModelAdmin):
@@ -22,8 +23,19 @@ class LocationAdmin(admin.ModelAdmin):
2223
list_display = ('name', 'latitude', 'longitude')
2324

2425

26+
class MeetingAdmin(admin.ModelAdmin):
27+
list_display = ('name', 'start_date', 'end_date', 'event', 'is_over', 'is_active')
28+
29+
30+
class AttendanceAdmin(admin.ModelAdmin):
31+
list_display = ('datetime', 'meeting', 'participant')
32+
search_fields = ['participant__email']
33+
34+
2535
admin.site.register(City, CityAdmin)
2636
admin.site.register(Event, EventAdmin)
2737
admin.site.register(EventParticipant, EventParticipantAdmin)
2838
admin.site.register(Interaction, InteractionAdmin)
2939
admin.site.register(Location, LocationAdmin)
40+
admin.site.register(Meeting, MeetingAdmin)
41+
admin.site.register(Attendance, AttendanceAdmin)

events/migrations/0001_initial.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Generated by Django 1.10.8 on 2018-04-19 11:27
2+
# Generated by Django 1.10.8 on 2018-05-13 02:10
33
from __future__ import unicode_literals
44

55
from django.conf import settings
@@ -16,6 +16,16 @@ class Migration(migrations.Migration):
1616
]
1717

1818
operations = [
19+
migrations.CreateModel(
20+
name='Attendance',
21+
fields=[
22+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
23+
('datetime', models.DateTimeField(auto_now_add=True)),
24+
],
25+
options={
26+
'ordering': ['-datetime'],
27+
},
28+
),
1929
migrations.CreateModel(
2030
name='City',
2131
fields=[
@@ -86,9 +96,38 @@ class Migration(migrations.Migration):
8696
'verbose_name_plural': 'locations',
8797
},
8898
),
99+
migrations.CreateModel(
100+
name='Meeting',
101+
fields=[
102+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
103+
('name', models.CharField(max_length=100, unique=True)),
104+
('start_date', models.DateTimeField()),
105+
('end_date', models.DateTimeField()),
106+
('is_active', models.BooleanField(default=True)),
107+
('is_over', models.BooleanField(default=False)),
108+
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.Event')),
109+
],
110+
options={
111+
'ordering': ['-start_date'],
112+
},
113+
),
89114
migrations.AddField(
90115
model_name='event',
91116
name='location',
92117
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='events.Location'),
93118
),
119+
migrations.AddField(
120+
model_name='attendance',
121+
name='meeting',
122+
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.Meeting'),
123+
),
124+
migrations.AddField(
125+
model_name='attendance',
126+
name='participant',
127+
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
128+
),
129+
migrations.AlterUniqueTogether(
130+
name='attendance',
131+
unique_together=set([('meeting', 'participant')]),
132+
),
94133
]

events/models.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,29 @@ class Meta(object):
8989
ordering = ['-pk']
9090
verbose_name = 'interaction item'
9191
verbose_name_plural = 'interaction items'
92+
93+
94+
@python_2_unicode_compatible
95+
class Meeting(models.Model):
96+
name = models.CharField(max_length=100, unique=True)
97+
event = models.ForeignKey(Event)
98+
start_date = models.DateTimeField()
99+
end_date = models.DateTimeField()
100+
is_active = models.BooleanField(default=True)
101+
is_over = models.BooleanField(default=False)
102+
103+
def __str__(self):
104+
return self.name
105+
106+
class Meta(object):
107+
ordering = ['-start_date']
108+
109+
110+
class Attendance(models.Model):
111+
meeting = models.ForeignKey(Meeting)
112+
participant = models.ForeignKey('participants.User')
113+
datetime = models.DateTimeField(auto_now_add=True)
114+
115+
class Meta(object):
116+
unique_together = ('meeting', 'participant')
117+
ordering = ["-datetime"]

events/permissions.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from rest_framework import permissions
2+
from rest_framework.compat import is_authenticated
3+
4+
from .models import Attendance
5+
6+
7+
SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
8+
9+
10+
class IsAttendee(permissions.BasePermission):
11+
message = 'Attendee restricted'
12+
13+
def has_permission(self, request, view):
14+
if request.user.is_anonymous:
15+
return (
16+
request.method in SAFE_METHODS or
17+
request.user and
18+
is_authenticated(request.user)
19+
)
20+
attendees = Attendance.objects.filter(participant__email=request.user.email).count()
21+
if attendees > 0:
22+
return True

events/serializers.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from rest_framework import serializers
2-
from .models import City, Event, Interaction
2+
from .models import City, Event, Interaction, Meeting
33

44

55
class CitySerializer(serializers.ModelSerializer):
@@ -19,3 +19,14 @@ class InteractionSerializer(serializers.ModelSerializer):
1919
class Meta(object):
2020
model = Interaction
2121
fields = '__all__'
22+
23+
24+
class MeetingSerializer(serializers.ModelSerializer):
25+
class Meta(object):
26+
model = Meeting
27+
fields = '__all__'
28+
29+
30+
class AttendanceRegisterSerializer(serializers.Serializer):
31+
meeting_id = serializers.IntegerField()
32+
user_email = serializers.CharField()

events/urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .views import event_detail, event_list, event_upcoming_list, event_past_list, event_featured, event_city_list
2+
from .views import meeting_list, register_attendance
23
# from .views import event_interaction, event_interaction_vote
34
from django.conf.urls import url
45
from ideas.views import idea_list, idea_vote
@@ -13,6 +14,8 @@
1314
url(r'^featured/$', event_featured, name='event_featured'),
1415
# url(r'^interaction/(?P<interaction_id>\d+)/vote$', event_interaction_vote, name='event_interaction_vote'),
1516
url(r'^list/$', event_list, name='event_list'),
17+
url(r'^meeting/list/$', meeting_list, name='meeting_list'),
1618
url(r'^upcoming/list/$', event_upcoming_list, name='event_upcoming_list'),
1719
url(r'^past/list/$', event_past_list, name='event_past_list'),
20+
url(r'^register/attendance/$', register_attendance, name='register_attendance'),
1821
]

events/views.py

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
1+
from constance import config
12
from django.shortcuts import get_object_or_404
23
from rest_framework import status
3-
from rest_framework.decorators import api_view
4+
from rest_framework.decorators import api_view, permission_classes
5+
from rest_framework.exceptions import NotAcceptable
46
from rest_framework.pagination import PageNumberPagination
7+
from rest_framework.permissions import IsAuthenticated
58
from rest_framework.response import Response
69
from utils.random_item import random_element_list
7-
from .models import Event, Interaction, City
8-
from .serializers import CitySerializer, EventSerializer, InteractionSerializer
10+
11+
from ideas.models import IdeaParticipant
12+
from ideas.serializers import IdeaParticipantsIdeasSerializer
13+
from participants.models import User
14+
from participants.permissions import IsStaff
15+
from participants.serializers import UserSerializer
16+
17+
from .models import Event, Interaction, City, Meeting, Attendance
18+
from .serializers import CitySerializer, EventSerializer, InteractionSerializer, MeetingSerializer
19+
from .serializers import AttendanceRegisterSerializer
920

1021

1122
@api_view(['GET', ])
@@ -32,6 +43,14 @@ def event_detail(request, event_id):
3243
def event_featured(request):
3344
"""
3445
Returns event featured
46+
---
47+
GET:
48+
parameters:
49+
- name: city
50+
description: set city_id to filter events by city
51+
type: string
52+
required: false
53+
paramType: query
3554
"""
3655
events = Event.objects.filter(is_active=True, is_featured=True)
3756

@@ -68,6 +87,14 @@ def event_featured(request):
6887
def event_interaction(request, event_id):
6988
"""
7089
Returns event interactions
90+
---
91+
GET:
92+
parameters:
93+
- name: pagination
94+
description: set true if you want paginated results
95+
type: string
96+
required: false
97+
paramType: query
7198
"""
7299
event = get_object_or_404(Event, pk=event_id, is_active=True)
73100
interactions = Interaction.objects.filter(event=event, is_active=True)
@@ -102,6 +129,14 @@ def event_interaction_vote(request, interaction_id):
102129
def event_list(request):
103130
"""
104131
Returns event list
132+
---
133+
GET:
134+
parameters:
135+
- name: city
136+
description: set city_id to filter events by city
137+
type: string
138+
required: false
139+
paramType: query
105140
"""
106141
events = Event.objects.all()
107142
if request.GET.get('city'):
@@ -126,6 +161,14 @@ def event_list(request):
126161
def event_upcoming_list(request):
127162
"""
128163
Returns upcoming event list
164+
---
165+
GET:
166+
parameters:
167+
- name: city
168+
description: set city_id to filter events by city
169+
type: string
170+
required: false
171+
paramType: query
129172
"""
130173
events = Event.objects.filter(is_upcoming=True, is_active=True)
131174
if request.GET.get('city'):
@@ -150,6 +193,14 @@ def event_upcoming_list(request):
150193
def event_past_list(request):
151194
"""
152195
Returns past event list
196+
---
197+
GET:
198+
parameters:
199+
- name: city
200+
description: set city_id to filter events by city
201+
type: string
202+
required: false
203+
paramType: query
153204
"""
154205
events = Event.objects.filter(is_upcoming=False, is_active=True)
155206
if request.GET.get('city'):
@@ -168,3 +219,43 @@ def event_past_list(request):
168219
else:
169220
serializer = EventSerializer(events, many=True)
170221
return Response(serializer.data, status=status.HTTP_200_OK)
222+
223+
224+
@api_view(['GET', ])
225+
@permission_classes((IsAuthenticated, IsStaff))
226+
def meeting_list(request):
227+
"""
228+
Returns meetings list to register attendance
229+
---
230+
GET:
231+
response_serializer: events.serializers.MeetingSerializer
232+
"""
233+
meetings = Meeting.objects.all().filter(is_active=True)
234+
serializer = MeetingSerializer(meetings, many=True)
235+
return Response(serializer.data, status=status.HTTP_200_OK)
236+
237+
238+
@api_view(['POST', ])
239+
@permission_classes((IsAuthenticated, IsStaff))
240+
def register_attendance(request):
241+
"""
242+
Register attendance to a meeting
243+
---
244+
POST:
245+
serializer: events.serializers.AttendanceRegisterSerializer
246+
"""
247+
serializer = AttendanceRegisterSerializer(data=request.data)
248+
if serializer.is_valid(raise_exception=True):
249+
meeting = get_object_or_404(Meeting, pk=serializer.validated_data['meeting_id'])
250+
user = get_object_or_404(User, email=serializer.validated_data['user_email'])
251+
try:
252+
Attendance.objects.create(meeting=meeting, participant=user)
253+
except Exception as e:
254+
print(e)
255+
raise NotAcceptable(config.PARTICIPANT_REGISTERED)
256+
257+
idea_participant = IdeaParticipant.objects.filter(user=user)
258+
user_serializer = UserSerializer(user)
259+
idea_serializer = IdeaParticipantsIdeasSerializer(idea_participant, many=True)
260+
return Response({'user': user_serializer.data,
261+
'ideas': idea_serializer.data}, status=status.HTTP_200_OK)

0 commit comments

Comments
 (0)