From 46dbc1a20d220dcfd957fc6dec3f6629ab6bae8c Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Sat, 22 Jul 2017 15:09:24 +0530 Subject: [PATCH 01/14] Add region model --- core/models.py | 4 ++++ core/tests.py | 25 ++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/core/models.py b/core/models.py index e7b5eed..2161d23 100644 --- a/core/models.py +++ b/core/models.py @@ -25,6 +25,10 @@ class Meta: def __str__(self): return '/%s/%s' % (self.user, self.repo) +class Region(models.Model): + """Used to store data for different regions.""" + region_name = models.CharField(max_length=100) + region_image = models.URLField(blank=True) class IssueLabel(models.Model): """ diff --git a/core/tests.py b/core/tests.py index b538cb2..c3fdffa 100644 --- a/core/tests.py +++ b/core/tests.py @@ -11,7 +11,7 @@ from requests.exceptions import ConnectionError from .models import (UserRepo, parse_issue, validate_and_store_issue, Issue, delete_closed_issues, - is_issue_valid, is_issue_state_open, periodic_issues_updater) + is_issue_valid, is_issue_state_open, periodic_issues_updater, Region) from .utils.mock_api import api_response_issues from .utils.services import request_github_issues @@ -63,6 +63,29 @@ def test_user_repo_model_can_delete_a_userrepo(self): new_count = UserRepo.objects.count() self.assertEqual(old_count, new_count) +class RegionModelTestCase(TestCase): + """This class defines the test suite for the `Region` model.""" + + def setUp(self): + """Define the test client and other test variables.""" + self.region_name = 'razat249' + self.region_image = 'github-view' + self.region_instance = Region(region_name=self.region_name, region_image=self.region_image) + + def test_region_model_can_create_region(self): + """Tests `Region` model can create Regions""" + old_count = Region.objects.count() + self.region_instance.save() + new_count = Region.objects.count() + self.assertNotEqual(old_count, new_count) + + def test_region_model_can_delete_region(self): + """Tests `Region` model can delete Regions""" + old_count = Region.objects.count() + self.region_instance.save() + self.region_instance.delete() + new_count = Region.objects.count() + self.assertEqual(old_count, new_count) class IssueModelAndFetcherTestCase(TestCase): """This class defines the test suite for the `issue fetcher` component.""" From 15a6fe93259da295eeaf392473754b02de634e7f Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Sat, 22 Jul 2017 15:31:35 +0530 Subject: [PATCH 02/14] connect issue model and user_repo mode with region model --- core/models.py | 14 ++++++++------ core/tests.py | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/core/models.py b/core/models.py index 2161d23..12de209 100644 --- a/core/models.py +++ b/core/models.py @@ -9,6 +9,11 @@ ISSUE_UPDATE_PERIOD = 15 # in minutes +class Region(models.Model): + """Used to store data for different regions.""" + region_name = models.CharField(max_length=100) + region_image = models.URLField(blank=True) + class UserRepo(models.Model): """ UserRepo model is used to store the username and repo-name @@ -16,6 +21,7 @@ class UserRepo(models.Model): """ user = models.CharField(max_length=100) repo = models.CharField(max_length=100) + regions = models.ManyToManyField(Region) created = models.DateTimeField(auto_now_add=True) class Meta: @@ -25,11 +31,6 @@ class Meta: def __str__(self): return '/%s/%s' % (self.user, self.repo) -class Region(models.Model): - """Used to store data for different regions.""" - region_name = models.CharField(max_length=100) - region_image = models.URLField(blank=True) - class IssueLabel(models.Model): """ Label model for storing labels of an issue. @@ -73,7 +74,8 @@ class Issue(models.Model): issue_labels = models.ManyToManyField(IssueLabel, blank=True) issue_url = models.URLField() issue_body = models.TextField() - + regions = models.ManyToManyField(Region) + class Meta: ordering = ('updated_at',) # Ascending order according to updated_at. diff --git a/core/tests.py b/core/tests.py index c3fdffa..e2f7da7 100644 --- a/core/tests.py +++ b/core/tests.py @@ -68,8 +68,8 @@ class RegionModelTestCase(TestCase): def setUp(self): """Define the test client and other test variables.""" - self.region_name = 'razat249' - self.region_image = 'github-view' + self.region_name = 'Mizilla India' + self.region_image = 'https://example.com/image.jpg' self.region_instance = Region(region_name=self.region_name, region_image=self.region_image) def test_region_model_can_create_region(self): From fcc2aee23c75ddc8688c9c2de919ed821a9f2b4d Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Sat, 22 Jul 2017 19:44:16 +0530 Subject: [PATCH 03/14] add regionlist view and change ordering in model by region name --- core/models.py | 3 +++ core/serializers.py | 13 +++++++++++-- core/tests.py | 17 +++++++++++++++++ core/views.py | 12 ++++++++++-- issue_parser/urls.py | 1 + 5 files changed, 42 insertions(+), 4 deletions(-) diff --git a/core/models.py b/core/models.py index 12de209..17065d7 100644 --- a/core/models.py +++ b/core/models.py @@ -14,6 +14,9 @@ class Region(models.Model): region_name = models.CharField(max_length=100) region_image = models.URLField(blank=True) + class Meta: + ordering = ('region_name',) # Ascending order according to region name. + class UserRepo(models.Model): """ UserRepo model is used to store the username and repo-name diff --git a/core/serializers.py b/core/serializers.py index 7d380b0..08e01d4 100644 --- a/core/serializers.py +++ b/core/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from core.models import UserRepo, Issue, IssueLabel +from core.models import UserRepo, Issue, IssueLabel, Region class UserRepoSerializer(serializers.ModelSerializer): @@ -20,6 +20,15 @@ class Meta: fields = ('label_id', 'label_name', 'label_color', 'label_url',) +class RegionSerializer(serializers.ModelSerializer): + """ + Serializer for `Region` Model. + """ + class Meta: + model = Region + fields = ('id','region_name', 'region_image',) + + class IssueSerializer(serializers.ModelSerializer): """ Serializer for `Issue` Model. @@ -30,4 +39,4 @@ class Meta: model = Issue fields = ('issue_id', 'title', 'experience_needed', 'expected_time', 'language', 'tech_stack', 'created_at', 'updated_at', - 'issue_number', 'issue_labels', 'issue_url', 'issue_body') + 'issue_number', 'issue_labels', 'issue_url', 'issue_body', 'regions',) diff --git a/core/tests.py b/core/tests.py index e2f7da7..92d7f82 100644 --- a/core/tests.py +++ b/core/tests.py @@ -158,10 +158,27 @@ class ViewTestCase(TestCase): def setUp(self): """Define the test client and other test variables.""" + self.mock_regions = ["a", "n", "e", "b", "d", "c"] self.client = APIClient() for issue in api_response_issues: validate_and_store_issue(issue) + def test_api_can_get_region_list(self): + """Test the api can get given region list.""" + response = self.client.get('/regionlist/', format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_api_can_get_region_list_ordered_by_name(self): + """Test the api gives list of regions in accessending order.""" + for s in self.mock_regions: + region_list = Region(region_name=s) + region_list.save() + response = self.client.get('/regionlist/', format="json") + response_content = json.loads(response.content) + sorted_mock_regions = sorted(self.mock_regions) + for i in xrange(len(sorted_mock_regions)): + self.assertEqual(sorted_mock_regions[i], response_content[i]['region_name']) + def test_api_can_get_metadata(self): """Test the api can get given metadata.""" response = self.client.get('/metadata/', format="json") diff --git a/core/views.py b/core/views.py index 6aa5c28..28cf71f 100644 --- a/core/views.py +++ b/core/views.py @@ -1,5 +1,5 @@ -from core.models import UserRepo, Issue -from core.serializers import UserRepoSerializer, IssueSerializer +from core.models import UserRepo, Issue, Region +from core.serializers import UserRepoSerializer, IssueSerializer, RegionSerializer from rest_framework import generics from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import OrderingFilter @@ -18,6 +18,14 @@ class UserRepoList(generics.ListAPIView): filter_fields = ('repo', 'user',) +class RegionList(generics.ListAPIView): + """ + Returns a list of regions. + """ + queryset = Region.objects.all() + serializer_class = RegionSerializer + + class IssueList(generics.ListAPIView): """ Returns a list of issues, by optionally filtering against diff --git a/issue_parser/urls.py b/issue_parser/urls.py index 1b6d9ba..83201c1 100644 --- a/issue_parser/urls.py +++ b/issue_parser/urls.py @@ -19,6 +19,7 @@ from django.contrib import admin urlpatterns = [ + url(r'^regionlist/$', views.RegionList.as_view()), url(r'^userrepos/$', views.UserRepoList.as_view()), url(r'^issues/$', views.IssueList.as_view()), url(r'^metadata/$', views.MetaData.as_view()), From 758b22147310acad12d0997d9fecb69ed7a2f243 Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Sat, 22 Jul 2017 20:08:03 +0530 Subject: [PATCH 04/14] add region filters --- core/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/views.py b/core/views.py index 28cf71f..0124d36 100644 --- a/core/views.py +++ b/core/views.py @@ -1,7 +1,7 @@ from core.models import UserRepo, Issue, Region from core.serializers import UserRepoSerializer, IssueSerializer, RegionSerializer from rest_framework import generics -from django_filters.rest_framework import DjangoFilterBackend +from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import OrderingFilter from rest_framework.views import APIView from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer @@ -35,7 +35,7 @@ class IssueList(generics.ListAPIView): queryset = Issue.objects.all() serializer_class = IssueSerializer filter_backends = (DjangoFilterBackend, OrderingFilter,) - filter_fields = ('language', 'tech_stack', 'experience_needed', 'expected_time',) + filter_fields = ('language', 'tech_stack', 'experience_needed', 'expected_time', 'regions',) ordering_fields = ('experience_needed', 'expected_time') From af70f16911c7c21511f1d9b089af2bcb7a8258ce Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Sun, 23 Jul 2017 12:58:13 +0530 Subject: [PATCH 05/14] Extend User model to use region field --- core/admin.py | 23 +++++++++++++++++++++-- core/models.py | 14 ++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/core/admin.py b/core/admin.py index 3345fc2..344e365 100644 --- a/core/admin.py +++ b/core/admin.py @@ -2,11 +2,30 @@ from __future__ import unicode_literals from django.contrib import admin +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin -# Register/Unregister models here. -from core.models import UserRepo, Issue, IssueLabel +from core.models import UserRepo, Issue, IssueLabel, Region, RegionAdmin from django.contrib.auth.models import * + +class RegionAdminInline(admin.StackedInline): + """ + Define an inline admin descriptor for RegionAdmin model + which acts a bit like a singleton. + """ + + model = RegionAdmin + can_delete = False + verbose_name_plural = 'region_admin' + +class UserAdmin(BaseUserAdmin): + """Define a new User admin.""" + inlines = (RegionAdminInline, ) + admin.site.unregister(Group) +# Re-register UserAdmin admin.site.unregister(User) +admin.site.register(User, UserAdmin) + admin.site.register(UserRepo) +admin.site.register(Region) diff --git a/core/models.py b/core/models.py index 17065d7..0bbf3ce 100644 --- a/core/models.py +++ b/core/models.py @@ -4,19 +4,29 @@ from datetime import timedelta from django.db import models from core.utils.services import request_github_issues - +from django.contrib.auth.models import User from celery.decorators import periodic_task ISSUE_UPDATE_PERIOD = 15 # in minutes + class Region(models.Model): """Used to store data for different regions.""" - region_name = models.CharField(max_length=100) + region_name = models.CharField(max_length=100, unique=True) region_image = models.URLField(blank=True) class Meta: ordering = ('region_name',) # Ascending order according to region name. + def __str__(self): + return '%s' % (self.region_name) + + +class RegionAdmin(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + regions = models.ManyToManyField(Region) + + class UserRepo(models.Model): """ UserRepo model is used to store the username and repo-name From 7f86f65adc752de8b348165242f86078e322136c Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Mon, 24 Jul 2017 02:14:48 +0530 Subject: [PATCH 06/14] implement functionality to automatically add user when submitting User Repo --- core/admin.py | 21 +++++++++++++++++++-- core/models.py | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/core/admin.py b/core/admin.py index 344e365..b17d30d 100644 --- a/core/admin.py +++ b/core/admin.py @@ -18,14 +18,31 @@ class RegionAdminInline(admin.StackedInline): can_delete = False verbose_name_plural = 'region_admin' + class UserAdmin(BaseUserAdmin): """Define a new User admin.""" inlines = (RegionAdminInline, ) -admin.site.unregister(Group) + +class UserRepoAdmin(admin.ModelAdmin): + """Used to alter `UserRepo` admin site.""" + fieldsets = ( + (None, { + 'fields': ('user', 'repo',) + }), + ) + + def save_form(self, request, form, change): + """Automatically fills author by extracting it from currunt login user.""" + obj = super( UserRepoAdmin, self).save_form(request, form, change) + if not change: + obj.author = request.user + return obj + # Re-register UserAdmin admin.site.unregister(User) admin.site.register(User, UserAdmin) +admin.site.register(RegionAdmin) -admin.site.register(UserRepo) +admin.site.register(UserRepo, UserRepoAdmin) admin.site.register(Region) diff --git a/core/models.py b/core/models.py index 0bbf3ce..f31ab36 100644 --- a/core/models.py +++ b/core/models.py @@ -34,7 +34,7 @@ class UserRepo(models.Model): """ user = models.CharField(max_length=100) repo = models.CharField(max_length=100) - regions = models.ManyToManyField(Region) + author = models.ForeignKey(User) created = models.DateTimeField(auto_now_add=True) class Meta: From eb596e3a6108a70221727a3867ec9a66c91fb9dd Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Mon, 24 Jul 2017 14:15:29 +0530 Subject: [PATCH 07/14] user can only see and modify repos related to region. --- core/admin.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/admin.py b/core/admin.py index b17d30d..f7520be 100644 --- a/core/admin.py +++ b/core/admin.py @@ -39,6 +39,22 @@ def save_form(self, request, form, change): obj.author = request.user return obj + def get_queryset(self, request): + qs = super(UserRepoAdmin, self).get_queryset(request) + if request.user.is_superuser: + return qs + return qs.filter(author=request.user) + + def save_model(self, request, obj, form, change): + obj.author = request.user + super(UserRepoAdmin, self).save_model(request, obj, form, change) + + def has_change_permission(self, request, obj=None): + if not obj: + return True + return obj.author == request.user or request.user.is_superuser + + # Re-register UserAdmin admin.site.unregister(User) admin.site.register(User, UserAdmin) From f99a696003b2e37f3bff21d904e568d7b26828e5 Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Mon, 24 Jul 2017 14:30:11 +0530 Subject: [PATCH 08/14] improve breaking test cases for userrepo model and add some documentation. --- core/admin.py | 3 +++ core/tests.py | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/core/admin.py b/core/admin.py index f7520be..5be091a 100644 --- a/core/admin.py +++ b/core/admin.py @@ -40,16 +40,19 @@ def save_form(self, request, form, change): return obj def get_queryset(self, request): + """Only let the user view their own `UserRepos`.""" qs = super(UserRepoAdmin, self).get_queryset(request) if request.user.is_superuser: return qs return qs.filter(author=request.user) def save_model(self, request, obj, form, change): + """Save Model""" obj.author = request.user super(UserRepoAdmin, self).save_model(request, obj, form, change) def has_change_permission(self, request, obj=None): + """Only give the user permissions to modify their own `UserRepos`.""" if not obj: return True return obj.author == request.user or request.user.is_superuser diff --git a/core/tests.py b/core/tests.py index 92d7f82..eb88d41 100644 --- a/core/tests.py +++ b/core/tests.py @@ -9,9 +9,10 @@ from rest_framework.test import APIClient from rest_framework import status from requests.exceptions import ConnectionError +from django.contrib.auth.models import User from .models import (UserRepo, parse_issue, validate_and_store_issue, Issue, delete_closed_issues, - is_issue_valid, is_issue_state_open, periodic_issues_updater, Region) + is_issue_valid, is_issue_state_open, periodic_issues_updater, Region, RegionAdmin) from .utils.mock_api import api_response_issues from .utils.services import request_github_issues @@ -46,7 +47,10 @@ def setUp(self): """Define the test client and other test variables.""" self.user = 'razat249' self.repo = 'github-view' - self.user_repo = UserRepo(user=self.user, repo=self.repo) + self.author = User.objects.create_user( + username='jacob', password='top_secret' + ) + self.user_repo = UserRepo(user=self.user, repo=self.repo, author=self.author) def test_user_repo_model_can_create_a_userrepo(self): """Test the `UserRepo` model can create a `user_repo`.""" From bb5480b3a932b692557ddb7559ad42301e2cc2d8 Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Mon, 24 Jul 2017 14:40:39 +0530 Subject: [PATCH 09/14] some fix in userrepo --- core/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/models.py b/core/models.py index f31ab36..98ffda4 100644 --- a/core/models.py +++ b/core/models.py @@ -39,7 +39,7 @@ class UserRepo(models.Model): class Meta: ordering = ('created',) # Ascending order according to date created. - unique_together = ("user", "repo") # Avoid repo duplicates. + unique_together = ("user", "repo", "author") # Avoid repo duplicates. def __str__(self): return '/%s/%s' % (self.user, self.repo) From bf53c4a3875ed14c652c0124bd0111d8009a6cd1 Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Tue, 25 Jul 2017 14:23:30 +0530 Subject: [PATCH 10/14] implement and test feature to add regions to issues --- core/admin.py | 6 +++--- core/models.py | 21 ++++++++++++++++----- core/tests.py | 26 +++++++++++++++++++++----- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/core/admin.py b/core/admin.py index 5be091a..1427221 100644 --- a/core/admin.py +++ b/core/admin.py @@ -13,7 +13,7 @@ class RegionAdminInline(admin.StackedInline): Define an inline admin descriptor for RegionAdmin model which acts a bit like a singleton. """ - + model = RegionAdmin can_delete = False verbose_name_plural = 'region_admin' @@ -31,7 +31,7 @@ class UserRepoAdmin(admin.ModelAdmin): 'fields': ('user', 'repo',) }), ) - + def save_form(self, request, form, change): """Automatically fills author by extracting it from currunt login user.""" obj = super( UserRepoAdmin, self).save_form(request, form, change) @@ -54,7 +54,7 @@ def save_model(self, request, obj, form, change): def has_change_permission(self, request, obj=None): """Only give the user permissions to modify their own `UserRepos`.""" if not obj: - return True + return True return obj.author == request.user or request.user.is_superuser diff --git a/core/models.py b/core/models.py index 98ffda4..562d681 100644 --- a/core/models.py +++ b/core/models.py @@ -26,6 +26,9 @@ class RegionAdmin(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) regions = models.ManyToManyField(Region) + class Meta: + ordering = ('user',) # Ascending order according to users. + class UserRepo(models.Model): """ @@ -44,6 +47,7 @@ class Meta: def __str__(self): return '/%s/%s' % (self.user, self.repo) + class IssueLabel(models.Model): """ Label model for storing labels of an issue. @@ -99,23 +103,29 @@ def periodic_issues_updater(): Update `Issue` model in the database in every `ISSUE_UPDATE_PERIOD` minutes. """ - list_of_repos = UserRepo.objects.values('user', 'repo',) + list_of_repos = UserRepo.objects.values('author', 'user', 'repo',) for repo in list_of_repos: + region_queryset = retrive_regions_for_a_user(repo['author']) issue_list = request_github_issues(repo['user'], repo['repo']) if issue_list['error']: print "Error" + str(issue_list['data']) else: for issue in issue_list['data']: - validate_and_store_issue(issue) + validate_and_store_issue(issue, region_queryset) + +def retrive_regions_for_a_user(user_id): + """Fetches all the regions related to a user.""" + region_queryset = Region.objects.filter(regionadmin=user_id) + return region_queryset -def validate_and_store_issue(issue): +def validate_and_store_issue(issue, region_queryset): """ Validate issue:- if valid - store it into database, else - Do not store in database """ if is_issue_state_open(issue): if is_issue_valid(issue): - store_issue_in_db(issue) + store_issue_in_db(issue, region_queryset) def is_issue_state_open(issue): """ @@ -140,7 +150,7 @@ def is_issue_valid(issue): print 'Issue with id ' + str(issue['id']) + ' is not valid for our system.' return True # issue is valid -def store_issue_in_db(issue): +def store_issue_in_db(issue, region_queryset): """Stores issue in db""" experience_needed, language, expected_time, technology_stack = parse_issue(issue['body']) experience_needed = experience_needed.strip().lower() @@ -159,6 +169,7 @@ def store_issue_in_db(issue): label_url=label['url'], label_color=label['color']) label_instance.save() issue_instance.issue_labels.add(label_instance) + issue_instance.regions.add(*region_queryset) def delete_closed_issues(issue): """Delete issues that are closed on GitHub but present in our db""" diff --git a/core/tests.py b/core/tests.py index eb88d41..bc5989a 100644 --- a/core/tests.py +++ b/core/tests.py @@ -12,7 +12,8 @@ from django.contrib.auth.models import User from .models import (UserRepo, parse_issue, validate_and_store_issue, Issue, delete_closed_issues, - is_issue_valid, is_issue_state_open, periodic_issues_updater, Region, RegionAdmin) + is_issue_valid, is_issue_state_open, periodic_issues_updater, Region, RegionAdmin, + retrive_regions_for_a_user) from .utils.mock_api import api_response_issues from .utils.services import request_github_issues @@ -96,7 +97,16 @@ class IssueModelAndFetcherTestCase(TestCase): def setUp(self): """Initial setup for running tests.""" - pass + self.USER_ID = 1 + self.author = User.objects.create_user( + id=1, username='jacob', password='top_secret' + ) + self.region = Region(region_name="Mozilla India") + self.region.save() + self.region_admin = RegionAdmin(user=self.author) + self.region_admin.save() + self.region_admin.regions.add(self.region) + self.region_queryset = Region.objects.filter(regionadmin=self.USER_ID) def test_api_can_request_issues(self): """Test the request function""" @@ -143,20 +153,25 @@ def test_issue_state_open_or_not(self): def test_validate_and_store_issue(self): """Test for validating and storing issues.""" old_count = Issue.objects.count() - validate_and_store_issue(SAMPLE_VALID_ISSUE) + validate_and_store_issue(SAMPLE_VALID_ISSUE, self.region_queryset) new_count = Issue.objects.count() self.assertLess(old_count, new_count) def test_api_can_delete_closed_issues_in_db(self): """Test for checking if issues are deleted when closed online but present in db""" issue = SAMPLE_VALID_ISSUE.copy() - validate_and_store_issue(issue) + validate_and_store_issue(issue, self.region_queryset) issue['state'] = 'closed' old_count = Issue.objects.count() delete_closed_issues(issue) new_count = Issue.objects.count() self.assertLess(new_count, old_count) + def test_retrive_regions_for_a_user(self): + """Test function can retrive regions for a user.""" + regions = retrive_regions_for_a_user(self.USER_ID) + self.assertQuerysetEqual(regions, self.region_queryset) + class ViewTestCase(TestCase): """This class defines the test suite for the api views.""" @@ -164,8 +179,9 @@ def setUp(self): """Define the test client and other test variables.""" self.mock_regions = ["a", "n", "e", "b", "d", "c"] self.client = APIClient() + region_queryset = Region.objects.all() for issue in api_response_issues: - validate_and_store_issue(issue) + validate_and_store_issue(issue, region_queryset) def test_api_can_get_region_list(self): """Test the api can get given region list.""" From d1cdeaea8c3d2523eda508a04d3be21aac31d6ef Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Tue, 25 Jul 2017 16:17:17 +0530 Subject: [PATCH 11/14] add custom user model `RegionAdmin` and remove extended User functionality --- core/admin.py | 17 +---------------- core/models.py | 13 +++++-------- issue_parser/settings.py | 2 ++ 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/core/admin.py b/core/admin.py index 1427221..a6533c8 100644 --- a/core/admin.py +++ b/core/admin.py @@ -2,26 +2,12 @@ from __future__ import unicode_literals from django.contrib import admin -from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from django.contrib.auth.admin import UserAdmin from core.models import UserRepo, Issue, IssueLabel, Region, RegionAdmin from django.contrib.auth.models import * -class RegionAdminInline(admin.StackedInline): - """ - Define an inline admin descriptor for RegionAdmin model - which acts a bit like a singleton. - """ - - model = RegionAdmin - can_delete = False - verbose_name_plural = 'region_admin' - - -class UserAdmin(BaseUserAdmin): - """Define a new User admin.""" - inlines = (RegionAdminInline, ) class UserRepoAdmin(admin.ModelAdmin): @@ -59,7 +45,6 @@ def has_change_permission(self, request, obj=None): # Re-register UserAdmin -admin.site.unregister(User) admin.site.register(User, UserAdmin) admin.site.register(RegionAdmin) diff --git a/core/models.py b/core/models.py index 562d681..28fb465 100644 --- a/core/models.py +++ b/core/models.py @@ -3,10 +3,11 @@ from datetime import timedelta from django.db import models -from core.utils.services import request_github_issues -from django.contrib.auth.models import User +from django.contrib.auth.models import AbstractUser from celery.decorators import periodic_task +from core.utils.services import request_github_issues + ISSUE_UPDATE_PERIOD = 15 # in minutes @@ -22,13 +23,9 @@ def __str__(self): return '%s' % (self.region_name) -class RegionAdmin(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE) +class RegionAdmin(AbstractUser): regions = models.ManyToManyField(Region) - class Meta: - ordering = ('user',) # Ascending order according to users. - class UserRepo(models.Model): """ @@ -37,7 +34,7 @@ class UserRepo(models.Model): """ user = models.CharField(max_length=100) repo = models.CharField(max_length=100) - author = models.ForeignKey(User) + author = models.ForeignKey(RegionAdmin) created = models.DateTimeField(auto_now_add=True) class Meta: diff --git a/issue_parser/settings.py b/issue_parser/settings.py index 526c24f..1066fbf 100644 --- a/issue_parser/settings.py +++ b/issue_parser/settings.py @@ -50,6 +50,8 @@ 'django_nose', ] +AUTH_USER_MODEL = 'core.RegionAdmin' + # Use nose to run all tests TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' From 6b65867cb74eb7e661a040ddb299d23c651443c5 Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Tue, 25 Jul 2017 16:42:56 +0530 Subject: [PATCH 12/14] remove error code in tests --- core/tests.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/core/tests.py b/core/tests.py index bc5989a..99ae43c 100644 --- a/core/tests.py +++ b/core/tests.py @@ -9,7 +9,6 @@ from rest_framework.test import APIClient from rest_framework import status from requests.exceptions import ConnectionError -from django.contrib.auth.models import User from .models import (UserRepo, parse_issue, validate_and_store_issue, Issue, delete_closed_issues, is_issue_valid, is_issue_state_open, periodic_issues_updater, Region, RegionAdmin, @@ -48,7 +47,7 @@ def setUp(self): """Define the test client and other test variables.""" self.user = 'razat249' self.repo = 'github-view' - self.author = User.objects.create_user( + self.author = RegionAdmin.objects.create_user( username='jacob', password='top_secret' ) self.user_repo = UserRepo(user=self.user, repo=self.repo, author=self.author) @@ -73,7 +72,7 @@ class RegionModelTestCase(TestCase): def setUp(self): """Define the test client and other test variables.""" - self.region_name = 'Mizilla India' + self.region_name = 'Mozilla India' self.region_image = 'https://example.com/image.jpg' self.region_instance = Region(region_name=self.region_name, region_image=self.region_image) @@ -98,14 +97,12 @@ class IssueModelAndFetcherTestCase(TestCase): def setUp(self): """Initial setup for running tests.""" self.USER_ID = 1 - self.author = User.objects.create_user( - id=1, username='jacob', password='top_secret' + self.author = RegionAdmin.objects.create_user( + id=self.USER_ID, username='jacob', password='top_secret' ) self.region = Region(region_name="Mozilla India") self.region.save() - self.region_admin = RegionAdmin(user=self.author) - self.region_admin.save() - self.region_admin.regions.add(self.region) + self.author.regions.add(self.region) self.region_queryset = Region.objects.filter(regionadmin=self.USER_ID) def test_api_can_request_issues(self): @@ -170,7 +167,7 @@ def test_api_can_delete_closed_issues_in_db(self): def test_retrive_regions_for_a_user(self): """Test function can retrive regions for a user.""" regions = retrive_regions_for_a_user(self.USER_ID) - self.assertQuerysetEqual(regions, self.region_queryset) + self.assertEqual(regions[0], self.region_queryset[0]) class ViewTestCase(TestCase): """This class defines the test suite for the api views.""" From a1d9663c62a4e1bad8c8ebf275bbdceb602baefd Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Sun, 30 Jul 2017 16:33:44 +0530 Subject: [PATCH 13/14] add regions field to userrepo model --- core/admin.py | 9 ++++++--- core/models.py | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/admin.py b/core/admin.py index a6533c8..43f4a6a 100644 --- a/core/admin.py +++ b/core/admin.py @@ -8,16 +8,19 @@ from django.contrib.auth.models import * - - class UserRepoAdmin(admin.ModelAdmin): """Used to alter `UserRepo` admin site.""" fieldsets = ( (None, { - 'fields': ('user', 'repo',) + 'fields': ('user', 'repo', 'regions') }), ) + def formfield_for_manytomany(self, db_field, request, **kwargs): + if db_field.name == "regions": + kwargs["queryset"] = Region.objects.filter(regionadmin=request.user) + return super(UserRepoAdmin, self).formfield_for_manytomany(db_field, request, **kwargs) + def save_form(self, request, form, change): """Automatically fills author by extracting it from currunt login user.""" obj = super( UserRepoAdmin, self).save_form(request, form, change) diff --git a/core/models.py b/core/models.py index 28fb465..fb33c1d 100644 --- a/core/models.py +++ b/core/models.py @@ -35,6 +35,7 @@ class UserRepo(models.Model): user = models.CharField(max_length=100) repo = models.CharField(max_length=100) author = models.ForeignKey(RegionAdmin) + regions = models.ManyToManyField(Region) created = models.DateTimeField(auto_now_add=True) class Meta: From c30c0263039f2c377e026cb556dc7af2e91926f4 Mon Sep 17 00:00:00 2001 From: Rajat Patwa Date: Sun, 30 Jul 2017 17:12:54 +0530 Subject: [PATCH 14/14] correct and test `retrive regions` function according to user repos --- core/admin.py | 2 ++ core/models.py | 8 ++++---- core/tests.py | 9 ++++++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/admin.py b/core/admin.py index 43f4a6a..58e13bf 100644 --- a/core/admin.py +++ b/core/admin.py @@ -17,6 +17,7 @@ class UserRepoAdmin(admin.ModelAdmin): ) def formfield_for_manytomany(self, db_field, request, **kwargs): + """Only show regions related to logged in user when filling `userrepo` form""" if db_field.name == "regions": kwargs["queryset"] = Region.objects.filter(regionadmin=request.user) return super(UserRepoAdmin, self).formfield_for_manytomany(db_field, request, **kwargs) @@ -53,3 +54,4 @@ def has_change_permission(self, request, obj=None): admin.site.register(UserRepo, UserRepoAdmin) admin.site.register(Region) +admin.site.register(Issue) diff --git a/core/models.py b/core/models.py index fb33c1d..592c024 100644 --- a/core/models.py +++ b/core/models.py @@ -101,9 +101,9 @@ def periodic_issues_updater(): Update `Issue` model in the database in every `ISSUE_UPDATE_PERIOD` minutes. """ - list_of_repos = UserRepo.objects.values('author', 'user', 'repo',) + list_of_repos = UserRepo.objects.values('id', 'user', 'repo',) for repo in list_of_repos: - region_queryset = retrive_regions_for_a_user(repo['author']) + region_queryset = retrive_regions_for_a_user(repo['id']) issue_list = request_github_issues(repo['user'], repo['repo']) if issue_list['error']: print "Error" + str(issue_list['data']) @@ -111,9 +111,9 @@ def periodic_issues_updater(): for issue in issue_list['data']: validate_and_store_issue(issue, region_queryset) -def retrive_regions_for_a_user(user_id): +def retrive_regions_for_a_user(user_repo_id): """Fetches all the regions related to a user.""" - region_queryset = Region.objects.filter(regionadmin=user_id) + region_queryset = Region.objects.filter(userrepo=user_repo_id) return region_queryset def validate_and_store_issue(issue, region_queryset): diff --git a/core/tests.py b/core/tests.py index 99ae43c..483c41b 100644 --- a/core/tests.py +++ b/core/tests.py @@ -97,13 +97,16 @@ class IssueModelAndFetcherTestCase(TestCase): def setUp(self): """Initial setup for running tests.""" self.USER_ID = 1 + self.USER_REPO_ID = 1 self.author = RegionAdmin.objects.create_user( id=self.USER_ID, username='jacob', password='top_secret' ) self.region = Region(region_name="Mozilla India") self.region.save() - self.author.regions.add(self.region) - self.region_queryset = Region.objects.filter(regionadmin=self.USER_ID) + self.user_repo = UserRepo(id=self.USER_REPO_ID, user='razat249', repo='github-view', author=self.author) + self.user_repo.save() + self.user_repo.regions.add(self.region) + self.region_queryset = Region.objects.filter(userrepo=self.USER_ID) def test_api_can_request_issues(self): """Test the request function""" @@ -166,7 +169,7 @@ def test_api_can_delete_closed_issues_in_db(self): def test_retrive_regions_for_a_user(self): """Test function can retrive regions for a user.""" - regions = retrive_regions_for_a_user(self.USER_ID) + regions = retrive_regions_for_a_user(self.USER_REPO_ID) self.assertEqual(regions[0], self.region_queryset[0]) class ViewTestCase(TestCase):