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 49 'rolepermissions',
50 50 'oauth2_provider',
51 51 'rest_framework',
  52 + 'rest_framework_swagger',
  53 + 'django_filters',
52 54 'django_bootstrap_breadcrumbs',
53 55 's3direct',
54 56 'django_summernote',
... ... @@ -313,10 +315,14 @@ S3DIRECT_DESTINATIONS = {
313 315 #TELL the rest framework to use a different backend
314 316 REST_FRAMEWORK = {
315 317 'DEFAULT_AUTHENTICATION_CLASSES':(
316   - 'oauth2_provider.contrib.rest_framework.OAuth2Authentication',),
  318 + 'oauth2_provider.contrib.rest_framework.OAuth2Authentication','rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',),
317 319 'DEFAULT_PERMISSION_CLASSES':(
318 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 328 OAUTH2_PROVIDER = {
... ...
amadeus/urls.py
... ... @@ -18,6 +18,9 @@ from django.conf import settings
18 18 from django.conf.urls import include, url
19 19 from django.conf.urls.static import static
20 20 from django.contrib import admin
  21 +
  22 +from rest_framework.documentation import include_docs_urls
  23 +
21 24 from .views import index
22 25  
23 26  
... ... @@ -48,6 +51,7 @@ urlpatterns = [
48 51 url(r'^analytics/', include('analytics.urls', namespace='analytics')),
49 52 url(r'^dashboards/', include('dashboards.urls', namespace='dashboards')),
50 53 url(r'^bulletin/', include('bulletin.urls', namespace='bulletin')),
  54 + url(r'^api-docs/', include_docs_urls(title = 'REST Api Documentation')),
51 55 #API
52 56 url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
53 57 #S3Direct
... ...
api/urls.py
1 1 from django.conf.urls import url, include
2 2  
3 3 # ========== API IMPORTS ============= #
4   -
5 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 9 from users.views import UserViewSet
8 10 from log.views import LogViewSet
9 11 from . import views
10 12  
  13 +schema_view = get_schema_view(title = 'REST API', renderer_classes = [OpenAPIRenderer, SwaggerUIRenderer])
  14 +
11 15 router = routers.DefaultRouter()
12 16  
13 17 router.register(r'logs', LogViewSet)
... ... @@ -21,4 +25,5 @@ urlpatterns = [
21 25 #API REST
22 26 url(r'^', include(router.urls)),
23 27 url(r'^token$', views.getToken),
  28 + url(r'^docs/', schema_view, name="docs"),
24 29 ]
25 30 \ No newline at end of file
... ...
api/views.py
... ... @@ -84,7 +84,16 @@ def getToken(request):
84 84 return HttpResponse(response)
85 85  
86 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 95 queryset = User.objects.all()
  96 + serializer_class = UserSerializer
88 97 permissions_classes = (IsAuthenticated,)
89 98  
90 99 @csrf_exempt
... ... @@ -149,8 +158,15 @@ class LoginViewset(viewsets.ReadOnlyModelViewSet):
149 158 return HttpResponse(response)
150 159  
151 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 167 queryset = Subject.objects.all()
153   - permissions_classes = (IsAuthenticated, )
  168 + serializer_class = SubjectSerializer
  169 + permissions_classes = (IsAuthenticated,)
154 170  
155 171 @csrf_exempt
156 172 @list_route(methods = ['POST'], permissions_classes = [IsAuthenticated])
... ... @@ -193,7 +209,13 @@ class SubjectViewset(viewsets.ReadOnlyModelViewSet):
193 209 return HttpResponse(response)
194 210  
195 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 217 queryset = User.objects.all()
  218 + serializer_class = UserSerializer
197 219 permissions_classes = (IsAuthenticated, )
198 220  
199 221 @csrf_exempt
... ... @@ -231,7 +253,16 @@ class ParticipantsViewset(viewsets.ReadOnlyModelViewSet):
231 253 return HttpResponse(response)
232 254  
233 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 264 queryset = TalkMessages.objects.all()
  265 + serializer_class = ChatSerializer
235 266 permissions_classes = (IsAuthenticated, )
236 267  
237 268 @csrf_exempt
... ...
links/forms.py
... ... @@ -4,6 +4,8 @@ from django.utils.translation import ugettext_lazy as _
4 4 from django.utils.html import strip_tags
5 5 from django.core.exceptions import ValidationError
6 6  
  7 +import validators
  8 +
7 9 from subjects.models import Tag
8 10 from subjects.forms import ParticipantsMultipleChoiceField
9 11  
... ... @@ -15,22 +17,22 @@ class LinkForm(forms.ModelForm):
15 17 MAX_UPLOAD_SIZE = 10*1024*1024
16 18  
17 19 students = ParticipantsMultipleChoiceField(queryset = None, required = False)
18   -
  20 +
19 21 def __init__(self, *args, **kwargs):
20 22 super(LinkForm, self).__init__(*args, **kwargs)
21 23  
22 24 self.subject = kwargs['initial'].get('subject', None)
23   -
  25 +
24 26 if self.instance.id:
25 27 self.subject = self.instance.topic.subject
26 28 self.initial['tags'] = ", ".join(self.instance.tags.all().values_list("name", flat = True))
27   -
  29 +
28 30 self.fields['students'].queryset = self.subject.students.all()
29 31 self.fields['groups'].queryset = self.subject.group_subject.all()
30 32  
31 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 36 class Meta:
35 37 model = Link
36 38 fields = ['name','link_url', 'brief_description', 'all_students', 'students', 'groups', 'visible']
... ... @@ -49,13 +51,13 @@ class LinkForm(forms.ModelForm):
49 51  
50 52 cleaned_data = self.cleaned_data
51 53  
52   -
  54 +
53 55 return cleaned_data
54   -
  56 +
55 57  
56 58 def clean_name(self):
57 59 name = self.cleaned_data.get('name', '')
58   -
  60 +
59 61 topics = self.subject.topic_subject.all()
60 62  
61 63 for topic in topics:
... ... @@ -63,7 +65,7 @@ class LinkForm(forms.ModelForm):
63 65 same_name = topic.resource_topic.filter(name__unaccent__iexact = name).exclude(id = self.instance.id).count()
64 66 else:
65 67 same_name = topic.resource_topic.filter(name__unaccent__iexact = name).count()
66   -
  68 +
67 69 if same_name > 0:
68 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 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 87 def save(self, commit = True):
78 88 super(LinkForm, self).save(commit = True)
... ... @@ -87,7 +97,7 @@ class LinkForm(forms.ModelForm):
87 97 for prev in previous_tags:
88 98 if not prev.name in tags:
89 99 self.instance.tags.remove(prev)
90   -
  100 +
91 101 for tag in tags:
92 102 tag = tag.strip()
93 103  
... ... @@ -101,4 +111,4 @@ class LinkForm(forms.ModelForm):
101 111 if not new_tag in self.instance.tags.all():
102 112 self.instance.tags.add(new_tag)
103 113  
104   - return self.instance
105 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 10  
11 11 # Create your models here.
12 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 16 class Meta:
17 17 verbose_name = "Link"
18 18 verbose_name_plural = "Links"
... ... @@ -28,6 +28,6 @@ class Link(Resource):
28 28  
29 29 def delete_link(self):
30 30 return 'links:delete'
31   -
  31 +
32 32 def delete_message(self):
33   - return _('Are you sure you want delete the Website link')
34 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 channels==1.0.3
7 7 click==6.6
8 8 constantly==15.1.0
  9 +coreapi==2.3.1
  10 +coreapi-cli==1.0.6
  11 +coreschema==0.0.4
9 12 coverage==4.2
10 13 daphne==1.0.2
11 14 decorator==4.0.10
... ... @@ -19,49 +22,95 @@ django-common-helpers==0.9.0
19 22 django-cron==0.5.0
20 23 django-crontab==0.7.1
21 24 django-discover-runner==1.0
  25 +django-filter==1.0.4
22 26 django-floppyforms==1.7.0
23 27 django-modalview==0.1.5
24 28 django-oauth-toolkit==1.0.0
  29 +django-oauth2-provider==0.2.6.1
  30 +django-rest-swagger==2.1.2
25 31 django-role-permissions==1.2.1
26 32 django-s3direct==0.4.2
27 33 django-session-security==2.4.0
28 34 django-summernote==0.8.6
  35 +django-tracking2==0.3.3
  36 +django-unixdatetimefield==0.1.6
29 37 django-widget-tweaks==1.4.1
30 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 42 et-xmlfile==1.0.1
  43 +fcm-django==0.2.11
33 44 file-resubmit==0.1.0
34 45 gunicorn==19.6.0
  46 +httplib2==0.9.2
35 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 54 jdcal==1.3
37 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 61 lxml==3.7.3
  62 +Markdown==2.6.6
39 63 MarkupSafe==0.23
  64 +mistune==0.7.3
40 65 msgpack-python==0.4.8
  66 +nbconvert==4.2.0
  67 +nbformat==4.0.1
  68 +notebook==4.2.1
41 69 numpy==1.12.1
  70 +oauth2==1.9.0.post1
  71 +oauth2-provider==0.0
42 72 oauthlib==2.0.1
  73 +openapi-codec==1.3.2
43 74 openpyxl==2.4.5
44 75 packaging==16.8
45 76 pandas==0.19.2
  77 +pexpect==4.2.0
  78 +pickleshare==0.7.2
46 79 Pillow==3.3.1
  80 +prompt-toolkit==1.0.3
47 81 psycopg2==2.6.2
  82 +ptyprocess==0.5.1
48 83 pycpfcnpj==1.0.2
  84 +pyfcm==1.3.1
  85 +Pygments==2.1.3
49 86 pyparsing==2.2.0
50 87 python-dateutil==2.6.0
  88 +python-slugify==1.2.0
51 89 pytz==2016.10
  90 +pyzmq==15.3.0
  91 +qtconsole==4.2.1
52 92 redis==2.10.5
53 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 98 six==1.10.0
55 99 slugify==0.0.1
  100 +terminado==0.6
  101 +tornado==4.3
  102 +traitlets==4.2.2
56 103 Twisted==16.6.0
57 104 txaio==2.6.0
  105 +Unidecode==0.4.19
  106 +uritemplate==3.0.0
58 107 validators==0.11.0
  108 +virtualenv==15.0.3
  109 +wcwidth==0.1.7
59 110 webencodings==0.5
60 111 Werkzeug==0.11.11
61 112 whitenoise==3.2.2
  113 +widgetsnbextension==1.2.3
62 114 xlrd==1.0.0
63 115 xlwt==1.2.0
64 116 zope.interface==4.3.3
65   -fcm-django==0.2.11
66   -pyfcm==1.3.1
67   -requests-toolbelt==0.8.0
68 117 \ No newline at end of file
... ...