Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Tag model to be able to tag Event #285

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api_volontaria/apps/user/tests/tests_view_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,12 @@ def test_profile(self):
'update': False,
'destroy': False,
},
'tag': {
'create': False,
'write': False
}
}

self.assertEqual(
content['permissions'],
permissions
Expand Down
5 changes: 4 additions & 1 deletion api_volontaria/apps/volunteer/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
TaskType,
Participation,
Cell,
)
Tag)


class ParticipationAdmin(ImportExportActionModelAdmin):
Expand Down Expand Up @@ -107,9 +107,11 @@ class EventAdmin(admin.ModelAdmin):
list_filter = [
'cell__name',
'task_type__name',
'tags'
]
date_hierarchy = 'start_time'
ordering = ('start_time',)
filter_horizontal = ('tags', )

@staticmethod
def status_volunteers(obj):
Expand All @@ -122,6 +124,7 @@ def status_volunteers_standby(obj):
str(obj.nb_volunteers_standby_needed)


admin.site.register(Tag)
admin.site.register(Event, EventAdmin)
admin.site.register(TaskType)
admin.site.register(Participation, ParticipationAdmin)
Expand Down
29 changes: 29 additions & 0 deletions api_volontaria/apps/volunteer/migrations/0004_add_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 2.2.12 on 2021-01-12 16:13

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('volunteer', '0003_event_description'),
]

operations = [
migrations.CreateModel(
name='Tag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, verbose_name='Name')),
],
options={
'verbose_name': 'Tag',
'verbose_name_plural': 'Tags',
},
),
migrations.AddField(
model_name='event',
name='tags',
field=models.ManyToManyField(related_name='events', to='volunteer.Tag'),
),
]
47 changes: 47 additions & 0 deletions api_volontaria/apps/volunteer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,48 @@ def has_object_update_permission(self, request):
return False


class Tag(models.Model):
"""
This class represents a event tag.
"""

class Meta:
verbose_name = _('Tag')
verbose_name_plural = _('Tags')

name = models.CharField(
verbose_name="Name",
max_length=100,
)

def __str__(self):
return self.name

@staticmethod
def has_create_permission(request):
return request.user.is_staff

@staticmethod
def has_write_permission(request):
return request.user.is_staff

@staticmethod
def has_delete_permission(request):
return request.user.is_staff

@staticmethod
def has_list_permission(request):
return True

@authenticated_users
def has_object_update_permission(self, request):
return request.user.is_staff

@authenticated_users
def has_object_destroy_permission(self, request):
return request.user.is_staff


class Event(models.Model):
"""
This class represents an event where volunteer can come to help.
Expand Down Expand Up @@ -184,6 +226,11 @@ class Meta:
on_delete=models.PROTECT,
)

tags = models.ManyToManyField(
Tag,
related_name='events',
)

def __str__(self):
return str(self.start_time) + ' - ' + str(self.end_time)

Expand Down
20 changes: 18 additions & 2 deletions api_volontaria/apps/volunteer/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from drf_writable_nested import WritableNestedModelSerializer
from rest_framework import serializers

from api_volontaria.apps.user.serializers import UserLightSerializer
Expand All @@ -6,7 +7,7 @@
Participation,
Cell,
Event,
)
Tag)


class CellSerializer(serializers.HyperlinkedModelSerializer):
Expand Down Expand Up @@ -60,9 +61,23 @@ def to_representation(self, instance):
return data


class EventSerializer(serializers.HyperlinkedModelSerializer):
class TagSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField()

class Meta:
model = Tag
fields = [
'id',
'url',
'name',
]


class EventSerializer(serializers.HyperlinkedModelSerializer,
WritableNestedModelSerializer):
id = serializers.ReadOnlyField()
tags = TagSerializer(many=True)

class Meta:
model = Event
fields = [
Expand All @@ -77,6 +92,7 @@ class Meta:
'nb_volunteers_standby',
'cell',
'task_type',
'tags',
]

def to_representation(self, instance):
Expand Down
105 changes: 102 additions & 3 deletions api_volontaria/apps/volunteer/tests/test_view_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Event,
Cell,
TaskType,
)
Tag)
from api_volontaria.factories import (
UserFactory,
AdminFactory,
Expand All @@ -37,7 +37,8 @@ class EventsTests(CustomAPITestCase):
'cell',
'task_type',
'nb_volunteers_standby',
'nb_volunteers'
'nb_volunteers',
'tags',
]

def setUp(self):
Expand Down Expand Up @@ -68,6 +69,10 @@ def setUp(self):
name='My new tasktype',
)

self.tag = Tag.objects.create(
name='My Tag',
)

self.event = Event.objects.create(
start_time=LOCAL_TIMEZONE.localize(datetime(2140, 1, 15, 8)),
end_time=LOCAL_TIMEZONE.localize(datetime(2140, 1, 17, 12)),
Expand All @@ -77,6 +82,8 @@ def setUp(self):
task_type=self.tasktype,
)

self.event.tags.add(self.tag)

def test_create_new_event_as_admin(self):
"""
Ensure we can create a new event if we are an admin.
Expand All @@ -94,7 +101,15 @@ def test_create_new_event_as_admin(self):
"task_type": reverse(
'tasktype-detail',
args=[self.tasktype.id],
)
),
"tags": [
{
"name": "Tag 1",
},
{
"name": "Tag 2",
},
],
}

