Skip to content

Commit

Permalink
Merge pull request #216 from CatalystCode/feature/random-document-sor…
Browse files Browse the repository at this point in the history
…t-order

Feature/Add option to randomize document order per user
  • Loading branch information
Hironsan committed Jun 10, 2019
2 parents bd00214 + bbc68ff commit 0c14143
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 7 deletions.
10 changes: 8 additions & 2 deletions app/server/api.py
Expand Up @@ -3,7 +3,7 @@
from django.conf import settings
from django.shortcuts import get_object_or_404, redirect
from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Count
from django.db.models import Count, F
from libcloud.base import DriverType, get_driver
from libcloud.storage.types import ContainerDoesNotExistError, ObjectDoesNotExistError
from rest_framework import generics, filters, status
Expand Down Expand Up @@ -129,7 +129,13 @@ class DocumentList(generics.ListCreateAPIView):
permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)

def get_queryset(self):
queryset = self.queryset.filter(project=self.kwargs['project_id'])
project = get_object_or_404(Project, pk=self.kwargs['project_id'])

queryset = self.queryset.filter(project=project)

if project.randomize_document_order:
queryset = queryset.annotate(sort_id=F('id') % self.request.user.id).order_by('sort_id')

return queryset

def perform_create(self, serializer):
Expand Down
2 changes: 1 addition & 1 deletion app/server/forms.py
Expand Up @@ -7,4 +7,4 @@ class ProjectForm(forms.ModelForm):

class Meta:
model = Project
fields = ('name', 'description', 'project_type', 'users')
fields = ('name', 'description', 'project_type', 'users', 'randomize_document_order')
18 changes: 18 additions & 0 deletions app/server/migrations/0002_project_randomize_document_order.py
@@ -0,0 +1,18 @@
# Generated by Django 2.1.7 on 2019-05-22 18:56

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('server', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='project',
name='randomize_document_order',
field=models.BooleanField(default=False),
),
]
1 change: 1 addition & 0 deletions app/server/models.py
Expand Up @@ -25,6 +25,7 @@ class Project(PolymorphicModel):
updated_at = models.DateTimeField(auto_now=True)
users = models.ManyToManyField(User, related_name='projects')
project_type = models.CharField(max_length=30, choices=PROJECT_CHOICES)
randomize_document_order = models.BooleanField(default=False)

def get_absolute_url(self):
return reverse('upload', args=[self.id])
Expand Down
12 changes: 8 additions & 4 deletions app/server/serializers.py
Expand Up @@ -75,31 +75,35 @@ class ProjectSerializer(serializers.ModelSerializer):

class Meta:
model = Project
fields = ('id', 'name', 'description', 'guideline', 'users', 'project_type', 'image', 'updated_at')
fields = ('id', 'name', 'description', 'guideline', 'users', 'project_type', 'image', 'updated_at',
'randomize_document_order')
read_only_fields = ('image', 'updated_at')


class TextClassificationProjectSerializer(serializers.ModelSerializer):

class Meta:
model = TextClassificationProject
fields = ('id', 'name', 'description', 'guideline', 'users', 'project_type', 'image', 'updated_at')
fields = ('id', 'name', 'description', 'guideline', 'users', 'project_type', 'image', 'updated_at',
'randomize_document_order')
read_only_fields = ('image', 'updated_at', 'users')


class SequenceLabelingProjectSerializer(serializers.ModelSerializer):

class Meta:
model = SequenceLabelingProject
fields = ('id', 'name', 'description', 'guideline', 'users', 'project_type', 'image', 'updated_at')
fields = ('id', 'name', 'description', 'guideline', 'users', 'project_type', 'image', 'updated_at',
'randomize_document_order')
read_only_fields = ('image', 'updated_at', 'users')


class Seq2seqProjectSerializer(serializers.ModelSerializer):

