mirror of https://github.com/jumpserver/jumpserver
Merge branch 'pam' of github.com:jumpserver/jumpserver into pam
commit
707a83ec19
|
@ -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,8 +1,21 @@
|
|||
from django.utils import timezone
|
||||
from datetime import datetime
|
||||
|
||||
__all__ = ['GatherAccountsFilter']
|
||||
|
||||
|
||||
def parse_date(date_str, default=''):
|
||||
if not date_str:
|
||||
return default
|
||||
if date_str == 'Never':
|
||||
return None
|
||||
try:
|
||||
dt = datetime.strptime(date_str, '%Y/%m/%d %H:%M:%S')
|
||||
return timezone.make_aware(dt, timezone.get_current_timezone())
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
|
||||
# TODO 后期会挪到 playbook 中
|
||||
class GatherAccountsFilter:
|
||||
def __init__(self, tp):
|
||||
|
@ -101,11 +114,26 @@ class GatherAccountsFilter:
|
|||
|
||||
@staticmethod
|
||||
def windows_filter(info):
|
||||
info = info[4:-2]
|
||||
result = {}
|
||||
for i in info:
|
||||
for username in i.split():
|
||||
result[username] = {}
|
||||
for user_details in info['user_details']:
|
||||
user_info = {}
|
||||
lines = user_details['stdout_lines']
|
||||
for line in lines:
|
||||
if not line.strip():
|
||||
continue
|
||||
parts = line.split(' ', 1)
|
||||
if len(parts) == 2:
|
||||
key, value = parts
|
||||
user_info[key.strip()] = value.strip()
|
||||
user = {
|
||||
'username': user_info.get('User name', ''),
|
||||
'groups': user_info.get('Global Group memberships', ''),
|
||||
'date_password_change': parse_date(user_info.get('Password last set', '')),
|
||||
'date_password_expired': parse_date(user_info.get('Password expires', '')),
|
||||
'date_last_login': parse_date(user_info.get('Last logon', '')),
|
||||
'can_change_password': user_info.get('User may change password', 'Yes')
|
||||
}
|
||||
result[user['username']] = user
|
||||
return result
|
||||
|
||||
def run(self, method_id_meta_mapper, info):
|
||||
|
|
|
@ -1,14 +1,32 @@
|
|||
- hosts: demo
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Gather windows account
|
||||
ansible.builtin.win_shell: net user
|
||||
register: result
|
||||
ignore_errors: true
|
||||
- name: Run net user command to get all users
|
||||
win_shell: net user
|
||||
register: user_list_output
|
||||
|
||||
- name: Define info by set_fact
|
||||
ansible.builtin.set_fact:
|
||||
info: "{{ result.stdout_lines }}"
|
||||
- name: Parse all users from net user command
|
||||
set_fact:
|
||||
all_users: >-
|
||||
{%- set users = [] -%}
|
||||
{%- for line in user_list_output.stdout_lines -%}
|
||||
{%- if loop.index > 4 and line.strip() != "" and not line.startswith("The command completed") -%}
|
||||
{%- for user in line.split() -%}
|
||||
{%- set _ = users.append(user) -%}
|
||||
{%- endfor -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{{ users }}
|
||||
|
||||
- name: Run net user command for each user to get details
|
||||
win_shell: net user {{ item }}
|
||||
loop: "{{ all_users }}"
|
||||
register: user_details
|
||||
ignore_errors: yes
|
||||
|
||||
- set_fact:
|
||||
info:
|
||||
user_details: "{{ user_details.results }}"
|
||||
|
||||
- debug:
|
||||
var: info
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ class BaseManager:
|
|||
recipients = self.execution.recipients
|
||||
if not recipients:
|
||||
return
|
||||
print("Send report to: ", ",".join(recipients))
|
||||
print("Send report to: ", ",".join([str(u) for u in recipients]))
|
||||
|
||||
report = self.gen_report()
|
||||
report = transform(report)
|
||||
|
|
Loading…
Reference in New Issue