Skip to content

Commit

Permalink
Merge branch 'master' into unfurl
Browse files Browse the repository at this point in the history
  • Loading branch information
jkppr authored Oct 25, 2023
2 parents 60689a5 + d0d6ae9 commit f4f4405
Show file tree
Hide file tree
Showing 13 changed files with 397 additions and 73 deletions.
2 changes: 2 additions & 0 deletions timesketch/api/v1/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ class ResourceMixin(object):
"name": fields.String,
"display_name": fields.String,
"description": fields.String,
"dfiq_identifier": fields.String,
"spec_json": fields.String,
"user": fields.Nested(user_fields),
"approaches": fields.List(fields.Nested(approach_fields)),
Expand All @@ -288,6 +289,7 @@ class ResourceMixin(object):
"name": fields.String,
"display_name": fields.String,
"description": fields.String,
"dfiq_identifier": fields.String,
"spec_json": fields.String,
"user": fields.Nested(user_fields),
"questions": fields.List(fields.Nested(question_fields)),
Expand Down
44 changes: 44 additions & 0 deletions timesketch/api/v1/resources/explore.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
from timesketch.models.sketch import Sketch
from timesketch.models.sketch import View
from timesketch.models.sketch import SearchHistory
from timesketch.models.sketch import Scenario
from timesketch.models.sketch import Facet
from timesketch.models.sketch import InvestigativeQuestion

# Metrics definitions
METRICS = {
Expand Down Expand Up @@ -93,6 +96,42 @@ def post(self, sketch_id):
"Unable to explore data, unable to validate form data",
)

# DFIQ context
scenario = None
facet = None
question = None

scenario_id = request.json.get("scenario", None)
facet_id = request.json.get("facet", None)
question_id = request.json.get("question", None)

if scenario_id:
scenario = Scenario.query.get(scenario_id)
if scenario:
if scenario.sketch_id != sketch.id:
abort(
HTTP_STATUS_CODE_BAD_REQUEST,
"Scenario is not part of this sketch.",
)

if facet_id:
facet = Facet.query.get(facet_id)
if facet:
if facet.scenario.sketch_id != sketch.id:
abort(
HTTP_STATUS_CODE_BAD_REQUEST,
"Facet is not part of this sketch.",
)

if question_id:
question = InvestigativeQuestion.query.get(question_id)
if question:
if question.facet.scenario.sketch_id != sketch.id:
abort(
HTTP_STATUS_CODE_BAD_REQUEST,
"Question is not part of this sketch.",
)

# TODO: Remove form and use json instead.
query_dsl = form.dsl.data
enable_scroll = form.enable_scroll.data
Expand Down Expand Up @@ -340,6 +379,11 @@ def post(self, sketch_id):
new_search.query_result_count = count_total_complete
new_search.query_time = result["took"]

# Add DFIQ context
new_search.scenario = scenario
new_search.facet = facet
new_search.question = question

if previous_search:
new_search.parent = previous_search

