Skip to content
This repository has been archived by the owner on Feb 21, 2019. It is now read-only.

Commit

Permalink
Merge pull request #45 from tracim/feature/806_add_label_filter_and_s…
Browse files Browse the repository at this point in the history
…ort_content_by_label_in_contents_endpoint

Feature/806 add label filter and sort content by label in contents endpoint
  • Loading branch information
buxx committed Sep 27, 2018
2 parents c4995e6 + 21b5bc8 commit 4c11dcd
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 54 deletions.
38 changes: 34 additions & 4 deletions backend/tracim_backend/lib/core/content.py
Expand Up @@ -18,6 +18,7 @@
from sqlalchemy.orm import aliased
from sqlalchemy.orm import joinedload
from sqlalchemy.orm.attributes import get_history
from sqlalchemy.orm.attributes import QueryableAttribute
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm.session import Session
from sqlalchemy.sql.elements import and_
Expand Down Expand Up @@ -1002,15 +1003,21 @@ def _get_all_query(
self,
parent_id: int = None,
content_type_slug: str = CONTENT_TYPES.Any_SLUG,
workspace: Workspace = None
workspace: Workspace = None,
label:str = None,
order_by_properties: typing.Optional[typing.List[typing.Union[str, QueryableAttribute]]] = None, # nopep8
) -> Query:
"""
Extended filter for better "get all data" query
:param parent_id: filter by parent_id
:param content_type_slug: filter by content_type slug
:param workspace: filter by workspace
:return:
:param order_by_properties: filter by properties can be both string of
attribute or attribute of Model object from sqlalchemy(preferred way,
QueryableAttribute object)
:return: Query object
"""
order_by_properties = order_by_properties or [] # FDV
assert parent_id is None or isinstance(parent_id, int)
assert content_type_slug is not None
resultset = self._base_query(workspace)
Expand All @@ -1028,11 +1035,34 @@ def _get_all_query(
resultset = resultset.filter(Content.parent_id==parent_id)
if parent_id == 0 or parent_id is False:
resultset = resultset.filter(Content.parent_id == None)
if label:
resultset = resultset.filter(Content.label.ilike('%{}%'.format(label))) # nopep8

for _property in order_by_properties:
resultset = resultset.order_by(_property)

return resultset

def get_all(self, parent_id: int=None, content_type: str=CONTENT_TYPES.Any_SLUG, workspace: Workspace=None) -> typing.List[Content]:
return self._get_all_query(parent_id, content_type, workspace).all()
def get_all(
self,
parent_id: int=None,
content_type: str=CONTENT_TYPES.Any_SLUG,
workspace: Workspace=None,
label: str=None,
order_by_properties: typing.Optional[typing.List[typing.Union[str, QueryableAttribute]]] = None, # nopep8
) -> typing.List[Content]:
"""
Return all content using some filters
:param parent_id: filter by parent_id
:param content_type: filter by content_type slug
:param workspace: filter by workspace
:param order_by_properties: filter by properties can be both string of
attribute or attribute of Model object from sqlalchemy(preferred way,
QueryableAttribute object)
:return: List of contents
"""
order_by_properties = order_by_properties or [] # FDV
return self._get_all_query(parent_id, content_type, workspace, label, order_by_properties).all()

# TODO - G.M - 2018-07-17 - [Cleanup] Drop this method if unneeded
# def get_children(self, parent_id: int, content_types: list, workspace: Workspace=None) -> typing.List[Content]:
Expand Down
2 changes: 2 additions & 0 deletions backend/tracim_backend/models/context_models.py
Expand Up @@ -304,6 +304,7 @@ def __init__(
show_deleted: int = 0,
show_active: int = 1,
content_type: str = None,
label: str = None,
offset: int = None,
limit: int = None,
) -> None:
Expand All @@ -314,6 +315,7 @@ def __init__(
self.show_active = bool(show_active)
self.limit = limit
self.offset = offset
self.label = label
self.content_type = content_type


Expand Down
132 changes: 85 additions & 47 deletions backend/tracim_backend/tests/functional/test_workspaces.py
Expand Up @@ -2100,18 +2100,16 @@ def test_api__get_workspace_content__ok_200__get_default(self):
# TODO - G.M - 30-05-2018 - Check this test
assert len(res) == 3
content = res[0]
assert content['content_id'] == 1
assert content['content_type'] == 'folder'
assert content['content_id'] == 11
assert content['content_type'] == 'html-document'
assert content['is_archived'] is False
assert content['is_deleted'] is False
assert content['label'] == 'Tools'
assert content['parent_id'] is None
assert content['label'] == 'Current Menu'
assert content['parent_id'] == 2
assert content['show_in_ui'] is True
assert content['slug'] == 'tools'
assert content['slug'] == 'current-menu'
assert content['status'] == 'open'
assert len(content['sub_content_types']) > 1
assert 'comment' in content['sub_content_types']
assert 'folder' in content['sub_content_types']
assert set(content['sub_content_types']) == {'comment'}
assert content['workspace_id'] == 1
content = res[1]
assert content['content_id'] == 2
Expand All @@ -2128,16 +2126,18 @@ def test_api__get_workspace_content__ok_200__get_default(self):
assert 'folder' in content['sub_content_types']
assert content['workspace_id'] == 1
content = res[2]
assert content['content_id'] == 11
assert content['content_type'] == 'html-document'
assert content['content_id'] == 1
assert content['content_type'] == 'folder'
assert content['is_archived'] is False
assert content['is_deleted'] is False
assert content['label'] == 'Current Menu'
assert content['parent_id'] == 2
assert content['label'] == 'Tools'
assert content['parent_id'] is None
assert content['show_in_ui'] is True
assert content['slug'] == 'current-menu'
assert content['slug'] == 'tools'
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'}
assert len(content['sub_content_types']) > 1
assert 'comment' in content['sub_content_types']
assert 'folder' in content['sub_content_types']
assert content['workspace_id'] == 1

def test_api__get_workspace_content__ok_200__get_default_html_documents(self):
Expand Down Expand Up @@ -2196,20 +2196,20 @@ def test_api__get_workspace_content__ok_200__get_all_root_content__legacy_html_s
).json_body # nopep8
# TODO - G.M - 30-05-2018 - Check this test
assert len(res) == 4
content = res[1]
content = res[0]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 15
assert content['content_id'] == 17
assert content['is_archived'] is False
assert content['is_deleted'] is False
assert content['label'] == 'New Fruit Salad'
assert content['is_deleted'] is True
assert content['label'].startswith('Bad Fruit Salad')
assert content['parent_id'] is None
assert content['show_in_ui'] is True
assert content['slug'] == 'new-fruit-salad'
assert content['slug'].startswith('bad-fruit-salad')
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'}
assert content['workspace_id'] == 3

content = res[2]
content = res[1]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 16
assert content['is_archived'] is True
Expand All @@ -2224,13 +2224,13 @@ def test_api__get_workspace_content__ok_200__get_all_root_content__legacy_html_s

content = res[3]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 17
assert content['content_id'] == 15
assert content['is_archived'] is False
assert content['is_deleted'] is True
assert content['label'].startswith('Bad Fruit Salad')
assert content['is_deleted'] is False
assert content['label'] == 'New Fruit Salad'
assert content['parent_id'] is None
assert content['show_in_ui'] is True
assert content['slug'].startswith('bad-fruit-salad')
assert content['slug'] == 'new-fruit-salad'
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'}
assert content['workspace_id'] == 3
Expand Down Expand Up @@ -2259,20 +2259,20 @@ def test_api__get_workspace_content__ok_200__get_all_root_content(self):
).json_body # nopep8
# TODO - G.M - 30-05-2018 - Check this test
assert len(res) == 4
content = res[1]
content = res[0]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 15
assert content['content_id'] == 17
assert content['is_archived'] is False
assert content['is_deleted'] is False
assert content['label'] == 'New Fruit Salad'
assert content['is_deleted'] is True
assert content['label'].startswith('Bad Fruit Salad')
assert content['parent_id'] is None
assert content['show_in_ui'] is True
assert content['slug'] == 'new-fruit-salad'
assert content['slug'].startswith('bad-fruit-salad')
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'}
assert content['workspace_id'] == 3

