Skip to content
This repository has been archived by the owner on Oct 24, 2018. It is now read-only.

Commit

Permalink
Merge 5761c84 into 6056263
Browse files Browse the repository at this point in the history
  • Loading branch information
inkhey committed Jul 13, 2018
2 parents 6056263 + 5761c84 commit c23fe01
Show file tree
Hide file tree
Showing 20 changed files with 701 additions and 306 deletions.
44 changes: 38 additions & 6 deletions tracim/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
import json
import time
try: # Python 3.5+
from http import HTTPStatus
except ImportError:
from http import client as HTTPStatus

from pyramid.config import Configurator
from pyramid.authentication import BasicAuthAuthenticationPolicy
Expand All @@ -15,6 +17,7 @@
from tracim.lib.utils.authentification import BASIC_AUTH_WEBUI_REALM
from tracim.lib.utils.authorization import AcceptAllAuthorizationPolicy
from tracim.lib.utils.authorization import TRACIM_DEFAULT_PERM
from tracim.lib.utils.cors import add_cors_support
from tracim.lib.webdav import WebdavAppFactory
from tracim.views import BASE_API_V2
from tracim.views.contents_api.html_document_controller import HTMLDocumentController # nopep8
Expand All @@ -25,7 +28,18 @@
from tracim.views.core_api.workspace_controller import WorkspaceController
from tracim.views.contents_api.comment_controller import CommentController
from tracim.views.errors import ErrorSchema
from tracim.lib.utils.cors import add_cors_support
from tracim.exceptions import NotAuthenticated
from tracim.exceptions import InvalidId
from tracim.exceptions import InsufficientUserProfile
from tracim.exceptions import InsufficientUserRoleInWorkspace
from tracim.exceptions import WorkspaceNotFoundInTracimRequest
from tracim.exceptions import UserNotFoundInTracimRequest
from tracim.exceptions import ContentNotFoundInTracimRequest
from tracim.exceptions import WorkspaceNotFound
from tracim.exceptions import ContentNotFound
from tracim.exceptions import UserDoesNotExist
from tracim.exceptions import AuthenticationFailed
from tracim.exceptions import ContentTypeNotAllowed


def web(global_config, **local_settings):
Expand Down Expand Up @@ -66,9 +80,27 @@ def web(global_config, **local_settings):
debug=app_config.DEBUG,
)
hapic.set_context(context)
context.handle_exception(NotFound, 404)
context.handle_exception(OperationalError, 500)
context.handle_exception(Exception, 500)
# INFO - G.M - 2018-07-04 - global-context exceptions
# Not found
context.handle_exception(NotFound, HTTPStatus.NOT_FOUND)
# Bad request
context.handle_exception(WorkspaceNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST) # nopep8
context.handle_exception(UserNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST) # nopep8
context.handle_exception(ContentNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST) # nopep8
context.handle_exception(WorkspaceNotFound, HTTPStatus.BAD_REQUEST)
context.handle_exception(UserDoesNotExist, HTTPStatus.BAD_REQUEST)
context.handle_exception(ContentNotFound, HTTPStatus.BAD_REQUEST)
context.handle_exception(ContentTypeNotAllowed, HTTPStatus.BAD_REQUEST)
context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
# Auth exception
context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
context.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN) # nopep8
context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
# Internal server error
context.handle_exception(OperationalError, HTTPStatus.INTERNAL_SERVER_ERROR)
context.handle_exception(Exception, HTTPStatus.INTERNAL_SERVER_ERROR)

# Add controllers
session_controller = SessionController()
system_controller = SystemController()
Expand Down
31 changes: 31 additions & 0 deletions tracim/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ class ContentNotFoundInTracimRequest(TracimException):
pass


class InvalidId(TracimException):
pass


class InvalidContentId(InvalidId):
pass


class InvalidCommentId(InvalidId):
pass


class InvalidWorkspaceId(InvalidId):
pass


class InvalidUserId(InvalidId):
pass

class ContentNotFound(TracimException):
pass

Expand All @@ -131,3 +150,15 @@ class ContentTypeNotAllowed(TracimException):

class WorkspacesDoNotMatch(TracimException):
pass


class EmptyValueNotAllowed(TracimException):
pass


class EmptyLabelNotAllowed(EmptyValueNotAllowed):
pass


class EmptyRawContentNotAllowed(EmptyValueNotAllowed):
pass
23 changes: 17 additions & 6 deletions tracim/lib/core/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import re
import typing
from operator import itemgetter
from operator import not_

import transaction
from sqlalchemy import func
Expand All @@ -25,7 +24,8 @@