self.client.force_authenticate(user=self.admin)
yanicolivier marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -108,8 +123,57 @@ def test_create_new_event_as_admin(self):
content = json.loads(response.content)

self.assertEqual(response.status_code, status.HTTP_201_CREATED)

self.assertEqual(len(content['tags']), 2)

self.check_attributes(content)

# def test_create_new_event_as_admin_with_existing_tag(self):
# """
# Ensure we can create a new event if we are
# an admin and add existing tag.
# """
# data_post = {
# "description": "My new event description",
# "start_time": LOCAL_TIMEZONE.localize(datetime(2100, 1, 13, 9)),
# "end_time": LOCAL_TIMEZONE.localize(datetime(2100, 1, 15, 10)),
# "nb_volunteers_needed": 10,
# "nb_volunteers_standby_needed": 0,
# "cell": reverse(
# 'cell-detail',
# args=[self.cell.id],
# ),
# "task_type": reverse(
# 'tasktype-detail',
# args=[self.tasktype.id],
# ),
# "tags": [
# {
# "url": "http://testserver/tags/" + str(self.tag.id),
# }
# ]
# }
#
# self.client.force_authenticate(user=self.admin)
#
# response = self.client.post(
# reverse('event-list'),
# data_post,
# format='json',
# )
#
# content = json.loads(response.content)
#
# self.assertEqual(response.status_code, status.HTTP_201_CREATED)
#
# test_tags_response = [
# {'id': 2, 'url': 'http://testserver/tags/2', 'name': 'Other Tag'}
# ]
#
# self.assertEqual(content['tags'], test_tags_response)
#
# self.check_attributes(content)

def test_create_new_event(self):
"""
Ensure we can't create a new event if we are a simple user.
Expand Down Expand Up @@ -264,6 +328,41 @@ def test_list_events(self):
self.assertEqual(len(content['results']), 1)
self.check_attributes(content['results'][0])

def test_list_events_with_tag_filter(self):
"""
Ensure we can list events with tag filtering.
"""
self.client.force_authenticate(user=self.user)

reverse_string = str(reverse('event-list') + "?tags__name=My Tag")

response = self.client.get(
reverse_string,
)

content = json.loads(response.content)

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(content['results']), 1)
self.check_attributes(content['results'][0])

def test_failed_to_list_events_with_tag_filter(self):
"""
Ensure we can list events with tag filtering.
"""
self.client.force_authenticate(user=self.user)

reverse_string = str(reverse('event-list') + "?tags__name=WRONG TAG")

response = self.client.get(
reverse_string,
)

content = json.loads(response.content)

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(content['results']), 0)

def test_bulk_events_as_users(self):
"""
Ensure we can't bulk add events if we are a simple user.
Expand Down
Loading