content = res[2]
content = res[1]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 16
assert content['is_archived'] is True
Expand All @@ -2287,13 +2287,51 @@ def test_api__get_workspace_content__ok_200__get_all_root_content(self):

content = res[3]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 17
assert content['content_id'] == 15
assert content['is_archived'] is False
assert content['is_deleted'] is True
assert content['label'].startswith('Bad Fruit Salad')
assert content['is_deleted'] is False
assert content['label'] == 'New Fruit Salad'
assert content['parent_id'] is None
assert content['show_in_ui'] is True
assert content['slug'].startswith('bad-fruit-salad')
assert content['slug'] == 'new-fruit-salad'
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'}
assert content['workspace_id'] == 3

def test_api__get_workspace_content__ok_200__get_all_root_content_filter_by_label(self): # nopep8
"""
Check obtain workspace all root contents
"""
params = {
'parent_id': 0,
'show_archived': 1,
'show_deleted': 1,
'show_active': 1,
'label': 'ew'
}
self.testapp.authorization = (
'Basic',
(
'bob@fsf.local',
'foobarbaz'
)
)
res = self.testapp.get(
'/api/v2/workspaces/3/contents',
status=200,
params=params,
).json_body # nopep8
# TODO - G.M - 30-05-2018 - Check this test
assert len(res) == 1
content = res[0]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 15
assert content['is_archived'] is False
assert content['is_deleted'] is False
assert content['label'] == 'New Fruit Salad'
assert content['parent_id'] is None
assert content['show_in_ui'] is True
assert content['slug'] == 'new-fruit-salad'
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'}
assert content['workspace_id'] == 3
Expand Down Expand Up @@ -2640,26 +2678,26 @@ def test_api__get_workspace_content__ok_200__get_all_filter_content_html_and_leg
assert content['content_id']
assert content['is_archived'] is False
assert content['is_deleted'] is False
assert content['label'] == 'test_page'
assert content['label'] == 'test_html_page'
assert content['parent_id'] == 1
assert content['show_in_ui'] is True
assert content['slug'] == 'test-page'
assert content['slug'] == 'test-html-page'
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'} # nopep8
assert content['workspace_id'] == 1
assert res[0]['content_id'] != res[1]['content_id']
content = res[1]
assert content['content_type'] == 'html-document'
assert content['content_id']
assert content['is_archived'] is False
assert content['is_deleted'] is False
assert content['label'] == 'test_html_page'
assert content['label'] == 'test_page'
assert content['parent_id'] == 1
assert content['show_in_ui'] is True
assert content['slug'] == 'test-html-page'
assert content['slug'] == 'test-page'
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'} # nopep8
assert content['workspace_id'] == 1
assert res[0]['content_id'] != res[1]['content_id']

