Skip to content

Commit 0dfd3da

Browse files
committed
save19
1 parent 6418ede commit 0dfd3da

4 files changed

Lines changed: 219 additions & 5 deletions

File tree

src/backend/core/api/viewsets.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2972,6 +2972,17 @@ def resolve(self, request, *args, **kwargs):
29722972
thread.save(update_fields=["resolved", "resolved_at", "resolved_by"])
29732973
return drf.response.Response(status=status.HTTP_204_NO_CONTENT)
29742974

2975+
@drf.decorators.action(detail=True, methods=["post"], url_path="unresolve")
2976+
def unresolve(self, request, *args, **kwargs):
2977+
"""Unresolve a thread."""
2978+
thread = self.get_object()
2979+
if thread.resolved:
2980+
thread.resolved = False
2981+
thread.resolved_at = None
2982+
thread.resolved_by = None
2983+
thread.save(update_fields=["resolved", "resolved_at", "resolved_by"])
2984+
return drf.response.Response(status=status.HTTP_204_NO_CONTENT)
2985+
29752986

29762987
class CommentViewSet(
29772988
CommentViewSetMixin,

src/backend/core/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,6 +1851,7 @@ def get_abilities(self, user):
18511851
"update": write_access,
18521852
"partial_update": write_access,
18531853
"resolve": write_access,
1854+
"unresolve": write_access,
18541855
"retrieve": read_access,
18551856
}
18561857