Expand Down
1 change: 1 addition & 0 deletions timesketch/api/v1/resources_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ class ExploreResourceTest(BaseTest):
"query_filter": "{}",
"query_result_count": 0,
"query_string": "test",
"scenario_id": None,
},
},
"objects": [
Expand Down
10 changes: 9 additions & 1 deletion timesketch/frontend-ng/src/components/Explore/EventList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ limitations under the License.
<v-tooltip top open-delay="500">
<template v-slot:activator="{ on }">
<v-btn v-on="on" icon @click="exportSearchResult()">
<v-icon>mdi-download</v-icon>
<v-icon>mdi-download</v-icon>
</v-btn>
</template>
<span>Download current view as csv</span>
Expand Down Expand Up @@ -646,6 +646,9 @@ export default {
}
return baseHeaders
},
activeContext() {
return this.$store.state.activeContext
},
},
methods: {
sortEvents(sortAsc) {
Expand Down Expand Up @@ -821,6 +824,11 @@ export default {
formData['parent'] = this.branchParent
}

// Get DFIQ context
formData['scenario'] = this.activeContext.scenario.id
formData['facet'] = this.activeContext.facet.id
formData['question'] = this.activeContext.question.id

ApiClient.search(this.sketch.id, formData)
.then((response) => {
this.eventList.objects = response.data.objects
Expand Down
102 changes: 97 additions & 5 deletions timesketch/frontend-ng/src/components/Scenarios/ContextCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,125 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<template>
<v-card outlined class="mt-3 mx-3" v-if="activeContext.question">
<v-toolbar dense flat>
<strong>{{ activeContext.question.display_name }}</strong>
<v-card outlined rounded class="mt-3 mx-3" v-if="activeContext.question">
<v-toolbar flat dense style="background-color: transparent">
<h3>
{{ activeContext.question.display_name }}
<small>
<a :href="getDfiqQuestionUrl(activeContext.question.dfiq_identifier)" target="_blank" rel="noreferrer"
>({{ activeContext.question.dfiq_identifier }})</a
>
</small>
</h3>
<v-spacer></v-spacer>
<v-btn v-if="activeContext.question.description" small icon @click="expanded = !expanded" class="mr-1">
<v-icon v-if="expanded">mdi-chevron-up</v-icon>
<v-icon v-else>mdi-chevron-down</v-icon>
</v-btn>

<v-btn small icon @click="$store.dispatch('clearActiveContext')" class="mr-1">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-toolbar>
<v-divider></v-divider>
<div class="pa-4 markdown-body" v-html="toHtml(activeContext.question.description)" style="font-size: 0.9em"></div>

<v-expand-transition>
<div v-show="expanded">
<div v-if="activeContext.question.description">
<div
class="px-4 pb-4 markdown-body"
style="background-color: transparent"
v-html="toHtml(activeContext.question.description)"
></div>
</div>

<!--Suggested queries-->
<div v-if="opensearchQueries.length" class="px-4 pb-4">
<strong style="font-size: 0.9em">Suggested queries</strong>
<ts-search-chip
v-for="opensearchQuery in opensearchQueries"
:key="opensearchQuery.value"
:searchchip="opensearchQuery"
type="link"
></ts-search-chip>
</div>

<!--Approaches-->
<div v-if="activeContext.question.approaches.length">
<div class="px-4 pb-3">
<v-btn depressed small @click="showApproaches = !showApproaches">
<span v-if="!showApproaches">Show {{ activeContext.question.approaches.length }} approaches</span>
<span v-else>Hide approaches</span>
</v-btn>
</div>
<v-expand-transition>
<div v-if="showApproaches">
<v-divider></v-divider>
<v-expansion-panels flat accordion hover>
<v-expansion-panel
v-for="(approach, index) in activeContext.question.approaches"
:key="approach.display_name"
>
<v-expansion-panel-header>
<span>{{ approach.display_name }}</span>
</v-expansion-panel-header>
<v-expansion-panel-content>
<ts-context-card-approach :approachJSON="approach"></ts-context-card-approach>
</v-expansion-panel-content>
<v-divider v-if="index != activeContext.question.approaches.length - 1"></v-divider>
</v-expansion-panel>
</v-expansion-panels>
</div>
</v-expand-transition>
</div>
</div>
</v-expand-transition>
</v-card>
</template>

<script>
import DOMPurify from 'dompurify'
import { marked } from 'marked'
import TsContextCardApproach from './ContextCardApproach'
import TsSearchChip from './SearchChip'

export default {
components: { TsContextCardApproach, TsSearchChip },
data: function () {
return {
showApproaches: false,
expanded: true,
}
},
computed: {
activeContext() {
return this.$store.state.activeContext
},
opensearchQueries() {
let opensearchQueries = []
let approaches = this.activeContext.question.approaches.map((approach) => JSON.parse(approach.spec_json))
approaches.forEach((approach) => {
approach._view.processors.forEach((processor) => {
processor.analysis.forEach((analysis) => {
if (analysis.name === 'OpenSearch') {
analysis.steps.forEach((step) => {
if (step.type === 'opensearch-query') {
opensearchQueries.push(step)
}
})
}
})
})
})
return opensearchQueries
},
},
methods: {
toHtml(markdown) {
return DOMPurify.sanitize(marked(markdown))
},
getDfiqQuestionUrl(id) {
return 'https://dfiq.org/questions/' + id + '/'
},
},
}
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<!--
Copyright 2023 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.
-->
<template>
<div style="font-size: 0.9em">
<div
class="pb-4 markdown-body"
style="font-size: 1em; background-color: transparent"
v-html="toHtml(approach.description.details)"
></div>

<div v-if="approach.description.references && approach.description.references.length">
<v-icon class="mr-2">mdi-link-variant</v-icon>
<strong>References</strong>
<ul class="mb-4 mt-2 markdown-body" style="line-height: 70%; background-color: transparent">
<li v-for="reference in approach.description.references" :key="reference">
<div v-html="toHtml(reference)" style="font-size: 0.9em"></div>
</li>
</ul>
</div>

<v-sheet style="max-width: 80%" class="mb-3">
<v-icon color="success" class="mr-2">mdi-check</v-icon>
<strong>Covered</strong>
<ul class="mt-2">
<li v-for="note in approach._view.notes.covered" :key="note">{{ note }}</li>
</ul>
</v-sheet>

<v-sheet style="max-width: 80%">
<v-icon color="error" class="mr-2">mdi-close</v-icon>
<strong>Not covered</strong>
<ul class="mt-2">
<li v-for="note in approach._view.notes.not_covered" :key="note">{{ note }}</li>
</ul>
</v-sheet>
</div>
</template>

<script>
import DOMPurify from 'dompurify'
import { marked } from 'marked'

export default {
props: ['approachJSON'],
data: function () {
return {
showDetails: true,
processorTab: null,
}
},
computed: {
approach() {
return JSON.parse(this.approachJSON.spec_json)
},
},
methods: {
toHtml(markdown) {
return DOMPurify.sanitize(marked(markdown))
},
},
}
</script>

Loading

0 comments on commit f4f4405

Please sign in to comment.