Verified Commit 23afda95 authored by Marek Veselý's avatar Marek Veselý
Browse files

add API for sandbox

parent 80209b52
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -222,8 +222,8 @@ def create_exercise(
    create_team_questionnaire_states(teams, definition)
    create_drive_permissions(teams, definition.files.filter(is_drive=True))

    if exercise.technical:
        create_opensearch_exercise(teams, exercise.id)
    # if exercise.technical:
    #     create_opensearch_exercise(teams, exercise.id)

    return exercise

+2 −2
Original line number Diff line number Diff line
@@ -268,8 +268,8 @@ class Query(graphene.ObjectType):
        if access.group < User.AuthGroup.INSTRUCTOR:
            type_filter.extend(ActionLog.INVISIBLE_LOG_TYPES)

        if not LogType.SANDBOX_LOG in log_filter.type_blacklist:
            sync_sandbox_logs(log_filter.team_ids)
        # if not LogType.SANDBOX_LOG in log_filter.type_blacklist:
        #     sync_sandbox_logs(log_filter.team_ids)

        logs = (
            ActionLog.objects.filter(team_id__in=log_filter.team_ids)
+5 −0
Original line number Diff line number Diff line
@@ -13,4 +13,9 @@ urlpatterns = [
        views.UploadFileView.as_view(),
        name="upload-file",
    ),
    path(
        "sandbox/<int:team_id>/",
        views.CreateSandboxLogView.as_view(),
        name="create-sandbox-log",
    ),
]
+71 −0
Original line number Diff line number Diff line
@@ -5,16 +5,22 @@ from rest_framework import parsers
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from dateutil import parser  # type: ignore[import-untyped]

from aai.access import (
    exercise_access,
)
from aai.decorators import protected
from common_lib.exceptions import ApiException
from common_lib.utils import ensure_exists
from exercise.models import Exercise, Team
from exercise_definition.models.models import Channel, InjectTypes
from running_exercise.lib.file_handler import (
    upload_file,
    get_uploaded_file,
)
from running_exercise.lib.utils import create_action_log
from running_exercise.models import SandboxLogDetails
from user.models import User


@@ -67,3 +73,68 @@ class UploadFileView(APIView):
                "detail": str(file_id),
            }
        )


class CreateSandboxLogView(APIView):
    parser_classes = [
        parsers.MultiPartParser,
        parsers.JSONParser,
        parsers.FormParser,
    ]
    renderer_classes = [JSONRenderer]

    # TODO: @protected(User.AuthGroup.TRAINEE)
    def post(self, request, *args, **kwargs):
        """Create a sandbox log entry."""
        team_id = self.kwargs.get("team_id", None)
        if team_id is None:
            raise ApiException("Invalid request, missing required parameters")

        team = ensure_exists(Team.objects.filter(id=team_id))
        # TODO: ensure the user belongs to the team
        exercise_id = team.exercise_id
        exercise = ensure_exists(Exercise.objects.filter(id=exercise_id))
        # the order by id should ensure that the same channel is always selected
        # TODO: add a channel for sandbox logs?
        channel = ensure_exists(
            Channel.objects.filter(
                definition_id=exercise.definition_id, type=InjectTypes.INFO
            ).order_by("id")
        )

        timestamp_str = request.data.get("@timestamp", "")
        try:
            timestamp = parser.parse(timestamp_str)
        except (ValueError, TypeError):
            return Response(
                {
                    "status": "error",
                    "detail": "Invalid or missing @timestamp",
                },
                status=400,
            )

        create_action_log(
            team_id=team_id,
            channel_id=channel.id,
            details=SandboxLogDetails.objects.create(
                cmd=request.data.get("cmd", ""),
                cmd_source=request.data.get("cmd_source", ""),
                working_directory=request.data.get("working_directory", ""),
                username=request.data.get("username", ""),
                container=request.data.get("container", ""),
            ),
            # TODO: calculate in_exercise_time?
            in_exercise_time=0,
            # if team only has one user, use it?
            timestamp=timestamp,
        )

        # TODO: subscription broadcast?

        return Response(
            {
                "status": "ok",
                "detail": "Sandbox log entry created",
            }
        )