from tracim.lib.utils.utils import cmp_to_key
from tracim.lib.core.notifications import NotifierFactory
from tracim.exceptions import SameValueError
from tracim.exceptions import SameValueError, EmptyRawContentNotAllowed
from tracim.exceptions import EmptyLabelNotAllowed
from tracim.exceptions import ContentNotFound
from tracim.exceptions import WorkspacesDoNotMatch
from tracim.lib.utils.utils import current_date_for_filename
Expand Down Expand Up @@ -393,18 +393,26 @@ def get_child_folders(self, parent: Content=None, workspace: Workspace=None, fil

return result

def create(self, content_type: str, workspace: Workspace, parent: Content=None, label:str ='', do_save=False, is_temporary: bool=False, do_notify=True) -> Content:
def create(self, content_type: str, workspace: Workspace, parent: Content=None, label: str ='', filename: str = '', do_save=False, is_temporary: bool=False, do_notify=True) -> Content:
assert content_type in ContentType.allowed_types()

if content_type == ContentType.Folder and not label:
label = self.generate_folder_label(workspace, parent)

content = Content()
if label:
content.label = label
elif filename:
# TODO - G.M - 2018-07-04 - File_name setting automatically
# set label and file_extension
content.file_name = label
else:
raise EmptyLabelNotAllowed()

content.owner = self._user
content.parent = parent
content.workspace = workspace
content.type = content_type
content.label = label
content.is_temporary = is_temporary
content.revision_type = ActionDescription.CREATION

Expand All @@ -419,9 +427,10 @@ def create(self, content_type: str, workspace: Workspace, parent: Content=None,
self.save(content, ActionDescription.CREATION, do_notify=do_notify)
return content


def create_comment(self, workspace: Workspace=None, parent: Content=None, content:str ='', do_save=False) -> Content:
assert parent and parent.type!=ContentType.Folder
assert parent and parent.type != ContentType.Folder
if not content:
raise EmptyRawContentNotAllowed()
item = Content()
item.owner = self._user
item.parent = parent
Expand Down Expand Up @@ -972,6 +981,8 @@ def update_content(self, item: Content, new_label: str, new_content: str=None) -
# TODO - G.M - 20-03-2018 - Fix internatization for webdav access.
# Internatization disabled in libcontent for now.
raise SameValueError('The content did not changed')
if not new_label:
raise EmptyLabelNotAllowed()
item.owner = self._user
item.label = new_label
item.description = new_content if new_content else item.description # TODO: convert urls into links
Expand Down
34 changes: 25 additions & 9 deletions tracim/lib/utils/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
from pyramid.request import Request
from sqlalchemy.orm.exc import NoResultFound

from tracim.exceptions import NotAuthenticated, ContentNotFound
from tracim.exceptions import NotAuthenticated
from tracim.exceptions import ContentNotFound
from tracim.exceptions import InvalidUserId
from tracim.exceptions import InvalidWorkspaceId
from tracim.exceptions import InvalidContentId
from tracim.exceptions import InvalidCommentId
from tracim.exceptions import ContentNotFoundInTracimRequest
from tracim.exceptions import WorkspaceNotFoundInTracimRequest
from tracim.exceptions import UserNotFoundInTracimRequest
Expand Down Expand Up @@ -214,6 +219,9 @@ def _get_current_comment(
comment_id = ''
try:
if 'comment_id' in request.matchdict:
comment_id_str = request.matchdict['content_id']
if not isinstance(comment_id_str, str) or not comment_id_str.isdecimal(): # nopep8
raise InvalidCommentId('comment_id is not a correct integer') # nopep8
comment_id = int(request.matchdict['comment_id'])
if not comment_id:
raise ContentNotFoundInTracimRequest('No comment_id property found in request') # nopep8
Expand All @@ -228,8 +236,6 @@ def _get_current_comment(
workspace=workspace,
parent=content,
)
except JSONDecodeError as exc:
raise ContentNotFound('Invalid JSON content') from exc
except NoResultFound as exc:
raise ContentNotFound(
'Comment {} does not exist '
Expand All @@ -253,6 +259,9 @@ def _get_current_content(
content_id = ''
try:
if 'content_id' in request.matchdict:
content_id_str = request.matchdict['content_id']
if not isinstance(content_id_str, str) or not content_id_str.isdecimal(): # nopep8
raise InvalidContentId('content_id is not a correct integer') # nopep8
content_id = int(request.matchdict['content_id'])
if not content_id:
raise ContentNotFoundInTracimRequest('No content_id property found in request') # nopep8
Expand All @@ -262,8 +271,6 @@ def _get_current_content(
config=request.registry.settings['CFG']
)
content = api.get_one(content_id=content_id, workspace=workspace, content_type=ContentType.Any) # nopep8
except JSONDecodeError as exc:
raise ContentNotFound('Invalid JSON content') from exc
except NoResultFound as exc:
raise ContentNotFound(
'Content {} does not exist '
Expand All @@ -286,7 +293,10 @@ def _get_candidate_user(
try:
login = None
if 'user_id' in request.matchdict:
login = request.matchdict['user_id']
user_id_str = request.matchdict['user_id']
if not isinstance(user_id_str, str) or not user_id_str.isdecimal():
raise InvalidUserId('user_id is not a correct integer') # nopep8
login = int(request.matchdict['user_id'])
if not login:
raise UserNotFoundInTracimRequest('You request a candidate user but the context not permit to found one') # nopep8
user = uapi.get_one(login)
Expand Down Expand Up @@ -329,7 +339,10 @@ def _get_current_workspace(
workspace_id = ''
try:
if 'workspace_id' in request.matchdict:
workspace_id = request.matchdict['workspace_id']
workspace_id_str = request.matchdict['workspace_id']
if not isinstance(workspace_id_str, str) or not workspace_id_str.isdecimal(): # nopep8
raise InvalidWorkspaceId('workspace_id is not a correct integer') # nopep8
workspace_id = int(request.matchdict['workspace_id'])
if not workspace_id:
raise WorkspaceNotFoundInTracimRequest('No workspace_id property found in request') # nopep8
wapi = WorkspaceApi(
Expand All @@ -338,8 +351,6 @@ def _get_current_workspace(
config=request.registry.settings['CFG']
)
workspace = wapi.get_one(workspace_id)
except JSONDecodeError as exc:
raise WorkspaceNotFound('Invalid JSON content') from exc
except NoResultFound as exc:
raise WorkspaceNotFound(
'Workspace {} does not exist '
Expand All @@ -362,6 +373,11 @@ def _get_candidate_workspace(
try:
if 'new_workspace_id' in request.json_body:
workspace_id = request.json_body['new_workspace_id']
if not isinstance(workspace_id, int):
if workspace_id.isdecimal():
workspace_id = int(workspace_id)
else:
raise InvalidWorkspaceId('workspace_id is not a correct integer') # nopep8
if not workspace_id:
raise WorkspaceNotFoundInTracimRequest('No new_workspace_id property found in body') # nopep8
wapi = WorkspaceApi(
Expand Down
1 change: 1 addition & 0 deletions tracim/lib/webdav/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ def create_file(self):
is_temporary = self._file_name.startswith('.~') or self._file_name.startswith('~')

file = self._api.create(
filename=self._file_name,
content_type=ContentType.File,
workspace=self._workspace,
parent=self._parent,
Expand Down
29 changes: 6 additions & 23 deletions tracim/models/context_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,22 +110,9 @@ def __init__(
self.status = status


class HTMLDocumentUpdate(object):
class TextBasedContentUpdate(object):
"""
Html Document update model
"""
def __init__(
self,
label: str,
raw_content: str,
) -> None:
self.label = label
self.raw_content = raw_content


class ThreadUpdate(object):
"""
Thread update model
TextBasedContent update model
"""
def __init__(
self,
Expand Down Expand Up @@ -350,10 +337,6 @@ def __init__(self, content: Content, dbsession: Session, config: CFG):
def content_id(self) -> int:
return self.content.content_id

@property
def id(self) -> int:
return self.content_id

@property
def parent_id(self) -> int:
"""
Expand Down Expand Up @@ -457,10 +440,6 @@ def __init__(self, content_revision: ContentRevisionRO, dbsession: Session, conf
def content_id(self) -> int:
return self.revision.content_id

@property
def id(self) -> int:
return self.content_id

@property
def parent_id(self) -> int:
"""
Expand All @@ -476,6 +455,10 @@ def workspace_id(self) -> int:
def label(self) -> str:
return self.revision.label

@property
def revision_type(self) -> str:
return self.revision.revision_type

@property
def content_type(self) -> str:
content_type = ContentType(self.revision.type)
Expand Down
19 changes: 19 additions & 0 deletions tracim/tests/functional/test_comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ def test_api__post_content_comment__ok_200__nominal_case(self) -> None:
assert len(res.json_body) == 4
assert comment == res.json_body[3]

def test_api__post_content_comment__err_400__empty_raw_content(self) -> None:
"""
Get alls comments of a content
"""
self.testapp.authorization = (
'Basic',
(
'admin@admin.admin',
'admin@admin.admin'
)
)
params = {
'raw_content': ''
}
res = self.testapp.post_json(
'/api/v2/workspaces/2/contents/7/comments',
params=params,
status=400
)
def test_api__delete_content_comment__ok_200__user_is_owner_and_workspace_manager(self) -> None: # nopep8
"""
delete comment (user is workspace_manager and owner)
Expand Down

0 comments on commit c23fe01

Please sign in to comment.