src/backend/core/tests/documents/test_api_documents_threads.py

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,3 +1224,210 @@ def test_api_documents_threads_resolve_restricted_document_privileged_roles(role
12241224
assert thread.resolved is True
12251225
assert thread.resolved_at is not None
12261226
assert thread.resolved_by == user
1227+
1228+
1229+
# Unresolve
1230+
1231+
1232+
def test_api_documents_threads_unresolve_public_document_anonymous_user():
1233+
"""
1234+
Anonymous users should not be allowed to unresolve threads on public documents.
1235+
"""
1236+
document = factories.DocumentFactory(
1237+
link_reach="public",
1238+
link_role=models.LinkRoleChoices.COMMENTER,
1239+
)
1240+
1241+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1242+
factories.CommentFactory(thread=thread, user=None)
1243+
1244+
client = APIClient()
1245+
response = client.post(
1246+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1247+
)
1248+
assert response.status_code == 401
1249+
1250+
1251+
def test_api_documents_threads_unresolve_public_document_authenticated_user():
1252+
"""
1253+
Authenticated users should not be allowed to unresolve threads on public documents.
1254+
"""
1255+
user = factories.UserFactory()
1256+
document = factories.DocumentFactory(
1257+
link_reach="public",
1258+
link_role=models.LinkRoleChoices.COMMENTER,
1259+
)
1260+
1261+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1262+
factories.CommentFactory(thread=thread, user=None)
1263+
1264+
client = APIClient()
1265+
client.force_login(user)
1266+
response = client.post(
1267+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1268+
)
1269+
assert response.status_code == 403
1270+
1271+
1272+
def test_api_documents_threads_unresolve_authenticated_document_anonymous_user():
1273+
"""
1274+
Anonymous users should not be allowed to unresolve threads on authenticated documents.
1275+
"""
1276+
document = factories.DocumentFactory(
1277+
link_reach="authenticated",
1278+
link_role=models.LinkRoleChoices.COMMENTER,
1279+
)
1280+
1281+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1282+
factories.CommentFactory(thread=thread, user=None)
1283+
1284+
client = APIClient()
1285+
response = client.post(
1286+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1287+
)
1288+
assert response.status_code == 401
1289+
1290+
1291+
def test_api_documents_threads_unresolve_authenticated_document_reader_role():
1292+
"""
1293+
Authenticated users should not be allowed to unresolve threads on authenticated
1294+
documents with reader link_role.
1295+
"""
1296+
user = factories.UserFactory()
1297+
document = factories.DocumentFactory(
1298+
link_reach="authenticated",
1299+
link_role=models.LinkRoleChoices.READER,
1300+
)
1301+
1302+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1303+
factories.CommentFactory(thread=thread, user=None)
1304+
1305+
client = APIClient()
1306+
client.force_login(user)
1307+
response = client.post(
1308+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1309+
)
1310+
assert response.status_code == 403
1311+
1312+
1313+
@pytest.mark.parametrize(
1314+
"link_role", [models.LinkRoleChoices.COMMENTER, models.LinkRoleChoices.EDITOR]
1315+
)
1316+
def test_api_documents_threads_unresolve_authenticated_document(link_role):
1317+
"""
1318+
Authenticated users should not be allowed to unresolve threads on authenticated documents with
1319+
commenter or editor link_role.
1320+
"""
1321+
user = factories.UserFactory()
1322+
document = factories.DocumentFactory(
1323+
link_reach="authenticated",
1324+
link_role=link_role,
1325+
)
1326+
1327+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1328+
factories.CommentFactory(thread=thread, user=None)
1329+
1330+
client = APIClient()
1331+
client.force_login(user)
1332+
response = client.post(
1333+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1334+
)
1335+
assert response.status_code == 403
1336+
1337+
1338+
def test_api_documents_threads_unresolve_restricted_document_anonymous_user():
1339+
"""
1340+
Anonymous users should not be allowed to unresolve threads on restricted documents.
1341+
"""
1342+
document = factories.DocumentFactory(
1343+
link_reach="restricted",
1344+
link_role=models.LinkRoleChoices.COMMENTER,
1345+
)
1346+
1347+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1348+
factories.CommentFactory(thread=thread, user=None)
1349+
1350+
client = APIClient()
1351+
response = client.post(
1352+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1353+
)
1354+
assert response.status_code == 401
1355+
1356+
1357+
def test_api_documents_threads_unresolve_restricted_document_reader_role():
1358+
"""
1359+
Authenticated users should not be allowed to unresolve threads on restricted documents with
1360+
reader roles.
1361+
"""
1362+
user = factories.UserFactory()
1363+
document = factories.DocumentFactory(
1364+
link_reach="restricted",
1365+
link_role=models.LinkRoleChoices.READER,
1366+
users=[(user, models.LinkRoleChoices.READER)],
1367+
)
1368+
1369+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1370+
factories.CommentFactory(thread=thread, user=None)
1371+
1372+
client = APIClient()
1373+
client.force_login(user)
1374+
response = client.post(
1375+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1376+
)
1377+
assert response.status_code == 403
1378+
1379+
1380+
@pytest.mark.parametrize(
1381+
"role", [models.RoleChoices.COMMENTER, models.RoleChoices.EDITOR]
1382+
)
1383+
def test_api_documents_threads_unresolve_restricted_document_editor(role):
1384+
"""
1385+
Authenticated users should not be allowed to unresolve threads on restricted documents with
1386+
commenter or editor roles.
1387+
"""
1388+
user = factories.UserFactory()
1389+
document = factories.DocumentFactory(
1390+
link_reach="restricted",
1391+
link_role=models.LinkRoleChoices.EDITOR,
1392+
users=[(user, role)],
1393+
)
1394+
1395+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1396+
factories.CommentFactory(thread=thread, user=None)
1397+
1398+
client = APIClient()
1399+
client.force_login(user)
1400+
response = client.post(
1401+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1402+
)
1403+
assert response.status_code == 403
1404+
1405+
1406+
@pytest.mark.parametrize("role", [models.RoleChoices.ADMIN, models.RoleChoices.OWNER])
1407+
def test_api_documents_threads_unresolve_restricted_document_privileged_roles(role):
1408+
"""
1409+
Authenticated users with privileged roles should be allowed to unresolve threads on
1410+
restricted documents.
1411+
"""
1412+
user = factories.UserFactory()
1413+
document = factories.DocumentFactory(
1414+
link_reach="restricted",
1415+
link_role=models.LinkRoleChoices.EDITOR,
1416+
users=[(user, role)],
1417+
)
1418+
1419+
thread = factories.ThreadFactory(document=document, creator=None, resolved=True)
1420+
factories.CommentFactory(thread=thread, user=None)
1421+
1422+
client = APIClient()
1423+
client.force_login(user)
1424+
response = client.post(
1425+
f"/api/v1.0/documents/{document.id!s}/threads/{thread.id!s}/unresolve/",
1426+
)
1427+
assert response.status_code == 204
1428+
1429+
# Verify thread is unresolved
1430+
thread.refresh_from_db()
1431+
assert thread.resolved is False
1432+
assert thread.resolved_at is None
1433+
assert thread.resolved_by is None

src/frontend/apps/impress/src/features/docs/doc-editor/components/comments/DocsThreadStore.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -534,11 +534,6 @@ export class DocsThreadStore extends ThreadStore {
534534
this.ping(threadId);
535535
};
536536

537-
/**
538-
* Todo: Not implemented backend side
539-
* @returns
540-
* @throws
541-
*/
542537
public unresolveThread = async (_options: { threadId: string }) => {
543538
const response = await fetchAPI(
544539
`documents/${this.docId}/threads/${_options.threadId}/unresolve/`,

0 commit comments

Comments
 (0)