Commit c523d908c526644702c5546e7a0f22a1bae2b417

Authored by Erik Zambom
Committed by GitHub
2 parents d0356470 954eeaba

Merge pull request #558 from amadeusproject/refactoring

Daily Update - 11_09_2017
amadeus/settings.py
@@ -49,6 +49,8 @@ INSTALLED_APPS = [ @@ -49,6 +49,8 @@ INSTALLED_APPS = [
49 'rolepermissions', 49 'rolepermissions',
50 'oauth2_provider', 50 'oauth2_provider',
51 'rest_framework', 51 'rest_framework',
  52 + 'rest_framework_swagger',
  53 + 'django_filters',
52 'django_bootstrap_breadcrumbs', 54 'django_bootstrap_breadcrumbs',
53 's3direct', 55 's3direct',
54 'django_summernote', 56 'django_summernote',
@@ -313,10 +315,14 @@ S3DIRECT_DESTINATIONS = { @@ -313,10 +315,14 @@ S3DIRECT_DESTINATIONS = {
313 #TELL the rest framework to use a different backend 315 #TELL the rest framework to use a different backend
314 REST_FRAMEWORK = { 316 REST_FRAMEWORK = {
315 'DEFAULT_AUTHENTICATION_CLASSES':( 317 'DEFAULT_AUTHENTICATION_CLASSES':(
316 - 'oauth2_provider.contrib.rest_framework.OAuth2Authentication',), 318 + 'oauth2_provider.contrib.rest_framework.OAuth2Authentication','rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',),
317 'DEFAULT_PERMISSION_CLASSES':( 319 'DEFAULT_PERMISSION_CLASSES':(
318 'rest_framework.permissions.IsAuthenticated',), 320 'rest_framework.permissions.IsAuthenticated',),
319 - 'PAGE_SIZE': 10, #pagination purposes 321 + 'PAGE_SIZE': 10, #pagination purposes
  322 +}
  323 +
  324 +SWAGGER_SETTINGS = {
  325 + 'JSON_EDITOR': True,
320 } 326 }
321 327
322 OAUTH2_PROVIDER = { 328 OAUTH2_PROVIDER = {
amadeus/urls.py
@@ -18,6 +18,9 @@ from django.conf import settings @@ -18,6 +18,9 @@ from django.conf import settings
18 from django.conf.urls import include, url 18 from django.conf.urls import include, url
19 from django.conf.urls.static import static 19 from django.conf.urls.static import static
20 from django.contrib import admin 20 from django.contrib import admin
  21 +
  22 +from rest_framework.documentation import include_docs_urls
  23 +
21 from .views import index 24 from .views import index
22 25
23 26
@@ -48,6 +51,7 @@ urlpatterns = [ @@ -48,6 +51,7 @@ urlpatterns = [
48 url(r'^analytics/', include('analytics.urls', namespace='analytics')), 51 url(r'^analytics/', include('analytics.urls', namespace='analytics')),
49 url(r'^dashboards/', include('dashboards.urls', namespace='dashboards')), 52 url(r'^dashboards/', include('dashboards.urls', namespace='dashboards')),
50 url(r'^bulletin/', include('bulletin.urls', namespace='bulletin')), 53 url(r'^bulletin/', include('bulletin.urls', namespace='bulletin')),
  54 + url(r'^api-docs/', include_docs_urls(title = 'REST Api Documentation')),
51 #API 55 #API
52 url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')), 56 url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
53 #S3Direct 57 #S3Direct
1 from django.conf.urls import url, include 1 from django.conf.urls import url, include
2 2
3 # ========== API IMPORTS ============= # 3 # ========== API IMPORTS ============= #
4 -  
5 from rest_framework import routers 4 from rest_framework import routers
6 5
  6 +from rest_framework.schemas import get_schema_view
  7 +from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer
  8 +
7 from users.views import UserViewSet 9 from users.views import UserViewSet
8 from log.views import LogViewSet 10 from log.views import LogViewSet
9 from . import views 11 from . import views
10 12
  13 +schema_view = get_schema_view(title = 'REST API', renderer_classes = [OpenAPIRenderer, SwaggerUIRenderer])
  14 +
11 router = routers.DefaultRouter() 15 router = routers.DefaultRouter()
12 16
13 router.register(r'logs', LogViewSet) 17 router.register(r'logs', LogViewSet)
@@ -21,4 +25,5 @@ urlpatterns = [ @@ -21,4 +25,5 @@ urlpatterns = [
21 #API REST 25 #API REST
22 url(r'^', include(router.urls)), 26 url(r'^', include(router.urls)),
23 url(r'^token$', views.getToken), 27 url(r'^token$', views.getToken),
  28 + url(r'^docs/', schema_view, name="docs"),
24 ] 29 ]
25 \ No newline at end of file 30 \ No newline at end of file
@@ -84,7 +84,16 @@ def getToken(request): @@ -84,7 +84,16 @@ def getToken(request):
84 return HttpResponse(response) 84 return HttpResponse(response)
85 85
86 class LoginViewset(viewsets.ReadOnlyModelViewSet): 86 class LoginViewset(viewsets.ReadOnlyModelViewSet):
  87 + """
  88 + login:
  89 + Log a user in the system
  90 +
  91 + register_device:
  92 + Register a mobile device for the logged user to provide app notifications
  93 + """
  94 +
87 queryset = User.objects.all() 95 queryset = User.objects.all()
  96 + serializer_class = UserSerializer
88 permissions_classes = (IsAuthenticated,) 97 permissions_classes = (IsAuthenticated,)
89 98
90 @csrf_exempt 99 @csrf_exempt
@@ -149,8 +158,15 @@ class LoginViewset(viewsets.ReadOnlyModelViewSet): @@ -149,8 +158,15 @@ class LoginViewset(viewsets.ReadOnlyModelViewSet):
149 return HttpResponse(response) 158 return HttpResponse(response)
150 159
151 class SubjectViewset(viewsets.ReadOnlyModelViewSet): 160 class SubjectViewset(viewsets.ReadOnlyModelViewSet):
  161 + """
  162 + ---
  163 + get_subjects:
  164 + Get list of subjects of a user. Require user email as parameter
  165 + """
  166 +
152 queryset = Subject.objects.all() 167 queryset = Subject.objects.all()
153 - permissions_classes = (IsAuthenticated, ) 168 + serializer_class = SubjectSerializer
  169 + permissions_classes = (IsAuthenticated,)
154 170
155 @csrf_exempt 171 @csrf_exempt
156 @list_route(methods = ['POST'], permissions_classes = [IsAuthenticated]) 172 @list_route(methods = ['POST'], permissions_classes = [IsAuthenticated])
@@ -193,7 +209,13 @@ class SubjectViewset(viewsets.ReadOnlyModelViewSet): @@ -193,7 +209,13 @@ class SubjectViewset(viewsets.ReadOnlyModelViewSet):
193 return HttpResponse(response) 209 return HttpResponse(response)
194 210
195 class ParticipantsViewset(viewsets.ReadOnlyModelViewSet): 211 class ParticipantsViewset(viewsets.ReadOnlyModelViewSet):
  212 + """
  213 + get_participants:
  214 + Get all users that participates in some subject. Require the logged user email and the subject slug
  215 + """
  216 +
196 queryset = User.objects.all() 217 queryset = User.objects.all()
  218 + serializer_class = UserSerializer
197 permissions_classes = (IsAuthenticated, ) 219 permissions_classes = (IsAuthenticated, )
198 220
199 @csrf_exempt 221 @csrf_exempt
@@ -231,7 +253,16 @@ class ParticipantsViewset(viewsets.ReadOnlyModelViewSet): @@ -231,7 +253,16 @@ class ParticipantsViewset(viewsets.ReadOnlyModelViewSet):
231 return HttpResponse(response) 253 return HttpResponse(response)
232 254
233 class ChatViewset(viewsets.ModelViewSet): 255 class ChatViewset(viewsets.ModelViewSet):
  256 + """
  257 + get_messages:
  258 + Get messages of a conversation
  259 +
  260 + send_message:
  261 + Send a message in a conversation
  262 + """
  263 +
234 queryset = TalkMessages.objects.all() 264 queryset = TalkMessages.objects.all()
  265 + serializer_class = ChatSerializer
235 permissions_classes = (IsAuthenticated, ) 266 permissions_classes = (IsAuthenticated, )
236 267
237 @csrf_exempt 268 @csrf_exempt
links/forms.py
@@ -4,6 +4,8 @@ from django.utils.translation import ugettext_lazy as _ @@ -4,6 +4,8 @@ from django.utils.translation import ugettext_lazy as _
4 from django.utils.html import strip_tags 4 from django.utils.html import strip_tags
5 from django.core.exceptions import ValidationError 5 from django.core.exceptions import ValidationError
6 6
  7 +import validators
  8 +
7 from subjects.models import Tag 9 from subjects.models import Tag
8 from subjects.forms import ParticipantsMultipleChoiceField 10 from subjects.forms import ParticipantsMultipleChoiceField
9 11
@@ -15,22 +17,22 @@ class LinkForm(forms.ModelForm): @@ -15,22 +17,22 @@ class LinkForm(forms.ModelForm):
15 MAX_UPLOAD_SIZE = 10*1024*1024 17 MAX_UPLOAD_SIZE = 10*1024*1024
16 18
17 students = ParticipantsMultipleChoiceField(queryset = None, required = False) 19 students = ParticipantsMultipleChoiceField(queryset = None, required = False)
18 - 20 +
19 def __init__(self, *args, **kwargs): 21 def __init__(self, *args, **kwargs):
20 super(LinkForm, self).__init__(*args, **kwargs) 22 super(LinkForm, self).__init__(*args, **kwargs)
21 23
22 self.subject = kwargs['initial'].get('subject', None) 24 self.subject = kwargs['initial'].get('subject', None)
23 - 25 +
24 if self.instance.id: 26 if self.instance.id:
25 self.subject = self.instance.topic.subject 27 self.subject = self.instance.topic.subject
26 self.initial['tags'] = ", ".join(self.instance.tags.all().values_list("name", flat = True)) 28 self.initial['tags'] = ", ".join(self.instance.tags.all().values_list("name", flat = True))
27 - 29 +
28 self.fields['students'].queryset = self.subject.students.all() 30 self.fields['students'].queryset = self.subject.students.all()
29 self.fields['groups'].queryset = self.subject.group_subject.all() 31 self.fields['groups'].queryset = self.subject.group_subject.all()
30 32
31 tags = forms.CharField(label = _('Tags'), required = False) 33 tags = forms.CharField(label = _('Tags'), required = False)
32 - link_url = forms.URLField(label = _('Website URL'),required=True)  
33 - 34 + link_url = forms.CharField(label = _('Website URL'),required=True)
  35 +
34 class Meta: 36 class Meta:
35 model = Link 37 model = Link
36 fields = ['name','link_url', 'brief_description', 'all_students', 'students', 'groups', 'visible'] 38 fields = ['name','link_url', 'brief_description', 'all_students', 'students', 'groups', 'visible']
@@ -49,13 +51,13 @@ class LinkForm(forms.ModelForm): @@ -49,13 +51,13 @@ class LinkForm(forms.ModelForm):
49 51
50 cleaned_data = self.cleaned_data 52 cleaned_data = self.cleaned_data
51 53
52 - 54 +
53 return cleaned_data 55 return cleaned_data
54 - 56 +
55 57
56 def clean_name(self): 58 def clean_name(self):
57 name = self.cleaned_data.get('name', '') 59 name = self.cleaned_data.get('name', '')
58 - 60 +
59 topics = self.subject.topic_subject.all() 61 topics = self.subject.topic_subject.all()
60 62
61 for topic in topics: 63 for topic in topics:
@@ -63,7 +65,7 @@ class LinkForm(forms.ModelForm): @@ -63,7 +65,7 @@ class LinkForm(forms.ModelForm):
63 same_name = topic.resource_topic.filter(name__unaccent__iexact = name).exclude(id = self.instance.id).count() 65 same_name = topic.resource_topic.filter(name__unaccent__iexact = name).exclude(id = self.instance.id).count()
64 else: 66 else:
65 same_name = topic.resource_topic.filter(name__unaccent__iexact = name).count() 67 same_name = topic.resource_topic.filter(name__unaccent__iexact = name).count()
66 - 68 +
67 if same_name > 0: 69 if same_name > 0:
68 self._errors['name'] = [_('There is already a link with this name on this subject')] 70 self._errors['name'] = [_('There is already a link with this name on this subject')]
69 71
@@ -72,7 +74,15 @@ class LinkForm(forms.ModelForm): @@ -72,7 +74,15 @@ class LinkForm(forms.ModelForm):
72 return name 74 return name
73 75
74 76
75 - 77 +
  78 + def clean_link_url(self):
  79 + link_url = self.cleaned_data.get('link_url','')
  80 + if link_url[0].lower() != "h": link_url = "https://" + link_url
  81 + if validators.url(link_url) != True:
  82 + self._errors['link_url'] = [_('Invalid URL. It should be an valid link.')]
  83 + return ValueError
  84 +
  85 + return link_url
76 86
77 def save(self, commit = True): 87 def save(self, commit = True):
78 super(LinkForm, self).save(commit = True) 88 super(LinkForm, self).save(commit = True)
@@ -87,7 +97,7 @@ class LinkForm(forms.ModelForm): @@ -87,7 +97,7 @@ class LinkForm(forms.ModelForm):
87 for prev in previous_tags: 97 for prev in previous_tags:
88 if not prev.name in tags: 98 if not prev.name in tags:
89 self.instance.tags.remove(prev) 99 self.instance.tags.remove(prev)
90 - 100 +
91 for tag in tags: 101 for tag in tags:
92 tag = tag.strip() 102 tag = tag.strip()
93 103
@@ -101,4 +111,4 @@ class LinkForm(forms.ModelForm): @@ -101,4 +111,4 @@ class LinkForm(forms.ModelForm):
101 if not new_tag in self.instance.tags.all(): 111 if not new_tag in self.instance.tags.all():
102 self.instance.tags.add(new_tag) 112 self.instance.tags.add(new_tag)
103 113
104 - return self.instance  
105 \ No newline at end of file 114 \ No newline at end of file
  115 + return self.instance
links/models.py
@@ -10,9 +10,9 @@ from django.core.urlresolvers import reverse_lazy @@ -10,9 +10,9 @@ from django.core.urlresolvers import reverse_lazy
10 10
11 # Create your models here. 11 # Create your models here.
12 class Link(Resource): 12 class Link(Resource):
13 - link_url = models.URLField(verbose_name = _("Link_URL"))  
14 -  
15 - 13 + link_url = models.CharField( _("Link_URL"),max_length=250 )
  14 +
  15 +
16 class Meta: 16 class Meta:
17 verbose_name = "Link" 17 verbose_name = "Link"
18 verbose_name_plural = "Links" 18 verbose_name_plural = "Links"
@@ -28,6 +28,6 @@ class Link(Resource): @@ -28,6 +28,6 @@ class Link(Resource):
28 28
29 def delete_link(self): 29 def delete_link(self):
30 return 'links:delete' 30 return 'links:delete'
31 - 31 +
32 def delete_message(self): 32 def delete_message(self):
33 - return _('Are you sure you want delete the Website link')  
34 \ No newline at end of file 33 \ No newline at end of file
  34 + return _('Are you sure you want delete the Website link')
requirements.txt
@@ -6,6 +6,9 @@ beautifulsoup4==4.5.1 @@ -6,6 +6,9 @@ beautifulsoup4==4.5.1
6 channels==1.0.3 6 channels==1.0.3
7 click==6.6 7 click==6.6
8 constantly==15.1.0 8 constantly==15.1.0
  9 +coreapi==2.3.1
  10 +coreapi-cli==1.0.6
  11 +coreschema==0.0.4
9 coverage==4.2 12 coverage==4.2
10 daphne==1.0.2 13 daphne==1.0.2
11 decorator==4.0.10 14 decorator==4.0.10
@@ -19,49 +22,95 @@ django-common-helpers==0.9.0 @@ -19,49 +22,95 @@ django-common-helpers==0.9.0
19 django-cron==0.5.0 22 django-cron==0.5.0
20 django-crontab==0.7.1 23 django-crontab==0.7.1
21 django-discover-runner==1.0 24 django-discover-runner==1.0
  25 +django-filter==1.0.4
22 django-floppyforms==1.7.0 26 django-floppyforms==1.7.0
23 django-modalview==0.1.5 27 django-modalview==0.1.5
24 django-oauth-toolkit==1.0.0 28 django-oauth-toolkit==1.0.0
  29 +django-oauth2-provider==0.2.6.1
  30 +django-rest-swagger==2.1.2
25 django-role-permissions==1.2.1 31 django-role-permissions==1.2.1
26 django-s3direct==0.4.2 32 django-s3direct==0.4.2
27 django-session-security==2.4.0 33 django-session-security==2.4.0
28 django-summernote==0.8.6 34 django-summernote==0.8.6
  35 +django-tracking2==0.3.3
  36 +django-unixdatetimefield==0.1.6
29 django-widget-tweaks==1.4.1 37 django-widget-tweaks==1.4.1
30 django-wysiwyg==0.8.0 38 django-wysiwyg==0.8.0
31 -djangorestframework==3.4.6 39 +djangoajax==2.3.6
  40 +djangorestframework==3.6.4
  41 +entrypoints==0.2.2
32 et-xmlfile==1.0.1 42 et-xmlfile==1.0.1
  43 +fcm-django==0.2.11
33 file-resubmit==0.1.0 44 file-resubmit==0.1.0
34 gunicorn==19.6.0 45 gunicorn==19.6.0
  46 +httplib2==0.9.2
35 incremental==16.10.1 47 incremental==16.10.1
  48 +ipykernel==4.3.1
  49 +ipython==4.2.1
  50 +ipython-genutils==0.1.0
  51 +ipywidgets==5.1.5
  52 +itsdangerous==0.24
  53 +itypes==1.1.0
36 jdcal==1.3 54 jdcal==1.3
37 Jinja2==2.8 55 Jinja2==2.8
  56 +jsonschema==2.5.1
  57 +jupyter==1.0.0
  58 +jupyter-client==4.3.0
  59 +jupyter-console==5.0.0
  60 +jupyter-core==4.1.0
38 lxml==3.7.3 61 lxml==3.7.3
  62 +Markdown==2.6.6
39 MarkupSafe==0.23 63 MarkupSafe==0.23
  64 +mistune==0.7.3
40 msgpack-python==0.4.8 65 msgpack-python==0.4.8
  66 +nbconvert==4.2.0
  67 +nbformat==4.0.1
  68 +notebook==4.2.1
41 numpy==1.12.1 69 numpy==1.12.1
  70 +oauth2==1.9.0.post1
  71 +oauth2-provider==0.0
42 oauthlib==2.0.1 72 oauthlib==2.0.1
  73 +openapi-codec==1.3.2
43 openpyxl==2.4.5 74 openpyxl==2.4.5
44 packaging==16.8 75 packaging==16.8
45 pandas==0.19.2 76 pandas==0.19.2
  77 +pexpect==4.2.0
  78 +pickleshare==0.7.2
46 Pillow==3.3.1 79 Pillow==3.3.1
  80 +prompt-toolkit==1.0.3
47 psycopg2==2.6.2 81 psycopg2==2.6.2
  82 +ptyprocess==0.5.1
48 pycpfcnpj==1.0.2 83 pycpfcnpj==1.0.2
  84 +pyfcm==1.3.1
  85 +Pygments==2.1.3
49 pyparsing==2.2.0 86 pyparsing==2.2.0
50 python-dateutil==2.6.0 87 python-dateutil==2.6.0
  88 +python-slugify==1.2.0
51 pytz==2016.10 89 pytz==2016.10
  90 +pyzmq==15.3.0
  91 +qtconsole==4.2.1
52 redis==2.10.5 92 redis==2.10.5
53 requests==2.13.0 93 requests==2.13.0
  94 +requests-toolbelt==0.8.0
  95 +shortuuid==0.4.3
  96 +simplegeneric==0.8.1
  97 +simplejson==3.11.1
54 six==1.10.0 98 six==1.10.0
55 slugify==0.0.1 99 slugify==0.0.1
  100 +terminado==0.6
  101 +tornado==4.3
  102 +traitlets==4.2.2
56 Twisted==16.6.0 103 Twisted==16.6.0
57 txaio==2.6.0 104 txaio==2.6.0
  105 +Unidecode==0.4.19
  106 +uritemplate==3.0.0
58 validators==0.11.0 107 validators==0.11.0
  108 +virtualenv==15.0.3
  109 +wcwidth==0.1.7
59 webencodings==0.5 110 webencodings==0.5
60 Werkzeug==0.11.11 111 Werkzeug==0.11.11
61 whitenoise==3.2.2 112 whitenoise==3.2.2
  113 +widgetsnbextension==1.2.3
62 xlrd==1.0.0 114 xlrd==1.0.0
63 xlwt==1.2.0 115 xlwt==1.2.0
64 zope.interface==4.3.3 116 zope.interface==4.3.3
65 -fcm-django==0.2.11  
66 -pyfcm==1.3.1  
67 -requests-toolbelt==0.8.0  
68 \ No newline at end of file 117 \ No newline at end of file