mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-08 10:47:54 +02:00
✨(backend) add unresolve action to ThreadViewSet
We have now the possibility to unresolve a thread from the frontend. We need to add the unresolve action to the ThreadViewSet.
This commit is contained in:
@@ -2972,6 +2972,17 @@ class ThreadViewSet(
|
||||
thread.save(update_fields=["resolved", "resolved_at", "resolved_by"])
|
||||
return drf.response.Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@drf.decorators.action(detail=True, methods=["post"], url_path="unresolve")
|
||||
def unresolve(self, request, *args, **kwargs):
|
||||
"""Unresolve a thread."""
|
||||
thread = self.get_object()
|
||||
if thread.resolved:
|
||||
thread.resolved = False
|
||||
thread.resolved_at = None
|
||||
thread.resolved_by = None
|
||||
thread.save(update_fields=["resolved", "resolved_at", "resolved_by"])
|
||||
return drf.response.Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
class CommentViewSet(
|
||||
CommentViewSetMixin,
|
||||
|
||||
@@ -1851,6 +1851,7 @@ class Thread(BaseModel):
|
||||
"update": write_access,
|
||||
"partial_update": write_access,
|
||||
"resolve": write_access,
|
||||
"unresolve": write_access,
|
||||
"retrieve": read_access,
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ def test_api_documents_threads_public_document(link_role):
|
||||
"update": False,
|
||||
"partial_update": False,
|
||||
"resolve": False,
|
||||
"unresolve": False,
|
||||
"retrieve": True,
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -179,6 +180,7 @@ def test_api_documents_threads_restricted_document_editor(role):
|
||||
"update": True,
|
||||
"partial_update": True,
|
||||
"resolve": True,
|
||||
"unresolve": True,
|
||||
"retrieve": True,
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -289,6 +291,7 @@ def test_api_documents_threads_authenticated_document(link_role):
|
||||
"update": True,
|
||||
"partial_update": True,
|
||||
"resolve": True,
|
||||
"unresolve": True,
|
||||
"retrieve": True,
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -549,6 +552,7 @@ def test_api_documents_threads_retrieve_public_document_link_role_higher_than_re
|
||||
"update": False,
|
||||
"partial_update": False,
|
||||
"resolve": False,
|
||||
"unresolve": False,
|
||||
"retrieve": True,
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -652,6 +656,7 @@ def test_api_documents_threads_retrieve_authenticated_document(link_role):
|
||||
"update": False,
|
||||
"partial_update": False,
|
||||
"resolve": False,
|
||||
"unresolve": False,
|
||||
"retrieve": True,
|
||||
},
|
||||
}
|
||||
@@ -749,6 +754,7 @@ def test_api_documents_threads_retrieve_restricted_document_editor(role):
|
||||
"update": False,
|
||||
"partial_update": False,
|
||||
"resolve": False,
|
||||
"unresolve": False,
|
||||
"retrieve": True,
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -808,6 +814,7 @@ def test_api_documents_threads_retrieve_restricted_document_privileged_roles(rol
|
||||
"update": True,
|
||||
"partial_update": True,
|
||||
"resolve": True,
|
||||
"unresolve": True,
|
||||
"retrieve": True,
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -1019,12 +1026,13 @@ def test_api_documents_threads_destroy_restricted_document_privileged_roles(role
|
||||
assert not models.Thread.objects.filter(id=thread.id).exists()
|
||||
|
||||
|
||||
# Resolve
|
||||
# Resolve / Unresolve
|
||||
|
||||
|
||||
def test_api_documents_threads_resolve_public_document_anonymous_user():
|
||||
@pytest.mark.parametrize("action", ["resolve", "unresolve"])
|
||||
def test_api_documents_threads_resolve_unresolve_public_document_anonymous_user(action):
|
||||
"""
|
||||
Anonymous users should not be allowed to resolve threads on public documents.
|
||||
Anonymous users should not be allowed to resolve or unresolve threads on public documents.
|
||||
"""
|
||||
document = factories.DocumentFactory(
|
||||
link_reach="public",
|
||||
@@ -1036,14 +1044,17 @@ def test_api_documents_threads_resolve_public_document_anonymous_user():
|
||||
|
||||
client = APIClient()
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/resolve/",
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/{action}/",
|
||||
)
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_api_documents_threads_resolve_public_document_authenticated_user():
|
||||
@pytest.mark.parametrize("action", ["resolve", "unresolve"])
|
||||
def test_api_documents_threads_resolve_unresolve_public_document_authenticated_user(
|
||||
action,
|
||||
):
|
||||
"""
|
||||
Authenticated users should not be allowed to resolve threads on public documents.
|
||||
Authenticated users should not be allowed to resolve or unresolve threads on public documents.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
document = factories.DocumentFactory(
|
||||
@@ -1057,14 +1068,18 @@ def test_api_documents_threads_resolve_public_document_authenticated_user():
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/resolve/",
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/{action}/",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_api_documents_threads_resolve_authenticated_document_anonymous_user():
|
||||
@pytest.mark.parametrize("action", ["resolve", "unresolve"])
|
||||
def test_api_documents_threads_resolve_unresolve_authenticated_document_anonymous_user(
|
||||
action,
|
||||
):
|
||||
"""
|
||||
Anonymous users should not be allowed to resolve threads on authenticated documents.
|
||||
Anonymous users should not be allowed to resolve or unresolve threads on authenticated
|
||||
documents.
|
||||
"""
|
||||
document = factories.DocumentFactory(
|
||||
link_reach="authenticated",
|
||||
@@ -1076,14 +1091,17 @@ def test_api_documents_threads_resolve_authenticated_document_anonymous_user():
|
||||
|
||||
client = APIClient()
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/resolve/",
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/{action}/",
|
||||
)
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_api_documents_threads_resolve_authenticated_document_reader_role():
|
||||
@pytest.mark.parametrize("action", ["resolve", "unresolve"])
|
||||
def test_api_documents_threads_resolve_unresolve_authenticated_document_reader_role(
|
||||
action,
|
||||
):
|
||||
"""
|
||||
Authenticated users should not be allowed to resolve threads on authenticated
|
||||
Authenticated users should not be allowed to resolve or unresolve threads on authenticated
|
||||
documents with reader link_role.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
@@ -1098,18 +1116,21 @@ def test_api_documents_threads_resolve_authenticated_document_reader_role():
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/resolve/",
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/{action}/",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.parametrize("action", ["resolve", "unresolve"])
|
||||
@pytest.mark.parametrize(
|
||||
"link_role", [models.LinkRoleChoices.COMMENTER, models.LinkRoleChoices.EDITOR]
|
||||
)
|
||||
def test_api_documents_threads_resolve_authenticated_document(link_role):
|
||||
def test_api_documents_threads_resolve_unresolve_authenticated_document(
|
||||
link_role, action
|
||||
):
|
||||
"""
|
||||
Authenticated users should not be allowed to resolve threads on authenticated documents with
|
||||
commenter or editor link_role.
|
||||
Authenticated users should not be allowed to resolve or unresolve threads on authenticated
|
||||
documents with commenter or editor link_role.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
document = factories.DocumentFactory(
|
||||
@@ -1123,14 +1144,17 @@ def test_api_documents_threads_resolve_authenticated_document(link_role):
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/resolve/",
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/{action}/",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_api_documents_threads_resolve_restricted_document_anonymous_user():
|
||||
@pytest.mark.parametrize("action", ["resolve", "unresolve"])
|
||||
def test_api_documents_threads_resolve_unresolve_restricted_document_anonymous_user(
|
||||
action,
|
||||
):
|
||||
"""
|
||||
Anonymous users should not be allowed to resolve threads on restricted documents.
|
||||
Anonymous users should not be allowed to resolve or unresolve threads on restricted documents.
|
||||
"""
|
||||
document = factories.DocumentFactory(
|
||||
link_reach="restricted",
|
||||
@@ -1142,15 +1166,18 @@ def test_api_documents_threads_resolve_restricted_document_anonymous_user():
|
||||
|
||||
client = APIClient()
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/resolve/",
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/{action}/",
|
||||
)
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_api_documents_threads_resolve_restricted_document_reader_role():
|
||||
@pytest.mark.parametrize("action", ["resolve", "unresolve"])
|
||||
def test_api_documents_threads_resolve_unresolve_restricted_document_reader_role(
|
||||
action,
|
||||
):
|
||||
"""
|
||||
Authenticated users should not be allowed to resolve threads on restricted documents with
|
||||
reader roles.
|
||||
Authenticated users should not be allowed to resolve or unresolve threads on restricted
|
||||
documents with reader roles.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
document = factories.DocumentFactory(
|
||||
@@ -1165,18 +1192,21 @@ def test_api_documents_threads_resolve_restricted_document_reader_role():
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/resolve/",
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/{action}/",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.parametrize("action", ["resolve", "unresolve"])
|
||||
@pytest.mark.parametrize(
|
||||
"role", [models.RoleChoices.COMMENTER, models.RoleChoices.EDITOR]
|
||||
)
|
||||
def test_api_documents_threads_resolve_restricted_document_editor(role):
|
||||
def test_api_documents_threads_resolve_unresolve_restricted_document_editor(
|
||||
role, action
|
||||
):
|
||||
"""
|
||||
Authenticated users should not be allowed to resolve threads on restricted documents with
|
||||
editor roles.
|
||||
Authenticated users should not be allowed to resolve or unresolve threads on restricted
|
||||
documents with commenter or editor roles.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
document = factories.DocumentFactory(
|
||||
@@ -1191,7 +1221,7 @@ def test_api_documents_threads_resolve_restricted_document_editor(role):
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/resolve/",
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/{action}/",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
@@ -1219,8 +1249,36 @@ def test_api_documents_threads_resolve_restricted_document_privileged_roles(role
|
||||
)
|
||||
assert response.status_code == 204
|
||||
|
||||
# Verify thread is resolved
|
||||
thread.refresh_from_db()
|
||||
assert thread.resolved is True
|
||||
assert thread.resolved_at is not None
|
||||
assert thread.resolved_by == user
|
||||
|
||||
|
||||
@pytest.mark.parametrize("role", [models.RoleChoices.ADMIN, models.RoleChoices.OWNER])
|
||||
def test_api_documents_threads_unresolve_restricted_document_privileged_roles(role):
|
||||
"""
|
||||
Authenticated users with privileged roles should be allowed to unresolve threads on
|
||||
restricted documents.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
document = factories.DocumentFactory(
|
||||
link_reach="restricted",
|
||||
link_role=models.LinkRoleChoices.EDITOR,
|
||||
users=[(user, role)],
|
||||
)
|
||||
|
||||
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
|
||||
factories.CommentFactory(thread=thread, user=None)
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
|
||||
)
|
||||
assert response.status_code == 204
|
||||
|
||||
thread.refresh_from_db()
|
||||
assert thread.resolved is False
|
||||
assert thread.resolved_at is None
|
||||
assert thread.resolved_by is None
|
||||
|
||||
-5
@@ -534,11 +534,6 @@ export class DocsThreadStore extends ThreadStore {
|
||||
this.ping(threadId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Todo: Not implemented backend side
|
||||
* @returns
|
||||
* @throws
|
||||
*/
|
||||
public unresolveThread = async (_options: { threadId: string }) => {
|
||||
const response = await fetchAPI(
|
||||
`documents/${this.docId}/threads/${_options.threadId}/unresolve/`,
|
||||
|
||||
+5
-6
@@ -53,12 +53,11 @@ export class DocsThreadStoreAuth extends ThreadStoreAuth {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented backend side
|
||||
* @param _thread
|
||||
* @returns
|
||||
*/
|
||||
canUnresolveThread(_thread: ClientThreadData): boolean {
|
||||
canUnresolveThread(thread: ClientThreadData): boolean {
|
||||
if (thread.metadata.abilities.unresolve) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface ThreadAbilities {
|
||||
partial_update: boolean;
|
||||
retrieve: boolean;
|
||||
resolve: boolean;
|
||||
unresolve: boolean;
|
||||
}
|
||||
|
||||
export interface ServerReaction {
|
||||
|
||||
Reference in New Issue
Block a user