mirror of
https://github.com/MISP/misp-galaxy.git
synced 2024-11-26 08:47:18 +00:00
Add [display relations] table with filters
This commit is contained in:
parent
29b39f55d7
commit
aed690df60
4 changed files with 115 additions and 82 deletions
4
tools/mkdocs/.gitignore
vendored
Normal file
4
tools/mkdocs/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/site/docs/*
|
||||||
|
!/site/docs/javascripts
|
||||||
|
|
||||||
|
/site/site
|
|
@ -250,28 +250,21 @@ class Cluster():
|
||||||
|
|
||||||
return related_clusters
|
return related_clusters
|
||||||
|
|
||||||
# def _create_related_entry(self, cluster_dict):
|
def _create_related_entry(self):
|
||||||
# if self.related_list and cluster_dict:
|
self.entry += f'\n'
|
||||||
# related_clusters = self.get_related_clusters(cluster_dict)
|
self.entry += f'??? info "Related clusters"\n'
|
||||||
# self.entry += f'\n'
|
self.entry += f'\n'
|
||||||
# self.entry += f'??? info "Related clusters"\n'
|
# self.entry += f'To see the related clusters, click [here](./{self.galaxie}/{self.uuid}.md).\n'
|
||||||
# self.entry += f'\n'
|
self.entry += f'To see the related clusters, click [here](./relations/{self.uuid}.md).\n'
|
||||||
# self.entry += f' ```mermaid\n'
|
|
||||||
# self.entry += f' graph TD\n'
|
|
||||||
|
|
||||||
# global relation_count_dict
|
|
||||||
# relation_count = 0
|
|
||||||
|
|
||||||
# for relation in related_clusters:
|
|
||||||
# relation_count += 1
|
|
||||||
# self.entry += f' {relation[0].uuid}[{relation[0].value}] --- {relation[1].uuid}[{relation[1].value}]\n'
|
|
||||||
# self.entry += f' ```\n'
|
|
||||||
# relation_count_dict[self.value] = relation_count
|
|
||||||
|
|
||||||
def _get_related_entry(self, relations):
|
def _get_related_entry(self, relations):
|
||||||
output = ""
|
output = ""
|
||||||
output += f'## Related clusters for {self.value}\n'
|
output += f'## Related clusters for {self.value}\n'
|
||||||
output += f'\n'
|
output += f'\n'
|
||||||
|
output += f' | Cluster A | Cluster B |\n'
|
||||||
|
output += f' |-----------|-----------|\n'
|
||||||
|
for relation in relations:
|
||||||
|
output += f' | {relation[0].value} ({relation[0].uuid}) | {relation[1].value} ({relation[1].uuid}) |\n'
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def create_entry(self, cluster_dict):
|
def create_entry(self, cluster_dict):
|
||||||
|
@ -281,8 +274,8 @@ class Cluster():
|
||||||
self._create_uuid_entry()
|
self._create_uuid_entry()
|
||||||
self._create_refs_entry()
|
self._create_refs_entry()
|
||||||
self._create_associated_metadata_entry()
|
self._create_associated_metadata_entry()
|
||||||
# self._create_related_entry(cluster_dict)
|
|
||||||
if self.related_list:
|
if self.related_list:
|
||||||
|
self._create_related_entry()
|
||||||
self._write_relations(cluster_dict, SITE_PATH)
|
self._write_relations(cluster_dict, SITE_PATH)
|
||||||
return self.entry
|
return self.entry
|
||||||
|
|
||||||
|
@ -293,7 +286,12 @@ class Cluster():
|
||||||
galaxy_path = os.path.join(path, self.galaxie)
|
galaxy_path = os.path.join(path, self.galaxie)
|
||||||
if not os.path.exists(galaxy_path):
|
if not os.path.exists(galaxy_path):
|
||||||
os.mkdir(galaxy_path)
|
os.mkdir(galaxy_path)
|
||||||
with open(os.path.join(galaxy_path, f'{self.uuid}.md'), "w") as index:
|
relation_path = os.path.join(galaxy_path, 'relations')
|
||||||
|
if not os.path.exists(relation_path):
|
||||||
|
os.mkdir(relation_path)
|
||||||
|
with open(os.path.join(relation_path, ".pages"), "w") as index:
|
||||||
|
index.write(f'hide: true\n')
|
||||||
|
with open(os.path.join(relation_path, f'{self.uuid}.md'), "w") as index:
|
||||||
index.write(self._get_related_entry(related_clusters))
|
index.write(self._get_related_entry(related_clusters))
|
||||||
|
|
||||||
def create_index(galaxies):
|
def create_index(galaxies):
|
||||||
|
@ -328,35 +326,41 @@ def create_xy_chart(title, width, height, x_axis, y_axis, bar):
|
||||||
output += f'\n'
|
output += f'\n'
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def create_pie_chart(title, cakepieces):
|
||||||
|
output = ""
|
||||||
|
output += f'```mermaid\n'
|
||||||
|
output += f'pie showData\n'
|
||||||
|
output += f' title {title}\n'
|
||||||
|
for cakepiece in cakepieces:
|
||||||
|
output += f' "{cakepiece[0]}" : {cakepiece[1]}\n'
|
||||||
|
output += f'```\n'
|
||||||
|
output += f'\n'
|
||||||
|
return output
|
||||||
|
|
||||||
|
def get_top_x(dict, x, big_to_small=True):
|
||||||
|
sorted_dict = sorted(dict.items(), key=operator.itemgetter(1), reverse=big_to_small)[:x]
|
||||||
|
top_x = [re.sub(r"[^A-Za-z0-9 ]", "", key) for key, value in sorted_dict]
|
||||||
|
top_x = ", ".join(top_x)
|
||||||
|
top_x_values = sorted(dict.values(), reverse=big_to_small)[:x]
|
||||||
|
return top_x, top_x_values
|
||||||
|
|
||||||
def create_statistics():
|
def create_statistics():
|
||||||
statistic_output = ""
|
statistic_output = ""
|
||||||
|
|
||||||
statistic_output += f'# Cluster statistics\n'
|
statistic_output += f'# Cluster statistics\n'
|
||||||
statistic_output += f'## Number of clusters\n'
|
statistic_output += f'## Number of clusters\n'
|
||||||
statistic_output += f'```mermaid\n'
|
statistic_output += create_pie_chart("Number of clusters", [("Public clusters", len(public_clusters_dict)), ("Private clusters", len(private_clusters))])
|
||||||
statistic_output += f"pie showData\n"
|
|
||||||
statistic_output += f' title Number of clusters\n'
|
|
||||||
statistic_output += f' "Public clusters" : {len(public_clusters_dict)}\n'
|
|
||||||
statistic_output += f' "Private clusters" : {len(private_clusters)}\n'
|
|
||||||
statistic_output += f'```\n'
|
|
||||||
statistic_output += f'\n'
|
|
||||||
|
|
||||||
statistic_output += f'## Galaxies with the most clusters\n'
|
statistic_output += f'## Galaxies with the most clusters\n'
|
||||||
galaxy_counts = {}
|
galaxy_counts = {}
|
||||||
for galaxy in public_clusters_dict.values():
|
for galaxy in public_clusters_dict.values():
|
||||||
galaxy_counts[galaxy] = galaxy_counts.get(galaxy, 0) + 1
|
galaxy_counts[galaxy] = galaxy_counts.get(galaxy, 0) + 1
|
||||||
sorted_galaxies = sorted(galaxy_counts, key=galaxy_counts.get, reverse=True)[:15]
|
top_galaxies, top_galaxies_values = get_top_x(galaxy_counts, 25)
|
||||||
top_15_galaxies = [re.sub(r"[^A-Za-z0-9 ]", "", galaxy) for galaxy in sorted_galaxies]
|
statistic_output += create_xy_chart("Galaxies with the most clusters", 2500, 500, top_galaxies, "Number of clusters", top_galaxies_values)
|
||||||
top_15_galaxies = ", ".join(top_15_galaxies)
|
|
||||||
top_15_galaxies_values = sorted(galaxy_counts.values(), reverse=True)[:15]
|
|
||||||
statistic_output += create_xy_chart("Galaxies with the most clusters", 1800, 500, top_15_galaxies, "Number of clusters", top_15_galaxies_values)
|
|
||||||
|
|
||||||
statistic_output += f'## Galaxies with the least clusters\n'
|
statistic_output += f'## Galaxies with the least clusters\n'
|
||||||
sorted_galaxies = sorted(galaxy_counts, key=galaxy_counts.get)[:15]
|
flop_galaxies, flop_galaxies_values = get_top_x(galaxy_counts, 25, False)
|
||||||
top_15_galaxies = [re.sub(r"[^A-Za-z0-9 ]", "", galaxy) for galaxy in sorted_galaxies]
|
statistic_output += create_xy_chart("Galaxies with the least clusters", 2500, 500, flop_galaxies, "Number of clusters", flop_galaxies_values)
|
||||||
top_15_galaxies = ", ".join(top_15_galaxies)
|
|
||||||
top_15_galaxies_values = sorted(galaxy_counts.values())[:15]
|
|
||||||
statistic_output += create_xy_chart("Galaxies with the least clusters", 1800, 500, top_15_galaxies, "Number of clusters", top_15_galaxies_values)
|
|
||||||
|
|
||||||
galaxy_number = 0
|
galaxy_number = 0
|
||||||
for galaxy in public_clusters_dict.values():
|
for galaxy in public_clusters_dict.values():
|
||||||
|
@ -365,44 +369,26 @@ def create_statistics():
|
||||||
|
|
||||||
statistic_output += f'# Relation statistics\n'
|
statistic_output += f'# Relation statistics\n'
|
||||||
statistic_output += f'## Number of relations\n'
|
statistic_output += f'## Number of relations\n'
|
||||||
statistic_output += f'```mermaid\n'
|
statistic_output += create_pie_chart("Number of relations", [("Public relations", public_relations_count), ("Private relations", private_relations_count)])
|
||||||
statistic_output += f"pie showData\n"
|
|
||||||
statistic_output += f' title Number of relations\n'
|
|
||||||
statistic_output += f' "Public relations" : {public_relations_count}\n'
|
|
||||||
statistic_output += f' "Private relations" : {private_relations_count}\n'
|
|
||||||
statistic_output += f'```\n'
|
|
||||||
statistic_output += f'\n'
|
|
||||||
|
|
||||||
statistic_output += f'**Average number of relations per cluster**: {sum(relation_count_dict.values()) / len(relation_count_dict)}\n'
|
statistic_output += f'**Average number of relations per cluster**: {sum(relation_count_dict.values()) / len(relation_count_dict)}\n'
|
||||||
|
|
||||||
statistic_output += f'## Cluster with the most relations\n'
|
statistic_output += f'## Cluster with the most relations\n'
|
||||||
sorted_relation = sorted(relation_count_dict.items(), key=operator.itemgetter(1), reverse=True)[:15]
|
top_25_relation, top_25_relation_values = get_top_x(relation_count_dict, 25)
|
||||||
top_15_relation = [re.sub(r"[^A-Za-z0-9 ]", "", key) for key, value in sorted_relation]
|
statistic_output += create_xy_chart("Cluster with the most relations", 2500, 500, top_25_relation, "Number of relations", top_25_relation_values)
|
||||||
top_15_relation = ", ".join(top_15_relation)
|
|
||||||
top_15_relation_values = sorted(relation_count_dict.values(), reverse=True)[:15]
|
|
||||||
statistic_output += create_xy_chart("Cluster with the most relations", 2000, 500, top_15_relation, "Number of relations", top_15_relation_values)
|
|
||||||
|
|
||||||
statistic_output += f'## Cluster with the least relations\n'
|
statistic_output += f'## Cluster with the least relations\n'
|
||||||
sorted_relation = sorted(relation_count_dict.items(), key=operator.itemgetter(1))[:15]
|
top_25_relation, top_25_relation_values = get_top_x(relation_count_dict, 25, False)
|
||||||
top_15_relation = [re.sub(r"[^A-Za-z0-9 ]", "", key) for key, value in sorted_relation]
|
statistic_output += create_xy_chart("Cluster with the least relations", 2500, 500, top_25_relation, "Number of relations", top_25_relation_values)
|
||||||
top_15_relation = ", ".join(top_15_relation)
|
|
||||||
top_15_relation_values = sorted(relation_count_dict.values())[:15]
|
|
||||||
statistic_output += create_xy_chart("Cluster with the least relations", 2000, 500, top_15_relation, "Number of relations", top_15_relation_values)
|
|
||||||
|
|
||||||
statistic_output += f'# Synonyms statistics\n'
|
statistic_output += f'# Synonyms statistics\n'
|
||||||
statistic_output += f'## Cluster with the most synonyms\n'
|
statistic_output += f'## Cluster with the most synonyms\n'
|
||||||
sorted_synonyms = sorted(synonyms_count_dict.items(), key=operator.itemgetter(1), reverse=True)[:15]
|
top_25_synonyms, top_25_synonyms_values = get_top_x(synonyms_count_dict, 25)
|
||||||
top_15_synonyms = [re.sub(r"[^A-Za-z0-9 ]", "", key) for key, value in sorted_synonyms]
|
statistic_output += create_xy_chart("Cluster with the most synonyms", 2500, 500, top_25_synonyms, "Number of synonyms", top_25_synonyms_values)
|
||||||
top_15_synonyms = ", ".join(top_15_synonyms)
|
|
||||||
top_15_synonyms_values = sorted(synonyms_count_dict.values(), reverse=True)[:15]
|
|
||||||
statistic_output += create_xy_chart("Cluster with the most synonyms", 1800, 500, top_15_synonyms, "Number of synonyms", top_15_synonyms_values)
|
|
||||||
|
|
||||||
statistic_output += f'## Cluster with the least synonyms\n'
|
statistic_output += f'## Cluster with the least synonyms\n'
|
||||||
sorted_synonyms = sorted(synonyms_count_dict.items(), key=operator.itemgetter(1))[:15]
|
top_25_synonyms, top_25_synonyms_values = get_top_x(synonyms_count_dict, 25, False)
|
||||||
top_15_synonyms = [re.sub(r"[^A-Za-z0-9 ]", "", key) for key, value in sorted_synonyms]
|
statistic_output += create_xy_chart("Cluster with the least synonyms", 2500, 500, top_25_synonyms, "Number of synonyms", top_25_synonyms_values)
|
||||||
top_15_synonyms = ", ".join(top_15_synonyms)
|
|
||||||
top_15_synonyms_values = sorted(synonyms_count_dict.values())[:15]
|
|
||||||
statistic_output += create_xy_chart("Cluster with the least synonyms", 1800, 500, top_15_synonyms, "Number of synonyms", top_15_synonyms_values)
|
|
||||||
|
|
||||||
statistic_output += f'# Empty UUIDs statistics\n'
|
statistic_output += f'# Empty UUIDs statistics\n'
|
||||||
statistic_output += f'**Number of empty UUIDs**: {sum(empty_uuids_dict.values())}\n'
|
statistic_output += f'**Number of empty UUIDs**: {sum(empty_uuids_dict.values())}\n'
|
||||||
|
@ -427,9 +413,6 @@ def create_statistics():
|
||||||
print(f"Number of empty UUIDs: {sum(empty_uuids_dict.values())}")
|
print(f"Number of empty UUIDs: {sum(empty_uuids_dict.values())}")
|
||||||
print(f"Empty UUIDs per cluster: {empty_uuids_dict}")
|
print(f"Empty UUIDs per cluster: {empty_uuids_dict}")
|
||||||
print(sorted(relation_count_dict.items(), key=operator.itemgetter(1), reverse=True)[:30])
|
print(sorted(relation_count_dict.items(), key=operator.itemgetter(1), reverse=True)[:30])
|
||||||
lol = [re.sub(r"[^A-Za-z0-9 ]", "", key) for key, value in sorted_relation]
|
|
||||||
print(", ".join(lol))
|
|
||||||
|
|
||||||
|
|
||||||
return statistic_output
|
return statistic_output
|
||||||
|
|
||||||
|
@ -438,9 +421,7 @@ def main():
|
||||||
for f in os.listdir(CLUSTER_PATH):
|
for f in os.listdir(CLUSTER_PATH):
|
||||||
if '.json' in f and f not in FILES_TO_IGNORE:
|
if '.json' in f and f not in FILES_TO_IGNORE:
|
||||||
galaxies_fnames.append(f)
|
galaxies_fnames.append(f)
|
||||||
|
|
||||||
galaxies_fnames.sort()
|
galaxies_fnames.sort()
|
||||||
galaxy_output = {}
|
|
||||||
|
|
||||||
galaxies = []
|
galaxies = []
|
||||||
for galaxy in galaxies_fnames:
|
for galaxy in galaxies_fnames:
|
||||||
|
@ -459,9 +440,15 @@ def main():
|
||||||
|
|
||||||
for galaxy in galaxies:
|
for galaxy in galaxies:
|
||||||
galaxy.write_entry(SITE_PATH, cluster_dict)
|
galaxy.write_entry(SITE_PATH, cluster_dict)
|
||||||
|
|
||||||
|
# count = 3
|
||||||
|
# for galaxy in galaxies:
|
||||||
|
# galaxy.write_entry(SITE_PATH, cluster_dict)
|
||||||
|
# count -= 1
|
||||||
|
# if count == 0:
|
||||||
|
# break
|
||||||
|
|
||||||
index_output = create_index(galaxies)
|
index_output = create_index(galaxies)
|
||||||
# galaxy_output = create_galaxies(galaxies, cluster_dict)
|
|
||||||
statistic_output = create_statistics()
|
statistic_output = create_statistics()
|
||||||
|
|
||||||
with open(os.path.join(SITE_PATH, 'index.md'), "w") as index:
|
with open(os.path.join(SITE_PATH, 'index.md'), "w") as index:
|
||||||
|
@ -470,18 +457,6 @@ def main():
|
||||||
with open(os.path.join(SITE_PATH, 'statistics.md'), "w") as index:
|
with open(os.path.join(SITE_PATH, 'statistics.md'), "w") as index:
|
||||||
index.write(statistic_output)
|
index.write(statistic_output)
|
||||||
|
|
||||||
# for f in galaxies_fnames:
|
|
||||||
# cluster_filename = f.split('.')[0]
|
|
||||||
# pathSiteCluster = os.path.join(SITE_PATH, cluster_filename)
|
|
||||||
# if not os.path.exists(pathSiteCluster):
|
|
||||||
# os.mkdir(pathSiteCluster)
|
|
||||||
# with open(os.path.join(pathSiteCluster, 'index.md'), "w") as index:
|
|
||||||
# index.write(galaxy_output[cluster_filename])
|
|
||||||
|
|
||||||
|
|
||||||
# for cluster in cluster_dict.values():
|
|
||||||
# print(cluster.uuid)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
45
tools/mkdocs/site/docs/javascripts/tablefilter.js
Normal file
45
tools/mkdocs/site/docs/javascripts/tablefilter.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
document$.subscribe(function () {
|
||||||
|
var tables = document.querySelectorAll("article table:not([class])")
|
||||||
|
tables.forEach(function (table) {
|
||||||
|
var tf = new TableFilter(table, {
|
||||||
|
base_path: "https://unpkg.com/tablefilter@0.7.3/dist/tablefilter/",
|
||||||
|
highlight_keywords: true,
|
||||||
|
// col_0: "select",
|
||||||
|
// col_1: "select",
|
||||||
|
grid_layout: false,
|
||||||
|
responsive: true,
|
||||||
|
watermark: ["Filter table ...", "Filter table ..."],
|
||||||
|
|
||||||
|
auto_filter: {
|
||||||
|
delay: 100 //milliseconds
|
||||||
|
},
|
||||||
|
filters_row_index: 1,
|
||||||
|
state: true,
|
||||||
|
// alternate_rows: true,
|
||||||
|
rows_counter: true,
|
||||||
|
status_bar: true,
|
||||||
|
|
||||||
|
themes: [{
|
||||||
|
name: "transparent",
|
||||||
|
}],
|
||||||
|
|
||||||
|
btn_reset: {
|
||||||
|
tooltip: "Reset",
|
||||||
|
toolbar_position: "right",
|
||||||
|
},
|
||||||
|
no_results_message: {
|
||||||
|
content: "No matching records found",
|
||||||
|
},
|
||||||
|
toolbar: true,
|
||||||
|
extensions: [{
|
||||||
|
name: "sort",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'filtersVisibility',
|
||||||
|
description: 'Sichtbarkeit der Filter',
|
||||||
|
toolbar_position: 'right',
|
||||||
|
},],
|
||||||
|
})
|
||||||
|
tf.init()
|
||||||
|
})
|
||||||
|
})
|
|
@ -23,6 +23,7 @@ theme:
|
||||||
- navigation.footer
|
- navigation.footer
|
||||||
- search.highlight
|
- search.highlight
|
||||||
- search.share
|
- search.share
|
||||||
|
- navigation.instant.preview
|
||||||
palette:
|
palette:
|
||||||
|
|
||||||
# Palette toggle for automatic mode
|
# Palette toggle for automatic mode
|
||||||
|
@ -46,7 +47,10 @@ theme:
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- admonition
|
- admonition
|
||||||
- pymdownx.details
|
- pymdownx.details
|
||||||
- pymdownx.superfences
|
- pymdownx.superfences:
|
||||||
|
custom_fences:
|
||||||
|
- name: mermaid
|
||||||
|
class: mermaid
|
||||||
- tables
|
- tables
|
||||||
- attr_list
|
- attr_list
|
||||||
- pymdownx.emoji:
|
- pymdownx.emoji:
|
||||||
|
@ -61,8 +65,13 @@ extra:
|
||||||
link: https://github.com/misp
|
link: https://github.com/misp
|
||||||
generator: false
|
generator: false
|
||||||
|
|
||||||
|
extra_javascript:
|
||||||
|
- javascripts/tablefilter.js
|
||||||
|
- "https://unpkg.com/tablefilter@0.7.3/dist/tablefilter/tablefilter.js"
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
- search
|
- search
|
||||||
- rss
|
- rss
|
||||||
|
- awesome-pages
|
||||||
#- git-committers:
|
#- git-committers:
|
||||||
# branch: main
|
# branch: main
|
||||||
|
|
Loading…
Reference in a new issue