diff --git a/mayan/apps/documents/__init__.py b/mayan/apps/documents/__init__.py index d9d6aa90c3..4432acf02b 100644 --- a/mayan/apps/documents/__init__.py +++ b/mayan/apps/documents/__init__.py @@ -160,3 +160,4 @@ namespace.add_statistic(DocumentUsageStatistics(name='document_usage', label=_(u endpoint = APIEndPoint('documents') endpoint.register_urls(api_urls) endpoint.add_endpoint('document-list', _(u'Returns a list of all the documents.')) +endpoint.add_endpoint('documenttype-list', _(u'Returns a list of all the document types.')) diff --git a/mayan/apps/documents/api_views.py b/mayan/apps/documents/api_views.py index 1c461e9009..2d52752e49 100644 --- a/mayan/apps/documents/api_views.py +++ b/mayan/apps/documents/api_views.py @@ -14,14 +14,19 @@ from permissions.models import Permission from rest_api.filters import MayanObjectPermissionsFilter from rest_api.permissions import MayanPermission -from .models import Document, DocumentPage, DocumentVersion +from .models import Document, DocumentPage, DocumentType, DocumentVersion from .permissions import (PERMISSION_DOCUMENT_CREATE, PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_PROPERTIES_EDIT, - PERMISSION_DOCUMENT_VIEW) + PERMISSION_DOCUMENT_VIEW, + PERMISSION_DOCUMENT_TYPE_CREATE, + PERMISSION_DOCUMENT_TYPE_DELETE, + PERMISSION_DOCUMENT_TYPE_EDIT, + PERMISSION_DOCUMENT_TYPE_VIEW) from .serializers import (DocumentImageSerializer, DocumentPageSerializer, - DocumentSerializer, DocumentVersionSerializer) + DocumentSerializer, DocumentTypeSerializer, + DocumentVersionSerializer) from .settings import DISPLAY_SIZE, ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL @@ -181,3 +186,34 @@ class APIDocumentPageView(generics.RetrieveUpdateAPIView): 'PATCH': [PERMISSION_DOCUMENT_EDIT] } mayan_permission_attribute_check = 'document' + + +class APIDocumentTypeListView(generics.ListCreateAPIView): + """ + Returns a list of all the document types. + """ + + serializer_class = DocumentTypeSerializer + queryset = DocumentType.objects.all() + + permission_classes = (MayanPermission,) + filter_backends = (MayanObjectPermissionsFilter,) + mayan_object_permissions = {'GET': [PERMISSION_DOCUMENT_TYPE_VIEW]} + mayan_view_permissions = {'POST': [PERMISSION_DOCUMENT_TYPE_CREATE]} + + +class APIDocumentTypeView(generics.RetrieveUpdateDestroyAPIView): + """ + Returns the selected document type details. + """ + + serializer_class = DocumentTypeSerializer + queryset = DocumentType.objects.all() + + permission_classes = (MayanPermission,) + mayan_object_permissions = { + 'GET': [PERMISSION_DOCUMENT_TYPE_VIEW], + 'PUT': [PERMISSION_DOCUMENT_TYPE_EDIT], + 'PATCH': [PERMISSION_DOCUMENT_TYPE_EDIT], + 'DELETE': [PERMISSION_DOCUMENT_TYPE_DELETE] + } diff --git a/mayan/apps/documents/models.py b/mayan/apps/documents/models.py index 02648cfa25..5cc78405bc 100644 --- a/mayan/apps/documents/models.py +++ b/mayan/apps/documents/models.py @@ -78,7 +78,7 @@ class Document(models.Model): Defines a single document with it's fields and properties """ uuid = models.CharField(max_length=48, blank=True, editable=False) - document_type = models.ForeignKey(DocumentType, verbose_name=_(u'Document type'), null=True, blank=True) + document_type = models.ForeignKey(DocumentType, verbose_name=_(u'Document type'), related_name='documents', null=True, blank=True) description = models.TextField(blank=True, null=True, verbose_name=_(u'Description')) date_added = models.DateTimeField(verbose_name=_(u'Added'), db_index=True, editable=False) diff --git a/mayan/apps/documents/serializers.py b/mayan/apps/documents/serializers.py index a83b43b35a..dc6d0d74b3 100644 --- a/mayan/apps/documents/serializers.py +++ b/mayan/apps/documents/serializers.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from rest_framework import serializers -from .models import Document, DocumentVersion, DocumentPage +from .models import Document, DocumentVersion, DocumentPage, DocumentType class DocumentPageSerializer(serializers.HyperlinkedModelSerializer): @@ -29,4 +29,13 @@ class DocumentSerializer(serializers.HyperlinkedModelSerializer): new_version = serializers.HyperlinkedIdentityField(view_name='document-new-version') class Meta: + fields = ('id', 'url', 'image', 'new_version', 'uuid', 'document_type', 'description', 'date_added', 'versions') model = Document + + +class DocumentTypeSerializer(serializers.HyperlinkedModelSerializer): + documents = DocumentSerializer(many=True, required=False) + + class Meta: + model = DocumentType + fields = ('id', 'url', 'name', 'documents') diff --git a/mayan/apps/documents/urls.py b/mayan/apps/documents/urls.py index 627bb4763b..d491d3071b 100644 --- a/mayan/apps/documents/urls.py +++ b/mayan/apps/documents/urls.py @@ -3,7 +3,8 @@ from __future__ import absolute_import from django.conf.urls import patterns, url from .api_views import (APIDocumentView, APIDocumentImageView, APIDocumentListView, - APIDocumentPageView, APIDocumentVersionCreateView, + APIDocumentPageView, APIDocumentTypeListView, + APIDocumentTypeView, APIDocumentVersionCreateView, APIDocumentVersionView) from .settings import PRINT_SIZE, DISPLAY_SIZE from .views import DocumentListView @@ -77,4 +78,6 @@ api_urls = patterns('', url(r'^document_page/(?P[0-9]+)/$', APIDocumentPageView.as_view(), name='documentpage-detail'), url(r'^documents/(?P[0-9]+)/image/$', APIDocumentImageView.as_view(), name='document-image'), url(r'^documents/(?P[0-9]+)/new_version/$', APIDocumentVersionCreateView.as_view(), name='document-new-version'), + url(r'^documenttypes/$', APIDocumentTypeListView.as_view(), name='documenttype-list'), + url(r'^documenttypes/(?P[0-9]+)/$', APIDocumentTypeView.as_view(), name='documenttype-detail'), ) diff --git a/mayan/apps/folders/__init__.py b/mayan/apps/folders/__init__.py index 09dabe64be..7f57d4502b 100644 --- a/mayan/apps/folders/__init__.py +++ b/mayan/apps/folders/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import -from django.utils.translation import ugettext as _ +from django.utils.translation import ugettext_lazy as _ from acls.api import class_permissions from acls.permissions import ACLS_EDIT_ACL, ACLS_VIEW_ACL @@ -9,6 +9,7 @@ from documents.models import Document from navigation.api import (register_links, register_model_list_columns, register_multi_item_links, register_sidebar_template, register_top_menu) +from rest_api.classes import APIEndPoint from .links import (folder_list, folder_create, folder_edit, folder_delete, folder_document_multiple_remove, folder_view, folder_add_document, @@ -18,6 +19,7 @@ from .models import Folder from .permissions import (PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) +from .urls import api_urls register_multi_item_links(['folders:folder_view'], [folder_document_multiple_remove]) @@ -52,3 +54,12 @@ register_model_list_columns(Folder, [ {'name': _(u'Created'), 'attribute': 'datetime_created'}, {'name': _(u'Documents'), 'attribute': encapsulate(lambda x: x.documents.count())}, ]) + +def document_folders(self): + return Folder.objects.filter(folderdocument__document=self) + +Document.add_to_class('folders', property(document_folders)) + +endpoint = APIEndPoint('folders') +endpoint.register_urls(api_urls) +endpoint.add_endpoint('folder-list', _(u'Returns a list of all the folders.')) diff --git a/mayan/apps/folders/api_views.py b/mayan/apps/folders/api_views.py new file mode 100644 index 0000000000..87c0cbc68a --- /dev/null +++ b/mayan/apps/folders/api_views.py @@ -0,0 +1,71 @@ +from __future__ import absolute_import + +from django.core.exceptions import PermissionDenied +from django.shortcuts import get_object_or_404 + +from rest_framework import generics + +from documents.models import Document +from documents.permissions import PERMISSION_DOCUMENT_VIEW +from permissions.models import Permission +from rest_api.filters import MayanObjectPermissionsFilter +from rest_api.permissions import MayanPermission + +from .models import Folder +from .permissions import (PERMISSION_FOLDER_CREATE, + PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_EDIT, + PERMISSION_FOLDER_VIEW) +from .serializers import FolderSerializer + + +class APIFolderListView(generics.ListCreateAPIView): + """ + Returns a list of all the folders. + """ + + serializer_class = FolderSerializer + queryset = Folder.objects.all() + + permission_classes = (MayanPermission,) + filter_backends = (MayanObjectPermissionsFilter,) + mayan_object_permissions = {'GET': [PERMISSION_FOLDER_VIEW]} + mayan_view_permissions = {'POST': [PERMISSION_FOLDER_CREATE]} + + +class APIFolderView(generics.RetrieveUpdateDestroyAPIView): + """ + Returns the selected folder details. + """ + + serializer_class = FolderSerializer + queryset = Folder.objects.all() + + permission_classes = (MayanPermission,) + mayan_object_permissions = { + 'GET': [PERMISSION_FOLDER_VIEW], + 'PUT': [PERMISSION_FOLDER_EDIT], + 'PATCH': [PERMISSION_FOLDER_EDIT], + 'DELETE': [PERMISSION_FOLDER_DELETE] + } + + +class APIDocumentFolderListView(generics.ListAPIView): + """ + Returns a list of all the folders to which a document belongs. + """ + + serializer_class = FolderSerializer + + permission_classes = (MayanPermission,) + filter_backends = (MayanObjectPermissionsFilter,) + mayan_object_permissions = {'GET': [PERMISSION_FOLDER_VIEW]} + + def get_queryset(self): + document = get_object_or_404(Document, pk=self.kwargs['pk']) + try: + Permission.objects.check_permissions(self.request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, self.request.user, document) + + queryset = document.folders.all() + return queryset diff --git a/mayan/apps/folders/serializers.py b/mayan/apps/folders/serializers.py new file mode 100644 index 0000000000..100fb91b91 --- /dev/null +++ b/mayan/apps/folders/serializers.py @@ -0,0 +1,20 @@ +from __future__ import absolute_import + +from rest_framework import serializers + +from .models import Folder + + +class FolderSerializer(serializers.HyperlinkedModelSerializer): + # FIXME: Doing a: from documents.serializers import DocumentSerializer + # causes an unexplained ImportError, so we import it hidden until the issue + # is resolved + + def __init__(self, *args, **kwargs): + from documents.serializers import DocumentSerializer + super(FolderSerializer, self).__init__(*args, **kwargs) + self.fields['documents'] = DocumentSerializer() + + class Meta: + fields = ('id', 'url', 'title', 'user', 'datetime_created') + model = Folder diff --git a/mayan/apps/folders/urls.py b/mayan/apps/folders/urls.py index e506dc6eb5..9ce888c2f2 100644 --- a/mayan/apps/folders/urls.py +++ b/mayan/apps/folders/urls.py @@ -1,5 +1,7 @@ from django.conf.urls import patterns, url +from .api_views import (APIDocumentFolderListView, APIFolderListView, + APIFolderView) from .views import FolderDetailView, FolderListView urlpatterns = patterns('folders.views', @@ -16,3 +18,9 @@ urlpatterns = patterns('folders.views', url(r'^(?P\d+)/acl/list/$', 'folder_acl_list', (), 'folder_acl_list'), ) + +api_urls = patterns('', + url(r'^folders/$', APIFolderListView.as_view(), name='folder-list'), + url(r'^folders/(?P[0-9]+)/$', APIFolderView.as_view(), name='folder-detail'), + url(r'^document/(?P[0-9]+)/folders/$', APIDocumentFolderListView.as_view(), name='document-folder-list'), +) diff --git a/mayan/apps/folders/views.py b/mayan/apps/folders/views.py index c2d48139e0..17d8fffc13 100644 --- a/mayan/apps/folders/views.py +++ b/mayan/apps/folders/views.py @@ -221,9 +221,9 @@ def document_folder_list(request, document_id): 'object': document, 'multi_select_as_buttons': True, 'hide_link': True, - } + } - queryset=Folder.objects.filter(folderdocument__document=document) + queryset = document.folders.all() try: Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_VIEW]) diff --git a/mayan/apps/tags/__init__.py b/mayan/apps/tags/__init__.py index 11038f76b7..d744f1796a 100644 --- a/mayan/apps/tags/__init__.py +++ b/mayan/apps/tags/__init__.py @@ -58,7 +58,11 @@ class_permissions(Tag, [ PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT, PERMISSION_TAG_VIEW, ]) +def tag_documents(self): + return Document.objects.filter(tags__in=[self]) + Document.add_to_class('tags', TaggableManager()) +Tag.add_to_class('documents', property(tag_documents)) endpoint = APIEndPoint('tags') endpoint.register_urls(api_urls) diff --git a/mayan/apps/tags/api_views.py b/mayan/apps/tags/api_views.py index 203e08b8b5..602d36f43b 100644 --- a/mayan/apps/tags/api_views.py +++ b/mayan/apps/tags/api_views.py @@ -1,8 +1,14 @@ from __future__ import absolute_import +from django.core.exceptions import PermissionDenied +from django.shortcuts import get_object_or_404 + from rest_framework import generics from taggit.models import Tag +from documents.models import Document +from documents.permissions import PERMISSION_DOCUMENT_VIEW +from permissions.models import Permission from rest_api.filters import MayanObjectPermissionsFilter from rest_api.permissions import MayanPermission @@ -31,3 +37,25 @@ class APITagListView(generics.ListAPIView): filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': [PERMISSION_TAG_VIEW]} + + +class APIDocumentTagListView(generics.ListAPIView): + """ + Returns a list of all the tags attached to a document. + """ + + serializer_class = TagSerializer + + permission_classes = (MayanPermission,) + filter_backends = (MayanObjectPermissionsFilter,) + mayan_object_permissions = {'GET': [PERMISSION_TAG_VIEW]} + + def get_queryset(self): + document = get_object_or_404(Document, pk=self.kwargs['pk']) + try: + Permission.objects.check_permissions(self.request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, self.request.user, document) + + queryset = document.tags.all() + return queryset diff --git a/mayan/apps/tags/serializers.py b/mayan/apps/tags/serializers.py index e6b44b5d10..9bba498440 100644 --- a/mayan/apps/tags/serializers.py +++ b/mayan/apps/tags/serializers.py @@ -5,7 +5,17 @@ from taggit.models import Tag class TagSerializer(serializers.HyperlinkedModelSerializer): + # FIXME: Doing a: from documents.serializers import DocumentSerializer + # causes an unexplained ImportError, so we import it hidden until the issue + # is resolved + + def __init__(self, *args, **kwargs): + from documents.serializers import DocumentSerializer + super(TagSerializer, self).__init__(*args, **kwargs) + self.fields['documents'] = DocumentSerializer() + color = serializers.CharField(source='properties.get.color') class Meta: + fields = ('id', 'url', 'name', 'color', 'slug') model = Tag diff --git a/mayan/apps/tags/urls.py b/mayan/apps/tags/urls.py index 0ed8113339..90673f6418 100644 --- a/mayan/apps/tags/urls.py +++ b/mayan/apps/tags/urls.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from django.conf.urls import patterns, url -from .api_views import APITagListView, APITagView +from .api_views import APIDocumentTagListView, APITagListView, APITagView from .views import TagTaggedItemListView urlpatterns = patterns('tags.views', @@ -27,4 +27,5 @@ urlpatterns = patterns('tags.views', api_urls = patterns('', url(r'^tags/(?P[0-9]+)/$', APITagView.as_view(), name='tag-detail'), url(r'^tags/$', APITagListView.as_view(), name='tag-list'), + url(r'^document/(?P[0-9]+)/tags/$', APIDocumentTagListView.as_view(), name='document-tag-list'), ) diff --git a/mayan/apps/tags/views.py b/mayan/apps/tags/views.py index f76f738788..7b512a642e 100644 --- a/mayan/apps/tags/views.py +++ b/mayan/apps/tags/views.py @@ -213,7 +213,7 @@ def tag_edit(request, tag_id): if form.is_valid(): tag.name = form.cleaned_data['name'] tag.save() - tag_properties = tag.tagproperties_set.get() + tag_properties = tag.properties.get() tag_properties.color = form.cleaned_data['color'] tag_properties.save() messages.success(request, _(u'Tag updated succesfully.')) @@ -237,7 +237,7 @@ class TagTaggedItemListView(DocumentListView): return get_object_or_404(Tag, pk=self.kwargs['pk']) def get_queryset(self): - return Document.objects.filter(tags__in=[self.get_tag()]) + return self.get_tag.documents.all() def get_extra_context(self): return { diff --git a/mayan/apps/user_management/__init__.py b/mayan/apps/user_management/__init__.py index 5a7502d2cf..3d33702df6 100644 --- a/mayan/apps/user_management/__init__.py +++ b/mayan/apps/user_management/__init__.py @@ -1,14 +1,17 @@ from __future__ import absolute_import from django.contrib.auth.models import User, Group +from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, register_multi_item_links from project_setup.api import register_setup +from rest_api.classes import APIEndPoint from .links import (user_list, user_setup, user_edit, user_add, user_delete, user_multiple_delete, user_set_password, user_multiple_set_password, user_groups, group_list, group_setup, group_edit, group_add, group_delete, group_multiple_delete, group_members) +from .urls import api_urls register_links(User, [user_edit, user_set_password, user_groups, user_delete]) register_links([User, 'user_management:user_multiple_set_password', 'user_management:user_multiple_delete', 'user_management:user_list', 'user_management:user_add'], [user_list, user_add], menu_name=u'secondary_menu') @@ -27,3 +30,7 @@ user_management_views = [ register_setup(user_setup) register_setup(group_setup) + +endpoint = APIEndPoint('users') +endpoint.register_urls(api_urls) +endpoint.add_endpoint('user-list', _(u'Returns a list of all the users.')) diff --git a/mayan/apps/user_management/api_views.py b/mayan/apps/user_management/api_views.py new file mode 100644 index 0000000000..93effdf2d7 --- /dev/null +++ b/mayan/apps/user_management/api_views.py @@ -0,0 +1,44 @@ +from __future__ import absolute_import + +from django.contrib.auth.models import User + +from rest_framework import generics + +from rest_api.filters import MayanObjectPermissionsFilter +from rest_api.permissions import MayanPermission + +from .permissions import (PERMISSION_USER_CREATE, + PERMISSION_USER_DELETE, PERMISSION_USER_EDIT, + PERMISSION_USER_VIEW) +from .serializers import UserSerializer + + +class APIUserListView(generics.ListCreateAPIView): + """ + Returns a list of all the folders. + """ + + serializer_class = UserSerializer + queryset = User.objects.all() + + permission_classes = (MayanPermission,) + filter_backends = (MayanObjectPermissionsFilter,) + mayan_object_permissions = {'GET': [PERMISSION_USER_VIEW]} + mayan_view_permissions = {'POST': [PERMISSION_USER_CREATE]} + + +class APIUserView(generics.RetrieveUpdateDestroyAPIView): + """ + Returns the selected folder details. + """ + + serializer_class = UserSerializer + queryset = User.objects.all() + + permission_classes = (MayanPermission,) + mayan_object_permissions = { + 'GET': [PERMISSION_USER_VIEW], + 'PUT': [PERMISSION_USER_EDIT], + 'PATCH': [PERMISSION_USER_EDIT], + 'DELETE': [PERMISSION_USER_DELETE] + } diff --git a/mayan/apps/user_management/serializers.py b/mayan/apps/user_management/serializers.py new file mode 100644 index 0000000000..255c1b3717 --- /dev/null +++ b/mayan/apps/user_management/serializers.py @@ -0,0 +1,11 @@ +from __future__ import absolute_import + +from django.contrib.auth.models import User + +from rest_framework import serializers + + +class UserSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + fields = ('id', 'url', 'username', 'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'is_superuser', 'last_login', 'date_joined') + model = User diff --git a/mayan/apps/user_management/urls.py b/mayan/apps/user_management/urls.py index dc2fbcd9f9..8e39795177 100644 --- a/mayan/apps/user_management/urls.py +++ b/mayan/apps/user_management/urls.py @@ -1,5 +1,7 @@ from django.conf.urls import patterns, url +from .api_views import APIUserListView, APIUserView + urlpatterns = patterns('user_management.views', url(r'^user/list/$', 'user_list', (), 'user_list'), url(r'^user/add/$', 'user_add', (), 'user_add'), @@ -17,3 +19,8 @@ urlpatterns = patterns('user_management.views', url(r'^group/multiple/delete/$', 'group_multiple_delete', (), 'group_multiple_delete'), url(r'^group/(?P\d+)/members/$', 'group_members', (), 'group_members'), ) + +api_urls = patterns('', + url(r'^users/$', APIUserListView.as_view(), name='user-list'), + url(r'^users/(?P[0-9]+)/$', APIUserView.as_view(), name='user-detail'), +) diff --git a/mayan/settings/base.py b/mayan/settings/base.py index 8065422746..9ff4b4966c 100644 --- a/mayan/settings/base.py +++ b/mayan/settings/base.py @@ -45,6 +45,7 @@ INSTALLED_APPS = ( 'django.contrib.comments', 'django.contrib.staticfiles', # 3rd party + 'corsheaders', 'south', 'kombu.transport.django', 'djcelery', @@ -99,6 +100,7 @@ INSTALLED_APPS = ( MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -263,3 +265,5 @@ BROKER_URL = 'django://' CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend' CELERY_TIMEZONE = 'UTC' CELERY_ENABLE_UTC = True +#------------ CORS ------------ +CORS_ORIGIN_ALLOW_ALL = True diff --git a/requirements/common.txt b/requirements/common.txt index 6cfc115e0d..71cc753bb7 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -8,6 +8,7 @@ django-celery==3.1.16 django-filetransfers==0.1.0 django-pagination==1.0.7 django-compressor==1.4 +django-cors-headers==0.13 django-taggit==0.12 django-mptt==0.6.1 django-rest-swagger==0.1.14