def test_api__get_workspace_content__ok_200__get_all_folder_content(self):
"""
Expand Down Expand Up @@ -2687,13 +2725,13 @@ def test_api__get_workspace_content__ok_200__get_all_folder_content(self):
assert len(res) == 3
content = res[0]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 12
assert content['content_id'] == 14
assert content['is_archived'] is False
assert content['is_deleted'] is False
assert content['label'] == 'New Fruit Salad'
assert content['is_deleted'] is True
assert content['label'].startswith('Bad Fruit Salad')
assert content['parent_id'] == 10
assert content['show_in_ui'] is True
assert content['slug'] == 'new-fruit-salad'
assert content['slug'].startswith('bad-fruit-salad')
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'} # nopep8
assert content['workspace_id'] == 2
Expand All @@ -2713,13 +2751,13 @@ def test_api__get_workspace_content__ok_200__get_all_folder_content(self):

content = res[2]
assert content['content_type'] == 'html-document'
assert content['content_id'] == 14
assert content['content_id'] == 12
assert content['is_archived'] is False
assert content['is_deleted'] is True
assert content['label'].startswith('Bad Fruit Salad')
assert content['is_deleted'] is False
assert content['label'] == 'New Fruit Salad'
assert content['parent_id'] == 10
assert content['show_in_ui'] is True
assert content['slug'].startswith('bad-fruit-salad')
assert content['slug'] == 'new-fruit-salad'
assert content['status'] == 'open'
assert set(content['sub_content_types']) == {'comment'} # nopep8
assert content['workspace_id'] == 2
Expand Down
15 changes: 12 additions & 3 deletions backend/tracim_backend/views/core_api/schemas.py
Expand Up @@ -440,6 +440,12 @@ class FilterContentQuerySchema(marshmallow.Schema):
default=CONTENT_TYPES.Any_SLUG,
validate=all_content_types_validator
)
label = marshmallow.fields.String(
example='myfilename',
default=None,
allow_none=True,
description='Filter by content label'
)

@post_load
def make_content_filter(self, data):
Expand Down Expand Up @@ -815,7 +821,8 @@ class ContentCreationSchema(marshmallow.Schema):
label = marshmallow.fields.String(
required=True,
example='contract for client XXX',
description='Title of the content to create'
description='Title of the content to create',
validate=Length(min=1),
)
content_type = marshmallow.fields.String(
required=True,
Expand Down Expand Up @@ -1002,8 +1009,9 @@ class CommentSchema(marshmallow.Schema):

class SetCommentSchema(marshmallow.Schema):
raw_content = marshmallow.fields.String(
example='<p>This is just an html comment !</p>',
validate=Length(min=1),
required=True,
example='<p>This is just an html comment !</p>'
)

@post_load()
Expand All @@ -1015,7 +1023,8 @@ class ContentModifyAbstractSchema(marshmallow.Schema):
label = marshmallow.fields.String(
required=True,
example='contract for client XXX',
description='New title of the content'
description='New title of the content',
validate=Length(min=1)
)


Expand Down
3 changes: 3 additions & 0 deletions backend/tracim_backend/views/core_api/workspace_controller.py
Expand Up @@ -32,6 +32,7 @@
from tracim_backend.models.context_models import ContentInContext
from tracim_backend.models.context_models import UserRoleWorkspaceInContext
from tracim_backend.models.data import ActionDescription
from tracim_backend.models.data import Content
from tracim_backend.models.data import UserRoleInWorkspace
from tracim_backend.models.revision_protection import new_revision
from tracim_backend.models.roles import WorkspaceRoles
Expand Down Expand Up @@ -416,6 +417,8 @@ def workspace_content(
parent_id=content_filter.parent_id,
workspace=request.current_workspace,
content_type=content_filter.content_type or CONTENT_TYPES.Any_SLUG,
label=content_filter.label,
order_by_properties=[Content.label]
)
contents = [
api.get_content_in_context(content) for content in contents
Expand Down

0 comments on commit 4c11dcd

Please sign in to comment.