|
4 | 4 | from uuid import UUID, uuid1
|
5 | 5 |
|
6 | 6 | from django.conf import settings
|
| 7 | +from django.contrib.auth import get_user_model |
7 | 8 | from django.db import transaction
|
8 | 9 | from django.http import HttpResponse
|
9 | 10 | from django.shortcuts import get_object_or_404
|
10 |
| -from guardian.shortcuts import get_objects_for_user |
11 |
| -from ninja import File, Query, Router, UploadedFile |
| 11 | +from guardian.shortcuts import assign_perm, get_objects_for_user, get_perms, remove_perm |
| 12 | +from ninja import File, PatchDict, Query, Router, UploadedFile |
12 | 13 | from ninja.security import django_auth
|
13 | 14 |
|
14 | 15 | from orochi.api.filters import DumpFilters, OperatingSytemFilters
|
15 |
| -from orochi.api.models import DumpIn, DumpInfoSchema, DumpSchema, ResultSmallOutSchema |
| 16 | +from orochi.api.models import ( |
| 17 | + DumpEditIn, |
| 18 | + DumpIn, |
| 19 | + DumpInfoSchema, |
| 20 | + DumpSchema, |
| 21 | + ErrorsOut, |
| 22 | + ResultSmallOutSchema, |
| 23 | + SuccessResponse, |
| 24 | +) |
16 | 25 | from orochi.website.defaults import RESULT_STATUS_NOT_STARTED, RESULT_STATUS_RUNNING
|
17 | 26 | from orochi.website.models import Dump, Folder, Result, UserPlugin
|
18 | 27 | from orochi.website.views import index_f_and_f
|
@@ -46,6 +55,44 @@ def list_dumps(request, filters: Query[OperatingSytemFilters]):
|
46 | 55 | return dumps
|
47 | 56 |
|
48 | 57 |
|
| 58 | +@router.delete( |
| 59 | + "/{pk}", |
| 60 | + auth=django_auth, |
| 61 | + url_name="delete_dump", |
| 62 | + response={200: SuccessResponse, 400: ErrorsOut}, |
| 63 | +) |
| 64 | +def delete_dump(request, pk: UUID): |
| 65 | + """ |
| 66 | + Deletes a dump identified by its primary key (pk). This function ensures that the user has permission to delete the dump before proceeding with the deletion. |
| 67 | +
|
| 68 | + Args: |
| 69 | + request: The HTTP request object. |
| 70 | + pk (UUID): The primary key of the dump to be deleted. |
| 71 | +
|
| 72 | + Returns: |
| 73 | + SuccessResponse: A response indicating the successful deletion of the dump. |
| 74 | +
|
| 75 | + Raises: |
| 76 | + Http404: If the dump with the specified primary key does not exist. |
| 77 | + ErrorsOut: If the user does not have permission to delete the dump. |
| 78 | +
|
| 79 | + Examples: |
| 80 | + DELETE /dumps/{pk} |
| 81 | + """ |
| 82 | + try: |
| 83 | + dump = get_object_or_404(Dump, index=pk) |
| 84 | + name = dump.name |
| 85 | + if dump not in get_objects_for_user(request.user, "website.can_see"): |
| 86 | + return 400, {"errors": "Error during index deletion."} |
| 87 | + dump.delete() |
| 88 | + shutil.rmtree(f"{settings.MEDIA_ROOT}/{dump.index}") |
| 89 | + return 200, {"message": f"Index {name} has been deleted successfully."} |
| 90 | + except Exception as excp: |
| 91 | + return 400, { |
| 92 | + "errors": str(excp) if excp else "Generic error during dump deletion" |
| 93 | + } |
| 94 | + |
| 95 | + |
49 | 96 | @router.get("/{pk}", response=DumpInfoSchema, auth=django_auth)
|
50 | 97 | def get_dump_info(request, pk: UUID):
|
51 | 98 | """
|
@@ -152,6 +199,65 @@ def create_dump(request, payload: DumpIn, upload: Optional[UploadedFile] = File(
|
152 | 199 | return HttpResponse(f"Bad Request ({excp})", status=400)
|
153 | 200 |
|
154 | 201 |
|
| 202 | +@router.patch("/{pk}", url_name="edit_index", response=DumpSchema, auth=django_auth) |
| 203 | +def edit_dump(request, pk: UUID, payload: PatchDict[DumpEditIn]): |
| 204 | + """ |
| 205 | + Edits an existing dump based on the provided payload. This function updates the dump's attributes and manages user permissions for accessing the dump. |
| 206 | +
|
| 207 | + Args: |
| 208 | + request: The HTTP request object. |
| 209 | + payload (PatchDict[DumpEditIn]): The data containing the updates to be applied to the dump. |
| 210 | +
|
| 211 | + Returns: |
| 212 | + DumpSchema: The updated dump object. |
| 213 | +
|
| 214 | + Raises: |
| 215 | + Http404: If the dump with the specified index does not exist. |
| 216 | + HttpResponse: If there is an error during the update process. |
| 217 | +
|
| 218 | + Examples: |
| 219 | + PATCH /dumps/{pk} |
| 220 | + """ |
| 221 | + |
| 222 | + try: |
| 223 | + dump = get_object_or_404(Dump, index=pk) |
| 224 | + if dump not in get_objects_for_user(request.user, "website.can_see"): |
| 225 | + return 403, {"message": "Unauthorized"} |
| 226 | + |
| 227 | + auth_users = [ |
| 228 | + user.pk |
| 229 | + for user in get_user_model().objects.all() |
| 230 | + if "can_see" in get_perms(user, dump) and user != request.user |
| 231 | + ] |
| 232 | + |
| 233 | + if payload["folder"]: |
| 234 | + folder, _ = Folder.objects.get_or_create( |
| 235 | + name=payload["folder"]["name"], user=request.user |
| 236 | + ) |
| 237 | + dump.folder = folder |
| 238 | + |
| 239 | + for attr, value in payload.items(): |
| 240 | + if attr not in ["authorized_users", "folder"]: |
| 241 | + setattr(dump, attr, value) |
| 242 | + else: |
| 243 | + for user_pk in payload.get("authorized_users", []): |
| 244 | + user = get_user_model().objects.get(pk=user_pk) |
| 245 | + if user.pk not in auth_users: |
| 246 | + assign_perm( |
| 247 | + "can_see", |
| 248 | + user, |
| 249 | + dump, |
| 250 | + ) |
| 251 | + for user_pk in auth_users: |
| 252 | + if user_pk not in payload.get("authorized_users", []): |
| 253 | + user = get_user_model().objects.get(pk=user_pk) |
| 254 | + remove_perm("can_see", user, dump) |
| 255 | + dump.save() |
| 256 | + return dump |
| 257 | + except Exception as excp: |
| 258 | + return HttpResponse(f"Bad Request ({excp})", status=400) |
| 259 | + |
| 260 | + |
155 | 261 | @router.get(
|
156 | 262 | "/{idxs:pks}/plugins",
|
157 | 263 | url_name="dumps_plugins",
|
@@ -188,3 +294,18 @@ def get_dump_plugins(request, pks: List[UUID], filters: Query[DumpFilters] = Non
|
188 | 294 | if filters and filters.result:
|
189 | 295 | res = res.filter(result=filters.result)
|
190 | 296 | return res
|
| 297 | + |
| 298 | + |
| 299 | +@router.get( |
| 300 | + "/{idxs:pks}/plugin/{str:plugin_name}", |
| 301 | + url_name="dumps_plugin_status", |
| 302 | + auth=django_auth, |
| 303 | +) |
| 304 | +def get_dump_plugin_status(request, pks: List[UUID], plugin_name: int): |
| 305 | + dumps_ok = get_objects_for_user(request.user, "website.can_see") |
| 306 | + dumps = [ |
| 307 | + dump.index for dump in Dump.objects.filter(index__in=pks) if dump in dumps_ok |
| 308 | + ] |
| 309 | + return Result.objects.select_related("dump", "plugin").filter( |
| 310 | + dump__index__in=dumps, plugin__name=plugin_name |
| 311 | + ) |
0 commit comments