class Meta:
model = Seq2seqProject
fields = ('id', 'name', 'description', 'guideline', 'users', 'project_type', 'image', 'updated_at')
fields = ('id', 'name', 'description', 'guideline', 'users', 'project_type', 'image', 'updated_at',
'randomize_document_order')
read_only_fields = ('image', 'updated_at', 'users')


Expand Down
13 changes: 13 additions & 0 deletions app/server/static/components/projects.vue
Expand Up @@ -42,6 +42,17 @@
option(value="Seq2seq") sequence to sequence
p.help.is-danger {{ projectTypeError }}

div.field
label.checkbox
input(
v-model="randomizeDocumentOrder"
name="randomize_document_order"
type="checkbox"
style="margin-right: 0.25em;"
required
)
| Randomize document order per user

footer.modal-card-foot.pt20.pb20.pr20.pl20.has-background-white-ter
button.button.is-primary(v-on:click="create()") Create
button.button(v-on:click="isActive = !isActive") Cancel
Expand Down Expand Up @@ -131,6 +142,7 @@ export default {
projectNameError: '',
username: '',
isSuperuser: false,
randomizeDocumentOrder: false,
}),
computed: {
Expand Down Expand Up @@ -182,6 +194,7 @@ export default {
name: this.projectName,
description: this.description,
project_type: this.projectType,
randomize_document_order: this.randomizeDocumentOrder,
guideline: 'Please write annotation guideline.',
resourcetype: this.resourceType(),
};
Expand Down
32 changes: 32 additions & 0 deletions app/server/tests/test_api.py
Expand Up @@ -297,9 +297,14 @@ def setUpTestData(cls):
cls.main_project = mommy.make('server.TextClassificationProject', users=[project_member, super_user])
mommy.make('server.Document', project=cls.main_project)

cls.random_order_project = mommy.make('server.TextClassificationProject', users=[project_member, super_user],
randomize_document_order=True)
mommy.make('server.Document', 100, project=cls.random_order_project)

sub_project = mommy.make('server.TextClassificationProject', users=[non_project_member])
mommy.make('server.Document', project=sub_project)
cls.url = reverse(viewname='doc_list', args=[cls.main_project.id])
cls.random_order_project_url = reverse(viewname='doc_list', args=[cls.random_order_project.id])
cls.data = {'text': 'example'}

def test_returns_docs_to_project_member(self):
Expand All @@ -308,6 +313,33 @@ def test_returns_docs_to_project_member(self):
response = self.client.get(self.url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_returns_docs_in_consistent_order_for_all_users(self):
self.client.login(username=self.project_member_name, password=self.project_member_pass)
user1_documents = self.client.get(self.url, format='json').json().get('results')
self.client.logout()

self.client.login(username=self.super_user_name, password=self.super_user_pass)
user2_documents = self.client.get(self.url, format='json').json().get('results')
self.client.logout()

self.assertEqual(user1_documents, user2_documents)

def test_can_return_docs_in_consistent_random_order(self):
self.client.login(username=self.project_member_name, password=self.project_member_pass)
user1_documents1 = self.client.get(self.random_order_project_url, format='json').json().get('results')
user1_documents2 = self.client.get(self.random_order_project_url, format='json').json().get('results')
self.client.logout()
self.assertEqual(user1_documents1, user1_documents2)

self.client.login(username=self.super_user_name, password=self.super_user_pass)
user2_documents1 = self.client.get(self.random_order_project_url, format='json').json().get('results')
user2_documents2 = self.client.get(self.random_order_project_url, format='json').json().get('results')
self.client.logout()
self.assertEqual(user2_documents1, user2_documents2)

self.assertNotEqual(user1_documents1, user2_documents1)
self.assertNotEqual(user1_documents2, user2_documents2)

def test_do_not_return_docs_to_non_project_member(self):
self.client.login(username=self.non_project_member_name,
password=self.non_project_member_pass)
Expand Down

0 comments on commit 0c14143

Please sign in to comment.