Skip to content

Commit

Permalink
API Client: Add investigative question handling. (#3144)
Browse files Browse the repository at this point in the history
* Adding dfiq handlign to the api client.

* linters

* fix tests

* Update api_client/python/timesketch_api_client/scenario_test.py

* Update api_client/python/timesketch_api_client/scenario.py

---------

Co-authored-by: Johan Berggren <[email protected]>
  • Loading branch information
jkppr and berggren authored Aug 21, 2024
1 parent 8f00d11 commit 79e1da3
Show file tree
Hide file tree
Showing 6 changed files with 678 additions and 25 deletions.
229 changes: 229 additions & 0 deletions api_client/python/timesketch_api_client/scenario.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
# Copyright 2024 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Timesketch API client library for working with scenarios."""


import logging

from . import error
from . import resource


logger = logging.getLogger("timesketch_api.scenario")


class Scenario(resource.BaseResource):
"""Timesketch scenario object.
Attributes:
id: The ID of the scenario.
api: An instance of TimesketchApi object.
"""

def __init__(self, sketch_id, scenario_id, api):
"""Initializes the Scenario object.
Args:
scenario_id: Primary key ID of the scenario.
api: An instance of TiscmesketchApi object.
sketch_id: ID of a sketch.
"""
self.id = scenario_id
self.api = api
self.sketch_id = sketch_id
super().__init__(
api=api, resource_uri=f"sketches/{self.sketch_id}/scenarios/{self.id}/"
)

@property
def name(self):
"""Property that returns the scenario name.
Returns:
Scenario name as string.
"""
scenario = self.lazyload_data()
return scenario["objects"][0]["name"]

@property
def scenario_id(self):
"""Property that returns the scenario id.
Returns:
Scenario id as integer.
"""
scenario = self.lazyload_data()
return scenario["objects"][0]["id"]

@property
def dfiq_id(self):
"""Property that returns the dfiq id.
Returns:
dfiq id as string.
"""
scenario = self.lazyload_data()
return scenario["objects"][0]["dfiq_identifier"]

@property
def description(self):
"""Property that returns the scenario description.
Returns:
Description as string.
"""
scenario = self.lazyload_data()
return scenario["objects"][0]["description"]

def to_dict(self):
"""Returns a dict representation of the scenario."""
return self.lazyload_data()


class ScenarioTemplateList(resource.BaseResource):
"""Timesketch scenario template list.
Attributes:
api: An instance of TimesketchApi object.
"""

def __init__(self, api):
"""Initializes the ScenarioList object.
Args:
api: An instance of TimesketchApi object.
"""
self.api = api
super().__init__(api=api, resource_uri="scenarios/")

def get(self):
"""
Retrieves a list of scenario templates.
Returns:
list: A list of Scenario tempaltes.
"""
resource_url = f"{self.api.api_root}/scenarios/"
response = self.api.session.get(resource_url)
response_json = error.get_response_json(response, logger)
scenario_objects = response_json.get("objects", [])
return scenario_objects


class Question(resource.BaseResource):
"""Timesketch question object.
Attributes:
id: The ID of the question.
api: An instance of TimesketchApi object.
"""

def __init__(self, sketch_id, question_id, api):
"""Initializes the question object.
Args:
question_id: Primary key ID of the scenario.
api: An instance of TiscmesketchApi object.
sketch_id: ID of a sketch.
"""
self.id = question_id
self.api = api
self.sketch_id = sketch_id
super().__init__(
api=api, resource_uri=f"sketches/{self.sketch_id}/questions/{self.id}/"
)

@property
def name(self):
"""Property that returns the question name.
Returns:
Question name as string.
"""
question = self.lazyload_data()
return question["objects"][0]["name"]

@property
def question_id(self):
"""Property that returns the question id.
Returns:
Question id as integer.
"""
question = self.lazyload_data()
return question["objects"][0]["id"]

@property
def dfiq_id(self):
"""Property that returns the question template id.
Returns:
Question ID as string.
"""
question = self.lazyload_data()
return question["objects"][0]["dfiq_identifier"]

@property
def description(self):
"""Property that returns the question description.
Returns:
Question description as string.
"""
question = self.lazyload_data()
return question["objects"][0]["description"]

@property
def approaches(self):
"""Property that returns the question approaches.
Returns:
Question approaches as list of dict.
"""
question = self.lazyload_data()
return question["objects"][0]["approaches"]

def to_dict(self):
"""Returns a dict representation of the question."""
return self.lazyload_data()


class QuestionTemplateList(resource.BaseResource):
"""Timesketch question template list.
Attributes:
api: An instance of TimesketchApi object.
"""

def __init__(self, api):
"""Initializes the QuestionList object.
Args:
api: An instance of TimesketchApi object.
"""
self.api = api
super().__init__(api=api, resource_uri="questions/")

def get(self):
"""
Retrieves a list of question templates.
Returns:
list: A list of question tempaltes.
"""
resource_url = f"{self.api.api_root}/questions/"
response = self.api.session.get(resource_url)
response_json = error.get_response_json(response, logger)
scenario_objects = response_json.get("objects", [])
return scenario_objects
85 changes: 85 additions & 0 deletions api_client/python/timesketch_api_client/scenario_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright 2024 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for the Timesketch API client"""

import unittest
import mock

from . import client
from . import test_lib
from . import scenario as scenario_lib


class ScenarioTest(unittest.TestCase):
"""Test Scenario object."""

@mock.patch("requests.Session", test_lib.mock_session)
def setUp(self):
"""Setup test case."""
self.api_client = client.TimesketchApi("http://127.0.0.1", "test", "test")
self.sketch = self.api_client.get_sketch(1)

def test_scenario_to_dict(self):
"""Test Scenario object to dict."""
scenario = self.sketch.list_scenarios()[0]
self.assertIsInstance(scenario.to_dict(), dict)


class ScenarioListTest(unittest.TestCase):
"""Test ScenarioList object."""

@mock.patch("requests.Session", test_lib.mock_session)
def setUp(self):
"""Setup test case."""
self.api_client = client.TimesketchApi("http://127.0.0.1", "test", "test")

def test_scenario_list(self):
"""Test ScenarioList object."""
scenario_list = scenario_lib.ScenarioTemplateList(self.api_client).get()
self.assertIsInstance(scenario_list, list)
self.assertEqual(len(scenario_list), 2)
self.assertEqual(scenario_list[0]["name"], "Test Scenario")
self.assertEqual(scenario_list[1]["id"], "S0002")


class QuestionTest(unittest.TestCase):
"""Test Question object."""

@mock.patch("requests.Session", test_lib.mock_session)
def setUp(self):
"""Setup test case."""
self.api_client = client.TimesketchApi("http://127.0.0.1", "test", "test")
self.sketch = self.api_client.get_sketch(1)

def test_question_to_dict(self):
"""Test Question object to dict."""
scenario = self.sketch.list_questions()[0]
self.assertIsInstance(scenario.to_dict(), dict)


class QuestionListTest(unittest.TestCase):
"""Test QuestionList object."""

@mock.patch("requests.Session", test_lib.mock_session)
def setUp(self):
"""Setup test case."""
self.api_client = client.TimesketchApi("http://127.0.0.1", "test", "test")

def test_question_list(self):
"""Test QuestionList object."""
question_list = scenario_lib.QuestionTemplateList(self.api_client).get()
self.assertIsInstance(question_list, list)
self.assertEqual(len(question_list), 2)
self.assertEqual(question_list[0]["name"], "Test question?")
self.assertEqual(question_list[1]["id"], "Q0002")
Loading

0 comments on commit 79e1da3

Please sign in to comment.