mirror of https://github.com/jumpserver/jumpserver
perf: Change secret report
parent
1dabaf04f0
commit
eb901b2946
|
@ -125,6 +125,7 @@ class ChangSecretExecutionViewSet(AutomationExecutionViewSet):
|
|||
("list", "accounts.view_changesecretexecution"),
|
||||
("retrieve", "accounts.view_changesecretexecution"),
|
||||
("create", "accounts.add_changesecretexecution"),
|
||||
("report", "accounts.view_changesecretexecution"),
|
||||
)
|
||||
|
||||
tp = AutomationTypes.change_secret
|
||||
|
|
|
@ -11,7 +11,7 @@ from accounts.const import (
|
|||
AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy, ChangeSecretRecordStatusChoice
|
||||
)
|
||||
from accounts.models import ChangeSecretRecord, BaseAccountQuerySet
|
||||
from accounts.notifications import ChangeSecretExecutionTaskMsg, ChangeSecretFailedMsg
|
||||
from accounts.notifications import ChangeSecretExecutionTaskMsg, ChangeSecretReportMsg
|
||||
from accounts.serializers import ChangeSecretRecordBackUpSerializer
|
||||
from assets.const import HostTypes
|
||||
from common.db.utils import safe_db_connection
|
||||
|
@ -183,6 +183,14 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
|||
with safe_db_connection():
|
||||
recorder.save(update_fields=['status', 'date_finished'])
|
||||
account.save(update_fields=['secret', 'version', 'date_updated'])
|
||||
self.summary['ok_accounts'] += 1
|
||||
self.result['ok_accounts'].append(
|
||||
{
|
||||
"asset": str(account.asset),
|
||||
"username": account.username,
|
||||
}
|
||||
)
|
||||
super().on_host_success(host, result)
|
||||
|
||||
def on_host_error(self, host, error, result):
|
||||
recorder = self.name_recorder_mapper.get(host)
|
||||
|
@ -195,9 +203,14 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
|||
recorder.save()
|
||||
except Exception as e:
|
||||
print(f"\033[31m Save {host} recorder error: {e} \033[0m\n")
|
||||
|
||||
def on_runner_failed(self, runner, e, **kwargs):
|
||||
logger.error("Account error: ", e)
|
||||
self.summary['fail_accounts'] += 1
|
||||
self.result['fail_accounts'].append(
|
||||
{
|
||||
"asset": str(recorder.asset),
|
||||
"username": recorder.account.username,
|
||||
}
|
||||
)
|
||||
super().on_host_success(host, result)
|
||||
|
||||
def check_secret(self):
|
||||
if self.secret_strategy == SecretStrategy.custom \
|
||||
|
@ -236,24 +249,13 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
|||
if self.record_map:
|
||||
return
|
||||
|
||||
failed_recorders = [
|
||||
r for r in recorders
|
||||
if r.status == ChangeSecretRecordStatusChoice.failed.value
|
||||
]
|
||||
|
||||
recipients = self.execution.recipients
|
||||
if not recipients:
|
||||
return
|
||||
|
||||
if failed_recorders:
|
||||
name = self.execution.snapshot.get('name')
|
||||
execution_id = str(self.execution.id)
|
||||
_ids = [r.id for r in failed_recorders]
|
||||
asset_account_errors = ChangeSecretRecord.objects.filter(
|
||||
id__in=_ids).values_list('asset__name', 'account__username', 'error')
|
||||
|
||||
for user in recipients:
|
||||
ChangeSecretFailedMsg(name, execution_id, user, asset_account_errors).publish()
|
||||
context = self.get_report_context()
|
||||
for user in recipients:
|
||||
ChangeSecretReportMsg(user, context).publish()
|
||||
|
||||
if not recorders:
|
||||
return
|
||||
|
@ -295,3 +297,6 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
|||
ws.write_string(row_index, col_index, col_data)
|
||||
wb.close()
|
||||
return True
|
||||
|
||||
def get_report_template(self):
|
||||
return "accounts/change_secret_report.html"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from premailer import transform
|
||||
|
||||
from accounts.models import ChangeSecretRecord
|
||||
from common.tasks import send_mail_attachment_async, upload_backup_to_obj_storage
|
||||
|
@ -101,24 +102,19 @@ class GatherAccountChangeMsg(UserMessage):
|
|||
return cls(user, {})
|
||||
|
||||
|
||||
class ChangeSecretFailedMsg(UserMessage):
|
||||
class ChangeSecretReportMsg(UserMessage):
|
||||
subject = _('Change secret or push account failed information')
|
||||
|
||||
def __init__(self, name, execution_id, user, asset_account_errors: list):
|
||||
self.name = name
|
||||
self.execution_id = execution_id
|
||||
self.asset_account_errors = asset_account_errors
|
||||
def __init__(self, user, context: dict):
|
||||
self.context = context
|
||||
super().__init__(user)
|
||||
|
||||
def get_html_msg(self) -> dict:
|
||||
context = {
|
||||
'name': self.name,
|
||||
'recipient': self.user,
|
||||
'execution_id': self.execution_id,
|
||||
'asset_account_errors': self.asset_account_errors
|
||||
}
|
||||
message = render_to_string('accounts/change_secret_failed_info.html', context)
|
||||
|
||||
report = render_to_string(
|
||||
'accounts/change_secret_report.html',
|
||||
self.context
|
||||
)
|
||||
message = transform(report)
|
||||
return {
|
||||
'subject': str(self.subject),
|
||||
'message': message
|
||||
|
@ -130,4 +126,4 @@ class ChangeSecretFailedMsg(UserMessage):
|
|||
user = User.objects.first()
|
||||
record = ChangeSecretRecord.objects.first()
|
||||
execution_id = str(record.execution_id)
|
||||
return cls(name, execution_id, user, [])
|
||||
return cls(user, {})
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
{% load i18n %}
|
||||
|
||||
<div class='summary'>
|
||||
<p>{% trans 'The following is a summary of account change secret tasks, please review and handle them' %}</p>
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>任务汇总:</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{% trans 'Task name' %}:</td>
|
||||
<td>{{ execution.automation.name }} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date start' %}:</td>
|
||||
<td>{{ execution.date_start | date:"Y/m/d H:i:s" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date end' %}:</td>
|
||||
<td>{{ execution.date_finished | date:"Y/m/d H:i:s" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time using' %}:</td>
|
||||
<td>{{ execution.duration }}s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Assets count' %}:</td>
|
||||
<td>{{ summary.total_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset success count' %}:</td>
|
||||
<td>{{ summary.ok_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset failed count' %}:</td>
|
||||
<td>{{ summary.fail_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset not support count' %}:</td>
|
||||
<td>{{ summary.error_assets }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class='result'>
|
||||
{% if summary.ok_accounts %}
|
||||
<p>{% trans 'Success accounts' %}: {{ summary.ok_accounts }}</p>
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account in result.ok_accounts %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ account.asset }}</td>
|
||||
<td>{{ account.username }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class='result'>
|
||||
{% if summary.lost_accounts %}
|
||||
<p>{% trans 'Failed accounts' %}: {{ summary.fail_accounts }}</p>
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account in result.fail_accounts %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ account.asset }}</td>
|
||||
<td>{{ account.username }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
max-width: 100%;
|
||||
text-align: left;
|
||||
margin-top: 10px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #f2f2f2;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
tr :first-child {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.result tr :first-child {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
|
@ -3,74 +3,88 @@
|
|||
<div class='summary'>
|
||||
<p>{% trans 'The following is a summary of the account check tasks. Please review and handle them' %}</p>
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>任务汇总: </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan='2'>任务汇总:</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{% trans 'Task name' %}: </td>
|
||||
<td>{{ execution.automation.name }} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date start' %}: </td>
|
||||
<td>{{ execution.date_start }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date end' %}: </td>
|
||||
<td>{{ execution.date_finished }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time using' %}: </td>
|
||||
<td>{{ execution.duration }}s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Assets count' %}: </td>
|
||||
<td>{{ summary.assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Account count' %}: </td>
|
||||
<td>{{ summary.accounts }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Week password count' %}:</td>
|
||||
<td> <span> {{ summary.weak_password }}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Ok count' %}: </td>
|
||||
<td>{{ summary.ok }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'No password count' %}: </td>
|
||||
<td>{{ summary.no_secret }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Task name' %}:</td>
|
||||
<td>{{ execution.automation.name }} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date start' %}:</td>
|
||||
<td>{{ execution.date_start | date:"Y/m/d H:i:s" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date end' %}:</td>
|
||||
<td>{{ execution.date_finished | date:"Y/m/d H:i:s" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time using' %}:</td>
|
||||
<td>{{ execution.duration }}s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Assets count' %}:</td>
|
||||
<td>{{ summary.assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset success count' %}:</td>
|
||||
<td>{{ summary.ok_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset failed count' %}:</td>
|
||||
<td>{{ summary.fail_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset not support count' %}:</td>
|
||||
<td>{{ summary.error_assets }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{% trans 'Account count' %}:</td>
|
||||
<td>{{ summary.accounts }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Ok count' %}:</td>
|
||||
<td>{{ summary.ok }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'No password count' %}:</td>
|
||||
<td>{{ summary.no_secret }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class='result'>
|
||||
<p>{% trans 'Account check details' %}:</p>
|
||||
<table style="">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
<th>{% trans 'Result' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account in result.weak_password %}
|
||||
{% if summary.weak_password %}
|
||||
<p>{% trans 'Week password' %}: {{ summary.weak_password }}</p>
|
||||
<p>{% trans 'Account check details' %}:</p>
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ account.asset }}</td>
|
||||
<td>{{ account.username }}</td>
|
||||
<td style="color: red">{% trans 'Week password' %}</td>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
<th>{% trans 'Result' %}</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account in result.weak_password %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ account.asset }}</td>
|
||||
<td>{{ account.username }}</td>
|
||||
<td style="color: red">{% trans 'Week password' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -3,129 +3,123 @@
|
|||
<div class='summary'>
|
||||
<p>{% trans 'The following is a summary of the account check tasks. Please review and handle them' %}</p>
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>任务汇总: </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan='2'>任务汇总:</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{% trans 'Task name' %}: </td>
|
||||
<td>{{ execution.automation.name }} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date start' %}: </td>
|
||||
<td>{{ execution.date_start }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date end' %}: </td>
|
||||
<td>{{ execution.date_finished }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time using' %}: </td>
|
||||
<td>{{ execution.duration }}s</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{% trans 'Assets count' %}: </td>
|
||||
<td>{{ summary.total_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset success count' %}: </td>
|
||||
<td>{{ summary.ok_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset failed count' %}: </td>
|
||||
<td>{{ summary.fail_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset not support count' %}: </td>
|
||||
<td>{{ summary.error_assets }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{% trans 'Account new found count' %}: </td>
|
||||
<td>{{ summary.new_accounts }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Account lost count' %}: </td>
|
||||
<td>{{ summary.lost_accounts }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Task name' %}:</td>
|
||||
<td>{{ execution.automation.name }} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date start' %}:</td>
|
||||
<td>{{ execution.date_start | date:"Y/m/d H:i:s" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date end' %}:</td>
|
||||
<td>{{ execution.date_finished | date:"Y/m/d H:i:s" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time using' %}:</td>
|
||||
<td>{{ execution.duration }}s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Assets count' %}:</td>
|
||||
<td>{{ summary.total_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset success count' %}:</td>
|
||||
<td>{{ summary.ok_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset failed count' %}:</td>
|
||||
<td>{{ summary.fail_assets }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset not support count' %}:</td>
|
||||
<td>{{ summary.error_assets }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class='result'>
|
||||
<p>{% trans 'New found accounts' %}: {{ summary.new_accounts }}</p>
|
||||
{% if summary.new_accounts %}
|
||||
<table style="">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account in result.new_accounts %}
|
||||
<p>{% trans 'New found accounts' %}: {{ summary.new_accounts }}</p>
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ account.asset }}</td>
|
||||
<td>{{ account.username }}</td>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account in result.new_accounts %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ account.asset }}</td>
|
||||
<td>{{ account.username }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class='result'>
|
||||
<p>{% trans 'Lost accounts' %}: {{ summary.lost_accounts }}</p>
|
||||
{% if summary.lost_accounts %}
|
||||
<table style="">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account in result.lost_accounts %}
|
||||
<p>{% trans 'Lost accounts' %}: {{ summary.lost_accounts }}</p>
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ account.asset }}</td>
|
||||
<td>{{ account.username }}</td>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account in result.lost_accounts %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ account.asset }}</td>
|
||||
<td>{{ account.username }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
<div class='result'>
|
||||
<p>{% trans 'New found risks' %}: {{ summary.new_risks }}</p>
|
||||
<p>{% trans 'New found risks' %}: {{ summary.new_risks }}</p>
|
||||
{% if summary.new_risks %}
|
||||
<table style="">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
<th>{% trans 'Result' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for risk in result.risks %}
|
||||
<table>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ risk.asset }}</td>
|
||||
<td>{{ risk.username }}</td>
|
||||
<td>{{ risk.risk }}</td>
|
||||
<th>{% trans 'No.' %}</th>
|
||||
<th>{% trans 'Asset' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
<th>{% trans 'Result' %}</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for risk in result.risks %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ risk.asset }}</td>
|
||||
<td>{{ risk.username }}</td>
|
||||
<td>{{ risk.risk }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Reference in New Issue